From 792e987e8222736c58fbb9e5ec3713493a91a749 Mon Sep 17 00:00:00 2001 From: weisj Date: Tue, 10 Mar 2020 22:07:23 +0100 Subject: [PATCH] Fixed paint loop for JButton. Added option to convert all buttons that are icon only to shadow variants. --- .../weisj/darklaf/components/ArrowButton.java | 4 + .../components/ClosableTabComponent.java | 7 +- .../uiresource/JButtonUIResource.java | 50 ++++ .../button/AbstractButtonLayoutDelegate.java | 87 +++++++ .../darklaf/ui/button/DarkButtonBorder.java | 17 +- .../weisj/darklaf/ui/button/DarkButtonUI.java | 217 +++++++++++------- .../colorchooser/DarkColorChooserPanel.java | 3 +- .../ui/filechooser/DarkFileChooserUI.java | 7 + .../ui/internalframe/DarkDesktopIconUI.java | 4 +- .../DarkInternalFrameTitlePane.java | 3 +- .../ui/scrollpane/DarkScrollBarUI.java | 3 +- .../darklaf/ui/tabbedpane/DarkHandler.java | 1 + .../DarkTabbedPaneScrollLayout.java | 19 +- .../darklaf/ui/tabbedpane/NewTabButton.java | 9 +- .../ui/tabbedpane/TabbedPaneScrollLayout.java | 1 - .../darklaf/ui/toolbar/DarkToolBarBorder.java | 57 ++++- .../darklaf/ui/toolbar/DarkToolBarUI.java | 1 - .../darklaf/properties/overwrites.properties | 1 + .../darklaf/properties/ui/button.properties | 1 + .../darklaf/properties/ui/text.properties | 4 +- .../java/ui/tabbedPane/TabbedPaneDemo.java | 1 - .../platform/windows/ui/WindowsTitlePane.java | 2 + 22 files changed, 377 insertions(+), 122 deletions(-) create mode 100644 core/src/main/java/com/github/weisj/darklaf/components/uiresource/JButtonUIResource.java create mode 100644 core/src/main/java/com/github/weisj/darklaf/ui/button/AbstractButtonLayoutDelegate.java diff --git a/core/src/main/java/com/github/weisj/darklaf/components/ArrowButton.java b/core/src/main/java/com/github/weisj/darklaf/components/ArrowButton.java index 6e006c59..71904beb 100644 --- a/core/src/main/java/com/github/weisj/darklaf/components/ArrowButton.java +++ b/core/src/main/java/com/github/weisj/darklaf/components/ArrowButton.java @@ -70,6 +70,10 @@ public final class ArrowButton implements SwingConstants { final int orientation, final boolean center, final boolean applyInsetsOnSize, final Insets insets) { return new BasicArrowButton(orientation, null, null, null, null) { + { + putClientProperty("JButton.noShadowOverwrite", true); + } + @Override public void paint(final Graphics g) { int x = (getWidth() - getIcon().getIconWidth()) / 2; diff --git a/core/src/main/java/com/github/weisj/darklaf/components/ClosableTabComponent.java b/core/src/main/java/com/github/weisj/darklaf/components/ClosableTabComponent.java index 059289da..825fe0dc 100644 --- a/core/src/main/java/com/github/weisj/darklaf/components/ClosableTabComponent.java +++ b/core/src/main/java/com/github/weisj/darklaf/components/ClosableTabComponent.java @@ -28,11 +28,7 @@ import com.github.weisj.darklaf.ui.tabbedpane.DarkTabbedPaneUI; import javax.swing.*; import javax.swing.plaf.ComponentUI; import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; +import java.awt.event.*; /** * @author Jannis Weis @@ -96,6 +92,7 @@ public class ClosableTabComponent extends JPanel { protected TabButton(final ClosableTabComponent tabComponent) { this.tabComponent = tabComponent; putClientProperty("JButton.variant", "onlyLabel"); + putClientProperty("JButton.noShadowOverwrite", true); setOpaque(false); setRolloverEnabled(true); setIcon(UIManager.getIcon("TabbedPane.tabCloseIcon")); diff --git a/core/src/main/java/com/github/weisj/darklaf/components/uiresource/JButtonUIResource.java b/core/src/main/java/com/github/weisj/darklaf/components/uiresource/JButtonUIResource.java new file mode 100644 index 00000000..0a579538 --- /dev/null +++ b/core/src/main/java/com/github/weisj/darklaf/components/uiresource/JButtonUIResource.java @@ -0,0 +1,50 @@ +/* + * 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 com.github.weisj.darklaf.components.uiresource; + +import javax.swing.*; +import javax.swing.plaf.UIResource; + +public class JButtonUIResource extends JButton implements UIResource { + + public JButtonUIResource() { + super(null, null); + } + + public JButtonUIResource(final Icon icon) { + super(null, icon); + } + + public JButtonUIResource(final String text) { + super(text, null); + } + + public JButtonUIResource(final Action a) { + super(a); + } + + public JButtonUIResource(final String text, final Icon icon) { + super(text, icon); + } +} diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/button/AbstractButtonLayoutDelegate.java b/core/src/main/java/com/github/weisj/darklaf/ui/button/AbstractButtonLayoutDelegate.java new file mode 100644 index 00000000..b2c46bd5 --- /dev/null +++ b/core/src/main/java/com/github/weisj/darklaf/ui/button/AbstractButtonLayoutDelegate.java @@ -0,0 +1,87 @@ +/* + * 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 com.github.weisj.darklaf.ui.button; + +import javax.swing.*; +import java.awt.*; + +public class AbstractButtonLayoutDelegate extends AbstractButton { + + protected AbstractButton delegate; + + public void setDelegate(final AbstractButton delegate) { + this.delegate = delegate; + if (delegate != null) putClientProperty("html", delegate.getClientProperty("html")); + } + + @Override + public Icon getIcon() { + return delegate.getIcon(); + } + + @Override + public String getText() { + return delegate.getText(); + } + + @Override + public Font getFont() { + return delegate.getFont(); + } + + @Override + public FontMetrics getFontMetrics(final Font font) { + return delegate.getFontMetrics(font); + } + + @Override + public int getVerticalAlignment() { + return delegate.getVerticalAlignment(); + } + + @Override + public int getHorizontalAlignment() { + return delegate.getHorizontalAlignment(); + } + + @Override + public int getVerticalTextPosition() { + return delegate.getVerticalTextPosition(); + } + + @Override + public int getHorizontalTextPosition() { + return delegate.getHorizontalTextPosition(); + } + + @Override + public Insets getInsets() { + return delegate.getInsets(); + } + + @Override + public ComponentOrientation getComponentOrientation() { + return delegate.getComponentOrientation(); + } +} diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/button/DarkButtonBorder.java b/core/src/main/java/com/github/weisj/darklaf/ui/button/DarkButtonBorder.java index 0f20585b..8a69c09e 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/button/DarkButtonBorder.java +++ b/core/src/main/java/com/github/weisj/darklaf/ui/button/DarkButtonBorder.java @@ -177,22 +177,17 @@ public class DarkButtonBorder implements Border, UIResource { if (DarkButtonUI.isLabelButton(c)) { return new InsetsUIResource(labelInsets.top, labelInsets.left, labelInsets.bottom, labelInsets.right); } - int shadow = DarkButtonUI.isShadowVariant(c) ? 0 : getShadowSize(); + boolean shadowVariant = DarkButtonUI.isShadowVariant(c); + int shadow = shadowVariant ? 0 : getShadowSize(); boolean square = DarkButtonUI.isSquare(c); - Insets pad = isThin(c) ? square ? squareThinInsets - : thinInsets - : square ? squareInsets - : insets; + Insets pad = DarkButtonUI.isThin(c) ? square ? squareThinInsets + : thinInsets + : square ? squareInsets + : insets; return new InsetsUIResource(pad.top, pad.left, pad.bottom + shadow, pad.right); } public boolean isBorderOpaque() { return false; } - - - public static boolean isThin(final Component c) { - return c instanceof JButton - && Boolean.TRUE.equals(((JButton) c).getClientProperty("JButton.thin")); - } } diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/button/DarkButtonUI.java b/core/src/main/java/com/github/weisj/darklaf/ui/button/DarkButtonUI.java index 8daefa9d..fe540c72 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/button/DarkButtonUI.java +++ b/core/src/main/java/com/github/weisj/darklaf/ui/button/DarkButtonUI.java @@ -68,15 +68,24 @@ public class DarkButtonUI extends BasicButtonUI implements PropertyChangeListene private int arc; private int squareArc; + protected final AbstractButtonLayoutDelegate layoutDelegate = new AbstractButtonLayoutDelegate() { + @Override + public Font getFont() { + return delegate != null ? delegate.getFont().deriveFont(Font.BOLD) : null; + } + }; + protected boolean oldRolloverEnabled; + protected boolean oldThin; + protected boolean oldSquare; + protected boolean oldAltArc; public static ComponentUI createUI(final JComponent c) { return new DarkButtonUI(); } - @Override - public void installUI(final JComponent c) { - button = (AbstractButton) c; - super.installUI(c); + public static boolean chooseAlternativeArc(final Component c) { + return c instanceof JButton + && Boolean.TRUE.equals(((JButton) c).getClientProperty("JButton.alternativeArc")); } @Override @@ -101,11 +110,6 @@ public class DarkButtonUI extends BasicButtonUI implements PropertyChangeListene squareArc = UIManager.getInt("Button.squareArc"); } - - public static boolean isSquare(final Component c) { - return c instanceof JButton && Boolean.TRUE.equals(((JButton) c).getClientProperty("JButton.square")); - } - @Override protected void installListeners(final AbstractButton b) { super.installListeners(b); @@ -118,6 +122,11 @@ public class DarkButtonUI extends BasicButtonUI implements PropertyChangeListene b.removePropertyChangeListener(this); } + public static boolean isLabelButton(final Component c) { + return c instanceof JButton + && "onlyLabel".equals(((JButton) c).getClientProperty("JButton.variant")); + } + @Override protected void paintText(final Graphics g, final JComponent c, final Rectangle textRect, final String text) { @@ -137,34 +146,18 @@ public class DarkButtonUI extends BasicButtonUI implements PropertyChangeListene config.restore(); } - @Override - public Dimension getPreferredSize(final JComponent c) { - AbstractButton b = (AbstractButton) c; - Font oldFont = b.getFont(); - b.setFont(b.getFont().deriveFont(Font.BOLD)); - Dimension size = BasicGraphicsUtils.getPreferredButtonSize(b, b.getIconTextGap()); - b.setFont(oldFont); - return size; - } - - @Override - public void paint(final Graphics g, final JComponent c) { - GraphicsContext config = new GraphicsContext(g); - AbstractButton b = (AbstractButton) c; - paintButton(g, c); - - if (isDefaultButton(b)) { - g.setFont(g.getFont().deriveFont(Font.BOLD)); - } else if (g.getFont().isBold()) { - g.setFont(g.getFont().deriveFont(Font.PLAIN)); + public static boolean isShadowVariant(final Component c) { + if (isFullShadow(c)) return true; + if (c instanceof JButton) { + JButton b = (JButton) c; + return (isIconOnly(b) && convertIconButtonToShadow(b)) + || "shadow".equals(b.getClientProperty("JButton.variant")); } + return false; + } - 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 static boolean isIconOnly(final AbstractButton b) { + return b.getIcon() != null && (b.getText() == null || b.getText().isEmpty()); } protected boolean isDefaultButton(final JComponent c) { @@ -179,36 +172,9 @@ public class DarkButtonUI extends BasicButtonUI implements PropertyChangeListene return fg; } - protected void paintButton(final Graphics g, final JComponent c) { - Graphics2D g2 = (Graphics2D) g; - if (shouldDrawBackground(c)) { - AbstractButton b = (AbstractButton) c; - Insets margin = b.getMargin(); - int arc = getArc(c); - if (isShadowVariant(c)) { - if (b.isEnabled() && b.getModel().isRollover()) { - GraphicsUtil.setupAAPainting(g2); - g.setColor(getShadowColor(b)); - if (isFullShadow(c)) { - g.fillRect(0, 0, c.getWidth(), c.getHeight()); - } else { - margin.set(0, 0, 0, 0); - DarkUIUtil.fillRoundRect((Graphics2D) g, margin.left, margin.top, - c.getWidth() - margin.left - margin.right, - c.getHeight() - margin.top - margin.bottom, arc); - } - } - } else { - g2.setColor(getBackgroundColor(c)); - if (isSquare(c) && !chooseAlternativeArc(c)) { - g2.fillRect(borderSize, borderSize, c.getWidth() - 2 * borderSize, - c.getHeight() - 2 * borderSize - shadowHeight); - } else { - DarkUIUtil.fillRoundRect((Graphics2D) g, borderSize, borderSize, c.getWidth() - 2 * borderSize, - c.getHeight() - 2 * borderSize - shadowHeight, arc); - } - } - } + public static boolean isFullShadow(final Component c) { + return c instanceof JButton + && "fullShadow".equals(((JButton) c).getClientProperty("JButton.variant")); } private boolean shouldDrawBackground(final JComponent c) { @@ -260,13 +226,6 @@ public class DarkButtonUI extends BasicButtonUI implements PropertyChangeListene return square ? alt ? arc : squareArc : alt ? squareArc : arc; } - - public static boolean isShadowVariant(final Component c) { - if (isFullShadow(c)) return true; - return c instanceof JButton - && "shadow".equals(((JButton) c).getClientProperty("JButton.variant")); - } - protected String layout(final AbstractButton b, final JComponent c, final FontMetrics fm, final int width, final int height) { Insets i = b.getInsets(); @@ -287,12 +246,6 @@ public class DarkButtonUI extends BasicButtonUI implements PropertyChangeListene b.getText() == null ? 0 : b.getIconTextGap()); } - - public static boolean isFullShadow(final Component c) { - return c instanceof JButton - && "fullShadow".equals(((JButton) c).getClientProperty("JButton.variant")); - } - protected void paintText(final Graphics g, final AbstractButton b, final JComponent c, final String text) { GraphicsContext context = GraphicsUtil.setupAntialiasing(g); g.setClip(textRect); @@ -314,22 +267,112 @@ public class DarkButtonUI extends BasicButtonUI implements PropertyChangeListene } } - - public static boolean chooseAlternativeArc(final Component c) { + public static boolean isNoArc(final Component c) { return c instanceof JButton - && Boolean.TRUE.equals(((JButton) c).getClientProperty("JButton.alternativeArc")); + && Boolean.TRUE.equals(((JButton) c).getClientProperty("JButton.noArc")); } + public static boolean isSquare(final Component c) { + return c instanceof JButton && Boolean.TRUE.equals(((JButton) c).getClientProperty("JButton.square")); + } - public static boolean isLabelButton(final Component c) { + public static boolean isThin(final Component c) { return c instanceof JButton - && "onlyLabel".equals(((JButton) c).getClientProperty("JButton.variant")); + && Boolean.TRUE.equals(((JButton) c).getClientProperty("JButton.thin")); } + protected static boolean convertIconButtonToShadow(final AbstractButton b) { + return !(b instanceof UIResource) + && UIManager.getBoolean("Button.convertIconOnlyToShadow") + && !Boolean.TRUE.equals(b.getClientProperty("JButton.noShadowOverwrite")); + } - public static boolean isNoArc(final Component c) { - return c instanceof JButton - && Boolean.TRUE.equals(((JButton) c).getClientProperty("JButton.noArc")); + @Override + public void installUI(final JComponent c) { + button = (AbstractButton) c; + super.installUI(c); + oldRolloverEnabled = button.isRolloverEnabled(); + updateRolloverEnabled(); + } + + public void updateRolloverEnabled() { + if (isIconOnly(button) && convertIconButtonToShadow(button)) { + oldRolloverEnabled = button.isRolloverEnabled(); + oldThin = isThin(button); + oldSquare = isSquare(button); + oldAltArc = chooseAlternativeArc(button); + button.setRolloverEnabled(true); + button.putClientProperty("JButton.square", true); + button.putClientProperty("JButton.thin", true); + button.putClientProperty("JButton.alternativeArc", true); + } else { + button.setRolloverEnabled(oldRolloverEnabled); + button.putClientProperty("JButton.square", oldSquare); + button.putClientProperty("JButton.thin", oldThin); + button.putClientProperty("JButton.alternativeArc", oldAltArc); + } + } + + @Override + public Dimension getPreferredSize(final JComponent c) { + AbstractButton b = (AbstractButton) c; + layoutDelegate.setDelegate(b); + return BasicGraphicsUtils.getPreferredButtonSize(layoutDelegate, b.getIconTextGap()); + } + + @Override + public void paint(final Graphics g, final JComponent c) { + GraphicsContext config = new GraphicsContext(g); + AbstractButton b = (AbstractButton) c; + paintButton(g, c); + + if (isDefaultButton(b)) { + g.setFont(g.getFont().deriveFont(Font.BOLD)); + } else if (g.getFont().isBold()) { + g.setFont(g.getFont().deriveFont(Font.PLAIN)); + } + + String text = layout(b, c, SwingUtilities2.getFontMetrics(b, g), + b.getWidth() + 2, b.getHeight()); + + paintIcon(g, b, c); + paintText(g, b, c, text); + config.restore(); + } + + protected void paintButton(final Graphics g, final JComponent c) { + Graphics2D g2 = (Graphics2D) g; + if (shouldDrawBackground(c)) { + AbstractButton b = (AbstractButton) c; + int arc = getArc(c); + Insets margin = b.getMargin(); + if (margin instanceof UIResource) margin = new Insets(0, 0, 0, 0); + if (isShadowVariant(c)) { + if (b.isEnabled() && b.getModel().isRollover()) { + GraphicsUtil.setupAAPainting(g2); + g.setColor(getShadowColor(b)); + if (isFullShadow(c)) { + g.fillRect(margin.left, margin.top, + c.getWidth() - margin.left - margin.right, + c.getHeight() - margin.top - margin.bottom); + } else { + g.fillRoundRect(margin.left, margin.top, + c.getWidth() - margin.left - margin.right, + c.getHeight() - margin.top - margin.bottom, + arc, arc); + } + } + } else { + g2.setColor(getBackgroundColor(c)); + if (isSquare(c) && !chooseAlternativeArc(c)) { + g2.fillRect(borderSize, borderSize, c.getWidth() - 2 * borderSize, + c.getHeight() - 2 * borderSize - shadowHeight); + } else { + DarkUIUtil.fillRoundRect((Graphics2D) g, borderSize, borderSize, c.getWidth() - 2 * borderSize, + c.getHeight() - 2 * borderSize - shadowHeight, arc); + } + } + } } @Override @@ -361,6 +404,8 @@ public class DarkButtonUI extends BasicButtonUI implements PropertyChangeListene if (key.startsWith("JButton.")) { button.repaint(); button.revalidate(); + } else if (JButton.TEXT_CHANGED_PROPERTY.equals(key)) { + updateRolloverEnabled(); } } } diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/colorchooser/DarkColorChooserPanel.java b/core/src/main/java/com/github/weisj/darklaf/ui/colorchooser/DarkColorChooserPanel.java index 9fb70f5c..e8af848b 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/colorchooser/DarkColorChooserPanel.java +++ b/core/src/main/java/com/github/weisj/darklaf/ui/colorchooser/DarkColorChooserPanel.java @@ -26,6 +26,7 @@ package com.github.weisj.darklaf.ui.colorchooser; import com.github.weisj.darklaf.color.DarkColorModel; import com.github.weisj.darklaf.components.DefaultColorPipette; +import com.github.weisj.darklaf.components.uiresource.JButtonUIResource; import com.github.weisj.darklaf.decorators.AncestorAdapter; import com.github.weisj.darklaf.util.ColorUtil; @@ -190,7 +191,7 @@ public class DarkColorChooserPanel extends AbstractColorChooserPanel implements final JPanel previewPanel = new JPanel(new BorderLayout()); if (enablePipette && pipette != null) { - JButton pipetteButton = new JButton(); + JButton pipetteButton = new JButtonUIResource(); pipetteButton.putClientProperty("JButton.variant", "onlyLabel"); pipetteButton.putClientProperty("JButton.thin", Boolean.TRUE); pipetteButton.setRolloverEnabled(true); diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/filechooser/DarkFileChooserUI.java b/core/src/main/java/com/github/weisj/darklaf/ui/filechooser/DarkFileChooserUI.java index 14b7528c..59a4c379 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/filechooser/DarkFileChooserUI.java +++ b/core/src/main/java/com/github/weisj/darklaf/ui/filechooser/DarkFileChooserUI.java @@ -102,6 +102,7 @@ public class DarkFileChooserUI extends DarkFileChooserUIBridge { // Up Button JButton upFolderButton = new TooltipAwareButton(getChangeToParentDirectoryAction()); + upFolderButton.putClientProperty("JButton.noShadowOverwrite", true); upFolderButton.setText(null); upFolderButton.setIcon(upFolderIcon); upFolderButton.setToolTipText(upFolderToolTipText); @@ -120,6 +121,7 @@ public class DarkFileChooserUI extends DarkFileChooserUIBridge { JButton b = new TooltipAwareButton(homeFolderIcon); + b.putClientProperty("JButton.noShadowOverwrite", true); b.setToolTipText(toolTipText); b.putClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY, homeFolderAccessibleName); @@ -134,6 +136,7 @@ public class DarkFileChooserUI extends DarkFileChooserUIBridge { // New Directory Button if (!UIManager.getBoolean("FileChooser.readOnly")) { b = new TooltipAwareButton(filePane.getNewFolderAction()); + b.putClientProperty("JButton.noShadowOverwrite", true); b.setText(null); b.setIcon(newFolderIcon); b.setToolTipText(newFolderToolTipText); @@ -151,6 +154,7 @@ public class DarkFileChooserUI extends DarkFileChooserUIBridge { // List Button listViewButton = new TooltipAwareToggleButton(listViewIcon); + listViewButton.putClientProperty("JButton.noShadowOverwrite", true); listViewButton.putClientProperty("JButton.square", Boolean.TRUE); listViewButton.setToolTipText(listViewButtonToolTipText); listViewButton.putClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY, @@ -168,6 +172,7 @@ public class DarkFileChooserUI extends DarkFileChooserUIBridge { // Details Button detailsViewButton = new TooltipAwareToggleButton(detailsViewIcon); + detailsViewButton.putClientProperty("JButton.noShadowOverwrite", true); detailsViewButton.putClientProperty("JButton.square", Boolean.TRUE); detailsViewButton.setToolTipText(detailsViewButtonToolTipText); detailsViewButton.putClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY, @@ -281,12 +286,14 @@ public class DarkFileChooserUI extends DarkFileChooserUIBridge { getButtonPanel().setLayout(new DarkButtonAreaLayout()); approveButton = new TooltipAwareButton(getApproveButtonText(fc)); + approveButton.putClientProperty("JButton.noShadowOverwrite", true); // Note: Metal does not use mnemonics for approve and cancel approveButton.addActionListener(getApproveSelectionAction()); approveButton.setToolTipText(getApproveButtonToolTipText(fc)); getButtonPanel().add(approveButton); cancelButton = new TooltipAwareButton(cancelButtonText); + cancelButton.putClientProperty("JButton.noShadowOverwrite", true); cancelButton.setToolTipText(cancelButtonToolTipText); cancelButton.addActionListener(getCancelSelectionAction()); getButtonPanel().add(cancelButton); diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/internalframe/DarkDesktopIconUI.java b/core/src/main/java/com/github/weisj/darklaf/ui/internalframe/DarkDesktopIconUI.java index f3822464..ad7ab166 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/internalframe/DarkDesktopIconUI.java +++ b/core/src/main/java/com/github/weisj/darklaf/ui/internalframe/DarkDesktopIconUI.java @@ -23,6 +23,8 @@ */ package com.github.weisj.darklaf.ui.internalframe; +import com.github.weisj.darklaf.components.uiresource.JButtonUIResource; + import javax.swing.*; import javax.swing.border.MatteBorder; import javax.swing.plaf.ComponentUI; @@ -50,7 +52,7 @@ public class DarkDesktopIconUI extends BasicDesktopIconUI { Icon icon = frame.getFrameIcon(); String title = frame.getTitle(); - button = new JButton(title, icon); + button = new JButtonUIResource(title, icon); button.setOpaque(false); button.putClientProperty("JButton.variant", "fullShadow"); button.putClientProperty("JButton.shadow.hover", UIManager.getColor("DesktopIcon.hoverColor")); diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/internalframe/DarkInternalFrameTitlePane.java b/core/src/main/java/com/github/weisj/darklaf/ui/internalframe/DarkInternalFrameTitlePane.java index 12ae7e0d..078c7067 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/internalframe/DarkInternalFrameTitlePane.java +++ b/core/src/main/java/com/github/weisj/darklaf/ui/internalframe/DarkInternalFrameTitlePane.java @@ -23,6 +23,7 @@ */ package com.github.weisj.darklaf.ui.internalframe; +import com.github.weisj.darklaf.components.uiresource.JButtonUIResource; import com.github.weisj.darklaf.icons.EmptyIcon; import com.github.weisj.darklaf.icons.ToggleIcon; import sun.swing.SwingUtilities2; @@ -209,7 +210,7 @@ public class DarkInternalFrameTitlePane extends BasicInternalFrameTitlePane { private static JButton createButton(final String accessibleName) { - JButton button = new JButton(); + JButton button = new JButtonUIResource(); button.setFocusable(false); button.setOpaque(true); button.setRolloverEnabled(true); diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/scrollpane/DarkScrollBarUI.java b/core/src/main/java/com/github/weisj/darklaf/ui/scrollpane/DarkScrollBarUI.java index e472a302..f9794aa6 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/scrollpane/DarkScrollBarUI.java +++ b/core/src/main/java/com/github/weisj/darklaf/ui/scrollpane/DarkScrollBarUI.java @@ -30,6 +30,7 @@ import com.github.weisj.darklaf.util.DarkUIUtil; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.UIResource; import javax.swing.plaf.basic.BasicScrollBarUI; import java.awt.*; import java.awt.event.*; @@ -633,7 +634,7 @@ public class DarkScrollBarUI extends BasicScrollBarUI { return bounds != null && bounds.contains(p); } - private static final class EmptyButton extends JButton { + private static final class EmptyButton extends JButton implements UIResource { private EmptyButton() { setFocusable(false); setRequestFocusEnabled(false); diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/DarkHandler.java b/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/DarkHandler.java index 1989743f..07c6d18f 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/DarkHandler.java +++ b/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/DarkHandler.java @@ -83,6 +83,7 @@ public class DarkHandler extends TabbedPaneHandler { ui.scrollableTabSupport.newTabButton.setVisible(show); } ui.tabPane.doLayout(); + ui.tabPane.repaint(); } else if ("JTabbedPane.leadingComponent".equals(key)) { ui.tabPane.remove(ui.leadingComp); Object val = e.getNewValue(); diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/DarkTabbedPaneScrollLayout.java b/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/DarkTabbedPaneScrollLayout.java index cdfb124c..e68a8be5 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/DarkTabbedPaneScrollLayout.java +++ b/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/DarkTabbedPaneScrollLayout.java @@ -388,7 +388,6 @@ public class DarkTabbedPaneScrollLayout extends TabbedPaneScrollLayout { } } ui.tabScroller.tabPanel.setPreferredSize(tabBounds.getSize()); - ui.tabScroller.tabPanel.invalidate(); } @@ -456,23 +455,29 @@ public class DarkTabbedPaneScrollLayout extends TabbedPaneScrollLayout { if (horizontal) { if (leftToRight) { if (ui.rects[tabCount - 1].x + ui.rects[tabCount - 1].width + buttonBounds.width > maxVal) { - ui.tabPane.add(button); + if (button.getParent() != ui.tabPane) ui.tabPane.add(button); } else { - ui.scrollableTabSupport.tabPanel.add(button); + if (button.getParent() != ui.scrollableTabSupport.tabPanel) { + ui.scrollableTabSupport.tabPanel.add(button); + } } } else { int x = ui.rects[tabCount - 1].x; if (x - buttonBounds.width < minVal) { - ui.tabPane.add(button); + if (button.getParent() != ui.tabPane) ui.tabPane.add(button); } else { - ui.scrollableTabSupport.tabPanel.add(button); + if (button.getParent() != ui.scrollableTabSupport.tabPanel) { + ui.scrollableTabSupport.tabPanel.add(button); + } } } } else { if (ui.rects[tabCount - 1].y + ui.rects[tabCount - 1].height + buttonBounds.height > maxVal) { - ui.tabPane.add(button); + if (button.getParent() != ui.tabPane) ui.tabPane.add(button); } else { - ui.scrollableTabSupport.tabPanel.add(button); + if (button.getParent() != ui.scrollableTabSupport.tabPanel) { + ui.scrollableTabSupport.tabPanel.add(button); + } } } } diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/NewTabButton.java b/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/NewTabButton.java index 9e49d51b..68e11c92 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/NewTabButton.java +++ b/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/NewTabButton.java @@ -23,6 +23,8 @@ */ package com.github.weisj.darklaf.ui.tabbedpane; +import com.github.weisj.darklaf.components.uiresource.JButtonUIResource; + import javax.swing.*; import javax.swing.plaf.UIResource; import java.awt.*; @@ -47,15 +49,16 @@ public class NewTabButton extends JPanel implements UIResource { } protected JButton createButton() { - JButton button = new JButton(); + JButton button = new JButtonUIResource(); button.setIcon(ui.getNewTabIcon()); button.putClientProperty("JButton.variant", "shadow"); - button.putClientProperty("JButton.square", true); + button.putClientProperty("JButton.square", Boolean.TRUE); button.putClientProperty("JButton.alternativeArc", Boolean.TRUE); button.putClientProperty("JButton.thin", Boolean.TRUE); button.setRolloverEnabled(true); button.setOpaque(false); - button.setMargin(UIManager.getInsets("TabbedPane.newTabButton.insets")); + Insets margin = UIManager.getInsets("TabbedPane.newTabButton.insets"); + button.setMargin(new Insets(margin.top, margin.left, margin.bottom, margin.right)); return button; } diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/TabbedPaneScrollLayout.java b/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/TabbedPaneScrollLayout.java index 0b5b4a58..3ae969e3 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/TabbedPaneScrollLayout.java +++ b/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/TabbedPaneScrollLayout.java @@ -129,7 +129,6 @@ abstract class TabbedPaneScrollLayout extends TabbedPaneLayout { } } ui.tabScroller.tabPanel.setPreferredSize(new Dimension(totalWidth, totalHeight)); - ui.tabScroller.tabPanel.invalidate(); } protected int preferredTabAreaWidth(final int tabPlacement, final int height) { diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/toolbar/DarkToolBarBorder.java b/core/src/main/java/com/github/weisj/darklaf/ui/toolbar/DarkToolBarBorder.java index 835da724..0003c3ab 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/toolbar/DarkToolBarBorder.java +++ b/core/src/main/java/com/github/weisj/darklaf/ui/toolbar/DarkToolBarBorder.java @@ -36,17 +36,18 @@ public class DarkToolBarBorder extends AbstractBorder implements UIResource, Swi protected Icon horizontalGrip; protected Icon verticalGrip; + protected Color borderColor; public DarkToolBarBorder() { horizontalGrip = UIManager.getIcon("ToolBar.horizontalGrip.icon"); verticalGrip = UIManager.getIcon("ToolBar.verticalGrip.icon"); + borderColor = UIManager.getColor("ToolBar.borderColor"); } public void paintBorder(final Component c, final Graphics g, final int x, final int y, final int w, final int h) { g.translate(x, y); - if (isFloatable(c)) { if (((JToolBar) c).getOrientation() == HORIZONTAL) { Icon icon = getHorizontalGrip(); @@ -62,9 +63,45 @@ public class DarkToolBarBorder extends AbstractBorder implements UIResource, Swi icon.paintIcon(c, g, xIcon, 0); } } + if (isDocked(c)) { + String constraints = getDockedConstrains(c); + JToolBar toolBar = (JToolBar) c; + g.setColor(borderColor); + if (toolBar.getOrientation() == JToolBar.HORIZONTAL) { + if (BorderLayout.NORTH.equals(constraints)) { + g.fillRect(0, toolBar.getHeight() - 1, toolBar.getWidth(), 1); + } else if (BorderLayout.SOUTH.equals(constraints)) { + g.fillRect(0, 0, toolBar.getWidth(), 1); + } + } else { + if (BorderLayout.WEST.equals(constraints)) { + g.fillRect(toolBar.getWidth() - 1, 0, 1, toolBar.getHeight()); + } else if (BorderLayout.EAST.equals(constraints)) { + g.fillRect(0, 0, 1, toolBar.getHeight()); + } + } + } g.translate(-x, -y); } + private boolean isDocked(final Component c) { + if (c instanceof JToolBar && ((JToolBar) c).getUI() instanceof DarkToolBarUI) { + return !((DarkToolBarUI) ((JToolBar) c).getUI()).isFloating(); + } + return false; + } + + private String getDockedConstrains(final Component c) { + if (c instanceof JComponent) { + Component parent = c.getParent(); + if (parent instanceof JComponent && ((JComponent) parent).getLayout() instanceof BorderLayout) { + BorderLayout layout = (BorderLayout) ((JComponent) parent).getLayout(); + Object constraints = layout.getConstraints(c); + if (constraints != null) return constraints.toString(); + } + } + return ""; + } private boolean isFloatable(final Component c) { return c instanceof JToolBar && ((JToolBar) c).isFloatable(); @@ -101,6 +138,22 @@ public class DarkToolBarBorder extends AbstractBorder implements UIResource, Swi newInsets.bottom += margin.bottom; } } + if (c instanceof JToolBar && isDocked(c)) { + String constraints = getDockedConstrains(c); + if (((JToolBar) c).getOrientation() == JToolBar.HORIZONTAL) { + if (BorderLayout.NORTH.equals(constraints)) { + newInsets.bottom++; + } else if (BorderLayout.SOUTH.equals(constraints)) { + newInsets.top++; + } + } else { + if (BorderLayout.WEST.equals(constraints)) { + newInsets.right++; + } else if (BorderLayout.EAST.equals(constraints)) { + newInsets.left++; + } + } + } return newInsets; } -} \ No newline at end of file +} diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/toolbar/DarkToolBarUI.java b/core/src/main/java/com/github/weisj/darklaf/ui/toolbar/DarkToolBarUI.java index 0d0bfea2..371082e3 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/toolbar/DarkToolBarUI.java +++ b/core/src/main/java/com/github/weisj/darklaf/ui/toolbar/DarkToolBarUI.java @@ -51,7 +51,6 @@ public class DarkToolBarUI extends DarkToolBarUIBridge { return new DarkToolBarUI(); } - private static Robot createRobot() { try { return new Robot(); diff --git a/core/src/main/resources/com/github/weisj/darklaf/properties/overwrites.properties b/core/src/main/resources/com/github/weisj/darklaf/properties/overwrites.properties index f2680489..7c78b37f 100644 --- a/core/src/main/resources/com/github/weisj/darklaf/properties/overwrites.properties +++ b/core/src/main/resources/com/github/weisj/darklaf/properties/overwrites.properties @@ -25,3 +25,4 @@ SplitPane.defaultDividerStyle = spDividerStyle Table.renderBooleanAsCheckBox = tableBooleanRenderer Tree.renderBooleanAsCheckBox = treeBooleanRenderer TextComponent.roundedSelection = roundedSelection +Button.convertIconOnlyToShadow = shadowIconButtons diff --git a/core/src/main/resources/com/github/weisj/darklaf/properties/ui/button.properties b/core/src/main/resources/com/github/weisj/darklaf/properties/ui/button.properties index 5f933714..fb580422 100644 --- a/core/src/main/resources/com/github/weisj/darklaf/properties/ui/button.properties +++ b/core/src/main/resources/com/github/weisj/darklaf/properties/ui/button.properties @@ -59,3 +59,4 @@ Button.shadow.hover = %hoverHighlight Button.shadow.click = %clickHighlight Button.defaultButtonFollowsFocus = false +Button.convertIconOnlyToShadow = false diff --git a/core/src/main/resources/com/github/weisj/darklaf/properties/ui/text.properties b/core/src/main/resources/com/github/weisj/darklaf/properties/ui/text.properties index 2dc164bc..927e881a 100644 --- a/core/src/main/resources/com/github/weisj/darklaf/properties/ui/text.properties +++ b/core/src/main/resources/com/github/weisj/darklaf/properties/ui/text.properties @@ -53,6 +53,7 @@ TextPane.selectionForeground = %textSelectionForeground TextPane.background = %textBackground TextPane.disabledBackground = %textBackgroundInactive TextPane.inactiveBackground = %textBackgroundInactive +TextPane.border = null EditorPane.selectionBackground = %textSelectionBackground @@ -61,6 +62,7 @@ EditorPane.inactiveForeground = %textForegroundInactive EditorPane.background = %textBackground EditorPane.disabledBackground = %textBackgroundInactive EditorPane.inactiveBackground = %textBackgroundInactive +EditorPane.border = null TextArea.selectionBackground = %textSelectionBackground @@ -68,7 +70,7 @@ TextArea.selectionForeground = %textSelectionForeground TextArea.background = %textBackground TextArea.disabledBackground = %textBackgroundInactive TextArea.inactiveBackground = %textBackgroundInactive - +TextArea.border = null FormattedTextFieldUI = com.github.weisj.darklaf.ui.text.DarkFormattedTextFieldUI FormattedTextField.border = com.github.weisj.darklaf.ui.text.DarkTextBorder diff --git a/core/src/test/java/ui/tabbedPane/TabbedPaneDemo.java b/core/src/test/java/ui/tabbedPane/TabbedPaneDemo.java index cb7f51ad..939cec49 100644 --- a/core/src/test/java/ui/tabbedPane/TabbedPaneDemo.java +++ b/core/src/test/java/ui/tabbedPane/TabbedPaneDemo.java @@ -65,7 +65,6 @@ public class TabbedPaneDemo implements ComponentDemo { addItem("SCROLL_TAB_LAYOUT"); addItem("WRAP_TAB_LAYOUT"); setSelectedItem("SCROLL_TAB_LAYOUT"); - //noinspection MagicConstant addItemListener(e -> tabbedPane.setTabLayoutPolicy(mapping.get(e.getItem().toString()))); }}, "sgx"); controlPanel.add(new JLabel("TabPlacement:", JLabel.RIGHT)); diff --git a/windows/src/main/java/com/github/weisj/darklaf/platform/windows/ui/WindowsTitlePane.java b/windows/src/main/java/com/github/weisj/darklaf/platform/windows/ui/WindowsTitlePane.java index a2198909..198c0f9d 100644 --- a/windows/src/main/java/com/github/weisj/darklaf/platform/windows/ui/WindowsTitlePane.java +++ b/windows/src/main/java/com/github/weisj/darklaf/platform/windows/ui/WindowsTitlePane.java @@ -144,6 +144,7 @@ public class WindowsTitlePane extends CustomTitlePane { button.putClientProperty("JButton.shadow.click", UIManager.getColor("Windows.TitlePane.close.clickColor")); } + button.putClientProperty("JButton.noShadowOverwrite", true); button.setFocusable(false); button.setOpaque(true); button.setRolloverEnabled(true); @@ -312,6 +313,7 @@ public class WindowsTitlePane extends CustomTitlePane { protected JButton createWindowIcon() { windowIconButton = new JButton(); + windowIconButton.putClientProperty("JButton.noShadowOverwrite", true); windowIconButton.setComponentPopupMenu(createMenu()); windowIconButton.putClientProperty("JButton.variant", "onlyLabel"); windowIconButton.addActionListener(e -> windowIconButton