diff --git a/src/main/java/com/github/weisj/darklaf/ui/button/DarkButtonUI.java b/src/main/java/com/github/weisj/darklaf/ui/button/DarkButtonUI.java index 74b2ab6c..9fd71bb3 100644 --- a/src/main/java/com/github/weisj/darklaf/ui/button/DarkButtonUI.java +++ b/src/main/java/com/github/weisj/darklaf/ui/button/DarkButtonUI.java @@ -40,12 +40,14 @@ import javax.swing.plaf.basic.BasicHTML; import javax.swing.text.View; import java.awt.*; import java.awt.geom.RoundRectangle2D; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; /** * @author Konstantin Bulenkov * @author Jannis Weis */ -public class DarkButtonUI extends BasicButtonUI { +public class DarkButtonUI extends BasicButtonUI implements PropertyChangeListener { protected static final Rectangle viewRect = new Rectangle(); protected static final Rectangle textRect = new Rectangle(); @@ -100,18 +102,21 @@ public class DarkButtonUI extends BasicButtonUI { squareArc = UIManager.getInt("Button.squareArc"); } - @Override - public void paint(final Graphics g, final JComponent c) { - GraphicsContext config = new GraphicsContext(g); - AbstractButton b = (AbstractButton) c; - paintButton(g, c); + @Contract("null -> false") + public static boolean isSquare(final Component c) { + return c instanceof JButton && Boolean.TRUE.equals(((JButton) c).getClientProperty("JButton.square")); + } - String text = layout(b, c, SwingUtilities2.getFontMetrics(b, g), - b.getWidth(), b.getHeight()); + @Override + protected void installListeners(final AbstractButton b) { + super.installListeners(b); + b.addPropertyChangeListener(this); + } - paintIcon(g, b, c); - paintText(g, b, c, text); - config.restore(); + @Override + protected void uninstallListeners(final AbstractButton b) { + super.uninstallListeners(b); + b.removePropertyChangeListener(this); } @Override @@ -136,12 +141,18 @@ public class DarkButtonUI extends BasicButtonUI { config.restore(); } - protected Color getForeground(@NotNull final AbstractButton button) { - Color fg = button.getForeground(); - if (fg instanceof UIResource && isDefaultButton(button)) { - fg = defaultForeground; - } - return fg; + @Override + public void paint(final Graphics g, final JComponent c) { + GraphicsContext config = new GraphicsContext(g); + AbstractButton b = (AbstractButton) c; + paintButton(g, c); + + String text = layout(b, c, SwingUtilities2.getFontMetrics(b, g), + b.getWidth(), b.getHeight()); + + paintIcon(g, b, c); + paintText(g, b, c, text); + config.restore(); } protected boolean isDefaultButton(final JComponent c) { @@ -284,9 +295,12 @@ public class DarkButtonUI extends BasicButtonUI { context.restore(); } - @Contract("null -> false") - public static boolean isSquare(final Component c) { - return c instanceof JButton && "square".equals(((JButton) c).getClientProperty("JButton.buttonType")); + protected Color getForeground(@NotNull final AbstractButton button) { + Color fg = button.getForeground(); + if (fg instanceof UIResource && isDefaultButton(button) && !isShadowVariant(button)) { + fg = defaultForeground; + } + return fg; } @Contract("null -> false") @@ -310,8 +324,11 @@ public class DarkButtonUI extends BasicButtonUI { @Override public void update(final Graphics g, final JComponent c) { super.update(g, c); - if (c instanceof JButton && ((JButton) c).isDefaultButton() && !SystemInfo.isMac && !c.getFont().isBold()) { + boolean isDefaultButton = isDefaultButton(c) && !SystemInfo.isMac; + if (isDefaultButton && !c.getFont().isBold()) { c.setFont(c.getFont().deriveFont(Font.BOLD)); + } else if (!isDefaultButton && c.getFont().isBold()) { + c.setFont(c.getFont().deriveFont(Font.PLAIN)); } } @@ -326,4 +343,13 @@ public class DarkButtonUI extends BasicButtonUI { return new RoundRectangle2D.Float(bs, bs, c.getWidth() - 2 * bs, c.getWidth() - 2 * bs, arc, arc).contains(x, y); } + + @Override + public void propertyChange(@NotNull final PropertyChangeEvent evt) { + String key = evt.getPropertyName(); + if (key.startsWith("JButton.")) { + button.repaint(); + button.revalidate(); + } + } } diff --git a/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/MoreTabsButton.java b/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/MoreTabsButton.java index 6e40c060..05719f18 100644 --- a/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/MoreTabsButton.java +++ b/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/MoreTabsButton.java @@ -44,7 +44,7 @@ public class MoreTabsButton extends DarkTabAreaButton { icon = ui.getMoreTabsIcon(); setIcon(EmptyIcon.create(icon.getIconWidth(), icon.getIconHeight())); putClientProperty("JButton.variant", "onlyLabel"); - putClientProperty("JButton.buttonType", "square"); + putClientProperty("JButton.square", true); setFont(getFont().deriveFont(8f)); } diff --git a/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/NewTabButton.java b/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/NewTabButton.java index d01fbc96..8925ba49 100644 --- a/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/NewTabButton.java +++ b/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/NewTabButton.java @@ -52,7 +52,7 @@ public class NewTabButton extends JPanel implements UIResource { JButton button = new JButton(); button.setIcon(ui.getNewTabIcon()); button.putClientProperty("JButton.variant", "shadow"); - button.putClientProperty("JButton.buttonType", "square"); + button.putClientProperty("JButton.square", true); button.putClientProperty("JButton.alternativeArc", Boolean.TRUE); button.putClientProperty("JButton.thin", Boolean.TRUE); button.setRolloverEnabled(true); diff --git a/src/main/java/com/github/weisj/darklaf/ui/tabframe/DarkPanelPopupUI.java b/src/main/java/com/github/weisj/darklaf/ui/tabframe/DarkPanelPopupUI.java index bfe5cd6b..7b8f933f 100644 --- a/src/main/java/com/github/weisj/darklaf/ui/tabframe/DarkPanelPopupUI.java +++ b/src/main/java/com/github/weisj/darklaf/ui/tabframe/DarkPanelPopupUI.java @@ -374,7 +374,7 @@ public class DarkPanelPopupUI extends DarkPanelUI implements PropertyChangeListe public HeaderButton(@NotNull final Icon icon, final DarkPanelPopupUI ui) { super(icon); this.ui = ui; - putClientProperty("JButton.buttonType", "square"); + putClientProperty("JButton.square", true); putClientProperty("JButton.alternativeArc", Boolean.TRUE); putClientProperty("JButton.variant", "shadow"); setRolloverEnabled(true); diff --git a/src/main/java/com/github/weisj/darklaf/ui/tabframe/DarkTabbedPopupUI.java b/src/main/java/com/github/weisj/darklaf/ui/tabframe/DarkTabbedPopupUI.java index 1063be05..90e5e305 100644 --- a/src/main/java/com/github/weisj/darklaf/ui/tabframe/DarkTabbedPopupUI.java +++ b/src/main/java/com/github/weisj/darklaf/ui/tabframe/DarkTabbedPopupUI.java @@ -158,7 +158,7 @@ public class DarkTabbedPopupUI extends DarkPanelPopupUI { protected JButton createButton() { HeaderButton button = new HeaderButton(ui.getNewTabIcon(), DarkTabbedPopupUI.this); button.putClientProperty("JButton.variant", "shadow"); - button.putClientProperty("JButton.buttonType", "square"); + button.putClientProperty("JButton.square", true); button.putClientProperty("JButton.thin", Boolean.TRUE); button.setRolloverEnabled(true); button.setOpaque(false); diff --git a/src/test/java/UIDemo.java b/src/test/java/UIDemo.java index 5b86523d..bb842ff6 100644 --- a/src/test/java/UIDemo.java +++ b/src/test/java/UIDemo.java @@ -87,12 +87,12 @@ public final class UIDemo { }}); add(new JButton(folderIcon) {{ setRolloverEnabled(true); - putClientProperty("JButton.buttonType", "square"); + putClientProperty("JButton.square", true); putClientProperty("JButton.variant", "shadow"); }}); add(new JButton(folderIcon) {{ setRolloverEnabled(true); - putClientProperty("JButton.buttonType", "square"); + putClientProperty("JButton.square", true); putClientProperty("JButton.thin", Boolean.TRUE); putClientProperty("JButton.alternativeArc", Boolean.TRUE); putClientProperty("JButton.variant", "shadow"); @@ -166,7 +166,7 @@ public final class UIDemo { putClientProperty("ToggleButton.variant", "slider"); }}); add(new JButton("square") {{ - putClientProperty("JButton.buttonType", "square"); + putClientProperty("JButton.square", true); }}); }}); panel.add(taskpanecontainer); diff --git a/src/test/java/demo/ButtonDemo.java b/src/test/java/demo/ButtonDemo.java new file mode 100644 index 00000000..8207f589 --- /dev/null +++ b/src/test/java/demo/ButtonDemo.java @@ -0,0 +1,106 @@ +/* + * MIT License + * + * Copyright (c) 2020 Jannis Weis + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package demo; + +import com.github.weisj.darklaf.LafManager; +import com.github.weisj.darklaf.icons.IconLoader; + +import javax.swing.*; +import java.awt.*; + +public class ButtonDemo implements ComponentDemo { + + public static void main(final String[] args) { + SwingUtilities.invokeLater(() -> { + LafManager.install(); + JFrame frame = DemoPanel.createFrame(); + frame.setContentPane(new ButtonDemo().createComponent()); + frame.pack(); + frame.setVisible(true); + }); + } + + @Override + public JComponent createComponent() { + Icon icon = IconLoader.get().getIcon("files/folder.svg", 19, 19, true); + JButton button = new JButton("Test Button", icon); + DemoPanel panel = new DemoPanel(button); + JPanel controlPanel = panel.getControls(); + controlPanel.setLayout(new GridLayout(5, 2)); + controlPanel.add(new JCheckBox("enabled") {{ + setSelected(button.isEnabled()); + addActionListener(e -> button.setEnabled(isSelected())); + }}); + controlPanel.add(new JCheckBox("default") {{ + setSelected(button.isDefaultButton()); + addActionListener(e -> SwingUtilities.getRootPane(button).setDefaultButton(isSelected() ? button + : null)); + }}); + controlPanel.add(new JCheckBox("LeftToRight") {{ + setSelected(button.getComponentOrientation().isLeftToRight()); + addActionListener(e -> button.setComponentOrientation(isSelected() ? ComponentOrientation.LEFT_TO_RIGHT + : ComponentOrientation.RIGHT_TO_LEFT)); + }}); + controlPanel.add(new JCheckBox("Rollover") {{ + setSelected(button.isRolloverEnabled()); + addActionListener(e -> button.setRolloverEnabled(isSelected())); + }}); + controlPanel.add(new JCheckBox("JButton.square") {{ + setSelected(false); + addActionListener(e -> button.putClientProperty("JButton.square", isSelected())); + }}); + controlPanel.add(new JCheckBox("JButton.thin") {{ + setSelected(false); + addActionListener(e -> button.putClientProperty("JButton.thin", isSelected())); + }}); + controlPanel.add(new JCheckBox("JButton.alternativeArc") {{ + setSelected(false); + addActionListener(e -> button.putClientProperty("JButton.alternativeArc", isSelected())); + }}); + controlPanel.add(new JComboBox() {{ + addItem("JButton.variant = onlyLabel"); + addItem("JButton.variant = shadow"); + addItem("JButton.variant = fullShadow"); + addItem("no JButton.variant"); + setSelectedItem("no JButton.variant"); + addItemListener(e -> { + if (e.getItem().equals("JButton.variant = onlyLabel")) { + button.putClientProperty("JButton.variant", "onlyLabel"); + } else if (e.getItem().equals("JButton.variant = shadow")) { + button.putClientProperty("JButton.variant", "shadow"); + } else if (e.getItem().equals("JButton.variant = fullShadow")) { + button.putClientProperty("JButton.variant", "fullShadow"); + } else { + button.putClientProperty("JButton.variant", null); + } + }); + }}); + controlPanel.add(new QuickColorChooser("JButton.shadow.hover", Color.BLACK, + (b, c) -> button.putClientProperty("JButton.shadow.hover", b ? c : null))); + controlPanel.add(new QuickColorChooser("JButton.shadow.click", Color.BLACK, + (b, c) -> button.putClientProperty("JButton.shadow.click", b ? c : null))); + return panel; + } + +} diff --git a/src/test/java/demo/ComponentDemo.java b/src/test/java/demo/ComponentDemo.java new file mode 100644 index 00000000..dd40131a --- /dev/null +++ b/src/test/java/demo/ComponentDemo.java @@ -0,0 +1,31 @@ +/* + * MIT License + * + * Copyright (c) 2020 Jannis Weis + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package demo; + +import javax.swing.*; + +public interface ComponentDemo { + + JComponent createComponent(); +} diff --git a/src/test/java/demo/DemoPanel.java b/src/test/java/demo/DemoPanel.java new file mode 100644 index 00000000..413bebd8 --- /dev/null +++ b/src/test/java/demo/DemoPanel.java @@ -0,0 +1,56 @@ +/* + * MIT License + * + * Copyright (c) 2020 Jannis Weis + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package demo; + +import com.github.weisj.darklaf.components.border.DarkBorders; + +import javax.swing.*; +import java.awt.*; + +public class DemoPanel extends JPanel { + + private final JPanel controls; + + public DemoPanel(final JComponent component) { + super(new BorderLayout()); + JPanel content = new JPanel(new GridBagLayout()); + content.add(component, null); + add(content, BorderLayout.CENTER); + controls = new JPanel(); + controls.setBorder(DarkBorders.createLineBorder(1, 0, 0, 0)); + controls.setLayout(new BoxLayout(controls, BoxLayout.X_AXIS)); + add(controls, BorderLayout.SOUTH); + } + + public static JFrame createFrame() { + JFrame frame = new JFrame(); + frame.setLocationRelativeTo(null); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + return frame; + } + + public JPanel getControls() { + return controls; + } +} diff --git a/src/test/java/demo/QuickColorChooser.java b/src/test/java/demo/QuickColorChooser.java new file mode 100644 index 00000000..858daaf2 --- /dev/null +++ b/src/test/java/demo/QuickColorChooser.java @@ -0,0 +1,59 @@ +/* + * MIT License + * + * Copyright (c) 2020 Jannis Weis + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package demo; + +import com.github.weisj.darklaf.decorators.MouseClickListener; + +import javax.swing.*; +import java.awt.*; +import java.util.function.BiConsumer; + +public class QuickColorChooser extends JPanel { + + private final SolidColorIcon icon; + private final JCheckBox checkBox; + + public QuickColorChooser(final String title, final Color color, final BiConsumer onStatusChange) { + super(new FlowLayout(FlowLayout.LEFT, 0, 0)); + icon = new SolidColorIcon(color); + JLabel label = new JLabel(title, icon, JLabel.LEFT); + checkBox = new JCheckBox(); + checkBox.addActionListener(e -> onStatusChange.accept(isSelected(), getColor())); + label.addMouseListener((MouseClickListener) e -> { + Color c = JColorChooser.showDialog(QuickColorChooser.this, title, icon.getColor()); + onStatusChange.accept(isSelected(), c); + icon.setColor(c); + }); + add(checkBox); + add(label); + } + + public boolean isSelected() { + return checkBox.isSelected(); + } + + public Color getColor() { + return icon.getColor(); + } +} diff --git a/src/test/java/demo/SolidColorIcon.java b/src/test/java/demo/SolidColorIcon.java new file mode 100644 index 00000000..eadbd5f1 --- /dev/null +++ b/src/test/java/demo/SolidColorIcon.java @@ -0,0 +1,69 @@ +/* + * MIT License + * + * Copyright (c) 2020 Jannis Weis + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package demo; + +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.*; + +final class SolidColorIcon implements Icon { + private final int width; + private final int height; + private Color color; + + SolidColorIcon(final Color color) { + this(color, 16, 16); + } + + private SolidColorIcon(final Color color, final int width, final int height) { + this.color = color; + this.width = width; + this.height = height; + } + + @Override + public void paintIcon(final Component c, @NotNull final Graphics g, final int x, final int y) { + g.setColor(color); + g.fillRect(x, y, getIconWidth(), getIconHeight()); + } + + @Override + public int getIconWidth() { + return width; + } + + @Override + public int getIconHeight() { + return height; + } + + public Color getColor() { + return color; + } + + public void setColor(final Color c) { + this.color = c; + } +}