From f6559434fca4de4d707bd027f81f9924ab630c58 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Sun, 11 May 2014 19:33:56 +0200 Subject: [PATCH] CheckBox and RadioButton menu items --- src/com/bulenkov/darcula/DarculaLaf.java | 3 + src/com/bulenkov/darcula/darcula.properties | 6 + .../darcula/ui/DarculaCheckBoxMenuItemUI.java | 77 +++++++ .../darcula/ui/DarculaMenuItemUIBase.java | 209 ++++++++++++++++++ .../ui/DarculaRadioButtonMenuItemUI.java | 86 +++++++ 5 files changed, 381 insertions(+) create mode 100644 src/com/bulenkov/darcula/ui/DarculaCheckBoxMenuItemUI.java create mode 100644 src/com/bulenkov/darcula/ui/DarculaMenuItemUIBase.java create mode 100644 src/com/bulenkov/darcula/ui/DarculaRadioButtonMenuItemUI.java diff --git a/src/com/bulenkov/darcula/DarculaLaf.java b/src/com/bulenkov/darcula/DarculaLaf.java index 9380dd3..76f99b1 100755 --- a/src/com/bulenkov/darcula/DarculaLaf.java +++ b/src/com/bulenkov/darcula/DarculaLaf.java @@ -18,6 +18,7 @@ package com.bulenkov.darcula; import com.bulenkov.iconloader.IconLoader; import com.bulenkov.iconloader.util.ColorUtil; +import com.bulenkov.iconloader.util.EmptyIcon; import com.bulenkov.iconloader.util.StringUtil; import com.bulenkov.iconloader.util.SystemInfo; import sun.awt.AppContext; @@ -95,6 +96,8 @@ public final class DarculaLaf extends BasicLookAndFeel { defaults.put("Spinner.arrowButtonSize", new Dimension(16, 5)); defaults.put("Tree.collapsedIcon", new IconUIResource(IconLoader.getIcon("/com/bulenkov/darcula/icons/treeNodeCollapsed.png"))); defaults.put("Tree.expandedIcon", new IconUIResource(IconLoader.getIcon("/com/bulenkov/darcula/icons/treeNodeExpanded.png"))); + defaults.put("CheckBoxMenuItem.checkIcon", EmptyIcon.create(16)); + defaults.put("RadioButtonMenuItem.checkIcon", EmptyIcon.create(16)); return defaults; } diff --git a/src/com/bulenkov/darcula/darcula.properties b/src/com/bulenkov/darcula/darcula.properties index 9d029a7..99c2556 100755 --- a/src/com/bulenkov/darcula/darcula.properties +++ b/src/com/bulenkov/darcula/darcula.properties @@ -114,6 +114,9 @@ CheckBox.darcula.focusedArmed.backgroundColor2=373737 CheckBox.darcula.focused.backgroundColor1=787878 CheckBox.darcula.focused.backgroundColor2=4b4b4b +CheckBoxMenuItemUI=com.bulenkov.darcula.ui.DarculaCheckBoxMenuItemUI +CheckBoxMenuItem.borderPainted=false + ComboBoxUI=com.bulenkov.darcula.ui.DarculaComboBoxUI ComboBox.disabledBackground=3c3f41 ComboBox.squareButton=false @@ -124,6 +127,9 @@ RadioButton.darcula.selectionDisabledColor=787878 RadioButton.darcula.selectionEnabledShadowColor=1e1e1e RadioButton.darcula.selectionDisabledShadowColor=3c3c3c +RadioButtonMenuItemUI=com.bulenkov.darcula.ui.DarculaRadioButtonMenuItemUI +RadioButtonMenuItem.borderPainted=false + StatusBar.topColor=2c2c2c StatusBar.top2Color=2c2c2c StatusBar.bottomColor=2c2c2c diff --git a/src/com/bulenkov/darcula/ui/DarculaCheckBoxMenuItemUI.java b/src/com/bulenkov/darcula/ui/DarculaCheckBoxMenuItemUI.java new file mode 100644 index 0000000..b5aa69d --- /dev/null +++ b/src/com/bulenkov/darcula/ui/DarculaCheckBoxMenuItemUI.java @@ -0,0 +1,77 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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 com.bulenkov.darcula.ui; + +import com.bulenkov.iconloader.util.GraphicsConfig; +import com.bulenkov.iconloader.util.Gray; +import com.bulenkov.iconloader.util.UIUtil; +import sun.swing.MenuItemLayoutHelper; + +import javax.swing.*; +import javax.swing.plaf.ComponentUI; +import java.awt.*; + +/** + * @author Konstantin Bulenkov + */ +public class DarculaCheckBoxMenuItemUI extends DarculaMenuItemUIBase { + + @SuppressWarnings({"MethodOverridesStaticMethodOfSuperclass", "UnusedDeclaration"}) + public static ComponentUI createUI(JComponent c) { + return new DarculaCheckBoxMenuItemUI(); + } + + protected String getPropertyPrefix() { + return "CheckBoxMenuItem"; + } + + @Override + protected void paintCheckIcon(Graphics g2, MenuItemLayoutHelper lh, MenuItemLayoutHelper.LayoutResult lr, Color holdc, Color foreground) { + Graphics2D g = (Graphics2D) g2; + final GraphicsConfig config = new GraphicsConfig(g); + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_DEFAULT); + + g.translate(lr.getCheckRect().x+2, lr.getCheckRect().y+2); + + final int sz = 13; + g.setPaint(new GradientPaint(sz / 2, 1, Gray._110, sz / 2, sz, Gray._95)); + g.fillRoundRect(0, 0, sz, sz - 1 , 4, 4); + + g.setPaint(new GradientPaint(sz / 2, 1, Gray._120.withAlpha(0x5a), sz / 2, sz, Gray._105.withAlpha(90))); + g.drawRoundRect(0, (UIUtil.isUnderDarcula() ? 1 : 0), sz, sz - 1, 4, 4); + + g.setPaint(Gray._40.withAlpha(180)); + g.drawRoundRect(0, 0, sz, sz - 1, 4, 4); + + + if (lh.getMenuItem().isSelected()) { + g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); + g.setStroke(new BasicStroke(2.0f, BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND)); + g.setPaint(Gray._30); + g.drawLine(4, 7, 7, 10); + g.drawLine(7, 10, sz, 2); + g.setPaint(Gray._170); + g.drawLine(4, 5, 7, 8); + g.drawLine(7, 8, sz, 0); + } + + g.translate(-lr.getCheckRect().x-2, -lr.getCheckRect().y-2); + config.restore(); + g.setColor(foreground); + } +} diff --git a/src/com/bulenkov/darcula/ui/DarculaMenuItemUIBase.java b/src/com/bulenkov/darcula/ui/DarculaMenuItemUIBase.java new file mode 100644 index 0000000..759417e --- /dev/null +++ b/src/com/bulenkov/darcula/ui/DarculaMenuItemUIBase.java @@ -0,0 +1,209 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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 com.bulenkov.darcula.ui; + +import sun.swing.MenuItemLayoutHelper; +import sun.swing.SwingUtilities2; + +import javax.swing.*; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicMenuItemUI; +import java.awt.*; +import java.awt.event.MouseEvent; + +/** + * @author Konstantin Bulenkov + */ +public class DarculaMenuItemUIBase extends BasicMenuItemUI { + @SuppressWarnings({"MethodOverridesStaticMethodOfSuperclass", "UnusedDeclaration"}) + public static ComponentUI createUI(JComponent c) { + return new DarculaMenuItemUIBase(); + } + + public void processMouseEvent(JMenuItem item, MouseEvent e, MenuElement path[], MenuSelectionManager manager) { + Point p = e.getPoint(); + if (p.x >= 0 && p.x < item.getWidth() && + p.y >= 0 && p.y < item.getHeight()) { + if (e.getID() == MouseEvent.MOUSE_RELEASED) { + manager.clearSelectedPath(); + item.doClick(0); + item.setArmed(false); + } else + manager.setSelectedPath(path); + } else if (item.getModel().isArmed()) { + MenuElement newPath[] = new MenuElement[path.length - 1]; + int i, c; + for (i = 0, c = path.length - 1; i < c; i++) + newPath[i] = path[i]; + manager.setSelectedPath(newPath); + } + } + + protected void paintMenuItem(Graphics g, JComponent c, + Icon checkIcon, Icon arrowIcon, + Color background, Color foreground, + int defaultTextIconGap) { + // Save original graphics font and color + Font holdf = g.getFont(); + Color holdc = g.getColor(); + + JMenuItem mi = (JMenuItem) c; + g.setFont(mi.getFont()); + + Rectangle viewRect = new Rectangle(0, 0, mi.getWidth(), mi.getHeight()); + applyInsets(viewRect, mi.getInsets()); + + MenuItemLayoutHelper lh = new MenuItemLayoutHelper(mi, checkIcon, + arrowIcon, viewRect, defaultTextIconGap, acceleratorDelimiter, + mi.getComponentOrientation().isLeftToRight(), mi.getFont(), + acceleratorFont, MenuItemLayoutHelper.useCheckAndArrow(menuItem), + getPropertyPrefix()); + MenuItemLayoutHelper.LayoutResult lr = lh.layoutMenuItem(); + + paintBackground(g, mi, background); + paintCheckIcon(g, lh, lr, holdc, foreground); + paintIcon(g, lh, lr, holdc); + g.setColor(foreground); + paintText(g, lh, lr); + paintAccText(g, lh, lr); + paintArrowIcon(g, lh, lr, foreground); + + // Restore original graphics font and color + g.setColor(holdc); + g.setFont(holdf); + } + + protected void paintIcon(Graphics g, MenuItemLayoutHelper lh, + MenuItemLayoutHelper.LayoutResult lr, Color holdc) { + if (lh.getIcon() != null) { + Icon icon; + ButtonModel model = lh.getMenuItem().getModel(); + if (!model.isEnabled()) { + icon = lh.getMenuItem().getDisabledIcon(); + } else if (model.isPressed() && model.isArmed()) { + icon = lh.getMenuItem().getPressedIcon(); + if (icon == null) { + // Use default icon + icon = lh.getMenuItem().getIcon(); + } + } else { + icon = lh.getMenuItem().getIcon(); + } + + if (icon != null) { + icon.paintIcon(lh.getMenuItem(), g, lr.getIconRect().x, + lr.getIconRect().y); + g.setColor(holdc); + } + } + } + + protected void paintCheckIcon(Graphics g, MenuItemLayoutHelper lh, + MenuItemLayoutHelper.LayoutResult lr, + Color holdc, Color foreground) { + if (lh.getCheckIcon() != null) { + ButtonModel model = lh.getMenuItem().getModel(); + if (model.isArmed() || (lh.getMenuItem() instanceof JMenu + && model.isSelected())) { + g.setColor(foreground); + } else { + g.setColor(holdc); + } + if (lh.useCheckAndArrow()) { + lh.getCheckIcon().paintIcon(lh.getMenuItem(), g, + lr.getCheckRect().x, lr.getCheckRect().y); + } + g.setColor(holdc); + } + } + + protected void paintAccText(Graphics g, MenuItemLayoutHelper lh, + MenuItemLayoutHelper.LayoutResult lr) { + if (!lh.getAccText().equals("")) { + ButtonModel model = lh.getMenuItem().getModel(); + g.setFont(lh.getAccFontMetrics().getFont()); + if (!model.isEnabled()) { + // *** paint the accText disabled + if (disabledForeground != null) { + g.setColor(disabledForeground); + SwingUtilities2.drawString(lh.getMenuItem(), g, + lh.getAccText(), lr.getAccRect().x, + lr.getAccRect().y + lh.getAccFontMetrics().getAscent()); + } else { + g.setColor(lh.getMenuItem().getBackground().brighter()); + SwingUtilities2.drawString(lh.getMenuItem(), g, + lh.getAccText(), lr.getAccRect().x, + lr.getAccRect().y + lh.getAccFontMetrics().getAscent()); + g.setColor(lh.getMenuItem().getBackground().darker()); + SwingUtilities2.drawString(lh.getMenuItem(), g, + lh.getAccText(), lr.getAccRect().x - 1, + lr.getAccRect().y + lh.getFontMetrics().getAscent() - 1); + } + } else { + // *** paint the accText normally + if (model.isArmed() + || (lh.getMenuItem() instanceof JMenu + && model.isSelected())) { + g.setColor(acceleratorSelectionForeground); + } else { + g.setColor(acceleratorForeground); + } + SwingUtilities2.drawString(lh.getMenuItem(), g, lh.getAccText(), + lr.getAccRect().x, lr.getAccRect().y + + lh.getAccFontMetrics().getAscent()); + } + } + } + + protected void paintText(Graphics g, MenuItemLayoutHelper lh, + MenuItemLayoutHelper.LayoutResult lr) { + if (!lh.getText().equals("")) { + if (lh.getHtmlView() != null) { + // Text is HTML + lh.getHtmlView().paint(g, lr.getTextRect()); + } else { + // Text isn't HTML + paintText(g, lh.getMenuItem(), lr.getTextRect(), lh.getText()); + } + } + } + + protected void paintArrowIcon(Graphics g, MenuItemLayoutHelper lh, + MenuItemLayoutHelper.LayoutResult lr, + Color foreground) { + if (lh.getArrowIcon() != null) { + ButtonModel model = lh.getMenuItem().getModel(); + if (model.isArmed() || (lh.getMenuItem() instanceof JMenu + && model.isSelected())) { + g.setColor(foreground); + } + if (lh.useCheckAndArrow()) { + lh.getArrowIcon().paintIcon(lh.getMenuItem(), g, + lr.getArrowRect().x, lr.getArrowRect().y); + } + } + } + + protected void applyInsets(Rectangle rect, Insets insets) { + if(insets != null) { + rect.x += insets.left; + rect.y += insets.top; + rect.width -= (insets.right + rect.x); + rect.height -= (insets.bottom + rect.y); + } + } +} diff --git a/src/com/bulenkov/darcula/ui/DarculaRadioButtonMenuItemUI.java b/src/com/bulenkov/darcula/ui/DarculaRadioButtonMenuItemUI.java new file mode 100644 index 0000000..7cde499 --- /dev/null +++ b/src/com/bulenkov/darcula/ui/DarculaRadioButtonMenuItemUI.java @@ -0,0 +1,86 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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 com.bulenkov.darcula.ui; + +import com.bulenkov.iconloader.util.ColorUtil; +import com.bulenkov.iconloader.util.GraphicsConfig; +import com.bulenkov.iconloader.util.Gray; +import sun.swing.MenuItemLayoutHelper; + +import javax.swing.*; +import javax.swing.plaf.ComponentUI; +import java.awt.*; + +/** + * @author Konstantin Bulenkov + */ +public class DarculaRadioButtonMenuItemUI extends DarculaMenuItemUIBase { + @SuppressWarnings({"MethodOverridesStaticMethodOfSuperclass", "UnusedDeclaration"}) + public static ComponentUI createUI(JComponent c) { + return new DarculaRadioButtonMenuItemUI(); + } + + protected String getPropertyPrefix() { + return "RadioButtonMenuItem"; + } + + @Override + protected void paintCheckIcon(Graphics g2, MenuItemLayoutHelper lh, MenuItemLayoutHelper.LayoutResult lr, Color holdc, Color foreground) { + Graphics2D g = (Graphics2D) g2; + final GraphicsConfig config = new GraphicsConfig(g); + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_DEFAULT); + + g.translate(lr.getCheckRect().x+1, lr.getCheckRect().y+1); + + int rad = 5; + + final int x = 0; + final int y = 0; + final int w = 13; + final int h = 13; + + g.translate(x, y); + + //setup AA for lines + Color bg = lh.getMenuItem().getBackground(); + g.setPaint(new GradientPaint(0, 0, ColorUtil.shift(bg, 1.5), + 0, 16, ColorUtil.shift(bg, 1.2))); + + g.fillOval(0, 1, w - 1, h - 1); + + g.setPaint(new GradientPaint(w / 2, 1, Gray._160.withAlpha(90), w / 2, h, Gray._100.withAlpha(90))); + g.drawOval(0, 2, w - 1, h - 1); + + g.setPaint(Gray._40.withAlpha(200)); + g.drawOval(0, 1, w - 1, h - 1); + + if (lh.getMenuItem().isSelected()) { + final boolean enabled = lh.getMenuItem().isEnabled(); + g.setColor(UIManager.getColor(enabled ? "RadioButton.darcula.selectionEnabledShadowColor" : "RadioButton.darcula.selectionDisabledShadowColor")); + g.fillOval((w - rad)/2 , h/2 , rad, rad); + g.setColor(UIManager.getColor(enabled ? "RadioButton.darcula.selectionEnabledColor" : "RadioButton.darcula.selectionDisabledColor")); + g.fillOval((w - rad)/2 , h/2 - 1, rad, rad); + } + config.restore(); + g.translate(-x, -y); + + + g.translate(-lr.getCheckRect().x-1, -lr.getCheckRect().y-1); + config.restore(); + } +}