/* * Copyright 2000-2009 JetBrains s.r.o. * Copyright 2013-2016 consulo.io * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package consulo.actionSystem.ex; import com.intellij.icons.AllIcons; import com.intellij.ide.ui.UISettings; import com.intellij.openapi.actionSystem.ex.ComboBoxAction; import com.intellij.openapi.actionSystem.ex.ComboBoxButton; import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.ColorUtil; import com.intellij.ui.Gray; import com.intellij.ui.JBColor; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.MouseEventAdapter; import com.intellij.util.ui.UIUtil; import javax.swing.*; import javax.swing.border.AbstractBorder; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicButtonUI; import java.awt.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionListener; /** * @author VISTALL * @since 25-Oct-16 * <p> * This is extract paint code from {@link com.intellij.openapi.actionSystem.ex.ComboBoxButton} */ public class ComboBoxButtonUI extends BasicButtonUI { protected boolean myMouseInside; public static ComponentUI createUI(JComponent c) { return new ComboBoxButtonUI((ComboBoxButton)c); } public ComboBoxButtonUI(ComboBoxButton comboBoxButton) { comboBoxButton.addMouseListener(new MouseAdapter() { @Override public void mouseEntered(MouseEvent e) { myMouseInside = true; comboBoxButton.repaint(); } @Override public void mouseExited(MouseEvent e) { myMouseInside = false; comboBoxButton.repaint(); } @Override public void mousePressed(final MouseEvent e) { if (SwingUtilities.isLeftMouseButton(e)) { e.consume(); comboBoxButton.doClick(); } } @Override public void mouseReleased(MouseEvent e) { dispatchEventToPopup(comboBoxButton, e); } }); comboBoxButton.addMouseMotionListener(new MouseMotionListener() { @Override public void mouseDragged(MouseEvent e) { mouseMoved( MouseEventAdapter.convert(e, e.getComponent(), MouseEvent.MOUSE_MOVED, e.getWhen(), e.getModifiers() | e.getModifiersEx(), e.getX(), e.getY())); } @Override public void mouseMoved(MouseEvent e) { dispatchEventToPopup(comboBoxButton, e); } }); setupBorder(comboBoxButton); } protected void setupBorder(ComboBoxButton comboBoxButton) { comboBoxButton.setBorder(new AbstractBorder() { @Override public Insets getBorderInsets(Component c) { final Insets insets = super.getBorderInsets(c); //noinspection UseDPIAwareInsets return new Insets(insets.top, insets.left + JBUI.scale(2), insets.bottom, insets.right + JBUI.scale(2) + getArrowIcon().getIconWidth()); } }); } public static Icon getArrowIcon() { return UIUtil.isUnderDarkBuildInLaf() ? AllIcons.General.ComboArrow : AllIcons.General.ComboBoxButtonArrow; } public static Icon getDisabledArrowIcon() { return IconLoader.getDisabledIcon(getArrowIcon()); } // Event forwarding. We need it if user does press-and-drag gesture for opening popup and choosing item there. // It works in JComboBox, here we provide the same behavior private void dispatchEventToPopup(ComboBoxButton comboBoxButton, MouseEvent e) { JBPopup popup = comboBoxButton.getPopup(); if (popup != null && popup.isVisible()) { JComponent content = popup.getContent(); Rectangle rectangle = content.getBounds(); Point location = rectangle.getLocation(); SwingUtilities.convertPointToScreen(location, content); Point eventPoint = e.getLocationOnScreen(); rectangle.setLocation(location); if (rectangle.contains(eventPoint)) { MouseEvent event = SwingUtilities.convertMouseEvent(e.getComponent(), e, popup.getContent()); Component component = SwingUtilities.getDeepestComponentAt(content, event.getX(), event.getY()); if (component != null) component.dispatchEvent(event); } } } @Override public Dimension getMinimumSize(JComponent c) { return new Dimension(super.getMinimumSize(c).width, getPreferredSize(c).height); } @Override public Dimension getPreferredSize(JComponent c) { ComboBoxButton comboBoxButton = (ComboBoxButton)c; ComboBoxAction comboBoxAction = comboBoxButton.getComboBoxAction(); final boolean isEmpty = comboBoxButton.getIcon() == null && StringUtil.isEmpty(comboBoxButton.getText()); int width = isEmpty ? JBUI.scale(10) + getArrowIcon().getIconWidth() : super.getPreferredSize(c).width; if (comboBoxAction.isSmallVariant()) width += JBUI.scale(4); return new Dimension(width, comboBoxAction.isSmallVariant() ? JBUI.scale(19) : super.getPreferredSize(c).height); } @Override public void paint(Graphics g, JComponent c) { ComboBoxButton comboBoxButton = (ComboBoxButton)c; ComboBoxAction comboBoxAction = comboBoxButton.getComboBoxAction(); UISettings.setupAntialiasing(g); final Dimension size = comboBoxButton.getSize(); final boolean isEmpty = comboBoxButton.getIcon() == null && StringUtil.isEmpty(comboBoxButton.getText()); final Color textColor = comboBoxButton.isEnabled() ? UIManager.getColor("Panel.foreground") : UIUtil.getInactiveTextColor(); if (comboBoxButton.isForceTransparent()) { final Icon icon = comboBoxButton.getIcon(); int x = 7; if (icon != null) { icon.paintIcon(c, g, x, (size.height - icon.getIconHeight()) / 2); x += icon.getIconWidth() + 3; } if (!StringUtil.isEmpty(comboBoxButton.getText())) { final Font font = comboBoxButton.getFont(); g.setFont(font); g.setColor(textColor); g.drawString(comboBoxButton.getText(), x, (size.height + font.getSize()) / 2 - 1); } } else { if (comboBoxAction.isSmallVariant()) { final Graphics2D g2 = (Graphics2D)g; g2.setColor(UIUtil.getControlColor()); final int w = comboBoxButton.getWidth(); final int h = comboBoxButton.getHeight(); if (comboBoxButton.getModel().isArmed() && comboBoxButton.getModel().isPressed()) { g2.setPaint(UIUtil.getGradientPaint(0, 0, UIUtil.getControlColor(), 0, h, ColorUtil.shift(UIUtil.getControlColor(), 0.8))); } else { if (UIUtil.isUnderDarcula()) { g2.setPaint(UIUtil.getGradientPaint(0, 0, ColorUtil.shift(UIUtil.getControlColor(), 1.1), 0, h, ColorUtil.shift(UIUtil.getControlColor(), 0.9))); } else { g2.setPaint(UIUtil.getGradientPaint(0, 0, new JBColor(SystemInfo.isMac ? Gray._226 : Gray._245, Gray._131), 0, h, new JBColor(SystemInfo.isMac ? Gray._198 : Gray._208, Gray._128))); } } g2.fillRoundRect(2, 0, w - 2, h, 5, 5); Color borderColor = myMouseInside ? new JBColor(Gray._111, Gray._118) : new JBColor(Gray._151, Gray._95); g2.setPaint(borderColor); g2.drawRoundRect(2, 0, w - 3, h - 1, 5, 5); final Icon icon = comboBoxButton.getIcon(); int x = 7; if (icon != null) { icon.paintIcon(c, g, x, (size.height - icon.getIconHeight()) / 2); x += icon.getIconWidth() + 3; } if (!StringUtil.isEmpty(comboBoxButton.getText())) { final Font font = comboBoxButton.getFont(); g2.setFont(font); g2.setColor(textColor); g2.drawString(comboBoxButton.getText(), x, (size.height + font.getSize()) / 2 - 1); } } else { super.paint(g, c); } } final Insets insets = comboBoxButton.insets(); // FIXME [VISTALL] we need this ? final Icon icon = comboBoxButton.isEnabled() ? getArrowIcon() : getDisabledArrowIcon(); final int x; if (isEmpty) { x = (size.width - icon.getIconWidth()) / 2; } else { if (comboBoxAction.isSmallVariant()) { x = size.width - icon.getIconWidth() - insets.right + 1; } else { x = size.width - icon.getIconWidth() - insets.right + (UIUtil.isUnderNimbusLookAndFeel() ? -3 : 2); } } icon.paintIcon(null, g, x, (size.height - icon.getIconHeight()) / 2); g.setPaintMode(); } }