From 71679d03e6b5fc8023e67a007720ae50807138ac Mon Sep 17 00:00:00 2001 From: "ekaterina.itsenko" Date: Thu, 6 Mar 2025 13:53:37 +0100 Subject: [PATCH] [pycharm] PY-79603 Debugger: add threshold settings to combobox (cherry picked from commit f7ab66227b511278fb924d42821aebdeacc4a034) GitOrigin-RevId: 4f205bf426a676ff42e3f61847193c999a5aafb0 --- .../messages/ImagesBundle.properties | 3 +- .../scientific/action/BinarizeImageAction.kt | 44 +------------ .../action/ImageOperationsActionGroup.kt | 66 ++++++++++++++++++- 3 files changed, 67 insertions(+), 46 deletions(-) diff --git a/images/resources/messages/ImagesBundle.properties b/images/resources/messages/ImagesBundle.properties index 0927fd6186c0..06628ead897d 100644 --- a/images/resources/messages/ImagesBundle.properties +++ b/images/resources/messages/ImagesBundle.properties @@ -95,4 +95,5 @@ image.color.mode.grayscale.image=Grayscale image.color.mode.binarize.image=Binarized image.binarize.dialog.title=Set Threshold image.binarize.dialog.message=Please enter a valid integer between 0 and 255. -image.binarize.dialog.invalid=Invalid Input \ No newline at end of file +image.binarize.dialog.invalid=Invalid Input +image.color.mode.configure.actions=Configure... \ No newline at end of file diff --git a/images/src/org/intellij/images/scientific/action/BinarizeImageAction.kt b/images/src/org/intellij/images/scientific/action/BinarizeImageAction.kt index a0805808d62c..8ad6d4f75c03 100644 --- a/images/src/org/intellij/images/scientific/action/BinarizeImageAction.kt +++ b/images/src/org/intellij/images/scientific/action/BinarizeImageAction.kt @@ -7,15 +7,12 @@ import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.CommonDataKeys import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.vfs.writeBytes -import org.intellij.images.ImagesBundle import org.intellij.images.editor.ImageDocument -import org.intellij.images.scientific.ScientificUtils import org.intellij.images.scientific.BinarizationThresholdConfig +import org.intellij.images.scientific.ScientificUtils import java.awt.image.BufferedImage import java.io.ByteArrayOutputStream import javax.imageio.ImageIO -import javax.swing.JOptionPane -import javax.swing.JTextField class BinarizeImageAction : AnAction() { @@ -26,16 +23,8 @@ class BinarizeImageAction : AnAction() { val imageFile = e.getData(CommonDataKeys.VIRTUAL_FILE) ?: return val originalImage = imageFile.getUserData(ScientificUtils.ORIGINAL_IMAGE_KEY) ?: return val thresholdConfig = ApplicationManager.getApplication().getService(BinarizationThresholdConfig::class.java) ?: return - val currentThreshold = thresholdConfig.threshold - val newThreshold = showThresholdDialog(e.project, currentThreshold) - if (newThreshold != null) { - thresholdConfig.threshold = newThreshold - } - else { - return - } val byteArrayOutputStream = ByteArrayOutputStream() - val binarizedImage = applyBinarization(originalImage, newThreshold) + val binarizedImage = applyBinarization(originalImage, thresholdConfig.threshold) ImageIO.write(binarizedImage, ScientificUtils.DEFAULT_IMAGE_FORMAT, byteArrayOutputStream) imageFile.writeBytes(byteArrayOutputStream.toByteArray()) val document = e.getData(ImageDocument.IMAGE_DOCUMENT_DATA_KEY) ?: return @@ -65,33 +54,4 @@ class BinarizeImageAction : AnAction() { } return binarizedImage } - - - private fun showThresholdDialog(project: com.intellij.openapi.project.Project?, initialValue: Int): Int? { - val inputField = JTextField(initialValue.toString()) - val optionPane = JOptionPane( - inputField, - JOptionPane.PLAIN_MESSAGE, - JOptionPane.OK_CANCEL_OPTION - ) - val dialog = optionPane.createDialog(null, ImagesBundle.message("image.binarize.dialog.title")) - dialog.isAlwaysOnTop = true - dialog.isVisible = true - if (optionPane.value == JOptionPane.OK_OPTION) { - val threshold = inputField.text.toIntOrNull() - if (threshold != null && threshold in 0..255) { - return threshold - } - else { - JOptionPane.showMessageDialog( - null, - ImagesBundle.message("image.binarize.dialog.message"), - ImagesBundle.message("image.binarize.dialog.invalid"), - JOptionPane.ERROR_MESSAGE - ) - return showThresholdDialog(project, initialValue) - } - } - return null - } } \ No newline at end of file diff --git a/images/src/org/intellij/images/scientific/action/ImageOperationsActionGroup.kt b/images/src/org/intellij/images/scientific/action/ImageOperationsActionGroup.kt index 24f0c54347cd..dbe1f0759965 100644 --- a/images/src/org/intellij/images/scientific/action/ImageOperationsActionGroup.kt +++ b/images/src/org/intellij/images/scientific/action/ImageOperationsActionGroup.kt @@ -3,11 +3,13 @@ package org.intellij.images.scientific.action import com.intellij.openapi.actionSystem.* import com.intellij.openapi.actionSystem.ex.CustomComponentAction +import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.project.DumbAware import com.intellij.openapi.ui.ComboBox import com.intellij.openapi.ui.popup.JBPopupFactory import com.intellij.openapi.util.registry.Registry import org.intellij.images.ImagesBundle +import org.intellij.images.scientific.BinarizationThresholdConfig import org.intellij.images.scientific.ScientificUtils import java.awt.FlowLayout import javax.swing.* @@ -15,6 +17,7 @@ import javax.swing.* class ImageOperationsActionGroup : DefaultActionGroup(), CustomComponentAction, DumbAware { private var selectedMode: String = ORIGINAL_IMAGE private val availableModes = listOf(ORIGINAL_IMAGE, INVERTED_IMAGE, GRAYSCALE_IMAGE, BINARIZE_IMAGE) + private val CONFIGURE_ACTIONS = ImagesBundle.message("image.color.mode.configure.actions") init { templatePresentation.apply { @@ -48,12 +51,19 @@ class ImageOperationsActionGroup : DefaultActionGroup(), CustomComponentAction, override fun createCustomComponent(presentation: Presentation, place: String): JComponent { selectedMode = ORIGINAL_IMAGE - val comboBox = ComboBox(DefaultComboBoxModel(availableModes.toTypedArray())).apply { + val comboBox = ComboBox(DefaultComboBoxModel((availableModes + CONFIGURE_ACTIONS).toTypedArray())).apply { selectedItem = selectedMode isOpaque = false addActionListener { - selectedMode = selectedItem as String - triggerModeAction(selectedMode) + val selectedItem = selectedItem as String + if (selectedItem == CONFIGURE_ACTIONS) { + openConfigurationDialog() + this.selectedItem = selectedMode + } + else { + selectedMode = selectedItem + triggerModeAction(selectedMode) + } } } return JPanel(FlowLayout(FlowLayout.CENTER, 0, 0)).apply { @@ -69,6 +79,18 @@ class ImageOperationsActionGroup : DefaultActionGroup(), CustomComponentAction, actionGroup.add(InvertChannelsAction()) actionGroup.add(GrayscaleImageAction()) actionGroup.add(BinarizeImageAction()) + actionGroup.addSeparator() + actionGroup.add(object : AnAction(CONFIGURE_ACTIONS) { + override fun actionPerformed(e: AnActionEvent) { + openConfigurationDialog() + } + + + override fun update(e: AnActionEvent) { + e.presentation.isEnabledAndVisible = true + } + }) + return actionGroup } @@ -82,6 +104,44 @@ class ImageOperationsActionGroup : DefaultActionGroup(), CustomComponentAction, } } + private fun openConfigurationDialog() { + val thresholdConfig = ApplicationManager.getApplication().getService(BinarizationThresholdConfig::class.java) ?: return + val currentThreshold = thresholdConfig.threshold + val newThreshold = showThresholdDialog(currentThreshold) + if (newThreshold != null) { + thresholdConfig.threshold = newThreshold + } + } + + private fun showThresholdDialog(initialValue: Int): Int? { + val inputField = JTextField(initialValue.toString()) + val optionPane = JOptionPane( + inputField, + JOptionPane.PLAIN_MESSAGE, + JOptionPane.OK_CANCEL_OPTION + ) + val dialog = optionPane.createDialog(null, ImagesBundle.message("image.binarize.dialog.title")) + dialog.isAlwaysOnTop = true + dialog.isVisible = true + + if (optionPane.value == JOptionPane.OK_OPTION) { + val threshold = inputField.text.toIntOrNull() + if (threshold != null && threshold in 0..255) { + return threshold + } + else { + JOptionPane.showMessageDialog( + null, + ImagesBundle.message("image.binarize.dialog.message"), + ImagesBundle.message("image.binarize.dialog.invalid"), + JOptionPane.ERROR_MESSAGE + ) + return showThresholdDialog(initialValue) + } + } + return null + } + companion object { private val ORIGINAL_IMAGE: String = ImagesBundle.message("image.color.mode.original.image") private val INVERTED_IMAGE: String = ImagesBundle.message("image.color.mode.inverted.image")