From aff8419812d7afa7684a4b79d53203ddaf2d3d4a Mon Sep 17 00:00:00 2001 From: "anna.gromova" Date: Mon, 29 Nov 2021 16:11:40 +0300 Subject: [PATCH] RIDER-70060 shrink by ellipses in middle of configuration name. except info state GitOrigin-RevId: 9b3a394e0269de98024887e13fc1d220f4a7091f --- .../runToolbar/RunToolbarMainSlotActive.kt | 25 +-- .../RunToolbarProcessStartedAction.kt | 189 ++++++++---------- .../RunToolbarRunConfigurationsAction.kt | 117 +++++++++-- .../components/ComboBoxArrowComponent.kt | 83 ++++++++ .../components/TrimmedMiddleLabel.kt | 43 ++++ 5 files changed, 322 insertions(+), 135 deletions(-) create mode 100644 platform/execution-impl/src/com/intellij/execution/runToolbar/components/ComboBoxArrowComponent.kt create mode 100644 platform/execution-impl/src/com/intellij/execution/runToolbar/components/TrimmedMiddleLabel.kt diff --git a/platform/execution-impl/src/com/intellij/execution/runToolbar/RunToolbarMainSlotActive.kt b/platform/execution-impl/src/com/intellij/execution/runToolbar/RunToolbarMainSlotActive.kt index 7c8ae52c96e5..28111f00a55d 100644 --- a/platform/execution-impl/src/com/intellij/execution/runToolbar/RunToolbarMainSlotActive.kt +++ b/platform/execution-impl/src/com/intellij/execution/runToolbar/RunToolbarMainSlotActive.kt @@ -2,6 +2,7 @@ package com.intellij.execution.runToolbar import com.intellij.execution.runToolbar.RunToolbarProcessStartedAction.Companion.PROP_ACTIVE_ENVIRONMENT +import com.intellij.execution.runToolbar.components.TrimmedMiddleLabel import com.intellij.icons.AllIcons import com.intellij.idea.ActionsBundle import com.intellij.openapi.actionSystem.ActionToolbar @@ -62,23 +63,23 @@ class RunToolbarMainSlotActive : SegmentedCustomAction(), RTBarAction { } private class RunToolbarMainSlotActive(presentation: Presentation) : SegmentedCustomPanel(presentation), PopupControllerComponent { - private val arrow = JLabel() + private val arrow = JLabel() - private val setting = object : JLabel() { - override fun getFont(): Font { - return UIUtil.getToolbarFont() - } + private val setting = object : TrimmedMiddleLabel() { + override fun getFont(): Font { + return UIUtil.getToolbarFont() } + } - private val process = object : JLabel() { - override fun getFont(): Font { - return UIUtil.getToolbarFont() - } - }.apply { - foreground = JBColor.namedColor("infoPanelForeground", JBColor(0x808080, 0x8C8C8C)) + private val process = object : JLabel() { + override fun getFont(): Font { + return UIUtil.getToolbarFont() } + }.apply { + foreground = JBColor.namedColor("infoPanelForeground", JBColor(0x808080, 0x8C8C8C)) + } - init { + init { layout = MigLayout("ins 0 0 0 3, fill, ay center") val pane = JPanel().apply { layout = MigLayout("ins 0, fill, novisualpadding, ay center, gap 0", "[pref!][min!]3[shp 1]3[]") diff --git a/platform/execution-impl/src/com/intellij/execution/runToolbar/RunToolbarProcessStartedAction.kt b/platform/execution-impl/src/com/intellij/execution/runToolbar/RunToolbarProcessStartedAction.kt index 4873e6f11855..94302d6b6dc8 100644 --- a/platform/execution-impl/src/com/intellij/execution/runToolbar/RunToolbarProcessStartedAction.kt +++ b/platform/execution-impl/src/com/intellij/execution/runToolbar/RunToolbarProcessStartedAction.kt @@ -1,26 +1,27 @@ // Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.execution.runToolbar +import com.intellij.execution.runToolbar.components.TrimmedMiddleLabel import com.intellij.execution.runners.ExecutionEnvironment import com.intellij.idea.ActionsBundle +import com.intellij.openapi.actionSystem.ActionToolbar import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.DefaultActionGroup import com.intellij.openapi.actionSystem.Presentation import com.intellij.openapi.actionSystem.ex.ComboBoxAction +import com.intellij.openapi.actionSystem.impl.segmentedActionBar.SegmentedCustomPanel import com.intellij.openapi.util.Key -import com.intellij.ui.JBColor -import com.intellij.util.ui.EmptyIcon -import com.intellij.util.ui.JBDimension import com.intellij.util.ui.JBUI import com.intellij.util.ui.UIUtil import net.miginfocom.swing.MigLayout import java.awt.Dimension import java.awt.Font -import java.awt.Insets +import java.awt.event.MouseAdapter +import java.awt.event.MouseEvent import java.beans.PropertyChangeEvent import javax.swing.JComponent import javax.swing.JLabel -import javax.swing.JPanel +import javax.swing.SwingUtilities class RunToolbarProcessStartedAction : ComboBoxAction(), RTRunConfiguration { companion object { @@ -69,99 +70,94 @@ class RunToolbarProcessStartedAction : ComboBoxAction(), RTRunConfiguration { } } - override fun createComboBoxButton(presentation: Presentation): ComboBoxButton { - return object : ComboBoxButton(presentation) { + override fun createCustomComponent(presentation: Presentation, place: String): JComponent { + return object : SegmentedCustomPanel(presentation) { + val PROP_ACTIVE_ENVIRONMENT = Key("PROP_ACTIVE_ENVIRONMENT") - override fun showPopup() { + private val setting = object : TrimmedMiddleLabel() { + override fun getFont(): Font { + return UIUtil.getToolbarFont() + } + } + + private val process = object : JLabel() { + override fun getFont(): Font { + return UIUtil.getToolbarFont() + } + }.apply { + foreground = UIUtil.getLabelInfoForeground() + } + + init { + addMouseListener(object : MouseAdapter() { + override fun mousePressed(e: MouseEvent) { + if (SwingUtilities.isLeftMouseButton(e)) { + e.consume() + if (e.isShiftDown) { + doShiftClick() + } + else { + showPopup() + } + } + else if (SwingUtilities.isRightMouseButton(e)) { + doRightClick() + } + } + }) + + fill() + } + + override fun presentationChanged(event: PropertyChangeEvent) { + setting.icon = presentation.icon + setting.text = presentation.text + + presentation.getClientProperty(RunToolbarProcessStartedAction.PROP_ACTIVE_ENVIRONMENT)?.let { environment -> + environment.getRunToolbarProcess()?.let { + updatePresentation(it) + if (environment.isProcessTerminating()) { + process.text = ActionsBundle.message("action.RunToolbarRemoveSlotAction.terminating") + } + true + } + } + } + + private fun updatePresentation(toolbarProcess: RunToolbarProcess) { + setting.text = presentation.text + setting.icon = presentation.icon + + isEnabled = true + + toolTipText = presentation.description + process.text = toolbarProcess.name + + background = toolbarProcess.pillColor + } + + private fun fill() { + layout = MigLayout("ins 0, novisualpadding, gap 0, fill", "4[shp 1]3[grow]4") + + add(setting, "ay center, pushx, wmin 10") + add(process, "ay center, pushx, wmin 0") + + setting.border = JBUI.Borders.empty() + process.border = JBUI.Borders.empty() + } + + private fun showPopup() { presentation.getClientProperty(PROP_ACTIVE_ENVIRONMENT)?.let { environment -> environment.showToolWindowTab() } } - override fun doRightClick() { - RunToolbarRunConfigurationsAction.doRightClick(dataContext) + private fun doRightClick() { + RunToolbarRunConfigurationsAction.doRightClick(ActionToolbar.getDataContextFor(this)) } - override fun doShiftClick() { - dataContext.editConfiguration() - } - - override fun isArrowVisible(presentation: Presentation): Boolean { - return false - } - - override fun presentationChanged(event: PropertyChangeEvent?) { - isVisible = presentation.getClientProperty(PROP_ACTIVE_ENVIRONMENT)?.let { environment -> - environment.getRunToolbarProcess()?.let { - updatePresentation(it) - if(environment.isProcessTerminating()) { - process.text = ActionsBundle.message("action.RunToolbarRemoveSlotAction.terminating") - } - true - } - - } ?: false - } - - private fun updatePresentation(it: RunToolbarProcess) { - setting.text = presentation.text - presentation.icon?.let { - icon = it - setting.icon = EmptyIcon.create(it.iconWidth).withIconPreScaled(true) - } ?: run { - setting.icon = null - icon = null - } - - isEnabled = true - - toolTipText = presentation.description - process.text = it.name - putClientProperty("JButton.backgroundColor", it.pillColor) - } - - private val setting = object : JLabel() { - override fun getFont(): Font? { - return if (isSmallVariant) UIUtil.getToolbarFont() else UIUtil.getLabelFont() - } - }.apply { - minimumSize = JBDimension(JBUI.scale(110), minHeight, true) - } - private val process = object : JLabel() { - override fun getFont(): Font? { - return if (isSmallVariant) UIUtil.getToolbarFont() else UIUtil.getLabelFont() - } - }.apply { - foreground = JBColor.namedColor("infoPanelForeground", JBColor(0x808080, 0x8C8C8C)) - minimumSize = JBDimension(JBUI.scale(40), minHeight, true) - } - - private val pane = object : JPanel(){ - override fun getInsets(): Insets { - return JBUI.insets(0, 0, 0, 3) - } - }.apply { - layout = MigLayout("ins 0, fill, novisualpadding", "4[shp 1]3[]") - - add(setting, "ay center, pushx, wmin 10") - add(process, "ay center, pushx, wmin 0") - - // setting.font = UIUtil.getToolbarFont() - process.font = UIUtil.getToolbarFont() - - setting.border = JBUI.Borders.empty() - process.border = JBUI.Borders.empty() - - isOpaque = false - } - - init { - layout = MigLayout("ins 0, fill") - add(pane) - text = null - - - // border = JBUI.Borders.empty() + private fun doShiftClick() { + ActionToolbar.getDataContextFor(this).editConfiguration() } override fun getPreferredSize(): Dimension { @@ -169,19 +165,6 @@ class RunToolbarProcessStartedAction : ComboBoxAction(), RTRunConfiguration { d.width = FixWidthSegmentedActionToolbarComponent.RUN_CONFIG_WIDTH return d } - - -/* override fun doShiftClick() { - val context = DataManager.getInstance().getDataContext(this) - val project = CommonDataKeys.PROJECT.getData(context) - if (project != null && !ActionUtil.isDumbMode(project)) { - EditConfigurationsDialog(project).show() - return - } - super.doShiftClick() - }*/ } } - - } \ No newline at end of file diff --git a/platform/execution-impl/src/com/intellij/execution/runToolbar/RunToolbarRunConfigurationsAction.kt b/platform/execution-impl/src/com/intellij/execution/runToolbar/RunToolbarRunConfigurationsAction.kt index fe5b9fbe139c..56f945bd4e63 100644 --- a/platform/execution-impl/src/com/intellij/execution/runToolbar/RunToolbarRunConfigurationsAction.kt +++ b/platform/execution-impl/src/com/intellij/execution/runToolbar/RunToolbarRunConfigurationsAction.kt @@ -3,15 +3,31 @@ package com.intellij.execution.runToolbar import com.intellij.execution.* import com.intellij.execution.actions.RunConfigurationsComboBoxAction +import com.intellij.execution.impl.EditConfigurationsDialog +import com.intellij.execution.runToolbar.components.ComboBoxArrowComponent +import com.intellij.execution.runToolbar.components.TrimmedMiddleLabel +import com.intellij.ide.DataManager +import com.intellij.ide.HelpTooltip import com.intellij.idea.ActionsBundle import com.intellij.openapi.actionSystem.* +import com.intellij.openapi.actionSystem.ex.ActionUtil +import com.intellij.openapi.actionSystem.impl.segmentedActionBar.SegmentedCustomPanel import com.intellij.openapi.project.DumbAwareAction import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.popup.JBPopup import com.intellij.openapi.ui.popup.JBPopupFactory -import com.intellij.ui.scale.JBUIScale +import com.intellij.openapi.util.registry.Registry +import com.intellij.openapi.wm.IdeFocusManager +import com.intellij.ui.Gray +import com.intellij.ui.JBColor import com.intellij.util.ui.JBUI +import com.intellij.util.ui.UIUtil +import net.miginfocom.swing.MigLayout import java.awt.Dimension -import java.awt.Insets +import java.awt.Font +import java.awt.event.MouseAdapter +import java.awt.event.MouseEvent +import java.beans.PropertyChangeEvent import javax.swing.JComponent import javax.swing.SwingUtilities @@ -72,30 +88,91 @@ open class RunToolbarRunConfigurationsAction : RunConfigurationsComboBoxAction() } override fun createCustomComponent(presentation: Presentation, place: String): JComponent { - return object : RunConfigurationsComboBoxButton(presentation) { + return object : SegmentedCustomPanel(presentation) { + private val setting = object : TrimmedMiddleLabel() { + override fun getFont(): Font { + return UIUtil.getToolbarFont() + } + } + private val arrow = ComboBoxArrowComponent().getView() - override fun getPreferredSize(): Dimension? { + init { + addMouseListener(object : MouseAdapter() { + override fun mousePressed(e: MouseEvent) { + if (SwingUtilities.isLeftMouseButton(e)) { + e.consume() + if (e.isShiftDown) { + doShiftClick() + } + else { + doClick() + } + } + else if (SwingUtilities.isRightMouseButton(e)) { + doRightClick() + } + } + }) + + fill() + + background = JBColor.namedColor("ComboBoxButton.background", Gray.xDF) + } + + override fun presentationChanged(event: PropertyChangeEvent) { + setting.icon = presentation.icon + setting.text = presentation.text + + isEnabled = true + + toolTipText = presentation.description + } + + private fun fill() { + layout = MigLayout("ins 0, novisualpadding, gap 0, fill, hidemode 3", "4[][min!]2") + + add(setting, "ay center, growx, wmin 10") + add(arrow) + + setting.border = JBUI.Borders.empty() + } + + private fun doRightClick() { + RunToolbarRunConfigurationsAction.doRightClick(ActionToolbar.getDataContextFor(this)) + } + + private fun doClick() { + IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown { showPopup() } + } + + fun showPopup() { + val popup: JBPopup = createPopup() {} + + if (Registry.`is`("ide.helptooltip.enabled")) { + HelpTooltip.setMasterPopup(this, popup) + } + popup.showUnderneathOf(this) + } + + private fun createPopup(onDispose: Runnable): JBPopup { + return createActionPopup(ActionToolbar.getDataContextFor(this), this, onDispose) + } + + private fun doShiftClick() { + val context = DataManager.getInstance().getDataContext(this) + val project = CommonDataKeys.PROJECT.getData(context) + if (project != null && !ActionUtil.isDumbMode(project)) { + EditConfigurationsDialog(project).show() + return + } + } + + override fun getPreferredSize(): Dimension { val d = super.getPreferredSize() d.width = FixWidthSegmentedActionToolbarComponent.RUN_CONFIG_WIDTH return d } - - override fun getArrowGap(): Int { - return JBUIScale.scale(5) - } - - override fun getMargin(): Insets { - return JBUI.insets(0, 8, 0, 8) - } - - override fun doRightClick() { - doRightClick(dataContext) - } - - override fun doShiftClick() { - dataContext.editConfiguration() - } } } diff --git a/platform/execution-impl/src/com/intellij/execution/runToolbar/components/ComboBoxArrowComponent.kt b/platform/execution-impl/src/com/intellij/execution/runToolbar/components/ComboBoxArrowComponent.kt new file mode 100644 index 000000000000..3730468e52bf --- /dev/null +++ b/platform/execution-impl/src/com/intellij/execution/runToolbar/components/ComboBoxArrowComponent.kt @@ -0,0 +1,83 @@ +// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.execution.runToolbar.components + +import com.intellij.icons.AllIcons +import com.intellij.openapi.util.IconLoader +import com.intellij.ui.scale.JBUIScale +import com.intellij.util.ui.JBUI +import com.intellij.util.ui.UIUtil +import java.awt.Component +import java.awt.Graphics +import java.awt.Graphics2D +import java.awt.RenderingHints +import java.awt.geom.Path2D +import javax.swing.Icon +import javax.swing.JComponent +import javax.swing.JLabel +import javax.swing.UIManager + +class ComboBoxArrowComponent { + fun getView(): JComponent = label + + + val label = object : JLabel() { + private val defaultIcon = ComboBoxArrowIcon() + + init { + updateIcon() + } + + override fun setEnabled(enabled: Boolean) { + super.setEnabled(enabled) + updateIcon() + } + + private fun updateIcon() { + /** according to { @see com.intellij.openapi.actionSystem.ex.ComboBoxAction.ComboBoxButton.MyButtonModel } logic */ + icon = if (UIUtil.isUnderWin10LookAndFeel()) { + if (isEnabled) { + UIManager.getIcon("ComboBoxButton.arrowIcon") ?: AllIcons.General.ArrowDown + } + else { + UIManager.getIcon("ComboBoxButton.arrowIconDisabled") ?: IconLoader.getDisabledIcon(AllIcons.General.ArrowDown) + } + } + else defaultIcon + } + } +} + +private class ComboBoxArrowIcon : Icon { + val iconSize: Int + get() = JBUIScale.scale(16) + + override fun paintIcon(c: Component, g: Graphics, x: Int, y: Int) { + val g2 = g.create() as Graphics2D + + try { + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON) + g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE) + + g2.color = JBUI.CurrentTheme.Arrow.foregroundColor(c.isEnabled) + + val arrow: Path2D = Path2D.Float(Path2D.WIND_EVEN_ODD) + arrow.moveTo(JBUIScale.scale(3.5f).toDouble(), JBUIScale.scale(6f).toDouble()) + arrow.lineTo(JBUIScale.scale(12.5f).toDouble(), JBUIScale.scale(6f).toDouble()) + arrow.lineTo(JBUIScale.scale(8f).toDouble(), JBUIScale.scale(11f).toDouble()) + arrow.closePath() + + g2.fill(arrow) + } + finally { + g2.dispose(); + } + } + + override fun getIconWidth(): Int { + return iconSize + } + + override fun getIconHeight(): Int { + return iconSize + } +} \ No newline at end of file diff --git a/platform/execution-impl/src/com/intellij/execution/runToolbar/components/TrimmedMiddleLabel.kt b/platform/execution-impl/src/com/intellij/execution/runToolbar/components/TrimmedMiddleLabel.kt new file mode 100644 index 000000000000..c96458cb9f34 --- /dev/null +++ b/platform/execution-impl/src/com/intellij/execution/runToolbar/components/TrimmedMiddleLabel.kt @@ -0,0 +1,43 @@ +// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.execution.runToolbar.components + +import com.intellij.ide.ui.UISettings +import com.intellij.openapi.util.text.StringUtil +import java.awt.Graphics +import java.awt.Graphics2D +import javax.swing.JLabel + +open class TrimmedMiddleLabel : JLabel() { + override fun paintComponent(g: Graphics) { + val fm = g.getFontMetrics(g.font) + g as Graphics2D + UISettings.setupAntialiasing(g) + val textW = fm.stringWidth(text) + var availableWidth = width - insets.right - insets.left + var x = insets.left + icon?.let { + x += iconTextGap + it.iconWidth + } + + if (textW < availableWidth) { + super.paintComponent(g) + } + else { + icon?.let { + icon.paintIcon(this, g, insets.left, 0) + } + availableWidth -= (x + fm.stringWidth(StringUtil.ELLIPSIS)) + + val charArray = text.toCharArray() + val stringLength = charArray.size + var w = 0 + for (nChars in 0 until stringLength) { + w += fm.charWidth(charArray[nChars]) + if (w > availableWidth) { + g.drawString(StringUtil.trimMiddle(text, nChars - 1), x, fm.ascent) + return + } + } + } + } +} \ No newline at end of file