diff --git a/core/src/main/java/com/github/weisj/darklaf/DarkLaf.java b/core/src/main/java/com/github/weisj/darklaf/DarkLaf.java index 38da4aca..cbd75e7e 100644 --- a/core/src/main/java/com/github/weisj/darklaf/DarkLaf.java +++ b/core/src/main/java/com/github/weisj/darklaf/DarkLaf.java @@ -26,8 +26,8 @@ package com.github.weisj.darklaf; import com.github.weisj.darklaf.components.border.DarkBorders; import com.github.weisj.darklaf.platform.Decorations; import com.github.weisj.darklaf.theme.Theme; +import com.github.weisj.darklaf.ui.DarkPopupFactory; import com.github.weisj.darklaf.ui.popupmenu.DarkPopupMenuUI; -import com.github.weisj.darklaf.ui.rootpane.DarkRootPaneUI; import com.github.weisj.darklaf.util.SystemInfo; import sun.awt.AppContext; @@ -354,27 +354,7 @@ public class DarkLaf extends BasicLookAndFeel implements PropertyChangeListener * This is disadvantageous for the behaviour of custom tooltips. */ call("initialize"); - PopupFactory.setSharedInstance(new PopupFactory() { - @Override - public Popup getPopup(final Component owner, final Component contents, - final int x, final int y) throws IllegalArgumentException { - Popup popup = super.getPopup(owner, contents, x, y); - // Sometimes the background is java.awt.SystemColor[i=7] - // It results in a flash of white background, that is repainted with - // the proper popup background later. - // That is why we set window background explicitly. - Window window = SwingUtilities.getWindowAncestor(contents); - if (window != null) { - window.setBackground(UIManager.getColor("PopupMenu.translucentBackground")); - if (window instanceof RootPaneContainer) { - JRootPane rootPane = ((RootPaneContainer) window).getRootPane(); - rootPane.putClientProperty(DarkRootPaneUI.KEY_IS_POPUP, true); - } - Decorations.initPopupWindow(window); - } - return popup; - } - }); + PopupFactory.setSharedInstance(new DarkPopupFactory()); PropertyLoader.reset(); UIManager.addPropertyChangeListener(this); } @@ -465,4 +445,5 @@ public class DarkLaf extends BasicLookAndFeel implements PropertyChangeListener public boolean getSupportsWindowDecorations() { return Decorations.isCustomDecorationSupported(); } + } diff --git a/core/src/main/java/com/github/weisj/darklaf/components/tooltip/DarkToolTip.java b/core/src/main/java/com/github/weisj/darklaf/components/tooltip/DarkToolTip.java index c4549a06..07868091 100644 --- a/core/src/main/java/com/github/weisj/darklaf/components/tooltip/DarkToolTip.java +++ b/core/src/main/java/com/github/weisj/darklaf/components/tooltip/DarkToolTip.java @@ -23,7 +23,6 @@ */ package com.github.weisj.darklaf.components.tooltip; -import com.github.weisj.darklaf.decorators.AncestorAdapter; import com.github.weisj.darklaf.ui.tooltip.DarkTooltipBorder; import com.github.weisj.darklaf.util.Alignment; import com.github.weisj.darklaf.util.Animator; @@ -31,7 +30,6 @@ import com.github.weisj.darklaf.util.GraphicsContext; import javax.swing.*; import javax.swing.border.Border; -import javax.swing.event.AncestorEvent; import java.awt.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; @@ -40,11 +38,9 @@ import java.util.Objects; public class DarkToolTip extends JToolTip implements PropertyChangeListener { public static final String TIP_TEXT_PROPERTY = "tiptext"; - private static final long REPAINT_THRESHOLD = 150; private static final AlphaComposite COMPOSITE = AlphaComposite.getInstance(AlphaComposite.SRC_OVER); private static final float MAX_ALPHA = 1.0f; private final Animator fadeAnimator; - private long lastHidden; private float alpha = 0; public DarkToolTip(final Alignment alignment) { @@ -52,24 +48,16 @@ public class DarkToolTip extends JToolTip implements PropertyChangeListener { setOpaque(false); fadeAnimator = new FadeInAnimator(); addPropertyChangeListener(this); - addAncestorListener(new AncestorAdapter() { - @Override - public void ancestorAdded(final AncestorEvent event) { - boolean resume = false; - if (Math.abs(System.currentTimeMillis() - lastHidden) < REPAINT_THRESHOLD) { - alpha = 1.0f; - } else { - alpha = 0; - resume = true; - } - setVisible(true); - notifyToolTipListeners(ToolTipEvent.SHOWN); - if (resume) { - fadeAnimator.reset(); - fadeAnimator.resume(); - } - } - }); + } + + @Override + public void addNotify() { + alpha = 0; + setVisible(true); + notifyToolTipListeners(ToolTipEvent.SHOWN); + fadeAnimator.reset(); + fadeAnimator.resume(); + super.addNotify(); } public void setAlignment(final Alignment alignment) { @@ -127,7 +115,6 @@ public class DarkToolTip extends JToolTip implements PropertyChangeListener { public void removeNotify() { super.removeNotify(); notifyToolTipListeners(ToolTipEvent.HIDDEN); - lastHidden = System.currentTimeMillis(); alpha = 0; } diff --git a/core/src/main/java/com/github/weisj/darklaf/platform/Decorations.java b/core/src/main/java/com/github/weisj/darklaf/platform/Decorations.java index 20408751..c5f8a67f 100644 --- a/core/src/main/java/com/github/weisj/darklaf/platform/Decorations.java +++ b/core/src/main/java/com/github/weisj/darklaf/platform/Decorations.java @@ -64,10 +64,13 @@ public final class Decorations { return decorationsProvider.createTitlePane(rootPane, decorationStyle); } - public static void initPopupWindow(final Window window) { - decorationsProvider.initPopupWindow(window); + public static void installPopupWindow(final Window window) { + decorationsProvider.installPopupMenu(window); } + public static void uninstallPopupWindow(final Window window) { + decorationsProvider.uninstallPopupWindow(window); + } public static boolean isCustomDecorationSupported() { return decorationsProvider.isCustomDecorationSupported() diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/DarkPopupFactory.java b/core/src/main/java/com/github/weisj/darklaf/ui/DarkPopupFactory.java new file mode 100644 index 00000000..caaf306f --- /dev/null +++ b/core/src/main/java/com/github/weisj/darklaf/ui/DarkPopupFactory.java @@ -0,0 +1,58 @@ +/* + * 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; + +import com.github.weisj.darklaf.platform.Decorations; +import com.github.weisj.darklaf.ui.rootpane.DarkRootPaneUI; + +import javax.swing.*; +import java.awt.*; + +public class DarkPopupFactory extends PopupFactory { + @Override + public Popup getPopup(final Component owner, final Component contents, + final int x, final int y) throws IllegalArgumentException { + Popup popup = super.getPopup(owner, contents, x, y); + // Sometimes the background is java.awt.SystemColor[i=7] + // It results in a flash of white background, that is repainted with + // the proper popup background later. + // That is why we set window background explicitly. + Window window = SwingUtilities.getWindowAncestor(contents); + if (window != null) { + window.setBackground(UIManager.getColor("PopupMenu.translucentBackground")); + boolean install = true; + if (window instanceof RootPaneContainer) { + JRootPane rootPane = ((RootPaneContainer) window).getRootPane(); + rootPane.putClientProperty(DarkRootPaneUI.KEY_IS_POPUP, true); + install = !Boolean.TRUE.equals(rootPane.getClientProperty(DarkRootPaneUI.KEY_IS_TOOLTIP)); + } + if (install) { + Decorations.installPopupWindow(window); + } else { + Decorations.uninstallPopupWindow(window); + } + } + return popup; + } +} diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/menu/DarkMenuUI.java b/core/src/main/java/com/github/weisj/darklaf/ui/menu/DarkMenuUI.java index 5bfa8f8a..0d87865a 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/menu/DarkMenuUI.java +++ b/core/src/main/java/com/github/weisj/darklaf/ui/menu/DarkMenuUI.java @@ -61,6 +61,9 @@ public class DarkMenuUI extends BasicMenuUI { if (listener.getClass().getEnclosingClass().equals(BasicMenuUI.class)) { menu.removeMouseListener(listener); mouseListener = new MouseDelegate(listener) { + private boolean pressed = false; + private boolean wasEnabled = false; + @Override public void mouseEntered(final MouseEvent e) { MenuSelectionManager manager = MenuSelectionManager.defaultManager(); @@ -72,6 +75,23 @@ public class DarkMenuUI extends BasicMenuUI { } super.mouseEntered(e); } + + @Override + public void mousePressed(final MouseEvent e) { + pressed = true; + wasEnabled = menu.isEnabled() && menu.isSelected() && menu.getPopupMenu().isShowing(); + super.mousePressed(e); + } + + @Override + public void mouseReleased(final MouseEvent e) { + if (!menu.isEnabled()) return; + if (pressed && wasEnabled) { + pressed = false; + return; + } + super.mouseReleased(e); + } }; menu.addMouseListener(mouseListener); break; diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/rootpane/DarkRootPaneUI.java b/core/src/main/java/com/github/weisj/darklaf/ui/rootpane/DarkRootPaneUI.java index f3044e7e..bda07c8e 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/rootpane/DarkRootPaneUI.java +++ b/core/src/main/java/com/github/weisj/darklaf/ui/rootpane/DarkRootPaneUI.java @@ -48,6 +48,7 @@ public class DarkRootPaneUI extends BasicRootPaneUI implements HierarchyListener public static final String KEY_PREFIX = "JRootPane."; public static final String KEY_IS_POPUP = KEY_PREFIX + "isPopup"; + public static final String KEY_IS_TOOLTIP = KEY_PREFIX + "isToolTip"; private Window window; private CustomTitlePane titlePane; private LayoutManager layoutManager; diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/tooltip/DarkTooltipUI.java b/core/src/main/java/com/github/weisj/darklaf/ui/tooltip/DarkTooltipUI.java index 38a2fe48..74b93380 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/tooltip/DarkTooltipUI.java +++ b/core/src/main/java/com/github/weisj/darklaf/ui/tooltip/DarkTooltipUI.java @@ -23,6 +23,8 @@ */ package com.github.weisj.darklaf.ui.tooltip; +import com.github.weisj.darklaf.components.tooltip.ToolTipStyle; +import com.github.weisj.darklaf.ui.rootpane.DarkRootPaneUI; import com.github.weisj.darklaf.util.Alignment; import com.github.weisj.darklaf.util.DarkUIUtil; import com.github.weisj.darklaf.util.PropertyKey; @@ -54,6 +56,8 @@ public class DarkTooltipUI extends BasicToolTipUI implements PropertyChangeListe public static final String VARIANT_BALLOON = "balloon"; protected JToolTip toolTip; + protected JRootPane lastRootPane; + protected ToolTipStyle style; protected MouseListener exitListener = new MouseAdapter() { @Override public void mouseExited(final MouseEvent e) { @@ -130,6 +134,7 @@ public class DarkTooltipUI extends BasicToolTipUI implements PropertyChangeListe toolTip = (JToolTip) c; super.installUI(c); toolTip.setBorder(new DarkTooltipBorder()); + toolTip.putClientProperty(KEY_STYLE, ToolTipStyle.BALLOON); } @Override @@ -211,8 +216,17 @@ public class DarkTooltipUI extends BasicToolTipUI implements PropertyChangeListe //For MediumWeightPopup still need to make parent non opaque. ((JComponent) toolTip.getParent()).setOpaque(false); } + if (lastRootPane != null) { + lastRootPane.putClientProperty(DarkRootPaneUI.KEY_IS_TOOLTIP, false); + } if (w != null && !isDecorated(w) && (w.getClass().getEnclosingClass().equals(Popup.class))) { w.setBackground(DarkUIUtil.TRANSPARENT_COLOR); + if (w instanceof RootPaneContainer) { + lastRootPane = ((RootPaneContainer) w).getRootPane(); + if (lastRootPane != null) { + lastRootPane.putClientProperty(DarkRootPaneUI.KEY_IS_TOOLTIP, true); + } + } } } @@ -270,6 +284,13 @@ public class DarkTooltipUI extends BasicToolTipUI implements PropertyChangeListe } } + protected ToolTipStyle getStyle() { + Object prop = toolTip.getClientProperty(KEY_STYLE); + String propValue = prop != null ? prop.toString() : null; + if (ToolTipStyle.BALLOON.name().equals(propValue)) return ToolTipStyle.BALLOON; + return ToolTipStyle.PLAIN; + } + protected void updateSize() { toolTip.setTipText(toolTip.getTipText()); toolTip.setPreferredSize(getPreferredSize(toolTip)); diff --git a/decorations-base/src/main/java/com/github/weisj/darklaf/decorations/DecorationsProvider.java b/decorations-base/src/main/java/com/github/weisj/darklaf/decorations/DecorationsProvider.java index cfac2727..ed3fe933 100644 --- a/decorations-base/src/main/java/com/github/weisj/darklaf/decorations/DecorationsProvider.java +++ b/decorations-base/src/main/java/com/github/weisj/darklaf/decorations/DecorationsProvider.java @@ -62,6 +62,12 @@ public interface DecorationsProvider { /** * Initialize the window of a popup menu. */ - default void initPopupWindow(final Window window) { + default void installPopupMenu(final Window window) { + } + + /** + * Uninstall the window of a popup menu. + */ + default void uninstallPopupWindow(final Window window) { } } diff --git a/windows/src/main/java/com/github/weisj/darklaf/platform/windows/WindowsDecorationsProvider.java b/windows/src/main/java/com/github/weisj/darklaf/platform/windows/WindowsDecorationsProvider.java index bad23eb0..c25d4ad6 100644 --- a/windows/src/main/java/com/github/weisj/darklaf/platform/windows/WindowsDecorationsProvider.java +++ b/windows/src/main/java/com/github/weisj/darklaf/platform/windows/WindowsDecorationsProvider.java @@ -54,7 +54,7 @@ public class WindowsDecorationsProvider implements DecorationsProvider { } @Override - public void initPopupWindow(final Window window) { + public void installPopupMenu(final Window window) { if (!window.isDisplayable()) { window.addNotify(); } @@ -70,6 +70,17 @@ public class WindowsDecorationsProvider implements DecorationsProvider { } } + @Override + public void uninstallPopupWindow(final Window window) { + if (window.isDisplayable()) { + long hwnd = PointerUtil.getHWND(window); + if (hwnd != 0) { + JNIDecorationsWindows.uninstallDecorations(hwnd); + } + window.dispose(); + } + } + @Override public void loadDecorationProperties(final Properties properties, final UIDefaults currentDefaults) { IconLoader iconLoader = IconLoader.get(WindowsDecorationsProvider.class);