From 4c28099ec93872490552e590de255273b0812dd6 Mon Sep 17 00:00:00 2001 From: Jannis Weis <31143295+weisJ@users.noreply.github.com> Date: Sun, 26 Dec 2021 22:47:02 +0100 Subject: [PATCH] ScrollBar: Use rounded scrollbars on Windows 11 --- .../darklaf/task/ThemeDefaultsInitTask.java | 9 +- .../ui/scrollpane/DarkMacScrollBarUI.java | 102 +------------ .../ui/scrollpane/DarkRoundedScrollBarUI.java | 136 ++++++++++++++++++ .../scrollpane/DarkWindows11ScrollBarUI.java | 43 ++++++ .../darklaf/platform/windows11.properties | 31 ++++ .../github/weisj/darklaf/util/SystemInfo.java | 4 +- 6 files changed, 222 insertions(+), 103 deletions(-) create mode 100644 core/src/main/java/com/github/weisj/darklaf/ui/scrollpane/DarkRoundedScrollBarUI.java create mode 100644 core/src/main/java/com/github/weisj/darklaf/ui/scrollpane/DarkWindows11ScrollBarUI.java create mode 100644 core/src/main/resources/com/github/weisj/darklaf/platform/windows11.properties diff --git a/core/src/main/java/com/github/weisj/darklaf/task/ThemeDefaultsInitTask.java b/core/src/main/java/com/github/weisj/darklaf/task/ThemeDefaultsInitTask.java index 3249cf8a..f846803e 100644 --- a/core/src/main/java/com/github/weisj/darklaf/task/ThemeDefaultsInitTask.java +++ b/core/src/main/java/com/github/weisj/darklaf/task/ThemeDefaultsInitTask.java @@ -25,6 +25,7 @@ import java.awt.*; import java.util.HashMap; import java.util.Objects; import java.util.Properties; +import java.util.function.Consumer; import javax.swing.*; @@ -155,9 +156,13 @@ public class ThemeDefaultsInitTask implements DefaultsInitTask { private void initPlatformProperties(final Theme currentTheme, final UIDefaults defaults, final Properties uiProps) { IconResolver iconResolver = DarkUIUtil.iconResolver(); - PropertyLoader.putProperties( - PropertyLoader.loadProperties(DarkLaf.class, getOsName(), "platform/"), + Consumer osPlatformLoader = osName -> PropertyLoader.putProperties( + PropertyLoader.loadProperties(DarkLaf.class, osName, "platform/"), uiProps, defaults, iconResolver); + osPlatformLoader.accept(getOsName()); + if (SystemInfo.isWindows11OrGreater) { + osPlatformLoader.accept("windows11"); + } currentTheme.customizePlatformProperties(uiProps, defaults, iconResolver); } diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/scrollpane/DarkMacScrollBarUI.java b/core/src/main/java/com/github/weisj/darklaf/ui/scrollpane/DarkMacScrollBarUI.java index 638ec323..fab745e4 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/scrollpane/DarkMacScrollBarUI.java +++ b/core/src/main/java/com/github/weisj/darklaf/ui/scrollpane/DarkMacScrollBarUI.java @@ -21,19 +21,10 @@ */ package com.github.weisj.darklaf.ui.scrollpane; -import java.awt.*; -import java.awt.geom.RoundRectangle2D; - import javax.swing.*; import javax.swing.plaf.ComponentUI; -import com.github.weisj.darklaf.graphics.LegacyAnimator; -import com.github.weisj.darklaf.util.graphics.GraphicsContext; -import com.github.weisj.darklaf.util.graphics.GraphicsUtil; - -public class DarkMacScrollBarUI extends DarkScrollBarUI { - - private boolean hideScrollBar; +public class DarkMacScrollBarUI extends DarkRoundedScrollBarUI { public static ComponentUI createUI(final JComponent c) { return new DarkMacScrollBarUI(); @@ -46,94 +37,7 @@ public class DarkMacScrollBarUI extends DarkScrollBarUI { } @Override - protected void paintTrack(final Graphics g, final JComponent c, final Rectangle bounds) {} - - @Override - protected void paintMaxiThumb(final Graphics2D g, final Rectangle rect) { - GraphicsContext context = GraphicsUtil.setupStrokePainting(g); - g.setComposite(COMPOSITE.derive(thumbAlpha)); - boolean horizontal = scrollbar.getOrientation() == JScrollBar.HORIZONTAL; - int ins = 2; - RoundRectangle2D roundRect = new RoundRectangle2D.Float(); - int width = rect.width - 2 * ins; - int height = rect.height - 2 * ins; - int x = rect.x + ins; - int y = rect.y + ins; - if (hideScrollBar) { - float animationState = scrollBarListener.getTrackState(); - if (horizontal) { - int newHeight = Math.round(height * animationState); - y += height - newHeight; - height = newHeight; - } else { - int newWidth = Math.round(width * animationState); - if (scrollbar.getComponentOrientation().isLeftToRight()) { - x += width - newWidth; - } - width = newWidth; - } - } - int arc = horizontal ? height : width; - roundRect.setRoundRect(x, y, width, height, arc, arc); - g.setColor(getThumbColor()); - g.fill(roundRect); - g.setColor(getThumbBorderColor()); - g.draw(roundRect); - context.restore(); - } - - @Override - protected DarkScrollBarListener createScrollBarListener() { - return new MacScrollBarListener(scrollbar, this); - } - - private static class MacScrollBarListener extends DarkScrollBarListener { - - private final Timer hideTimer; - - public MacScrollBarListener(final JScrollBar scrollbar, final DarkMacScrollBarUI ui) { - super(scrollbar, ui); - int hideDelay = getTrackFadeOutDelay(); - hideTimer = new Timer(hideDelay, e -> { - Point p = MouseInfo.getPointerInfo().getLocation(); - SwingUtilities.convertPointFromScreen(p, scrollbar); - mouseOverTrack = scrollbar.contains(p); - resetTrackAnimator(); - }); - hideTimer.setRepeats(false); - } - - @Override - protected boolean animateTrackOnScroll(final JScrollBar scrollbar) { - return ui.hideScrollBar; - } - - @Override - protected LegacyAnimator createTrackFadeinAnimator() { - return ui.hideScrollBar ? super.createTrackFadeinAnimator() : null; - } - - @Override - protected LegacyAnimator createTrackFadeoutAnimator() { - return ui.hideScrollBar ? super.createTrackFadeoutAnimator() : null; - } - - @Override - protected int getTrackFadeOutDelay() { - return UIManager.getInt("ScrollBar.macos.hideDelay"); - } - - @Override - protected void runOnScrollTrackAnimation() { - super.runOnScrollTrackAnimation(); - hideTimer.stop(); - hideTimer.start(); - } - - @Override - protected void resetTrackAnimator() { - hideTimer.stop(); - super.resetTrackAnimator(); - } + protected int getTrackFadeOutDelay() { + return UIManager.getInt("ScrollBar.macos.hideDelay"); } } diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/scrollpane/DarkRoundedScrollBarUI.java b/core/src/main/java/com/github/weisj/darklaf/ui/scrollpane/DarkRoundedScrollBarUI.java new file mode 100644 index 00000000..8528c292 --- /dev/null +++ b/core/src/main/java/com/github/weisj/darklaf/ui/scrollpane/DarkRoundedScrollBarUI.java @@ -0,0 +1,136 @@ +/* + * MIT License + * + * Copyright (c) 2021 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.scrollpane; + +import java.awt.*; +import java.awt.geom.RoundRectangle2D; + +import javax.swing.*; + +import com.github.weisj.darklaf.graphics.LegacyAnimator; +import com.github.weisj.darklaf.util.graphics.GraphicsContext; +import com.github.weisj.darklaf.util.graphics.GraphicsUtil; + +public abstract class DarkRoundedScrollBarUI extends DarkScrollBarUI { + + protected boolean hideScrollBar = false; + + @Override + protected void installDefaults() { + super.installDefaults(); + hideScrollBar = UIManager.getBoolean("ScrollBar.macos.hideScrollBar"); + } + + protected abstract int getTrackFadeOutDelay(); + + @Override + protected void paintTrack(final Graphics g, final JComponent c, final Rectangle bounds) {} + + @Override + protected void paintMaxiThumb(final Graphics2D g, final Rectangle rect) { + GraphicsContext context = GraphicsUtil.setupStrokePainting(g); + g.setComposite(COMPOSITE.derive(thumbAlpha)); + boolean horizontal = scrollbar.getOrientation() == JScrollBar.HORIZONTAL; + int ins = 2; + RoundRectangle2D roundRect = new RoundRectangle2D.Float(); + int width = rect.width - 2 * ins; + int height = rect.height - 2 * ins; + int x = rect.x + ins; + int y = rect.y + ins; + if (hideScrollBar) { + float animationState = scrollBarListener.getTrackState(); + if (horizontal) { + int newHeight = Math.round(height * animationState); + y += height - newHeight; + height = newHeight; + } else { + int newWidth = Math.round(width * animationState); + if (scrollbar.getComponentOrientation().isLeftToRight()) { + x += width - newWidth; + } + width = newWidth; + } + } + int arc = horizontal ? height : width; + roundRect.setRoundRect(x, y, width, height, arc, arc); + g.setColor(getThumbColor()); + g.fill(roundRect); + g.setColor(getThumbBorderColor()); + g.draw(roundRect); + context.restore(); + } + + @Override + protected DarkScrollBarListener createScrollBarListener() { + return new RoundedScrollBarListener(scrollbar, this); + } + + private static class RoundedScrollBarListener extends DarkScrollBarListener { + + private final Timer hideTimer; + + public RoundedScrollBarListener(final JScrollBar scrollbar, final DarkRoundedScrollBarUI ui) { + super(scrollbar, ui); + int hideDelay = getTrackFadeOutDelay(); + hideTimer = new Timer(hideDelay, e -> { + Point p = MouseInfo.getPointerInfo().getLocation(); + SwingUtilities.convertPointFromScreen(p, scrollbar); + mouseOverTrack = scrollbar.contains(p); + resetTrackAnimator(); + }); + hideTimer.setRepeats(false); + } + + @Override + protected boolean animateTrackOnScroll(final JScrollBar scrollbar) { + return ui.hideScrollBar; + } + + @Override + protected LegacyAnimator createTrackFadeinAnimator() { + return ui.hideScrollBar ? super.createTrackFadeinAnimator() : null; + } + + @Override + protected LegacyAnimator createTrackFadeoutAnimator() { + return ui.hideScrollBar ? super.createTrackFadeoutAnimator() : null; + } + + @Override + protected int getTrackFadeOutDelay() { + return ui.getTrackFadeOutDelay(); + } + + @Override + protected void runOnScrollTrackAnimation() { + super.runOnScrollTrackAnimation(); + hideTimer.stop(); + hideTimer.start(); + } + + @Override + protected void resetTrackAnimator() { + hideTimer.stop(); + super.resetTrackAnimator(); + } + } +} diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/scrollpane/DarkWindows11ScrollBarUI.java b/core/src/main/java/com/github/weisj/darklaf/ui/scrollpane/DarkWindows11ScrollBarUI.java new file mode 100644 index 00000000..ba0e036f --- /dev/null +++ b/core/src/main/java/com/github/weisj/darklaf/ui/scrollpane/DarkWindows11ScrollBarUI.java @@ -0,0 +1,43 @@ +/* + * MIT License + * + * Copyright (c) 2021 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.scrollpane; + +import javax.swing.*; +import javax.swing.plaf.ComponentUI; + +public class DarkWindows11ScrollBarUI extends DarkRoundedScrollBarUI { + + public static ComponentUI createUI(final JComponent c) { + return new DarkWindows11ScrollBarUI(); + } + + @Override + protected void installDefaults() { + super.installDefaults(); + hideScrollBar = UIManager.getBoolean("ScrollBar.windows11.hideScrollBar"); + } + + @Override + protected int getTrackFadeOutDelay() { + return UIManager.getInt("ScrollBar.windows11.hideDelay"); + } +} diff --git a/core/src/main/resources/com/github/weisj/darklaf/platform/windows11.properties b/core/src/main/resources/com/github/weisj/darklaf/platform/windows11.properties new file mode 100644 index 00000000..58d459b1 --- /dev/null +++ b/core/src/main/resources/com/github/weisj/darklaf/platform/windows11.properties @@ -0,0 +1,31 @@ +# +# MIT License +# +# Copyright (c) 2021 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. +# +# +# suppress inspection "UnusedProperty" for whole file +# +ScrollBarUI = com.github.weisj.darklaf.ui.scrollpane.DarkWindows11ScrollBarUI +ScrollBar.smallWidth = 10 +ScrollBar.width = 12 +ScrollBar.windows11.hideScrollBar = false +ScrollBar.windows11.hideDelay = 1200 diff --git a/utils/src/main/java/com/github/weisj/darklaf/util/SystemInfo.java b/utils/src/main/java/com/github/weisj/darklaf/util/SystemInfo.java index 636af589..892a033e 100644 --- a/utils/src/main/java/com/github/weisj/darklaf/util/SystemInfo.java +++ b/utils/src/main/java/com/github/weisj/darklaf/util/SystemInfo.java @@ -69,6 +69,7 @@ public final class SystemInfo { public static final boolean isMacOSMojave; public static final boolean isMacOSCatalina; public static final boolean isMacOSYosemite; + public static final boolean isWindows11OrGreater; public static final boolean isWindows10OrGreater; public static final boolean isWindows7; public static final boolean isWindowsVista; @@ -96,8 +97,7 @@ public final class SystemInfo { isMacOSYosemite = isMacOSCatalina || (isMac && isOsVersionAtLeast("10.10")); isWindows10OrGreater = isWindows && isOsVersionAtLeast("10.0"); - System.out.println(OS_VERSION); - System.out.println(OS_NAME); + isWindows11OrGreater = isWindows && _OS_NAME.contains("windows 11"); isWindows7 = isWindows10OrGreater || (isWindows && isOsVersionAtLeast("6.1")); isWindowsVista = isWindows7 || (isWindows && isOsVersionAtLeast("6.0"));