diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b055641..ecce5cce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ FlatLaf Change Log for editable comboboxes). - ComboBox: Support custom borders in combobox editors. (issue #102) - Ubuntu Linux: Fixed poorly rendered font. (issue #105) +- macOS Catalina: Use Helvetica Neue font. ## 0.35 diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java index d8c72c3a..e535daf6 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java @@ -411,7 +411,10 @@ public abstract class FlatLaf } else if( SystemInfo.IS_MAC ) { String fontName; - if( SystemInfo.IS_MAC_OS_10_11_EL_CAPITAN_OR_LATER ) { + if( SystemInfo.IS_MAC_OS_10_15_CATALINA_OR_LATER ) { + // use Helvetica Neue font + fontName = "Helvetica Neue"; + } else if( SystemInfo.IS_MAC_OS_10_11_EL_CAPITAN_OR_LATER ) { // use San Francisco Text font fontName = ".SF NS Text"; } else { diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatInternalFrameAbstractIcon.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatInternalFrameAbstractIcon.java index edf0dd7d..1c993ab1 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatInternalFrameAbstractIcon.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatInternalFrameAbstractIcon.java @@ -27,6 +27,7 @@ import com.formdev.flatlaf.ui.FlatUIUtils; /** * Base class for internal frame icons. * + * @uiDefault InternalFrame.buttonSize Dimension * @uiDefault InternalFrame.buttonHoverBackground Color * @uiDefault InternalFrame.buttonPressedBackground Color * diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatInternalFrameCloseIcon.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatInternalFrameCloseIcon.java index 2461480d..db6526fd 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatInternalFrameCloseIcon.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatInternalFrameCloseIcon.java @@ -28,8 +28,11 @@ import com.formdev.flatlaf.ui.FlatButtonUI; /** * "close" icon for {@link javax.swing.JInternalFrame}. * - * @uiDefault InternalFrame.buttonHoverBackground Color - * @uiDefault InternalFrame.buttonPressedBackground Color + * @uiDefault InternalFrame.buttonSize Dimension + * @uiDefault InternalFrame.closeHoverBackground Color + * @uiDefault InternalFrame.closePressedBackground Color + * @uiDefault InternalFrame.closeHoverForeground Color + * @uiDefault InternalFrame.closePressedForeground Color * * @author Karl Tauber */ diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatInternalFrameMinimizeIcon.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatInternalFrameRestoreIcon.java similarity index 89% rename from flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatInternalFrameMinimizeIcon.java rename to flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatInternalFrameRestoreIcon.java index 7256d1a2..dcf79e71 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatInternalFrameMinimizeIcon.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatInternalFrameRestoreIcon.java @@ -24,14 +24,14 @@ import java.awt.geom.Rectangle2D; import com.formdev.flatlaf.ui.FlatUIUtils; /** - * "minimize" (actually "restore") icon for {@link javax.swing.JInternalFrame}. + * "restore" (or "minimize") icon for {@link javax.swing.JInternalFrame}. * * @author Karl Tauber */ -public class FlatInternalFrameMinimizeIcon +public class FlatInternalFrameRestoreIcon extends FlatInternalFrameAbstractIcon { - public FlatInternalFrameMinimizeIcon() { + public FlatInternalFrameRestoreIcon() { } @Override diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatArrowButton.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatArrowButton.java index 70dbdc2f..6627edb9 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatArrowButton.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatArrowButton.java @@ -145,11 +145,21 @@ public class FlatArrowButton int direction = getDirection(); boolean vert = (direction == NORTH || direction == SOUTH); + // compute width/height int w = scale( arrowWidth + (chevron ? 0 : 1) ); int h = scale( (arrowWidth / 2) + (chevron ? 0 : 1) ); + + // rotate width/height int rw = vert ? w : h; int rh = vert ? h : w; + // chevron lines end 1px outside of width/height + if( chevron ) { + // add 1px to width/height for position calculation only + rw++; + rh++; + } + // Adding -/+0.35 before rounding tends move up NORTH arrows and move down SOUTH arrows. // This makes top margin of NORTH arrow equal to bottom margin of SOUTH arrow. float rd = 0.35f; @@ -159,12 +169,6 @@ public class FlatArrowButton int x = Math.round( (width - rw) / 2f + scale( (float) xOffset ) + xrd ); int y = Math.round( (height - rh) / 2f + scale( (float) yOffset ) + yrd ); - // optimization for small chevron arrows (e.g. OneTouchButtons in SplitPane) - if( x + rw >= width && x > 0 ) - x--; - if( y + rh >= height && y > 0 ) - y--; - // move arrow for round borders Container parent = getParent(); if( vert && parent instanceof JComponent && FlatUIUtils.hasRoundBorder( (JComponent) parent ) ) @@ -176,7 +180,7 @@ public class FlatArrowButton : disabledForeground ); g.translate( x, y ); /*debug - debugPaint( g2, vert, w, h ); + debugPaint( g2, vert, rw, rh ); debug*/ Shape arrowShape = createArrowShape( direction, chevron, w, h ); if( chevron ) { @@ -203,7 +207,7 @@ debug*/ private void debugPaint( Graphics g, boolean vert, int w, int h ) { Color oldColor = g.getColor(); g.setColor( Color.red ); - g.drawRect( 0, 0, (vert ? w : h) - 1, (vert ? h : w) - 1 ); + g.drawRect( 0, 0, w - 1, h - 1 ); int xy1 = -2; int xy2 = h + 1; diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatRootPaneUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatRootPaneUI.java index 3ce1f6c4..3362753b 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatRootPaneUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatRootPaneUI.java @@ -16,6 +16,7 @@ package com.formdev.flatlaf.ui; +import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; @@ -25,10 +26,14 @@ import java.awt.LayoutManager2; import java.beans.PropertyChangeEvent; import java.util.function.Function; import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.JFrame; import javax.swing.JLayeredPane; import javax.swing.JMenuBar; import javax.swing.JRootPane; +import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.UIResource; import javax.swing.plaf.basic.BasicRootPaneUI; import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.util.SystemInfo; @@ -70,6 +75,23 @@ public class FlatRootPaneUI rootPane = null; } + @Override + protected void installDefaults( JRootPane c ) { + super.installDefaults( c ); + + // Update background color of JFrame or JDialog parent to avoid bad border + // on HiDPI screens when switching from light to dark Laf. + // The background of JFrame is initialized in JFrame.frameInit() and + // the background of JDialog in JDialog.dialogInit(), + // but it was not updated when switching Laf. + Container parent = c.getParent(); + if( parent instanceof JFrame || parent instanceof JDialog ) { + Color background = parent.getBackground(); + if( background == null || background instanceof UIResource ) + parent.setBackground( UIManager.getColor( "control" ) ); + } + } + private void installClientDecorations() { // install title pane setTitlePane( new FlatTitlePane( rootPane ) ); diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/util/SystemInfo.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/util/SystemInfo.java index 91aedb84..24a54fff 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/util/SystemInfo.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/util/SystemInfo.java @@ -34,6 +34,7 @@ public class SystemInfo // OS versions public static final boolean IS_WINDOWS_10_OR_LATER; public static final boolean IS_MAC_OS_10_11_EL_CAPITAN_OR_LATER; + public static final boolean IS_MAC_OS_10_15_CATALINA_OR_LATER; // Java versions public static final boolean IS_JAVA_9_OR_LATER; @@ -57,6 +58,7 @@ public class SystemInfo long osVersion = scanVersion( System.getProperty( "os.version" ) ); IS_WINDOWS_10_OR_LATER = (IS_WINDOWS && osVersion >= toVersion( 10, 0, 0, 0 )); IS_MAC_OS_10_11_EL_CAPITAN_OR_LATER = (IS_MAC && osVersion >= toVersion( 10, 11, 0, 0 )); + IS_MAC_OS_10_15_CATALINA_OR_LATER = (IS_MAC && osVersion >= toVersion( 10, 15, 0, 0 )); // Java versions long javaVersion = scanVersion( System.getProperty( "java.version" ) ); diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties index 0f9748ec..bb199a39 100644 --- a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties +++ b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties @@ -261,7 +261,7 @@ InternalFrame.buttonSize=24,24 InternalFrame.closeIcon=com.formdev.flatlaf.icons.FlatInternalFrameCloseIcon InternalFrame.iconifyIcon=com.formdev.flatlaf.icons.FlatInternalFrameIconifyIcon InternalFrame.maximizeIcon=com.formdev.flatlaf.icons.FlatInternalFrameMaximizeIcon -InternalFrame.minimizeIcon=com.formdev.flatlaf.icons.FlatInternalFrameMinimizeIcon +InternalFrame.minimizeIcon=com.formdev.flatlaf.icons.FlatInternalFrameRestoreIcon InternalFrame.windowBindings=null # drop shadow diff --git a/flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/intellijthemes/themes.json b/flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/intellijthemes/themes.json index ea644c30..5665ec31 100644 --- a/flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/intellijthemes/themes.json +++ b/flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/intellijthemes/themes.json @@ -46,21 +46,21 @@ "license": "MIT", "licenseFile": "Gradianto.LICENSE.txt", "sourceCodeUrl": "https://github.com/thvardhan/Gradianto", - "sourceCodePath": "blob/master/resources/Gradianto_dark_fuchsia.theme.json" + "sourceCodePath": "blob/master/src/main/resources/Gradianto_dark_fuchsia.theme.json" }, "Gradianto_deep_ocean.theme.json": { "name": "Gradianto Deep Ocean", "license": "MIT", "licenseFile": "Gradianto.LICENSE.txt", "sourceCodeUrl": "https://github.com/thvardhan/Gradianto", - "sourceCodePath": "blob/master/resources/Gradianto_deep_ocean.theme.json" + "sourceCodePath": "blob/master/src/main/resources/Gradianto_deep_ocean.theme.json" }, "Gradianto_midnight_blue.theme.json": { "name": "Gradianto Midnight Blue", "license": "MIT", "licenseFile": "Gradianto.LICENSE.txt", "sourceCodeUrl": "https://github.com/thvardhan/Gradianto", - "sourceCodePath": "blob/master/resources/Gradianto_midnight_blue.theme.json" + "sourceCodePath": "blob/master/src/main/resources/Gradianto_midnight_blue.theme.json" }, "Gray.theme.json": { "name": "Gray", diff --git a/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/Dracula.theme.json b/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/Dracula.theme.json index 0f8d3a49..f963edfd 100644 --- a/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/Dracula.theme.json +++ b/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/Dracula.theme.json @@ -159,6 +159,13 @@ "inactiveBackground": "#44475a" } }, + "ScrollBar": { + "Mac": { + "Transparent": { + "hoverThumbColor": "#bd93f9" + } + } + }, "SearchEverywhere": { "SearchField": { "background": "#44475a" diff --git a/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/Gradianto_dark_fuchsia.theme.json b/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/Gradianto_dark_fuchsia.theme.json index 2881d526..88298cb0 100644 --- a/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/Gradianto_dark_fuchsia.theme.json +++ b/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/Gradianto_dark_fuchsia.theme.json @@ -1,7 +1,7 @@ { "name": "Gradianto Dark Fuchsia", "dark": true, - "author": "", + "author": "thvardhan", "editorScheme": "/Gradianto_dark_fuchsia.xml", "ui": { "*": { diff --git a/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/Gradianto_deep_ocean.theme.json b/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/Gradianto_deep_ocean.theme.json index ae71adc3..678f8866 100644 --- a/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/Gradianto_deep_ocean.theme.json +++ b/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/Gradianto_deep_ocean.theme.json @@ -1,7 +1,7 @@ { "name": "Gradianto Deep Ocean", "dark": true, - "author": "", + "author": "thvardhan", "editorScheme": "/Gradianto_deep_ocean.xml", "ui": { "*": { @@ -214,7 +214,7 @@ "tagBackground": "#3d445a", "lightSelectionBackground": "#3c4b7e" }, - "EditorPane.inactiveBackground": "#040c25" + "EditorPane.inactiveBackground": "#25334aff" }, "icons": { "ColorPalette": { diff --git a/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/Gradianto_midnight_blue.theme.json b/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/Gradianto_midnight_blue.theme.json index ec6ecb49..f67f5d98 100644 --- a/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/Gradianto_midnight_blue.theme.json +++ b/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/Gradianto_midnight_blue.theme.json @@ -1,7 +1,7 @@ { "name": "Gradianto Midnight Blue", "dark": true, - "author": "", + "author": "thvardhan", "editorScheme": "/Gradianto_midnight_blue.xml", "ui": { "*": { @@ -217,7 +217,7 @@ "tagBackground": "#40405a", "lightSelectionBackground": "#48387e" }, - "EditorPane.inactiveBackground": "#1a0225" + "EditorPane.inactiveBackground": "#414157ff" }, "icons": { "ColorPalette": { diff --git a/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/gruvbox_dark_hard.theme.json b/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/gruvbox_dark_hard.theme.json index 65c5ceec..008d26e4 100644 --- a/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/gruvbox_dark_hard.theme.json +++ b/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/gruvbox_dark_hard.theme.json @@ -5,6 +5,7 @@ "editorScheme": "/gruvbox_dark_hard.xml", "colors": { "bg0": "#282828", + "bg0_hh": "#101415", "bg0_h": "#1d2021", "bg0_s": "#32302f", "bg1": "#3c3836", @@ -51,7 +52,7 @@ "selectionBackgroundInactive": "bg0_s", "selectionInactiveBackground": "bg0_s", - "selectedBackground": "bg0_h", + "selectedBackground": "bg0_hh", "selectedForeground": "fg0", "selectedInactiveBackground": "bg0_s", "selectedBackgroundInactive": "bg0_s", @@ -59,7 +60,7 @@ "hoverBackground": "#28282866", "borderColor": "bg2", - "disabledBorderColor": "bg0_h", + "disabledBorderColor": "bg0_hh", "separatorColor": "bg2" }, @@ -91,6 +92,7 @@ }, "EditorTabs": { "selectedBackground": "bg0_s", + "underlinedTabBackground": "bg2", "underlineColor": "blue1", "inactiveMaskColor": "#28282866" }, @@ -101,8 +103,8 @@ }, "HeaderTab": { - "selectedInactiveBackground": "bg0_h", - "hoverInactiveBackground": "bg0_h" + "selectedInactiveBackground": "bg0_hh", + "hoverInactiveBackground": "bg0_hh" } }, "Table": { diff --git a/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/gruvbox_dark_medium.theme.json b/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/gruvbox_dark_medium.theme.json index d4e0191a..6dcfcaa6 100644 --- a/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/gruvbox_dark_medium.theme.json +++ b/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/gruvbox_dark_medium.theme.json @@ -91,6 +91,7 @@ }, "EditorTabs": { "selectedBackground": "bg0_s", + "underlinedTabBackground": "bg2", "underlineColor": "blue1", "inactiveMaskColor": "#28282866" }, diff --git a/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/gruvbox_dark_soft.theme.json b/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/gruvbox_dark_soft.theme.json index 1f56814c..079a2e86 100644 --- a/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/gruvbox_dark_soft.theme.json +++ b/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/gruvbox_dark_soft.theme.json @@ -91,6 +91,7 @@ }, "EditorTabs": { "selectedBackground": "bg0_s", + "underlinedTabBackground": "bg2", "underlineColor": "blue1", "inactiveMaskColor": "#28282866" }, diff --git a/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/material-theme-ui-lite/Atom One Light Contrast.theme.json b/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/material-theme-ui-lite/Atom One Light Contrast.theme.json index f0ce2f3f..fac18fc2 100644 --- a/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/material-theme-ui-lite/Atom One Light Contrast.theme.json +++ b/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/material-theme-ui-lite/Atom One Light Contrast.theme.json @@ -1,5 +1,5 @@ { - "name": "Atom One Light", + "name": "Atom One Light Contrast", "dark": false, "author": "Mallowigi", "editorScheme": "/colors/Atom One Light.xml", diff --git a/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/one_dark.theme.json b/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/one_dark.theme.json index 2d511479..8f06c691 100644 --- a/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/one_dark.theme.json +++ b/flatlaf-intellij-themes/src/main/resources/com/formdev/flatlaf/intellijthemes/themes/one_dark.theme.json @@ -24,7 +24,7 @@ "errorForeground": "#cd3359", - "borderColor": "#46494f", + "borderColor": "#333841", "disabledBorderColor": "#2d3137", "focusColor": "#21252b", "focusedBorderColor": "#568AF2", @@ -93,8 +93,6 @@ "foreground": "#abb2bf" }, - "DebuggerPopup.borderColor": "#46494f", - "DefaultTabs": { "underlineColor": "#568AF2", "inactiveUnderlineColor": "#4269b9", @@ -104,7 +102,7 @@ "DragAndDrop": { "areaForeground": "#abb2bf", "areaBackground": "#323844", - "areaBorderColor": "#46494f" + "areaBorderColor": "#333841" }, "Editor": { @@ -139,11 +137,6 @@ "visitedForeground": "#6494ed" }, - "MenuBar.borderColor": "#46494f", - "Menu.borderColor": "#2d3137", - - "NavBar.borderColor": "#46494f", - "Notification": { "background": "#3d424b", "borderColor": "#53565f", @@ -312,8 +305,7 @@ "Header": { "background": "#414855", - "inactiveBackground": "#323844", - "borderColor": "#21252b" + "inactiveBackground": "#323844" }, "HeaderTab": { diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatInspector.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatInspector.java index 65989707..58a88d4c 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatInspector.java +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatInspector.java @@ -28,15 +28,19 @@ import java.awt.Graphics2D; import java.awt.Insets; import java.awt.KeyboardFocusManager; import java.awt.LayoutManager; +import java.awt.MouseInfo; import java.awt.Point; import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.Window; +import java.awt.event.AWTEventListener; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.awt.event.MouseMotionListener; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; import java.lang.reflect.Field; import javax.swing.AbstractButton; import javax.swing.JComponent; @@ -68,7 +72,10 @@ public class FlatInspector private final JRootPane rootPane; private final MouseMotionListener mouseMotionListener; + private final AWTEventListener keyListener; + private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport( this ); + private boolean enabled; private Component lastComponent; private int lastX; private int lastY; @@ -113,14 +120,40 @@ public class FlatInspector public void mouseMoved( MouseEvent e ) { lastX = e.getX(); lastY = e.getY(); - inspectParentLevel = (e.isControlDown() ? 1 : 0) - + (e.isShiftDown() ? 2 : 0) - + (e.isAltDown() ? 4 : 0); inspect( lastX, lastY ); } }; rootPane.getGlassPane().addMouseMotionListener( mouseMotionListener ); + + keyListener = e -> { + KeyEvent keyEvent = (KeyEvent) e; + int keyCode = keyEvent.getKeyCode(); + + if( e.getID() == KeyEvent.KEY_RELEASED ) { + if( keyCode == KeyEvent.VK_CONTROL ) { + inspectParentLevel++; + inspect( lastX, lastY ); + } else if( keyCode == KeyEvent.VK_SHIFT && inspectParentLevel > 0 ) { + inspectParentLevel--; + inspect( lastX, lastY ); + } + } + + if( keyCode == KeyEvent.VK_ESCAPE ) { + // consume pressed and released ESC key events to e.g. avoid that dialog is closed + keyEvent.consume(); + + if( e.getID() == KeyEvent.KEY_PRESSED ) { + FlatInspector inspector = (FlatInspector) rootPane.getClientProperty( FlatInspector.class ); + if( inspector == FlatInspector.this ) { + uninstall(); + rootPane.putClientProperty( FlatInspector.class, null ); + } else + setEnabled( false ); + } + } + }; } private void uninstall() { @@ -129,11 +162,43 @@ public class FlatInspector rootPane.getGlassPane().removeMouseMotionListener( mouseMotionListener ); } + + public void addPropertyChangeListener( PropertyChangeListener l ) { + propertyChangeSupport.addPropertyChangeListener( l ); + } + + public void removePropertyChangeListener( PropertyChangeListener l ) { + propertyChangeSupport.removePropertyChangeListener( l ); + } + + public boolean isEnabled() { + return enabled; + } + public void setEnabled( boolean enabled ) { + if( this.enabled == enabled ) + return; + + this.enabled = enabled; + rootPane.getGlassPane().setVisible( enabled ); - if( !enabled ) { + Toolkit toolkit = Toolkit.getDefaultToolkit(); + if( enabled ) + toolkit.addAWTEventListener( keyListener, AWTEvent.KEY_EVENT_MASK ); + else + toolkit.removeAWTEventListener( keyListener ); + + if( enabled ) { + Point pt = new Point( MouseInfo.getPointerInfo().getLocation() ); + SwingUtilities.convertPointFromScreen( pt, rootPane ); + + lastX = pt.x; + lastY = pt.y; + inspect( lastX, lastY ); + } else { lastComponent = null; + inspectParentLevel = 0; if( highlightFigure != null ) highlightFigure.getParent().remove( highlightFigure ); @@ -143,6 +208,8 @@ public class FlatInspector tip.getParent().remove( tip ); tip = null; } + + propertyChangeSupport.firePropertyChange( "enabled", !enabled, enabled ); } public void update() { @@ -157,11 +224,14 @@ public class FlatInspector } private void inspect( int x, int y ) { - Container contentPane = rootPane.getContentPane(); - Point pt = SwingUtilities.convertPoint( rootPane.getGlassPane(), x, y, contentPane ); - Component c = SwingUtilities.getDeepestComponentAt( contentPane, pt.x, pt.y ); + Point pt = SwingUtilities.convertPoint( rootPane.getGlassPane(), x, y, rootPane ); + Component c = getDeepestComponentAt( rootPane, pt.x, pt.y ); for( int i = 0; i < inspectParentLevel && c != null; i++ ) { - c = c.getParent(); + Container parent = c.getParent(); + if( parent == null ) + break; + + c = parent; } if( c == lastComponent ) @@ -173,6 +243,38 @@ public class FlatInspector showToolTip( c, x, y ); } + private Component getDeepestComponentAt( Component parent, int x, int y ) { + if( !parent.contains( x, y ) ) + return null; + + if( parent instanceof Container ) { + for( Component child : ((Container)parent).getComponents() ) { + if( child == null || !child.isVisible() ) + continue; + + int cx = x - child.getX(); + int cy = y - child.getY(); + Component c = (child instanceof Container) + ? getDeepestComponentAt( child, cx, cy ) + : child.getComponentAt( cx, cy ); + if( c == null || !c.isVisible() ) + continue; + + // ignore highlight figure and tooltip + if( c == highlightFigure || c == tip ) + continue; + + // ignore glass pane + if( c.getParent() instanceof JRootPane && c == ((JRootPane)c.getParent()).getGlassPane() ) + continue; + + return c; + } + } + + return parent; + } + private void highlight( Component c ) { if( highlightFigure == null ) { highlightFigure = createHighlightFigure(); @@ -182,9 +284,9 @@ public class FlatInspector highlightFigure.setVisible( c != null ); if( c != null ) { - Rectangle bounds = c.getBounds(); - Rectangle highlightBounds = SwingUtilities.convertRectangle( c.getParent(), bounds, rootPane ); - highlightFigure.setBounds( highlightBounds ); + highlightFigure.setBounds( new Rectangle( + SwingUtilities.convertPoint( c, 0, 0, rootPane ), + c.getSize() ) ); } } @@ -308,11 +410,16 @@ public class FlatInspector text += "ContentAreaFilled: " + ((AbstractButton)c).isContentAreaFilled() + '\n'; text += "Focusable: " + c.isFocusable() + '\n'; text += "Left-to-right: " + c.getComponentOrientation().isLeftToRight() + '\n'; - text += "Parent: " + c.getParent().getClass().getName(); + text += "Parent: " + (c.getParent() != null ? c.getParent().getClass().getName() : "null"); if( inspectParentLevel > 0 ) text += "\n\nParent level: " + inspectParentLevel; + if( inspectParentLevel > 0 ) + text += "\n(press Ctrl/Shift to increase/decrease level)"; + else + text += "\n\n(press Ctrl key to inspect parent)"; + return text; } diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTestFrame.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTestFrame.java index 243b3c02..aa9b8087 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTestFrame.java +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTestFrame.java @@ -455,8 +455,12 @@ public class FlatTestFrame } private void inspectChanged() { - if( inspector == null ) - inspector = new FlatInspector( contentPanel ); + if( inspector == null ) { + inspector = new FlatInspector( getRootPane() ); + inspector.addPropertyChangeListener( e -> { + inspectCheckBox.setSelected( inspector.isEnabled() ); + } ); + } inspector.setEnabled( inspectCheckBox.isSelected() ); } diff --git a/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatDarkLaf_1.8.0_202.txt b/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatDarkLaf_1.8.0_202.txt index 3d818fb4..957de7b7 100644 --- a/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatDarkLaf_1.8.0_202.txt +++ b/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatDarkLaf_1.8.0_202.txt @@ -364,7 +364,7 @@ InternalFrame.inactiveDropShadowOpacity 0.75 InternalFrame.inactiveTitleBackground #303234 javax.swing.plaf.ColorUIResource [UI] InternalFrame.inactiveTitleForeground #777777 javax.swing.plaf.ColorUIResource [UI] InternalFrame.maximizeIcon [lazy] 24,24 com.formdev.flatlaf.icons.FlatInternalFrameMaximizeIcon [UI] -InternalFrame.minimizeIcon [lazy] 24,24 com.formdev.flatlaf.icons.FlatInternalFrameMinimizeIcon [UI] +InternalFrame.minimizeIcon [lazy] 24,24 com.formdev.flatlaf.icons.FlatInternalFrameRestoreIcon [UI] InternalFrame.titleFont [active] $defaultFont [UI] diff --git a/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatLightLaf_1.8.0_202.txt b/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatLightLaf_1.8.0_202.txt index f584833e..8861a633 100644 --- a/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatLightLaf_1.8.0_202.txt +++ b/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatLightLaf_1.8.0_202.txt @@ -366,7 +366,7 @@ InternalFrame.inactiveDropShadowOpacity 0.5 InternalFrame.inactiveTitleBackground #fafafa javax.swing.plaf.ColorUIResource [UI] InternalFrame.inactiveTitleForeground #8c8c8c javax.swing.plaf.ColorUIResource [UI] InternalFrame.maximizeIcon [lazy] 24,24 com.formdev.flatlaf.icons.FlatInternalFrameMaximizeIcon [UI] -InternalFrame.minimizeIcon [lazy] 24,24 com.formdev.flatlaf.icons.FlatInternalFrameMinimizeIcon [UI] +InternalFrame.minimizeIcon [lazy] 24,24 com.formdev.flatlaf.icons.FlatInternalFrameRestoreIcon [UI] InternalFrame.titleFont [active] $defaultFont [UI]