mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2026-02-11 22:47:13 -06:00
Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1462636e97 | ||
|
|
7e59a7f4af | ||
|
|
e9a21848bc | ||
|
|
1dcb251ecb | ||
|
|
3f33543cee | ||
|
|
84bd2088f2 | ||
|
|
4f4a3132c5 | ||
|
|
e064c934cb | ||
|
|
16fc3cabf2 | ||
|
|
7e002ff6c2 | ||
|
|
323c0c62c3 | ||
|
|
ff5bd301cc | ||
|
|
c37712b0f0 | ||
|
|
ee9e238592 | ||
|
|
da5d6fa157 | ||
|
|
d471f08b15 | ||
|
|
b97424f767 | ||
|
|
c29a276188 | ||
|
|
d1694aa8bd | ||
|
|
570cf6fc51 | ||
|
|
8eab86e489 | ||
|
|
566568f61a | ||
|
|
56a73a4d17 | ||
|
|
656d25b75e | ||
|
|
dcdc80ade3 | ||
|
|
09f2d65d5e | ||
|
|
b304d46f7e | ||
|
|
3391f971ec | ||
|
|
778fed27a5 | ||
|
|
1755dbc877 | ||
|
|
4e6f538519 | ||
|
|
a6ecb0ef85 | ||
|
|
438ec6ac5c | ||
|
|
8089e66642 | ||
|
|
d27e0561f2 | ||
|
|
97b21bfa8b | ||
|
|
ec4343ed30 | ||
|
|
948decb3b5 | ||
|
|
d510fee7f6 |
7
.github/workflows/ci.yml
vendored
7
.github/workflows/ci.yml
vendored
@@ -33,10 +33,11 @@ jobs:
|
|||||||
- 11 # LTS
|
- 11 # LTS
|
||||||
- 17 # LTS
|
- 17 # LTS
|
||||||
- 21 # LTS
|
- 21 # LTS
|
||||||
|
- 23 # latest
|
||||||
toolchain: [""]
|
toolchain: [""]
|
||||||
include:
|
# include:
|
||||||
- java: 21
|
# - java: 21
|
||||||
toolchain: 22 # latest
|
# toolchain: 22 # latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|||||||
93
CHANGELOG.md
93
CHANGELOG.md
@@ -1,6 +1,85 @@
|
|||||||
FlatLaf Change Log
|
FlatLaf Change Log
|
||||||
==================
|
==================
|
||||||
|
|
||||||
|
## 3.5.3
|
||||||
|
|
||||||
|
#### Fixed bugs
|
||||||
|
|
||||||
|
- HTML: Fixed wrong rendering if HTML text contains `<style>` tag with
|
||||||
|
attributes (e.g. `<style type='text/css'>`). (issue #905; regression in 3.5.1)
|
||||||
|
- FlatLaf window decorations:
|
||||||
|
- Windows: Fixed possible deadlock with TabbedPane in window title area in
|
||||||
|
"full window content" mode. (issue #909)
|
||||||
|
- Windows: Fixed wrong layout in maximized frame after changing screen scale
|
||||||
|
factor. (issue #904)
|
||||||
|
- Linux: Fixed continuous cursor toggling between resize and standard cursor
|
||||||
|
when resizing window. (issue #907)
|
||||||
|
- Fixed sometimes broken window moving with SplitPane in window title area in
|
||||||
|
"full window content" mode. (issue #926)
|
||||||
|
- Popup: On Windows 10, fixed misplaced popup drop shadow. (issue #911;
|
||||||
|
regression in 3.5)
|
||||||
|
- Popup: Fixed NPE if `GraphicsConfiguration` is `null` on Windows. (issue #921)
|
||||||
|
- Theme Editor: Fixed using color picker on secondary screen.
|
||||||
|
- Fixed detection of Windows 11 if custom exe launcher does not specify Windows
|
||||||
|
10+ compatibility in application manifest. (issue #916)
|
||||||
|
- Linux: Fixed slightly different font size (or letter width) used to paint HTML
|
||||||
|
text when default font family is _Cantarell_ (e.g. on Fedora). (issue #912)
|
||||||
|
|
||||||
|
#### Other Changes
|
||||||
|
|
||||||
|
- Class `FlatPropertiesLaf` now supports FlatLaf macOS themes as base themes.
|
||||||
|
|
||||||
|
|
||||||
|
## 3.5.2
|
||||||
|
|
||||||
|
#### Fixed bugs
|
||||||
|
|
||||||
|
- Windows: Fixed repaint issues (ghosting) on some systems (probably depending
|
||||||
|
on graphics card/driver). This is done by setting Java system property
|
||||||
|
`sun.java2d.d3d.onscreen` to `false` (but only if `sun.java2d.d3d.onscreen`,
|
||||||
|
`sun.java2d.d3d` and `sun.java2d.noddraw` are not yet set), which disables
|
||||||
|
usage of Windows Direct3D (DirectX) onscreen surfaces. Component rendering
|
||||||
|
still uses Direct3D. (issue #887)
|
||||||
|
- FlatLaf window decorations:
|
||||||
|
- Iconify/maximize/close buttons did not fill whole title bar height, if some
|
||||||
|
custom component in menu bar increases title bar height. (issue #897)
|
||||||
|
- Windows: Fixed possible application freeze when using custom component that
|
||||||
|
overrides `Component.contains(int x, int y)` and invokes
|
||||||
|
`SwingUtilities.convertPoint()` (or similar) from the overridden method.
|
||||||
|
(issue #878)
|
||||||
|
- TextComponents: Fixed too fast scrolling in multi-line text components when
|
||||||
|
using touchpads (e.g. on macOS). (issue #892)
|
||||||
|
- ToolBar: Fixed endless loop if button in Toolbar has focus and is made
|
||||||
|
invisible. (issue #884)
|
||||||
|
|
||||||
|
#### Other Changes
|
||||||
|
|
||||||
|
- FlatLaf window decorations: Added client property `JRootPane.titleBarHeight`
|
||||||
|
to allow specifying a (larger) preferred height for the title bar. (issue
|
||||||
|
#897)
|
||||||
|
- Added system property `flatlaf.useRoundedPopupBorder` to allow disabling
|
||||||
|
native rounded popup borders on Windows 11 and macOS. On macOS 14.4+, where
|
||||||
|
rounded popup borders are disabled since FlatLaf 3.5 because of occasional
|
||||||
|
problems, you can use this to enable rounded popup borders (at your risk).
|
||||||
|
|
||||||
|
|
||||||
|
## 3.5.1
|
||||||
|
|
||||||
|
#### Fixed bugs
|
||||||
|
|
||||||
|
- HTML: Fixed occasional cutoff wrapped text when using multi-line text in HTML
|
||||||
|
tags `<h1>`...`<h6>`, `<code>`, `<kbd>`, `<big>`, `<small>` or `<samp>`.
|
||||||
|
(issue #873; regression in 3.5)
|
||||||
|
- Popup: Fixed `UnsupportedOperationException: PERPIXEL_TRANSLUCENT translucency
|
||||||
|
is not supported` exception on Haiku OS when showing popup (partly) outside of
|
||||||
|
window. (issue #869)
|
||||||
|
- HiDPI: Fixed occasional wrong repaint areas when using
|
||||||
|
`HiDPIUtils.installHiDPIRepaintManager()`. (see PR #864)
|
||||||
|
- Added system property `flatlaf.useSubMenuSafeTriangle` to allow disabling
|
||||||
|
submenu safe triangle (PR #490) for
|
||||||
|
[SWTSwing](https://github.com/Chrriis/SWTSwing). (issue #870)
|
||||||
|
|
||||||
|
|
||||||
## 3.5
|
## 3.5
|
||||||
|
|
||||||
#### New features and improvements
|
#### New features and improvements
|
||||||
@@ -16,6 +95,13 @@ FlatLaf Change Log
|
|||||||
|
|
||||||
#### Fixed bugs
|
#### Fixed bugs
|
||||||
|
|
||||||
|
- macOS: Disabled rounded popup border (see PR #772) on macOS 14.4+ because it
|
||||||
|
may freeze the application and crash the macOS WindowServer process (reports
|
||||||
|
vary from Finder restarts to OS restarts). This is a temporary change until a
|
||||||
|
solution is found. See NetBeans issues
|
||||||
|
[apache/netbeans#7560](https://github.com/apache/netbeans/issues/7560#issuecomment-2226439215)
|
||||||
|
and
|
||||||
|
[apache/netbeans#6647](https://github.com/apache/netbeans/issues/6647#issuecomment-2070124442).
|
||||||
- FlatLaf window decorations: Window top border on Windows 10 in "full window
|
- FlatLaf window decorations: Window top border on Windows 10 in "full window
|
||||||
content" mode was not fully repainted when activating or deactivating window.
|
content" mode was not fully repainted when activating or deactivating window.
|
||||||
(issue #809)
|
(issue #809)
|
||||||
@@ -70,13 +156,6 @@ FlatLaf Change Log
|
|||||||
(some security software allows loading native library but blocks method
|
(some security software allows loading native library but blocks method
|
||||||
invocation).
|
invocation).
|
||||||
- macOS: Fixed crash when running in WebSwing. (issue #826; regression in 3.4)
|
- macOS: Fixed crash when running in WebSwing. (issue #826; regression in 3.4)
|
||||||
- macOS: Disabled rounded popup border (see PR #772) on macOS 14.4+ because it
|
|
||||||
may freeze the application and crash the macOS WindowServer process (reports
|
|
||||||
vary from Finder restarts to OS restarts). This is a temporary change until a
|
|
||||||
solution is found. See NetBeans issues
|
|
||||||
[apache/netbeans#7560](https://github.com/apache/netbeans/issues/7560#issuecomment-2226439215)
|
|
||||||
and
|
|
||||||
[apache/netbeans#6647](https://github.com/apache/netbeans/issues/6647#issuecomment-2070124442).
|
|
||||||
|
|
||||||
#### Incompatibilities
|
#### Incompatibilities
|
||||||
|
|
||||||
|
|||||||
10
README.md
10
README.md
@@ -33,14 +33,20 @@ FlatLaf can use 3rd party themes created for IntelliJ Platform (see
|
|||||||
Sponsors
|
Sponsors
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
### Current Sponsors
|
||||||
|
|
||||||
|
[](https://www.formdev.com/flatlaf/sponsor/)
|
||||||
|
|
||||||
|
[Become a Sponsor](https://www.formdev.com/flatlaf/sponsor/)
|
||||||
|
|
||||||
|
### Previous Sponsors
|
||||||
|
|
||||||
<a href="https://www.ej-technologies.com/"><img src="https://www.formdev.com/flatlaf/sponsor/ej-technologies.png" width="200" alt="ej-technologies" title="ej-technologies - Java APM, Java Profiler, Java Installer Builder"></a>
|
<a href="https://www.ej-technologies.com/"><img src="https://www.formdev.com/flatlaf/sponsor/ej-technologies.png" width="200" alt="ej-technologies" title="ej-technologies - Java APM, Java Profiler, Java Installer Builder"></a>
|
||||||
|
|
||||||
<a href="https://www.dbvis.com/"><img src="https://www.formdev.com/flatlaf/sponsor/dbvisualizer.svg" width="200" alt="DbVisualizer" title="DbVisualizer - SQL Client and Editor"></a>
|
<a href="https://www.dbvis.com/"><img src="https://www.formdev.com/flatlaf/sponsor/dbvisualizer.svg" width="200" alt="DbVisualizer" title="DbVisualizer - SQL Client and Editor"></a>
|
||||||
|
|
||||||
<a href="https://www.dscsag.com/"><img src="https://www.formdev.com/flatlaf/sponsor/DSC.png" height="48" alt="DSC Software AG" title="DSC Software AG - Your Companion for Integrative PLM"></a>
|
<a href="https://www.dscsag.com/"><img src="https://www.formdev.com/flatlaf/sponsor/DSC.png" height="48" alt="DSC Software AG" title="DSC Software AG - Your Companion for Integrative PLM"></a>
|
||||||
|
|
||||||
[Become a Sponsor](https://www.formdev.com/flatlaf/sponsor/)
|
|
||||||
|
|
||||||
Demo
|
Demo
|
||||||
----
|
----
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#Signature file v4.1
|
#Signature file v4.1
|
||||||
#Version 3.5
|
#Version 3.5.2
|
||||||
|
|
||||||
CLSS public abstract interface com.formdev.flatlaf.FlatClientProperties
|
CLSS public abstract interface com.formdev.flatlaf.FlatClientProperties
|
||||||
fld public final static java.lang.String BUTTON_TYPE = "JButton.buttonType"
|
fld public final static java.lang.String BUTTON_TYPE = "JButton.buttonType"
|
||||||
@@ -100,6 +100,7 @@ fld public final static java.lang.String TEXT_FIELD_TRAILING_COMPONENT = "JTextF
|
|||||||
fld public final static java.lang.String TEXT_FIELD_TRAILING_ICON = "JTextField.trailingIcon"
|
fld public final static java.lang.String TEXT_FIELD_TRAILING_ICON = "JTextField.trailingIcon"
|
||||||
fld public final static java.lang.String TITLE_BAR_BACKGROUND = "JRootPane.titleBarBackground"
|
fld public final static java.lang.String TITLE_BAR_BACKGROUND = "JRootPane.titleBarBackground"
|
||||||
fld public final static java.lang.String TITLE_BAR_FOREGROUND = "JRootPane.titleBarForeground"
|
fld public final static java.lang.String TITLE_BAR_FOREGROUND = "JRootPane.titleBarForeground"
|
||||||
|
fld public final static java.lang.String TITLE_BAR_HEIGHT = "JRootPane.titleBarHeight"
|
||||||
fld public final static java.lang.String TITLE_BAR_SHOW_CLOSE = "JRootPane.titleBarShowClose"
|
fld public final static java.lang.String TITLE_BAR_SHOW_CLOSE = "JRootPane.titleBarShowClose"
|
||||||
fld public final static java.lang.String TITLE_BAR_SHOW_ICON = "JRootPane.titleBarShowIcon"
|
fld public final static java.lang.String TITLE_BAR_SHOW_ICON = "JRootPane.titleBarShowIcon"
|
||||||
fld public final static java.lang.String TITLE_BAR_SHOW_ICONIFFY = "JRootPane.titleBarShowIconify"
|
fld public final static java.lang.String TITLE_BAR_SHOW_ICONIFFY = "JRootPane.titleBarShowIconify"
|
||||||
@@ -223,6 +224,7 @@ meth public static java.util.Map<java.lang.String,java.lang.Class<?>> getStyleab
|
|||||||
meth public static java.util.Map<java.lang.String,java.lang.String> getGlobalExtraDefaults()
|
meth public static java.util.Map<java.lang.String,java.lang.String> getGlobalExtraDefaults()
|
||||||
meth public static java.util.function.Function<java.lang.String,java.awt.Color> getSystemColorGetter()
|
meth public static java.util.function.Function<java.lang.String,java.awt.Color> getSystemColorGetter()
|
||||||
meth public static javax.swing.UIDefaults$ActiveValue createActiveFontValue(float)
|
meth public static javax.swing.UIDefaults$ActiveValue createActiveFontValue(float)
|
||||||
|
meth public static void disableWindowsD3Donscreen()
|
||||||
meth public static void hideMnemonics()
|
meth public static void hideMnemonics()
|
||||||
meth public static void initIconColors(javax.swing.UIDefaults,boolean)
|
meth public static void initIconColors(javax.swing.UIDefaults,boolean)
|
||||||
meth public static void installLafInfo(java.lang.String,java.lang.Class<? extends javax.swing.LookAndFeel>)
|
meth public static void installLafInfo(java.lang.String,java.lang.Class<? extends javax.swing.LookAndFeel>)
|
||||||
@@ -296,6 +298,8 @@ fld public final static java.lang.String UPDATE_UI_ON_SYSTEM_FONT_CHANGE = "flat
|
|||||||
fld public final static java.lang.String USE_JETBRAINS_CUSTOM_DECORATIONS = "flatlaf.useJetBrainsCustomDecorations"
|
fld public final static java.lang.String USE_JETBRAINS_CUSTOM_DECORATIONS = "flatlaf.useJetBrainsCustomDecorations"
|
||||||
anno 0 java.lang.Deprecated()
|
anno 0 java.lang.Deprecated()
|
||||||
fld public final static java.lang.String USE_NATIVE_LIBRARY = "flatlaf.useNativeLibrary"
|
fld public final static java.lang.String USE_NATIVE_LIBRARY = "flatlaf.useNativeLibrary"
|
||||||
|
fld public final static java.lang.String USE_ROUNDED_POPUP_BORDER = "flatlaf.useRoundedPopupBorder"
|
||||||
|
fld public final static java.lang.String USE_SUB_MENU_SAFE_TRIANGLE = "flatlaf.useSubMenuSafeTriangle"
|
||||||
fld public final static java.lang.String USE_TEXT_Y_CORRECTION = "flatlaf.useTextYCorrection"
|
fld public final static java.lang.String USE_TEXT_Y_CORRECTION = "flatlaf.useTextYCorrection"
|
||||||
fld public final static java.lang.String USE_UBUNTU_FONT = "flatlaf.useUbuntuFont"
|
fld public final static java.lang.String USE_UBUNTU_FONT = "flatlaf.useUbuntuFont"
|
||||||
fld public final static java.lang.String USE_WINDOW_DECORATIONS = "flatlaf.useWindowDecorations"
|
fld public final static java.lang.String USE_WINDOW_DECORATIONS = "flatlaf.useWindowDecorations"
|
||||||
|
|||||||
@@ -461,7 +461,7 @@ public interface FlatClientProperties
|
|||||||
* {@link FlatSystemProperties#USE_WINDOW_DECORATIONS}, but higher priority
|
* {@link FlatSystemProperties#USE_WINDOW_DECORATIONS}, but higher priority
|
||||||
* than UI default {@code TitlePane.useWindowDecorations}.
|
* than UI default {@code TitlePane.useWindowDecorations}.
|
||||||
* <p>
|
* <p>
|
||||||
* (requires Window 10)
|
* (requires Windows 10/11)
|
||||||
* <p>
|
* <p>
|
||||||
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||||
@@ -481,7 +481,7 @@ public interface FlatClientProperties
|
|||||||
* {@link FlatSystemProperties#MENUBAR_EMBEDDED}, but higher priority
|
* {@link FlatSystemProperties#MENUBAR_EMBEDDED}, but higher priority
|
||||||
* than UI default {@code TitlePane.menuBarEmbedded}.
|
* than UI default {@code TitlePane.menuBarEmbedded}.
|
||||||
* <p>
|
* <p>
|
||||||
* (requires Window 10)
|
* (requires Windows 10/11)
|
||||||
* <p>
|
* <p>
|
||||||
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||||
@@ -507,6 +507,8 @@ public interface FlatClientProperties
|
|||||||
* The user can left-click-and-drag on the title bar area to move the window,
|
* The user can left-click-and-drag on the title bar area to move the window,
|
||||||
* except when clicking on a component that processes mouse events (e.g. buttons or menus).
|
* except when clicking on a component that processes mouse events (e.g. buttons or menus).
|
||||||
* <p>
|
* <p>
|
||||||
|
* (requires Windows 10/11)
|
||||||
|
* <p>
|
||||||
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||||
*
|
*
|
||||||
@@ -537,7 +539,7 @@ public interface FlatClientProperties
|
|||||||
* <p>
|
* <p>
|
||||||
* This client property has higher priority than UI default {@code TitlePane.showIcon}.
|
* This client property has higher priority than UI default {@code TitlePane.showIcon}.
|
||||||
* <p>
|
* <p>
|
||||||
* (requires Window 10)
|
* (requires Windows 10/11)
|
||||||
* <p>
|
* <p>
|
||||||
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||||
@@ -553,6 +555,8 @@ public interface FlatClientProperties
|
|||||||
* Setting this shows/hides the windows title
|
* Setting this shows/hides the windows title
|
||||||
* for the {@code JFrame} or {@code JDialog} that contains the root pane.
|
* for the {@code JFrame} or {@code JDialog} that contains the root pane.
|
||||||
* <p>
|
* <p>
|
||||||
|
* (requires Windows 10/11)
|
||||||
|
* <p>
|
||||||
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||||
*
|
*
|
||||||
@@ -567,6 +571,8 @@ public interface FlatClientProperties
|
|||||||
* Setting this shows/hides the "iconify" button
|
* Setting this shows/hides the "iconify" button
|
||||||
* for the {@code JFrame} that contains the root pane.
|
* for the {@code JFrame} that contains the root pane.
|
||||||
* <p>
|
* <p>
|
||||||
|
* (requires Windows 10/11)
|
||||||
|
* <p>
|
||||||
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||||
*
|
*
|
||||||
@@ -581,6 +587,8 @@ public interface FlatClientProperties
|
|||||||
* Setting this shows/hides the "maximize/restore" button
|
* Setting this shows/hides the "maximize/restore" button
|
||||||
* for the {@code JFrame} that contains the root pane.
|
* for the {@code JFrame} that contains the root pane.
|
||||||
* <p>
|
* <p>
|
||||||
|
* (requires Windows 10/11)
|
||||||
|
* <p>
|
||||||
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||||
*
|
*
|
||||||
@@ -595,6 +603,8 @@ public interface FlatClientProperties
|
|||||||
* Setting this shows/hides the "close" button
|
* Setting this shows/hides the "close" button
|
||||||
* for the {@code JFrame} or {@code JDialog} that contains the root pane.
|
* for the {@code JFrame} or {@code JDialog} that contains the root pane.
|
||||||
* <p>
|
* <p>
|
||||||
|
* (requires Windows 10/11)
|
||||||
|
* <p>
|
||||||
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||||
*
|
*
|
||||||
@@ -605,7 +615,7 @@ public interface FlatClientProperties
|
|||||||
/**
|
/**
|
||||||
* Background color of window title bar (requires enabled window decorations).
|
* Background color of window title bar (requires enabled window decorations).
|
||||||
* <p>
|
* <p>
|
||||||
* (requires Window 10)
|
* (requires Windows 10/11)
|
||||||
* <p>
|
* <p>
|
||||||
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||||
* <strong>Value type</strong> {@link java.awt.Color}
|
* <strong>Value type</strong> {@link java.awt.Color}
|
||||||
@@ -617,7 +627,7 @@ public interface FlatClientProperties
|
|||||||
/**
|
/**
|
||||||
* Foreground color of window title bar (requires enabled window decorations).
|
* Foreground color of window title bar (requires enabled window decorations).
|
||||||
* <p>
|
* <p>
|
||||||
* (requires Window 10)
|
* (requires Windows 10/11)
|
||||||
* <p>
|
* <p>
|
||||||
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||||
* <strong>Value type</strong> {@link java.awt.Color}
|
* <strong>Value type</strong> {@link java.awt.Color}
|
||||||
@@ -626,10 +636,24 @@ public interface FlatClientProperties
|
|||||||
*/
|
*/
|
||||||
String TITLE_BAR_FOREGROUND = "JRootPane.titleBarForeground";
|
String TITLE_BAR_FOREGROUND = "JRootPane.titleBarForeground";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the preferred height of title bar (requires enabled window decorations).
|
||||||
|
* <p>
|
||||||
|
* (requires Windows 10/11)
|
||||||
|
* <p>
|
||||||
|
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||||
|
* <strong>Value type</strong> {@link java.lang.Integer}
|
||||||
|
*
|
||||||
|
* @since 3.5.2
|
||||||
|
*/
|
||||||
|
String TITLE_BAR_HEIGHT = "JRootPane.titleBarHeight";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies whether the glass pane should have full height and overlap the title bar,
|
* Specifies whether the glass pane should have full height and overlap the title bar,
|
||||||
* if FlatLaf window decorations are enabled. Default is {@code false}.
|
* if FlatLaf window decorations are enabled. Default is {@code false}.
|
||||||
* <p>
|
* <p>
|
||||||
|
* (requires Windows 10/11)
|
||||||
|
* <p>
|
||||||
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import java.awt.Color;
|
|||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.EventQueue;
|
import java.awt.EventQueue;
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
|
import java.awt.GraphicsEnvironment;
|
||||||
import java.awt.Image;
|
import java.awt.Image;
|
||||||
import java.awt.RenderingHints;
|
import java.awt.RenderingHints;
|
||||||
import java.awt.Toolkit;
|
import java.awt.Toolkit;
|
||||||
@@ -119,6 +120,46 @@ public abstract class FlatLaf
|
|||||||
private static String preferredSemiboldFontFamily;
|
private static String preferredSemiboldFontFamily;
|
||||||
private static String preferredMonospacedFontFamily;
|
private static String preferredMonospacedFontFamily;
|
||||||
|
|
||||||
|
static {
|
||||||
|
// see disableWindowsD3Donscreen() for details
|
||||||
|
// https://github.com/JFormDesigner/FlatLaf/issues/887
|
||||||
|
if( SystemInfo.isWindows &&
|
||||||
|
System.getProperty( "sun.java2d.d3d.onscreen" ) == null &&
|
||||||
|
System.getProperty( "sun.java2d.d3d" ) == null &&
|
||||||
|
System.getProperty( "sun.java2d.noddraw" ) == null )
|
||||||
|
System.setProperty( "sun.java2d.d3d.onscreen", "false" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable usage of Windows Direct3D (DirectX) onscreen surfaces because this may lead to
|
||||||
|
* repaint issues (ghosting) on some systems (probably depending on graphics card/driver).
|
||||||
|
* Problem occurs usually when a small heavy-weight popup window (menu, combobox, tooltip) is shown.
|
||||||
|
* <p>
|
||||||
|
* Sets system property {@code sun.java2d.d3d.onscreen} to {@code false},
|
||||||
|
* but only if {@code sun.java2d.d3d.onscreen}, {@code sun.java2d.d3d}
|
||||||
|
* and {@code sun.java2d.noddraw} are not yet set.
|
||||||
|
* <p>
|
||||||
|
* <strong>Note</strong>: Must be invoked very early before the graphics environment is created.
|
||||||
|
* <p>
|
||||||
|
* This method is automatically invoked when loading this class,
|
||||||
|
* which is usually before the graphics environment is created.
|
||||||
|
* E.g. when doing {@code FlatLightLaf.setup()} or
|
||||||
|
* {@code UIManager.setLookAndFeel( "com.formdev.flatlaf.FlatLightLaf" )}.
|
||||||
|
* <p>
|
||||||
|
* However, it may be invoked too late if you use some methods from {@link UIManager}
|
||||||
|
* of {@link GraphicsEnvironment} before setting look and feel.
|
||||||
|
* E.g. {@link UIManager#put(Object, Object)}.
|
||||||
|
* In that case invoke this method yourself very early.
|
||||||
|
* <p>
|
||||||
|
* <strong>Tip</strong>: How to find out when the graphics environment is created?
|
||||||
|
* Set a breakpoint at constructor of class {@link GraphicsEnvironment} and look at the stack.
|
||||||
|
*
|
||||||
|
* @since 3.5.2
|
||||||
|
*/
|
||||||
|
public static void disableWindowsD3Donscreen() {
|
||||||
|
// dummy method used to trigger invocation of "static {...}" block
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the application look and feel to the given LaF
|
* Sets the application look and feel to the given LaF
|
||||||
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
|
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
|
||||||
|
|||||||
@@ -23,13 +23,15 @@ import java.io.InputStream;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
import com.formdev.flatlaf.themes.FlatMacDarkLaf;
|
||||||
|
import com.formdev.flatlaf.themes.FlatMacLightLaf;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Flat LaF that is able to load UI defaults from properties passed to the constructor.
|
* A Flat LaF that is able to load UI defaults from properties passed to the constructor.
|
||||||
* <p>
|
* <p>
|
||||||
* Specify the base theme in the properties with {@code @baseTheme=<baseTheme>}.
|
* Specify the base theme in the properties with {@code @baseTheme=<baseTheme>}.
|
||||||
* Allowed values for {@code <baseTheme>} are {@code light} (the default), {@code dark},
|
* Allowed values for {@code <baseTheme>} are {@code light} (the default), {@code dark},
|
||||||
* {@code intellij} or {@code darcula}.
|
* {@code intellij}, {@code darcula}, {@code maclight} or {@code macdark}.
|
||||||
* <p>
|
* <p>
|
||||||
* The properties are applied after loading the base theme and may overwrite base properties.
|
* The properties are applied after loading the base theme and may overwrite base properties.
|
||||||
* All features of FlatLaf properties files are available.
|
* All features of FlatLaf properties files are available.
|
||||||
@@ -71,7 +73,8 @@ public class FlatPropertiesLaf
|
|||||||
this.properties = properties;
|
this.properties = properties;
|
||||||
|
|
||||||
baseTheme = properties.getProperty( "@baseTheme", "light" );
|
baseTheme = properties.getProperty( "@baseTheme", "light" );
|
||||||
dark = "dark".equalsIgnoreCase( baseTheme ) || "darcula".equalsIgnoreCase( baseTheme );
|
dark = "dark".equalsIgnoreCase( baseTheme ) || "darcula".equalsIgnoreCase( baseTheme ) ||
|
||||||
|
"macdark".equalsIgnoreCase( baseTheme );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -116,6 +119,16 @@ public class FlatPropertiesLaf
|
|||||||
lafClasses.add( FlatDarkLaf.class );
|
lafClasses.add( FlatDarkLaf.class );
|
||||||
lafClasses.add( FlatDarculaLaf.class );
|
lafClasses.add( FlatDarculaLaf.class );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "maclight":
|
||||||
|
lafClasses.add( FlatLightLaf.class );
|
||||||
|
lafClasses.add( FlatMacLightLaf.class );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "macdark":
|
||||||
|
lafClasses.add( FlatDarkLaf.class );
|
||||||
|
lafClasses.add( FlatMacDarkLaf.class );
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return lafClasses;
|
return lafClasses;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ public interface FlatSystemProperties
|
|||||||
* {@link FlatClientProperties#USE_WINDOW_DECORATIONS} and
|
* {@link FlatClientProperties#USE_WINDOW_DECORATIONS} and
|
||||||
* UI default {@code TitlePane.useWindowDecorations}.
|
* UI default {@code TitlePane.useWindowDecorations}.
|
||||||
* <p>
|
* <p>
|
||||||
* (requires Window 10/11)
|
* (requires Windows 10/11)
|
||||||
* <p>
|
* <p>
|
||||||
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
||||||
* <strong>Default</strong> none
|
* <strong>Default</strong> none
|
||||||
@@ -99,7 +99,7 @@ public interface FlatSystemProperties
|
|||||||
* Setting this to {@code false} disables using JetBrains Runtime custom window decorations.
|
* Setting this to {@code false} disables using JetBrains Runtime custom window decorations.
|
||||||
* Then FlatLaf native window decorations are used.
|
* Then FlatLaf native window decorations are used.
|
||||||
* <p>
|
* <p>
|
||||||
* (requires Window 10/11)
|
* (requires Windows 10/11)
|
||||||
* <p>
|
* <p>
|
||||||
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
||||||
* <strong>Default</strong> {@code false} (since v2; was {@code true} in v1)
|
* <strong>Default</strong> {@code false} (since v2; was {@code true} in v1)
|
||||||
@@ -120,7 +120,7 @@ public interface FlatSystemProperties
|
|||||||
* {@link FlatClientProperties#MENU_BAR_EMBEDDED} and
|
* {@link FlatClientProperties#MENU_BAR_EMBEDDED} and
|
||||||
* UI default {@code TitlePane.menuBarEmbedded}.
|
* UI default {@code TitlePane.menuBarEmbedded}.
|
||||||
* <p>
|
* <p>
|
||||||
* (requires Window 10/11)
|
* (requires Windows 10/11)
|
||||||
* <p>
|
* <p>
|
||||||
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
||||||
* <strong>Default</strong> none
|
* <strong>Default</strong> none
|
||||||
@@ -135,6 +135,18 @@ public interface FlatSystemProperties
|
|||||||
*/
|
*/
|
||||||
String ANIMATION = "flatlaf.animation";
|
String ANIMATION = "flatlaf.animation";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies whether native rounded popup borders should be used (if supported by operating system).
|
||||||
|
* <p>
|
||||||
|
* (requires Windows 11 or macOS)
|
||||||
|
* <p>
|
||||||
|
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
||||||
|
* <strong>Default</strong> {@code true}; except on macOS 14.4+ where it is {@code false}
|
||||||
|
*
|
||||||
|
* @since 3.5.2
|
||||||
|
*/
|
||||||
|
String USE_ROUNDED_POPUP_BORDER = "flatlaf.useRoundedPopupBorder";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies whether vertical text position is corrected when UI is scaled on HiDPI screens.
|
* Specifies whether vertical text position is corrected when UI is scaled on HiDPI screens.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -204,6 +216,16 @@ public interface FlatSystemProperties
|
|||||||
*/
|
*/
|
||||||
String NATIVE_LIBRARY_PATH = "flatlaf.nativeLibraryPath";
|
String NATIVE_LIBRARY_PATH = "flatlaf.nativeLibraryPath";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies whether safe triangle is used to improve usability of submenus.
|
||||||
|
* <p>
|
||||||
|
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
||||||
|
* <strong>Default</strong> {@code true}
|
||||||
|
*
|
||||||
|
* @since 3.5.1
|
||||||
|
*/
|
||||||
|
String USE_SUB_MENU_SAFE_TRIANGLE = "flatlaf.useSubMenuSafeTriangle";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether a system property is set and returns {@code true} if its value
|
* Checks whether a system property is set and returns {@code true} if its value
|
||||||
* is {@code "true"} (case-insensitive), otherwise it returns {@code false}.
|
* is {@code "true"} (case-insensitive), otherwise it returns {@code false}.
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ class LinuxFontPolicy
|
|||||||
if( logicalFamily != null )
|
if( logicalFamily != null )
|
||||||
family = logicalFamily;
|
family = logicalFamily;
|
||||||
|
|
||||||
return createFontEx( family, style, size, dsize );
|
return createFontEx( family, style, size );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -121,9 +121,9 @@ class LinuxFontPolicy
|
|||||||
* E.g. family 'URW Bookman Light' is not found, but 'URW Bookman' is found.
|
* E.g. family 'URW Bookman Light' is not found, but 'URW Bookman' is found.
|
||||||
* If still not found, then font of family 'Dialog' is returned.
|
* If still not found, then font of family 'Dialog' is returned.
|
||||||
*/
|
*/
|
||||||
private static Font createFontEx( String family, int style, int size, double dsize ) {
|
private static Font createFontEx( String family, int style, int size ) {
|
||||||
for(;;) {
|
for(;;) {
|
||||||
Font font = createFont( family, style, size, dsize );
|
Font font = FlatLaf.createCompositeFont( family, style, size );
|
||||||
|
|
||||||
if( Font.DIALOG.equals( family ) )
|
if( Font.DIALOG.equals( family ) )
|
||||||
return font;
|
return font;
|
||||||
@@ -135,7 +135,7 @@ class LinuxFontPolicy
|
|||||||
// - character width is zero (e.g. font Cantarell; Fedora; Oracle Java 8)
|
// - character width is zero (e.g. font Cantarell; Fedora; Oracle Java 8)
|
||||||
FontMetrics fm = StyleContext.getDefaultStyleContext().getFontMetrics( font );
|
FontMetrics fm = StyleContext.getDefaultStyleContext().getFontMetrics( font );
|
||||||
if( fm.getHeight() > size * 2 || fm.stringWidth( "a" ) == 0 )
|
if( fm.getHeight() > size * 2 || fm.stringWidth( "a" ) == 0 )
|
||||||
return createFont( Font.DIALOG, style, size, dsize );
|
return FlatLaf.createCompositeFont( Font.DIALOG, style, size );
|
||||||
|
|
||||||
return font;
|
return font;
|
||||||
}
|
}
|
||||||
@@ -143,7 +143,7 @@ class LinuxFontPolicy
|
|||||||
// find last word in family
|
// find last word in family
|
||||||
int index = family.lastIndexOf( ' ' );
|
int index = family.lastIndexOf( ' ' );
|
||||||
if( index < 0 )
|
if( index < 0 )
|
||||||
return createFont( Font.DIALOG, style, size, dsize );
|
return FlatLaf.createCompositeFont( Font.DIALOG, style, size );
|
||||||
|
|
||||||
// check whether last work contains some font weight (e.g. Ultra-Bold or Heavy)
|
// check whether last work contains some font weight (e.g. Ultra-Bold or Heavy)
|
||||||
String lastWord = family.substring( index + 1 ).toLowerCase( Locale.ENGLISH );
|
String lastWord = family.substring( index + 1 ).toLowerCase( Locale.ENGLISH );
|
||||||
@@ -155,15 +155,6 @@ class LinuxFontPolicy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Font createFont( String family, int style, int size, double dsize ) {
|
|
||||||
Font font = FlatLaf.createCompositeFont( family, style, size );
|
|
||||||
|
|
||||||
// set font size in floating points
|
|
||||||
font = font.deriveFont( style, (float) dsize );
|
|
||||||
|
|
||||||
return font;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static double getGnomeFontScale() {
|
private static double getGnomeFontScale() {
|
||||||
// do not scale font here if JRE scales
|
// do not scale font here if JRE scales
|
||||||
if( isSystemScaling() )
|
if( isSystemScaling() )
|
||||||
@@ -257,7 +248,7 @@ class LinuxFontPolicy
|
|||||||
if( size < 1 )
|
if( size < 1 )
|
||||||
size = 1;
|
size = 1;
|
||||||
|
|
||||||
return createFont( family, style, size, dsize );
|
return FlatLaf.createCompositeFont( family, style, size );
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings( "MixedMutabilityReturnType" ) // Error Prone
|
@SuppressWarnings( "MixedMutabilityReturnType" ) // Error Prone
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ import javax.swing.UIManager;
|
|||||||
import javax.swing.event.ChangeEvent;
|
import javax.swing.event.ChangeEvent;
|
||||||
import javax.swing.event.ChangeListener;
|
import javax.swing.event.ChangeListener;
|
||||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||||
|
import com.formdev.flatlaf.util.LoggingFacade;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Improves usability of submenus by using a
|
* Improves usability of submenus by using a
|
||||||
@@ -64,6 +65,7 @@ class SubMenuUsabilityHelper
|
|||||||
// https://github.com/apache/netbeans/issues/4231#issuecomment-1179616607
|
// https://github.com/apache/netbeans/issues/4231#issuecomment-1179616607
|
||||||
private static SubMenuUsabilityHelper instance;
|
private static SubMenuUsabilityHelper instance;
|
||||||
|
|
||||||
|
private boolean eventQueuePushNotSupported;
|
||||||
private SubMenuEventQueue subMenuEventQueue;
|
private SubMenuEventQueue subMenuEventQueue;
|
||||||
private SafeTrianglePainter safeTrianglePainter;
|
private SafeTrianglePainter safeTrianglePainter;
|
||||||
private boolean changePending;
|
private boolean changePending;
|
||||||
@@ -83,6 +85,9 @@ class SubMenuUsabilityHelper
|
|||||||
if( instance != null )
|
if( instance != null )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if( !FlatSystemProperties.getBoolean( FlatSystemProperties.USE_SUB_MENU_SAFE_TRIANGLE, true ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
instance = new SubMenuUsabilityHelper();
|
instance = new SubMenuUsabilityHelper();
|
||||||
MenuSelectionManager.defaultManager().addChangeListener( instance );
|
MenuSelectionManager.defaultManager().addChangeListener( instance );
|
||||||
return true;
|
return true;
|
||||||
@@ -99,7 +104,7 @@ class SubMenuUsabilityHelper
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stateChanged( ChangeEvent e ) {
|
public void stateChanged( ChangeEvent e ) {
|
||||||
if( !FlatUIUtils.getUIBoolean( KEY_USE_SAFE_TRIANGLE, true ))
|
if( eventQueuePushNotSupported || !FlatUIUtils.getUIBoolean( KEY_USE_SAFE_TRIANGLE, true ))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// handle menu selection change later, but only once in case of temporary changes
|
// handle menu selection change later, but only once in case of temporary changes
|
||||||
@@ -173,8 +178,29 @@ debug*/
|
|||||||
targetBottomY = popupLocation.y + popupSize.height;
|
targetBottomY = popupLocation.y + popupSize.height;
|
||||||
|
|
||||||
// install own event queue to suppress mouse events when mouse is moved within safe triangle
|
// install own event queue to suppress mouse events when mouse is moved within safe triangle
|
||||||
if( subMenuEventQueue == null )
|
if( subMenuEventQueue == null ) {
|
||||||
subMenuEventQueue = new SubMenuEventQueue();
|
SubMenuEventQueue queue = new SubMenuEventQueue();
|
||||||
|
|
||||||
|
try {
|
||||||
|
Toolkit toolkit = Toolkit.getDefaultToolkit();
|
||||||
|
toolkit.getSystemEventQueue().push( queue );
|
||||||
|
|
||||||
|
// check whether push() worked
|
||||||
|
// (e.g. SWTSwing uses own event queue that does not support push())
|
||||||
|
if( toolkit.getSystemEventQueue() != queue ) {
|
||||||
|
eventQueuePushNotSupported = true;
|
||||||
|
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to push submenu event queue. Disabling submenu safe triangle.", null );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
subMenuEventQueue = queue;
|
||||||
|
} catch( RuntimeException ex ) {
|
||||||
|
// catch runtime exception from EventQueue.push()
|
||||||
|
eventQueuePushNotSupported = true;
|
||||||
|
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to push submenu event queue. Disabling submenu safe triangle.", ex );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// create safe triangle painter
|
// create safe triangle painter
|
||||||
if( safeTrianglePainter == null && UIManager.getBoolean( KEY_SHOW_SAFE_TRIANGLE ) )
|
if( safeTrianglePainter == null && UIManager.getBoolean( KEY_SHOW_SAFE_TRIANGLE ) )
|
||||||
@@ -247,8 +273,6 @@ debug*/
|
|||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
timeoutTimer.setRepeats( false );
|
timeoutTimer.setRepeats( false );
|
||||||
|
|
||||||
Toolkit.getDefaultToolkit().getSystemEventQueue().push( this );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void uninstall() {
|
void uninstall() {
|
||||||
|
|||||||
@@ -57,6 +57,8 @@ public abstract class FlatAbstractIcon
|
|||||||
// g2.setColor( Color.blue );
|
// g2.setColor( Color.blue );
|
||||||
// g2.drawRect( x, y, getIconWidth() - 1, getIconHeight() - 1 );
|
// g2.drawRect( x, y, getIconWidth() - 1, getIconHeight() - 1 );
|
||||||
|
|
||||||
|
paintBackground( c, g2, x, y );
|
||||||
|
|
||||||
g2.translate( x, y );
|
g2.translate( x, y );
|
||||||
UIScale.scaleGraphics( g2 );
|
UIScale.scaleGraphics( g2 );
|
||||||
|
|
||||||
@@ -69,7 +71,11 @@ public abstract class FlatAbstractIcon
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void paintIcon( Component c, Graphics2D g2 );
|
/** @since 3.5.2 */
|
||||||
|
protected void paintBackground( Component c, Graphics2D g, int x, int y ) {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void paintIcon( Component c, Graphics2D g );
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getIconWidth() {
|
public int getIconWidth() {
|
||||||
|
|||||||
@@ -60,23 +60,24 @@ public abstract class FlatWindowAbstractIcon
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void paintIcon( Component c, Graphics2D g ) {
|
protected void paintIcon( Component c, Graphics2D g ) {
|
||||||
paintBackground( c, g );
|
|
||||||
|
|
||||||
g.setColor( getForeground( c ) );
|
g.setColor( getForeground( c ) );
|
||||||
HiDPIUtils.paintAtScale1x( g, 0, 0, width, height, this::paintIconAt1x );
|
HiDPIUtils.paintAtScale1x( g, 0, 0, width, height, this::paintIconAt1x );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor );
|
protected abstract void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor );
|
||||||
|
|
||||||
protected void paintBackground( Component c, Graphics2D g ) {
|
/** @since 3.5.2 */
|
||||||
|
@Override
|
||||||
|
protected void paintBackground( Component c, Graphics2D g, int x, int y ) {
|
||||||
Color background = FlatButtonUI.buttonStateColor( c, null, null, null, hoverBackground, pressedBackground );
|
Color background = FlatButtonUI.buttonStateColor( c, null, null, null, hoverBackground, pressedBackground );
|
||||||
if( background != null ) {
|
if( background != null ) {
|
||||||
// disable antialiasing for background rectangle painting to avoid blurry edges when scaled (e.g. at 125% or 175%)
|
// disable antialiasing for background rectangle painting to avoid blurry edges when scaled (e.g. at 125% or 175%)
|
||||||
Object oldHint = g.getRenderingHint( RenderingHints.KEY_ANTIALIASING );
|
Object oldHint = g.getRenderingHint( RenderingHints.KEY_ANTIALIASING );
|
||||||
g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF );
|
g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF );
|
||||||
|
|
||||||
|
// fill background of whole component
|
||||||
g.setColor( FlatUIUtils.deriveColor( background, c.getBackground() ) );
|
g.setColor( FlatUIUtils.deriveColor( background, c.getBackground() ) );
|
||||||
g.fillRect( 0, 0, width, height );
|
g.fillRect( 0, 0, c.getWidth(), c.getHeight() );
|
||||||
|
|
||||||
g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, oldHint );
|
g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, oldHint );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -585,7 +585,7 @@ public class FlatComboBoxUI
|
|||||||
FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc );
|
FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc );
|
||||||
|
|
||||||
// paint arrow button background
|
// paint arrow button background
|
||||||
if( enabled && !isCellRenderer ) {
|
if( enabled && !isCellRenderer && arrowButton.isVisible() ) {
|
||||||
Color buttonColor = paintButton
|
Color buttonColor = paintButton
|
||||||
? buttonEditableBackground
|
? buttonEditableBackground
|
||||||
: (buttonFocusedBackground != null || focusedBackground != null) && isPermanentFocusOwner( comboBox )
|
: (buttonFocusedBackground != null || focusedBackground != null) && isPermanentFocusOwner( comboBox )
|
||||||
@@ -612,7 +612,7 @@ public class FlatComboBoxUI
|
|||||||
}
|
}
|
||||||
|
|
||||||
// paint vertical line between value and arrow button
|
// paint vertical line between value and arrow button
|
||||||
if( paintButton ) {
|
if( paintButton && arrowButton.isVisible() ) {
|
||||||
Color separatorColor = enabled ? buttonSeparatorColor : buttonDisabledSeparatorColor;
|
Color separatorColor = enabled ? buttonSeparatorColor : buttonDisabledSeparatorColor;
|
||||||
if( separatorColor != null && buttonSeparatorWidth > 0 ) {
|
if( separatorColor != null && buttonSeparatorWidth > 0 ) {
|
||||||
g2.setColor( separatorColor );
|
g2.setColor( separatorColor );
|
||||||
|
|||||||
@@ -19,13 +19,22 @@ package com.formdev.flatlaf.ui;
|
|||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import javax.swing.AbstractButton;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JToolTip;
|
||||||
import javax.swing.plaf.basic.BasicHTML;
|
import javax.swing.plaf.basic.BasicHTML;
|
||||||
|
import javax.swing.text.AttributeSet;
|
||||||
import javax.swing.text.Document;
|
import javax.swing.text.Document;
|
||||||
import javax.swing.text.LabelView;
|
import javax.swing.text.LabelView;
|
||||||
import javax.swing.text.Style;
|
import javax.swing.text.Style;
|
||||||
import javax.swing.text.StyleConstants;
|
import javax.swing.text.StyleConstants;
|
||||||
import javax.swing.text.View;
|
import javax.swing.text.View;
|
||||||
|
import javax.swing.text.html.CSS;
|
||||||
import javax.swing.text.html.HTMLDocument;
|
import javax.swing.text.html.HTMLDocument;
|
||||||
import javax.swing.text.html.StyleSheet;
|
import javax.swing.text.html.StyleSheet;
|
||||||
|
|
||||||
@@ -42,7 +51,7 @@ public class FlatHTML
|
|||||||
* which re-calculates font sizes based on current component font size.
|
* which re-calculates font sizes based on current component font size.
|
||||||
* This is necessary for "absolute-size" keywords (e.g. "x-large")
|
* This is necessary for "absolute-size" keywords (e.g. "x-large")
|
||||||
* for "font-size" attributes in default style sheet (see javax/swing/text/html/default.css).
|
* for "font-size" attributes in default style sheet (see javax/swing/text/html/default.css).
|
||||||
* See also <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/font-size?retiredLocale=de#values">CSS font-size</a>.
|
* See also <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/font-size#values">CSS font-size</a>.
|
||||||
* <p>
|
* <p>
|
||||||
* This method should be invoked after {@link BasicHTML#updateRenderer(JComponent, String)}.
|
* This method should be invoked after {@link BasicHTML#updateRenderer(JComponent, String)}.
|
||||||
*/
|
*/
|
||||||
@@ -61,16 +70,120 @@ public class FlatHTML
|
|||||||
// - if point size at index 7 is not 36, then probably HTML text contains BASE_SIZE rule
|
// - if point size at index 7 is not 36, then probably HTML text contains BASE_SIZE rule
|
||||||
// - if point size at index 4 is equal to given font size, then it is not necessary to add BASE_SIZE rule
|
// - if point size at index 4 is equal to given font size, then it is not necessary to add BASE_SIZE rule
|
||||||
StyleSheet styleSheet = ((HTMLDocument)doc).getStyleSheet();
|
StyleSheet styleSheet = ((HTMLDocument)doc).getStyleSheet();
|
||||||
|
/*debug
|
||||||
|
for( int i = 1; i <= 7; i++ )
|
||||||
|
System.out.println( i+": "+ styleSheet.getPointSize( i ) );
|
||||||
|
debug*/
|
||||||
int fontBaseSize = c.getFont().getSize();
|
int fontBaseSize = c.getFont().getSize();
|
||||||
if( styleSheet.getPointSize( 7 ) != 36f ||
|
if( styleSheet.getPointSize( 7 ) != 36f ||
|
||||||
styleSheet.getPointSize( 4 ) == fontBaseSize )
|
styleSheet.getPointSize( 4 ) == fontBaseSize )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// BASE_SIZE rule is parsed in javax.swing.text.html.StyleSheet.addRule()
|
// check whether view uses "absolute-size" keywords (e.g. "x-large") for font-size
|
||||||
styleSheet.addRule( "BASE_SIZE " + fontBaseSize );
|
if( !usesAbsoluteSizeKeywordForFontSize( view ) )
|
||||||
clearViewCaches( view );
|
return;
|
||||||
|
|
||||||
// dumpViews( view, 0 );
|
// get HTML text from component
|
||||||
|
String text;
|
||||||
|
if( c instanceof JLabel )
|
||||||
|
text = ((JLabel)c).getText();
|
||||||
|
else if( c instanceof AbstractButton )
|
||||||
|
text = ((AbstractButton)c).getText();
|
||||||
|
else if( c instanceof JToolTip )
|
||||||
|
text = ((JToolTip)c).getTipText();
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
if( text == null || !BasicHTML.isHTMLString( text ) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// BASE_SIZE rule is parsed in javax.swing.text.html.StyleSheet.addRule()
|
||||||
|
String style = "<style>BASE_SIZE " + c.getFont().getSize() + "</style>";
|
||||||
|
String openTag = "";
|
||||||
|
String closeTag = "";
|
||||||
|
|
||||||
|
int headIndex;
|
||||||
|
int styleIndex;
|
||||||
|
|
||||||
|
int insertIndex;
|
||||||
|
if( (headIndex = indexOfTag( text, "head", true )) >= 0 ) {
|
||||||
|
// there is a <head> tag --> insert after <head> tag
|
||||||
|
insertIndex = headIndex;
|
||||||
|
} else if( (styleIndex = indexOfTag( text, "style", false )) >= 0 ) {
|
||||||
|
// there is a <style> tag --> insert before <style> tag
|
||||||
|
insertIndex = styleIndex;
|
||||||
|
} else {
|
||||||
|
// no <head> or <style> tag --> insert <head> tag after <html> tag
|
||||||
|
insertIndex = "<html>".length();
|
||||||
|
openTag = "<head>";
|
||||||
|
closeTag = "</head>";
|
||||||
|
}
|
||||||
|
|
||||||
|
String newText = text.substring( 0, insertIndex )
|
||||||
|
+ openTag + style + closeTag
|
||||||
|
+ text.substring( insertIndex );
|
||||||
|
|
||||||
|
BasicHTML.updateRenderer( c, newText );
|
||||||
|
|
||||||
|
// for unit tests
|
||||||
|
if( testUpdateRenderer != null )
|
||||||
|
testUpdateRenderer.accept( c, newText );
|
||||||
|
}
|
||||||
|
|
||||||
|
// for unit tests
|
||||||
|
static BiConsumer<JComponent, String> testUpdateRenderer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns start or end index of a HTML tag.
|
||||||
|
* Checks only for leading '<' character and (case-ignore) tag name.
|
||||||
|
*/
|
||||||
|
private static int indexOfTag( String html, String tag, boolean endIndex ) {
|
||||||
|
int tagLength = tag.length();
|
||||||
|
int maxLength = html.length() - tagLength - 2;
|
||||||
|
char lastTagChar = tag.charAt( tagLength - 1 );
|
||||||
|
|
||||||
|
for( int i = "<html>".length(); i < maxLength; i++ ) {
|
||||||
|
// check for leading '<' and last tag name character
|
||||||
|
if( html.charAt( i ) == '<' && Character.toLowerCase( html.charAt( i + tagLength ) ) == lastTagChar ) {
|
||||||
|
// compare tag characters from last to first
|
||||||
|
for( int j = tagLength - 2; j >= 0; j-- ) {
|
||||||
|
if( Character.toLowerCase( html.charAt( i + 1 + j ) ) != tag.charAt( j ) )
|
||||||
|
break; // not equal
|
||||||
|
|
||||||
|
if( j == 0 ) {
|
||||||
|
// tag found
|
||||||
|
return endIndex ? html.indexOf( '>', i + tagLength ) + 1 : i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Set<String> absoluteSizeKeywordsSet = new HashSet<>( Arrays.asList(
|
||||||
|
"xx-small", "x-small", "small", "medium", "large", "x-large", "xx-large" ) );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether view uses "absolute-size" keywords (e.g. "x-large") for font-size
|
||||||
|
* (see javax/swing/text/html/default.css).
|
||||||
|
*/
|
||||||
|
private static boolean usesAbsoluteSizeKeywordForFontSize( View view ) {
|
||||||
|
AttributeSet attributes = view.getAttributes();
|
||||||
|
if( attributes != null ) {
|
||||||
|
Object fontSize = attributes.getAttribute( CSS.Attribute.FONT_SIZE );
|
||||||
|
if( fontSize != null ) {
|
||||||
|
if( absoluteSizeKeywordsSet.contains( fontSize.toString() ) )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int viewCount = view.getViewCount();
|
||||||
|
for( int i = 0; i < viewCount; i++ ) {
|
||||||
|
if( usesAbsoluteSizeKeywordForFontSize( view.getView( i ) ) )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -128,8 +241,8 @@ public class FlatHTML
|
|||||||
* updates the HTML view.
|
* updates the HTML view.
|
||||||
*/
|
*/
|
||||||
public static void propertyChange( PropertyChangeEvent e ) {
|
public static void propertyChange( PropertyChangeEvent e ) {
|
||||||
if( BasicHTML.propertyKey.equals( e.getPropertyName() ) )
|
if( BasicHTML.propertyKey.equals( e.getPropertyName() ) && e.getNewValue() instanceof View )
|
||||||
FlatHTML.updateRendererCSSFontBaseSize( (JComponent) e.getSource() );
|
updateRendererCSSFontBaseSize( (JComponent) e.getSource() );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*debug
|
/*debug
|
||||||
@@ -142,15 +255,27 @@ public class FlatHTML
|
|||||||
public static void dumpViews( View view, int indent ) {
|
public static void dumpViews( View view, int indent ) {
|
||||||
for( int i = 0; i < indent; i++ )
|
for( int i = 0; i < indent; i++ )
|
||||||
System.out.print( " " );
|
System.out.print( " " );
|
||||||
System.out.print( view.getClass().isAnonymousClass() ? view.getClass().getName() : view.getClass().getSimpleName() );
|
|
||||||
if( view instanceof LabelView ) {
|
System.out.printf( "%s @%-8x %3d,%2d",
|
||||||
LabelView lview = ((LabelView)view);
|
view.getClass().isAnonymousClass() ? view.getClass().getName() : view.getClass().getSimpleName(),
|
||||||
Font font = lview.getFont();
|
System.identityHashCode( view ),
|
||||||
Color foreground = lview.getForeground();
|
(int) view.getPreferredSpan( View.X_AXIS ),
|
||||||
System.out.printf( " %2d-%-2d %-14s %d #%06x",
|
(int) view.getPreferredSpan( View.Y_AXIS ) );
|
||||||
lview.getStartOffset(), lview.getEndOffset() - 1,
|
|
||||||
font.getName(), font.getSize(),
|
AttributeSet attrs = view.getAttributes();
|
||||||
foreground.getRGB() & 0xffffff );
|
if( attrs != null ) {
|
||||||
|
Object fontSize = attrs.getAttribute( CSS.Attribute.FONT_SIZE );
|
||||||
|
System.out.printf( " %-8s", fontSize );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( view instanceof javax.swing.text.GlyphView ) {
|
||||||
|
javax.swing.text.GlyphView gview = ((javax.swing.text.GlyphView)view);
|
||||||
|
java.awt.Font font = gview.getFont();
|
||||||
|
System.out.printf( " %3d-%-3d %s %2d (@%x) #%06x '%s'",
|
||||||
|
gview.getStartOffset(), gview.getEndOffset() - 1,
|
||||||
|
font.getName(), font.getSize(), System.identityHashCode( font ),
|
||||||
|
gview.getForeground().getRGB() & 0xffffff,
|
||||||
|
gview.getText( gview.getStartOffset(), gview.getEndOffset() ) );
|
||||||
}
|
}
|
||||||
System.out.println();
|
System.out.println();
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.formdev.flatlaf.ui;
|
package com.formdev.flatlaf.ui;
|
||||||
|
|
||||||
|
import java.awt.GraphicsConfiguration;
|
||||||
import java.awt.Point;
|
import java.awt.Point;
|
||||||
import java.awt.Toolkit;
|
import java.awt.Toolkit;
|
||||||
import java.awt.Window;
|
import java.awt.Window;
|
||||||
@@ -96,7 +97,11 @@ class FlatNativeLinuxLibrary
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static Point scale( Window window, Point pt ) {
|
private static Point scale( Window window, Point pt ) {
|
||||||
AffineTransform transform = window.getGraphicsConfiguration().getDefaultTransform();
|
GraphicsConfiguration gc = window.getGraphicsConfiguration();
|
||||||
|
if( gc == null )
|
||||||
|
return pt;
|
||||||
|
|
||||||
|
AffineTransform transform = gc.getDefaultTransform();
|
||||||
int x = (int) Math.round( pt.x * transform.getScaleX() );
|
int x = (int) Math.round( pt.x * transform.getScaleX() );
|
||||||
int y = (int) Math.round( pt.y * transform.getScaleY() );
|
int y = (int) Math.round( pt.y * transform.getScaleY() );
|
||||||
return new Point( x, y );
|
return new Point( x, y );
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ import java.awt.Toolkit;
|
|||||||
import java.awt.Window;
|
import java.awt.Window;
|
||||||
import java.awt.event.ComponentEvent;
|
import java.awt.event.ComponentEvent;
|
||||||
import java.awt.event.ComponentListener;
|
import java.awt.event.ComponentListener;
|
||||||
|
import java.awt.event.HierarchyEvent;
|
||||||
|
import java.awt.event.HierarchyListener;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.awt.event.WindowFocusListener;
|
import java.awt.event.WindowFocusListener;
|
||||||
import java.lang.invoke.MethodHandle;
|
import java.lang.invoke.MethodHandle;
|
||||||
@@ -43,6 +45,7 @@ import java.lang.invoke.MethodHandles;
|
|||||||
import java.lang.invoke.MethodType;
|
import java.lang.invoke.MethodType;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JLayeredPane;
|
import javax.swing.JLayeredPane;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
@@ -60,6 +63,7 @@ import javax.swing.border.EmptyBorder;
|
|||||||
import javax.swing.border.LineBorder;
|
import javax.swing.border.LineBorder;
|
||||||
import javax.swing.plaf.basic.BasicComboPopup;
|
import javax.swing.plaf.basic.BasicComboPopup;
|
||||||
import com.formdev.flatlaf.FlatClientProperties;
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
|
import com.formdev.flatlaf.FlatSystemProperties;
|
||||||
import com.formdev.flatlaf.util.SystemInfo;
|
import com.formdev.flatlaf.util.SystemInfo;
|
||||||
import com.formdev.flatlaf.util.UIScale;
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
|
|
||||||
@@ -113,13 +117,7 @@ public class FlatPopupFactory
|
|||||||
// macOS and Linux adds drop shadow to heavy weight popups
|
// macOS and Linux adds drop shadow to heavy weight popups
|
||||||
if( SystemInfo.isMacOS || SystemInfo.isLinux ) {
|
if( SystemInfo.isMacOS || SystemInfo.isLinux ) {
|
||||||
NonFlashingPopup popup = new NonFlashingPopup( getPopupForScreenOfOwner( owner, contents, x, y, true ), owner, contents );
|
NonFlashingPopup popup = new NonFlashingPopup( getPopupForScreenOfOwner( owner, contents, x, y, true ), owner, contents );
|
||||||
if( popup.popupWindow != null && SystemInfo.isMacOS &&
|
if( popup.popupWindow != null && isMacOSBorderSupported() )
|
||||||
// do not use rounded border on macOS 14.4+ because it may freeze the application
|
|
||||||
// and crash the macOS WindowServer process (reports vary from Finder restarts to OS restarts)
|
|
||||||
// https://github.com/apache/netbeans/issues/7560#issuecomment-2226439215
|
|
||||||
// https://github.com/apache/netbeans/issues/6647#issuecomment-2070124442
|
|
||||||
SystemInfo.osVersion < SystemInfo.toVersion( 14, 4, 0, 0 ) &&
|
|
||||||
FlatNativeMacLibrary.isLoaded() )
|
|
||||||
setupRoundedBorder( popup.popupWindow, owner, contents );
|
setupRoundedBorder( popup.popupWindow, owner, contents );
|
||||||
return popup;
|
return popup;
|
||||||
}
|
}
|
||||||
@@ -139,7 +137,11 @@ public class FlatPopupFactory
|
|||||||
forceHeavyWeight = true;
|
forceHeavyWeight = true;
|
||||||
|
|
||||||
// create drop shadow popup
|
// create drop shadow popup
|
||||||
return new DropShadowPopup( getPopupForScreenOfOwner( owner, contents, x, y, forceHeavyWeight ), owner, contents );
|
Popup popupForScreenOfOwner = getPopupForScreenOfOwner( owner, contents, x, y, forceHeavyWeight );
|
||||||
|
GraphicsConfiguration gc = owner.getGraphicsConfiguration();
|
||||||
|
return (gc != null && gc.isTranslucencyCapable())
|
||||||
|
? new DropShadowPopup( popupForScreenOfOwner, owner, contents )
|
||||||
|
: new NonFlashingPopup( popupForScreenOfOwner, owner, contents );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -357,19 +359,29 @@ public class FlatPopupFactory
|
|||||||
//---- native rounded border ----------------------------------------------
|
//---- native rounded border ----------------------------------------------
|
||||||
|
|
||||||
private static boolean isWindows11BorderSupported() {
|
private static boolean isWindows11BorderSupported() {
|
||||||
return SystemInfo.isWindows_11_orLater && FlatNativeWindowsLibrary.isLoaded();
|
return SystemInfo.isWindows_11_orLater &&
|
||||||
|
FlatSystemProperties.getBoolean( FlatSystemProperties.USE_ROUNDED_POPUP_BORDER, true ) &&
|
||||||
|
FlatNativeWindowsLibrary.isLoaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isMacOSBorderSupported() {
|
||||||
|
// do not use rounded border on macOS 14.4+ because it may freeze the application
|
||||||
|
// and crash the macOS WindowServer process (reports vary from Finder restarts to OS restarts)
|
||||||
|
// https://github.com/apache/netbeans/issues/7560#issuecomment-2226439215
|
||||||
|
// https://github.com/apache/netbeans/issues/6647#issuecomment-2070124442
|
||||||
|
boolean isMacOS_14_4_orLater = (SystemInfo.osVersion >= SystemInfo.toVersion( 14, 4, 0, 0 ));
|
||||||
|
|
||||||
|
return SystemInfo.isMacOS &&
|
||||||
|
FlatSystemProperties.getBoolean( FlatSystemProperties.USE_ROUNDED_POPUP_BORDER, !isMacOS_14_4_orLater ) &&
|
||||||
|
FlatNativeMacLibrary.isLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void setupRoundedBorder( Window popupWindow, Component owner, Component contents ) {
|
private static void setupRoundedBorder( Window popupWindow, Component owner, Component contents ) {
|
||||||
// make sure that the native window is created
|
|
||||||
if( !popupWindow.isDisplayable() )
|
|
||||||
popupWindow.addNotify();
|
|
||||||
|
|
||||||
int borderCornerRadius = getBorderCornerRadius( owner, contents );
|
int borderCornerRadius = getBorderCornerRadius( owner, contents );
|
||||||
float borderWidth = getRoundedBorderWidth( owner, contents );
|
float borderWidth = getRoundedBorderWidth( owner, contents );
|
||||||
|
|
||||||
// get Swing border color
|
// get Swing border color
|
||||||
Color borderColor = null; // use system default color
|
Color borderColor;
|
||||||
if( contents instanceof JComponent ) {
|
if( contents instanceof JComponent ) {
|
||||||
Border border = ((JComponent)contents).getBorder();
|
Border border = ((JComponent)contents).getBorder();
|
||||||
border = FlatUIUtils.unwrapNonUIResourceBorder( border );
|
border = FlatUIUtils.unwrapNonUIResourceBorder( border );
|
||||||
@@ -381,11 +393,33 @@ public class FlatPopupFactory
|
|||||||
borderColor = ((LineBorder)border).getLineColor();
|
borderColor = ((LineBorder)border).getLineColor();
|
||||||
else if( border instanceof EmptyBorder )
|
else if( border instanceof EmptyBorder )
|
||||||
borderColor = FlatNativeWindowsLibrary.COLOR_NONE; // do not paint border
|
borderColor = FlatNativeWindowsLibrary.COLOR_NONE; // do not paint border
|
||||||
|
else
|
||||||
|
borderColor = null; // use system default color
|
||||||
|
|
||||||
// avoid that FlatLineBorder paints the Swing border
|
// avoid that FlatLineBorder paints the Swing border
|
||||||
((JComponent)contents).putClientProperty( KEY_POPUP_USES_NATIVE_BORDER, true );
|
((JComponent)contents).putClientProperty( KEY_POPUP_USES_NATIVE_BORDER, true );
|
||||||
}
|
} else
|
||||||
|
borderColor = null; // use system default color
|
||||||
|
|
||||||
|
if( popupWindow.isDisplayable() ) {
|
||||||
|
// native window already created
|
||||||
|
setupRoundedBorderImpl( popupWindow, borderCornerRadius, borderWidth, borderColor );
|
||||||
|
} else {
|
||||||
|
// native window not yet created --> add listener to set native border after window creation
|
||||||
|
AtomicReference<HierarchyListener> l = new AtomicReference<>();
|
||||||
|
l.set( e -> {
|
||||||
|
if( e.getID() == HierarchyEvent.HIERARCHY_CHANGED &&
|
||||||
|
(e.getChangeFlags() & HierarchyEvent.DISPLAYABILITY_CHANGED) != 0 )
|
||||||
|
{
|
||||||
|
setupRoundedBorderImpl( popupWindow, borderCornerRadius, borderWidth, borderColor );
|
||||||
|
popupWindow.removeHierarchyListener( l.get() );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
popupWindow.addHierarchyListener( l.get() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void setupRoundedBorderImpl( Window popupWindow, int borderCornerRadius, float borderWidth, Color borderColor ) {
|
||||||
if( SystemInfo.isWindows ) {
|
if( SystemInfo.isWindows ) {
|
||||||
// get native window handle
|
// get native window handle
|
||||||
long hwnd = FlatNativeWindowsLibrary.getHWND( popupWindow );
|
long hwnd = FlatNativeWindowsLibrary.getHWND( popupWindow );
|
||||||
@@ -662,8 +696,6 @@ public class FlatPopupFactory
|
|||||||
Container contentPane = ((JWindow)popupWindow).getContentPane();
|
Container contentPane = ((JWindow)popupWindow).getContentPane();
|
||||||
contentPane.removeAll();
|
contentPane.removeAll();
|
||||||
contentPane.add( contents, BorderLayout.CENTER );
|
contentPane.add( contents, BorderLayout.CENTER );
|
||||||
popupWindow.invalidate();
|
|
||||||
popupWindow.validate();
|
|
||||||
popupWindow.pack();
|
popupWindow.pack();
|
||||||
|
|
||||||
// update client property on contents
|
// update client property on contents
|
||||||
@@ -924,12 +956,13 @@ public class FlatPopupFactory
|
|||||||
int w = prefSize.width + insets.left + insets.right;
|
int w = prefSize.width + insets.left + insets.right;
|
||||||
int h = prefSize.height + insets.top + insets.bottom;
|
int h = prefSize.height + insets.top + insets.bottom;
|
||||||
dropShadowPanel2.setPreferredSize( new Dimension( w, h ) );
|
dropShadowPanel2.setPreferredSize( new Dimension( w, h ) );
|
||||||
|
dropShadowPanel2.invalidate();
|
||||||
|
dropShadowWindow.pack();
|
||||||
|
|
||||||
// update drop shadow popup window location and size
|
// update drop shadow popup window location
|
||||||
int x = popupWindow.getX() - insets.left;
|
int x = popupWindow.getX() - insets.left;
|
||||||
int y = popupWindow.getY() - insets.top;
|
int y = popupWindow.getY() - insets.top;
|
||||||
dropShadowWindow.setBounds( x, y, w, h );
|
dropShadowWindow.setLocation( x, y );
|
||||||
dropShadowWindow.pack();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -239,11 +239,13 @@ public class FlatPopupMenuUI
|
|||||||
if( gc == null && popupMenu.getInvoker() != null )
|
if( gc == null && popupMenu.getInvoker() != null )
|
||||||
gc = popupMenu.getInvoker().getGraphicsConfiguration();
|
gc = popupMenu.getInvoker().getGraphicsConfiguration();
|
||||||
|
|
||||||
// compute screen height
|
if( gc == null )
|
||||||
|
return new Rectangle( Toolkit.getDefaultToolkit().getScreenSize() );
|
||||||
|
|
||||||
|
// compute screen bounds
|
||||||
// (always subtract screen insets because there is no API to detect whether
|
// (always subtract screen insets because there is no API to detect whether
|
||||||
// the popup can overlap the taskbar; see JPopupMenu.canPopupOverlapTaskBar())
|
// the popup can overlap the taskbar; see JPopupMenu.canPopupOverlapTaskBar())
|
||||||
Toolkit toolkit = Toolkit.getDefaultToolkit();
|
Rectangle screenBounds = gc.getBounds();
|
||||||
Rectangle screenBounds = (gc != null) ? gc.getBounds() : new Rectangle( toolkit.getScreenSize() );
|
|
||||||
Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets( gc );
|
Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets( gc );
|
||||||
return FlatUIUtils.subtractInsets( screenBounds, screenInsets );
|
return FlatUIUtils.subtractInsets( screenBounds, screenInsets );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -448,6 +448,11 @@ public class FlatRootPaneUI
|
|||||||
titlePane.titleBarColorsChanged();
|
titlePane.titleBarColorsChanged();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case FlatClientProperties.TITLE_BAR_HEIGHT:
|
||||||
|
if( titlePane != null )
|
||||||
|
titlePane.revalidate();
|
||||||
|
break;
|
||||||
|
|
||||||
case FlatClientProperties.FULL_WINDOW_CONTENT:
|
case FlatClientProperties.FULL_WINDOW_CONTENT:
|
||||||
if( titlePane != null ) {
|
if( titlePane != null ) {
|
||||||
rootPane.getLayeredPane().setLayer( titlePane, getLayerForTitlePane() );
|
rootPane.getLayeredPane().setLayer( titlePane, getLayerForTitlePane() );
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ public class FlatScrollPaneUI
|
|||||||
|
|
||||||
// Use (0, 0) view position to obtain a constant unit increment of first item.
|
// Use (0, 0) view position to obtain a constant unit increment of first item.
|
||||||
// Unit increment may be different for each item.
|
// Unit increment may be different for each item.
|
||||||
Rectangle visibleRect = new Rectangle( viewport.getViewSize() );
|
Rectangle visibleRect = new Rectangle( viewport.getExtentSize() );
|
||||||
unitIncrement = scrollable.getScrollableUnitIncrement( visibleRect, orientation, 1 );
|
unitIncrement = scrollable.getScrollableUnitIncrement( visibleRect, orientation, 1 );
|
||||||
|
|
||||||
if( unitIncrement > 0 ) {
|
if( unitIncrement > 0 ) {
|
||||||
|
|||||||
@@ -1685,7 +1685,7 @@ debug*/
|
|||||||
w - (ci.left / 100f) - (ci.right / 100f), h - (ci.top / 100f) - (ci.bottom / 100f) ), false );
|
w - (ci.left / 100f) - (ci.right / 100f), h - (ci.top / 100f) - (ci.bottom / 100f) ), false );
|
||||||
|
|
||||||
// add gap for selected tab to path
|
// add gap for selected tab to path
|
||||||
if( getTabType() == TAB_TYPE_CARD ) {
|
if( getTabType() == TAB_TYPE_CARD && selectedIndex >= 0 ) {
|
||||||
float csh = scale( (float) contentSeparatorHeight );
|
float csh = scale( (float) contentSeparatorHeight );
|
||||||
|
|
||||||
Rectangle tabRect = getTabBounds( tabPane, selectedIndex );
|
Rectangle tabRect = getTabBounds( tabPane, selectedIndex );
|
||||||
@@ -2306,8 +2306,23 @@ debug*/
|
|||||||
/** @since 3.4 */
|
/** @since 3.4 */
|
||||||
@Override
|
@Override
|
||||||
public Boolean isTitleBarCaptionAt( int x, int y ) {
|
public Boolean isTitleBarCaptionAt( int x, int y ) {
|
||||||
if( tabForCoordinate( tabPane, x, y ) >= 0 )
|
// Note: not using tabForCoordinate() here because this may validate layout and cause dead lock
|
||||||
return false;
|
|
||||||
|
if( moreTabsButton != null ) {
|
||||||
|
// convert x,y from JTabbedPane coordinate space to ScrollableTabPanel coordinate space
|
||||||
|
Point viewPosition = tabViewport.getViewPosition();
|
||||||
|
x = x - tabViewport.getX() + viewPosition.x;
|
||||||
|
y = y - tabViewport.getY() + viewPosition.y;
|
||||||
|
|
||||||
|
// check whether point is within viewport
|
||||||
|
if( !tabViewport.getViewRect().contains( x, y ) )
|
||||||
|
return null; // check children
|
||||||
|
}
|
||||||
|
|
||||||
|
for( int i = 0; i < rects.length; i++ ) {
|
||||||
|
if( rects[i].contains( x, y ) )
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return null; // check children
|
return null; // check children
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -359,6 +359,10 @@ public class FlatTitlePane
|
|||||||
@Override
|
@Override
|
||||||
public Dimension getPreferredSize() {
|
public Dimension getPreferredSize() {
|
||||||
Dimension size = super.getPreferredSize();
|
Dimension size = super.getPreferredSize();
|
||||||
|
int titleBarHeight = clientPropertyInt( rootPane, TITLE_BAR_HEIGHT, -1 );
|
||||||
|
if( titleBarHeight >= 0 )
|
||||||
|
return new Dimension( size.width, UIScale.scale( titleBarHeight ) );
|
||||||
|
|
||||||
if( buttonMaximizedHeight > 0 && isWindowMaximized() && !hasVisibleEmbeddedMenuBar( rootPane.getJMenuBar() ) ) {
|
if( buttonMaximizedHeight > 0 && isWindowMaximized() && !hasVisibleEmbeddedMenuBar( rootPane.getJMenuBar() ) ) {
|
||||||
// make title pane height smaller when frame is maximized
|
// make title pane height smaller when frame is maximized
|
||||||
size = new Dimension( size.width, Math.min( size.height, UIScale.scale( buttonMaximizedHeight ) ) );
|
size = new Dimension( size.width, Math.min( size.height, UIScale.scale( buttonMaximizedHeight ) ) );
|
||||||
@@ -395,6 +399,12 @@ public class FlatTitlePane
|
|||||||
// allow the button to shrink if space is rare
|
// allow the button to shrink if space is rare
|
||||||
return new Dimension( UIScale.scale( buttonMinimumWidth ), super.getMinimumSize().height );
|
return new Dimension( UIScale.scale( buttonMinimumWidth ), super.getMinimumSize().height );
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
|
public Dimension getMaximumSize() {
|
||||||
|
// allow the button to fill whole button area height
|
||||||
|
// see also BasicMenuUI.getMaximumSize()
|
||||||
|
return new Dimension( super.getMaximumSize().width, Short.MAX_VALUE );
|
||||||
|
}
|
||||||
};
|
};
|
||||||
button.setFocusable( false );
|
button.setFocusable( false );
|
||||||
button.setContentAreaFilled( false );
|
button.setContentAreaFilled( false );
|
||||||
@@ -814,7 +824,8 @@ public class FlatTitlePane
|
|||||||
Rectangle oldMaximizedBounds = frame.getMaximizedBounds();
|
Rectangle oldMaximizedBounds = frame.getMaximizedBounds();
|
||||||
if( !hasNativeCustomDecoration() &&
|
if( !hasNativeCustomDecoration() &&
|
||||||
(oldMaximizedBounds == null ||
|
(oldMaximizedBounds == null ||
|
||||||
Objects.equals( oldMaximizedBounds, rootPane.getClientProperty( "_flatlaf.maximizedBounds" ) )) )
|
Objects.equals( oldMaximizedBounds, rootPane.getClientProperty( "_flatlaf.maximizedBounds" ) )) &&
|
||||||
|
window.getGraphicsConfiguration() != null )
|
||||||
{
|
{
|
||||||
GraphicsConfiguration gc = window.getGraphicsConfiguration();
|
GraphicsConfiguration gc = window.getGraphicsConfiguration();
|
||||||
|
|
||||||
@@ -1048,10 +1059,11 @@ public class FlatTitlePane
|
|||||||
* <p>
|
* <p>
|
||||||
* Note:
|
* Note:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>This method is invoked often when mouse is moved over title bar
|
* <li>This method is invoked often when mouse is moved over window title bar area
|
||||||
* and should therefore return quickly.
|
* and should therefore return quickly.
|
||||||
* <li>This method is invoked on 'AWT-Windows' thread (not 'AWT-EventQueue' thread)
|
* <li>This method is invoked on 'AWT-Windows' thread (not 'AWT-EventQueue' thread)
|
||||||
* while processing Windows messages.
|
* while processing Windows messages.
|
||||||
|
* It <b>must not</b> change any component property or layout because this could cause a dead lock.
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
private boolean captionHitTest( Point pt ) {
|
private boolean captionHitTest( Point pt ) {
|
||||||
@@ -1079,7 +1091,7 @@ public class FlatTitlePane
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean isTitleBarCaptionAt( Component c, int x, int y ) {
|
private boolean isTitleBarCaptionAt( Component c, int x, int y ) {
|
||||||
if( !c.isDisplayable() || !c.isVisible() || !c.contains( x, y ) || c == mouseLayer )
|
if( !c.isDisplayable() || !c.isVisible() || !contains( c, x, y ) || c == mouseLayer )
|
||||||
return true; // continue checking with next component
|
return true; // continue checking with next component
|
||||||
|
|
||||||
if( c.isEnabled() &&
|
if( c.isEnabled() &&
|
||||||
@@ -1097,8 +1109,18 @@ public class FlatTitlePane
|
|||||||
// if component is not fully layouted, do not invoke function
|
// if component is not fully layouted, do not invoke function
|
||||||
// because it is too dangerous that the function tries to layout the component,
|
// because it is too dangerous that the function tries to layout the component,
|
||||||
// which could cause a dead lock
|
// which could cause a dead lock
|
||||||
if( !c.isValid() )
|
if( !c.isValid() ) {
|
||||||
|
// revalidate if necessary so that it is valid when invoked again later
|
||||||
|
EventQueue.invokeLater( () -> {
|
||||||
|
Window w = SwingUtilities.windowForComponent( c );
|
||||||
|
if( w != null )
|
||||||
|
w.revalidate();
|
||||||
|
else
|
||||||
|
c.revalidate();
|
||||||
|
} );
|
||||||
|
|
||||||
return false; // assume that this is not a caption because the component has mouse listeners
|
return false; // assume that this is not a caption because the component has mouse listeners
|
||||||
|
}
|
||||||
|
|
||||||
if( caption instanceof Function ) {
|
if( caption instanceof Function ) {
|
||||||
// check client property function value
|
// check client property function value
|
||||||
@@ -1131,6 +1153,16 @@ public class FlatTitlePane
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as {@link Component#contains(int, int)}, but not using that method
|
||||||
|
* because it may be overridden by custom components and invoke code that
|
||||||
|
* tries to request AWT tree lock on 'AWT-Windows' thread.
|
||||||
|
* This could freeze the application if AWT tree is already locked on 'AWT-EventQueue' thread.
|
||||||
|
*/
|
||||||
|
private boolean contains( Component c, int x, int y ) {
|
||||||
|
return x >= 0 && y >= 0 && x < c.getWidth() && y < c.getHeight();
|
||||||
|
}
|
||||||
|
|
||||||
private int lastCaptionHitTestX;
|
private int lastCaptionHitTestX;
|
||||||
private int lastCaptionHitTestY;
|
private int lastCaptionHitTestY;
|
||||||
private long lastCaptionHitTestTime;
|
private long lastCaptionHitTestTime;
|
||||||
@@ -1558,6 +1590,15 @@ debug*/
|
|||||||
* Useful for components that do not use mouse input on whole component bounds.
|
* Useful for components that do not use mouse input on whole component bounds.
|
||||||
* E.g. a tabbed pane with a few tabs has some empty space beside the tabs
|
* E.g. a tabbed pane with a few tabs has some empty space beside the tabs
|
||||||
* that can be used to move the window.
|
* that can be used to move the window.
|
||||||
|
* <p>
|
||||||
|
* Note:
|
||||||
|
* <ul>
|
||||||
|
* <li>This method is invoked often when mouse is moved over window title bar area
|
||||||
|
* and should therefore return quickly.
|
||||||
|
* <li>This method is invoked on 'AWT-Windows' thread (not 'AWT-EventQueue' thread)
|
||||||
|
* while processing Windows messages.
|
||||||
|
* It <b>must not</b> change any component property or layout because this could cause a dead lock.
|
||||||
|
* </ul>
|
||||||
*
|
*
|
||||||
* @return {@code true} if the component is not interested in mouse input at the given location
|
* @return {@code true} if the component is not interested in mouse input at the given location
|
||||||
* {@code false} if the component wants process mouse input at the given location
|
* {@code false} if the component wants process mouse input at the given location
|
||||||
|
|||||||
@@ -531,8 +531,11 @@ public class FlatToolBarUI
|
|||||||
|
|
||||||
private Component getRecentComponent( Container aContainer, boolean first ) {
|
private Component getRecentComponent( Container aContainer, boolean first ) {
|
||||||
// if moving focus into the toolbar, focus recently focused toolbar button
|
// if moving focus into the toolbar, focus recently focused toolbar button
|
||||||
if( focusedCompIndex >= 0 && focusedCompIndex < toolBar.getComponentCount() )
|
if( focusedCompIndex >= 0 && focusedCompIndex < toolBar.getComponentCount() ) {
|
||||||
return toolBar.getComponent( focusedCompIndex );
|
Component c = toolBar.getComponent( focusedCompIndex );
|
||||||
|
if( accept( c ) )
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
return first
|
return first
|
||||||
? super.getFirstComponent( aContainer )
|
? super.getFirstComponent( aContainer )
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ import javax.swing.DesktopManager;
|
|||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JInternalFrame;
|
import javax.swing.JInternalFrame;
|
||||||
import javax.swing.JLayeredPane;
|
import javax.swing.JLayeredPane;
|
||||||
|
import javax.swing.JPanel;
|
||||||
import javax.swing.JRootPane;
|
import javax.swing.JRootPane;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
@@ -191,7 +192,7 @@ public abstract class FlatWindowResizer
|
|||||||
protected abstract Dimension getWindowMinimumSize();
|
protected abstract Dimension getWindowMinimumSize();
|
||||||
protected abstract Dimension getWindowMaximumSize();
|
protected abstract Dimension getWindowMaximumSize();
|
||||||
|
|
||||||
protected void beginResizing( int direction ) {}
|
protected void beginResizing( int resizeDir ) {}
|
||||||
protected void endResizing() {}
|
protected void endResizing() {}
|
||||||
|
|
||||||
//---- interface PropertyChangeListener ----
|
//---- interface PropertyChangeListener ----
|
||||||
@@ -234,17 +235,46 @@ public abstract class FlatWindowResizer
|
|||||||
{
|
{
|
||||||
protected Window window;
|
protected Window window;
|
||||||
|
|
||||||
|
private final JComponent centerComp;
|
||||||
private final boolean limitResizeToScreenBounds;
|
private final boolean limitResizeToScreenBounds;
|
||||||
|
|
||||||
public WindowResizer( JRootPane rootPane ) {
|
public WindowResizer( JRootPane rootPane ) {
|
||||||
super( rootPane );
|
super( rootPane );
|
||||||
|
|
||||||
|
// Transparent "center" component that is made visible only while resizing window.
|
||||||
|
// It uses same cursor as the area where resize dragging started.
|
||||||
|
// This ensures that the cursor shape stays stable while dragging mouse
|
||||||
|
// into the window to make window smaller. Otherwise it would toggling between
|
||||||
|
// resize and standard cursor because the component layout is not updated
|
||||||
|
// fast enough and the mouse cursor is always updated from the component
|
||||||
|
// at the mouse location.
|
||||||
|
centerComp = new JPanel();
|
||||||
|
centerComp.setOpaque( false );
|
||||||
|
centerComp.setVisible( false );
|
||||||
|
Container cont = rootPane.getLayeredPane();
|
||||||
|
cont.add( centerComp, WINDOW_RESIZER_LAYER, 4 );
|
||||||
|
|
||||||
// On Linux, limit window resizing to screen bounds because otherwise
|
// On Linux, limit window resizing to screen bounds because otherwise
|
||||||
// there would be a strange effect when the mouse is moved over a sidebar
|
// there would be a strange effect when the mouse is moved over a sidebar
|
||||||
// while resizing and the opposite window side is also resized.
|
// while resizing and the opposite window side is also resized.
|
||||||
limitResizeToScreenBounds = SystemInfo.isLinux;
|
limitResizeToScreenBounds = SystemInfo.isLinux;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void uninstall() {
|
||||||
|
Container cont = topDragComp.getParent();
|
||||||
|
cont.remove( centerComp );
|
||||||
|
|
||||||
|
super.uninstall();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doLayout() {
|
||||||
|
super.doLayout();
|
||||||
|
|
||||||
|
centerComp.setBounds( 0, 0, resizeComp.getWidth(), resizeComp.getHeight() );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void addNotify() {
|
protected void addNotify() {
|
||||||
Container parent = resizeComp.getParent();
|
Container parent = resizeComp.getParent();
|
||||||
@@ -299,20 +329,17 @@ public abstract class FlatWindowResizer
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean limitToParentBounds() {
|
protected boolean limitToParentBounds() {
|
||||||
return limitResizeToScreenBounds && window != null;
|
return limitResizeToScreenBounds && window != null && window.getGraphicsConfiguration() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Rectangle getParentBounds() {
|
protected Rectangle getParentBounds() {
|
||||||
if( limitResizeToScreenBounds && window != null ) {
|
GraphicsConfiguration gc = window.getGraphicsConfiguration();
|
||||||
GraphicsConfiguration gc = window.getGraphicsConfiguration();
|
Rectangle bounds = gc.getBounds();
|
||||||
Rectangle bounds = gc.getBounds();
|
Insets insets = window.getToolkit().getScreenInsets( gc );
|
||||||
Insets insets = window.getToolkit().getScreenInsets( gc );
|
return new Rectangle( bounds.x + insets.left, bounds.y + insets.top,
|
||||||
return new Rectangle( bounds.x + insets.left, bounds.y + insets.top,
|
bounds.width - insets.left - insets.right,
|
||||||
bounds.width - insets.left - insets.right,
|
bounds.height - insets.top - insets.bottom );
|
||||||
bounds.height - insets.top - insets.bottom );
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -346,6 +373,18 @@ public abstract class FlatWindowResizer
|
|||||||
public void windowStateChanged( WindowEvent e ) {
|
public void windowStateChanged( WindowEvent e ) {
|
||||||
updateVisibility();
|
updateVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void beginResizing( int resizeDir ) {
|
||||||
|
centerComp.setCursor( getPredefinedCursor( resizeDir ) );
|
||||||
|
centerComp.setVisible( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void endResizing() {
|
||||||
|
centerComp.setVisible( false );
|
||||||
|
centerComp.setCursor( null );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//---- class InternalFrameResizer -----------------------------------------
|
//---- class InternalFrameResizer -----------------------------------------
|
||||||
@@ -427,7 +466,18 @@ public abstract class FlatWindowResizer
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void beginResizing( int direction ) {
|
protected void beginResizing( int resizeDir ) {
|
||||||
|
int direction = 0;
|
||||||
|
switch( resizeDir ) {
|
||||||
|
case N_RESIZE_CURSOR: direction = NORTH; break;
|
||||||
|
case S_RESIZE_CURSOR: direction = SOUTH; break;
|
||||||
|
case W_RESIZE_CURSOR: direction = WEST; break;
|
||||||
|
case E_RESIZE_CURSOR: direction = EAST; break;
|
||||||
|
case NW_RESIZE_CURSOR: direction = NORTH_WEST; break;
|
||||||
|
case NE_RESIZE_CURSOR: direction = NORTH_EAST; break;
|
||||||
|
case SW_RESIZE_CURSOR: direction = SOUTH_WEST; break;
|
||||||
|
case SE_RESIZE_CURSOR: direction = SOUTH_EAST; break;
|
||||||
|
}
|
||||||
desktopManager.get().beginResizingFrame( getFrame(), direction );
|
desktopManager.get().beginResizingFrame( getFrame(), direction );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -535,18 +585,7 @@ debug*/
|
|||||||
dragRightOffset = windowBounds.x + windowBounds.width - xOnScreen;
|
dragRightOffset = windowBounds.x + windowBounds.width - xOnScreen;
|
||||||
dragBottomOffset = windowBounds.y + windowBounds.height - yOnScreen;
|
dragBottomOffset = windowBounds.y + windowBounds.height - yOnScreen;
|
||||||
|
|
||||||
int direction = 0;
|
beginResizing( resizeDir );
|
||||||
switch( resizeDir ) {
|
|
||||||
case N_RESIZE_CURSOR: direction = NORTH; break;
|
|
||||||
case S_RESIZE_CURSOR: direction = SOUTH; break;
|
|
||||||
case W_RESIZE_CURSOR: direction = WEST; break;
|
|
||||||
case E_RESIZE_CURSOR: direction = EAST; break;
|
|
||||||
case NW_RESIZE_CURSOR: direction = NORTH_WEST; break;
|
|
||||||
case NE_RESIZE_CURSOR: direction = NORTH_EAST; break;
|
|
||||||
case SW_RESIZE_CURSOR: direction = SOUTH_WEST; break;
|
|
||||||
case SE_RESIZE_CURSOR: direction = SOUTH_EAST; break;
|
|
||||||
}
|
|
||||||
beginResizing( direction );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -521,12 +521,12 @@ public class HiDPIUtils
|
|||||||
int x2 = x + c.getX();
|
int x2 = x + c.getX();
|
||||||
int y2 = y + c.getY();
|
int y2 = y + c.getY();
|
||||||
for( Component p = c.getParent(); p != null; p = p.getParent() ) {
|
for( Component p = c.getParent(); p != null; p = p.getParent() ) {
|
||||||
x2 += p.getX();
|
|
||||||
y2 += p.getY();
|
|
||||||
if( x2 + width < p.getWidth() && y2 + height < p.getHeight() && p instanceof JComponent ) {
|
if( x2 + width < p.getWidth() && y2 + height < p.getHeight() && p instanceof JComponent ) {
|
||||||
callback.addDirtyRegion( (JComponent) p, x2, y2, width, height );
|
callback.addDirtyRegion( (JComponent) p, x2, y2, width, height );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
x2 += p.getX();
|
||||||
|
y2 += p.getY();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import javax.swing.plaf.DimensionUIResource;
|
|||||||
import javax.swing.plaf.FontUIResource;
|
import javax.swing.plaf.FontUIResource;
|
||||||
import javax.swing.plaf.InsetsUIResource;
|
import javax.swing.plaf.InsetsUIResource;
|
||||||
import javax.swing.plaf.UIResource;
|
import javax.swing.plaf.UIResource;
|
||||||
|
import com.formdev.flatlaf.FlatLaf;
|
||||||
import com.formdev.flatlaf.FlatSystemProperties;
|
import com.formdev.flatlaf.FlatSystemProperties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -188,7 +189,9 @@ public class UIScale
|
|||||||
// because even if we are on a HiDPI display it is not sure
|
// because even if we are on a HiDPI display it is not sure
|
||||||
// that a larger font size is set by the current LaF
|
// that a larger font size is set by the current LaF
|
||||||
// (e.g. can avoid large icons with small text)
|
// (e.g. can avoid large icons with small text)
|
||||||
Font font = UIManager.getFont( "defaultFont" );
|
Font font = null;
|
||||||
|
if( UIManager.getLookAndFeel() instanceof FlatLaf )
|
||||||
|
font = UIManager.getFont( "defaultFont" );
|
||||||
if( font == null )
|
if( font == null )
|
||||||
font = UIManager.getFont( "Label.font" );
|
font = UIManager.getFont( "Label.font" );
|
||||||
|
|
||||||
@@ -244,6 +247,16 @@ public class UIScale
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static float computeScaleFactor( Font font ) {
|
private static float computeScaleFactor( Font font ) {
|
||||||
|
String customFontSizeDivider = System.getProperty( "flatlaf.uiScale.fontSizeDivider" );
|
||||||
|
if( customFontSizeDivider != null ) {
|
||||||
|
try {
|
||||||
|
float fontSizeDivider = Math.max( Integer.parseInt( customFontSizeDivider ), 10 );
|
||||||
|
return font.getSize() / fontSizeDivider;
|
||||||
|
} catch( NumberFormatException ex ) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// default font size
|
// default font size
|
||||||
float fontSizeDivider = 12f;
|
float fontSizeDivider = 12f;
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2024 FormDev Software GmbH
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.formdev.flatlaf.ui;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import java.util.Locale;
|
||||||
|
import javax.swing.JComponent;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.UIManager;
|
||||||
|
import javax.swing.plaf.basic.BasicHTML;
|
||||||
|
import javax.swing.text.BadLocationException;
|
||||||
|
import javax.swing.text.Document;
|
||||||
|
import javax.swing.text.View;
|
||||||
|
import org.junit.jupiter.api.AfterAll;
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Karl Tauber
|
||||||
|
*/
|
||||||
|
public class TestFlatHTML
|
||||||
|
{
|
||||||
|
private final String body = "some <small>small</small> text";
|
||||||
|
private final String bodyInBody = "<body>" + body + "</body>";
|
||||||
|
private final String bodyPlain = "some small text";
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
static void setup() {
|
||||||
|
TestUtils.setup( false );
|
||||||
|
TestUtils.scaleFont( 2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterAll
|
||||||
|
static void cleanup() {
|
||||||
|
TestUtils.cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void simple() {
|
||||||
|
testHtmlBaseSize( "<html>${BASE_SIZE_IN_HEAD}" + body + "</html>", bodyPlain );
|
||||||
|
testHtmlBaseSize( "<html>${BASE_SIZE_IN_HEAD}" + bodyInBody + "</html>", bodyPlain );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void htmlWithHeadTag() {
|
||||||
|
testHtmlBaseSize( "<html><head>${BASE_SIZE}<title>test</title><head>" + body + "</html>", bodyPlain );
|
||||||
|
testHtmlBaseSize( "<html><head>${BASE_SIZE}<title>test</title><head>" + bodyInBody + "</html>", bodyPlain );
|
||||||
|
|
||||||
|
testHtmlBaseSize( "<html><head id=\"abc\">${BASE_SIZE}<title>test</title><head>" + body + "</html>", bodyPlain );
|
||||||
|
testHtmlBaseSize( "<html><head id=\"abc\">${BASE_SIZE}<title>test</title><head>" + bodyInBody + "</html>", bodyPlain );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void htmlWithStyleTag() {
|
||||||
|
testHtmlBaseSize( "<html>${BASE_SIZE}<style>body { color: #f00; }</style>" + bodyInBody + "</html>", bodyPlain );
|
||||||
|
testHtmlBaseSize( "<html>${BASE_SIZE}<style>body { color: #f00; }</style><h1>header1</h1>" + body + "</html>", "header1\n" + bodyPlain );
|
||||||
|
|
||||||
|
testHtmlBaseSize( "<html>${BASE_SIZE}<style type='text/css'>body { color: #f00; }</style>" + bodyInBody + "</html>", bodyPlain );
|
||||||
|
testHtmlBaseSize( "<html>${BASE_SIZE}<style type='text/css'>body { color: #f00; }</style><h1>header1</h1>" + body + "</html>", "header1\n" + bodyPlain );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testHtmlBaseSize( String html, String expectedPlain ) {
|
||||||
|
testHtmlBaseSizeImpl( html, expectedPlain );
|
||||||
|
testHtmlBaseSizeImpl( html.toUpperCase( Locale.ENGLISH ), expectedPlain.toUpperCase( Locale.ENGLISH ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testHtmlBaseSizeImpl( String html, String expectedPlain ) {
|
||||||
|
String baseSize = "<style>BASE_SIZE " + UIManager.getFont( "Label.font" ).getSize() + "</style>";
|
||||||
|
String baseSizeInHead = "<head>" + baseSize + "</head>";
|
||||||
|
|
||||||
|
String expectedHtml = html.replace( "${BASE_SIZE}", baseSize ).replace( "${BASE_SIZE_IN_HEAD}", baseSizeInHead );
|
||||||
|
html = html.replace( "${BASE_SIZE}", "" ).replace( "${BASE_SIZE_IN_HEAD}", "" );
|
||||||
|
|
||||||
|
testHtml( html, expectedHtml, expectedPlain );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testHtml( String html, String expectedHtml, String expectedPlain ) {
|
||||||
|
FlatHTML.testUpdateRenderer = (c, newHtml) -> {
|
||||||
|
assertEquals( expectedHtml, newHtml );
|
||||||
|
assertEquals( expectedPlain, getPlainText( c ) );
|
||||||
|
};
|
||||||
|
new JLabel( html );
|
||||||
|
FlatHTML.testUpdateRenderer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getPlainText( JComponent c ) {
|
||||||
|
View view = (View) c.getClientProperty( BasicHTML.propertyKey );
|
||||||
|
if( view == null )
|
||||||
|
return null;
|
||||||
|
|
||||||
|
Document doc = view.getDocument();
|
||||||
|
try {
|
||||||
|
return doc.getText( 0, doc.getLength() ).trim();
|
||||||
|
} catch( BadLocationException ex ) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
# when the Demo window is activated.
|
# when the Demo window is activated.
|
||||||
|
|
||||||
|
|
||||||
# base theme (light, dark, intellij or darcula)
|
# base theme (light, dark, intellij, darcula, maclight or macdark)
|
||||||
@baseTheme = light
|
@baseTheme = light
|
||||||
|
|
||||||
# add you theme defaults here
|
# add you theme defaults here
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import java.awt.Dimension;
|
|||||||
import java.awt.EventQueue;
|
import java.awt.EventQueue;
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
|
import java.awt.GraphicsConfiguration;
|
||||||
import java.awt.Insets;
|
import java.awt.Insets;
|
||||||
import java.awt.KeyboardFocusManager;
|
import java.awt.KeyboardFocusManager;
|
||||||
import java.awt.LayoutManager;
|
import java.awt.LayoutManager;
|
||||||
@@ -450,15 +451,18 @@ public class FlatInspector
|
|||||||
Dimension size = tip.getPreferredSize();
|
Dimension size = tip.getPreferredSize();
|
||||||
|
|
||||||
// position the tip in the visible area
|
// position the tip in the visible area
|
||||||
Rectangle visibleRect = rootPane.getGraphicsConfiguration().getBounds();
|
GraphicsConfiguration gc = rootPane.getGraphicsConfiguration();
|
||||||
if( tx + size.width > visibleRect.x + visibleRect.width )
|
if( gc != null ) {
|
||||||
tx -= size.width + UIScale.scale( 16 );
|
Rectangle visibleRect = gc.getBounds();
|
||||||
if( ty + size.height > visibleRect.y + visibleRect.height )
|
if( tx + size.width > visibleRect.x + visibleRect.width )
|
||||||
ty -= size.height + UIScale.scale( 32 );
|
tx -= size.width + UIScale.scale( 16 );
|
||||||
if( tx < visibleRect.x )
|
if( ty + size.height > visibleRect.y + visibleRect.height )
|
||||||
tx = visibleRect.x;
|
ty -= size.height + UIScale.scale( 32 );
|
||||||
if( ty < visibleRect.y )
|
if( tx < visibleRect.x )
|
||||||
ty = visibleRect.y;
|
tx = visibleRect.x;
|
||||||
|
if( ty < visibleRect.y )
|
||||||
|
ty = visibleRect.y;
|
||||||
|
}
|
||||||
|
|
||||||
PopupFactory popupFactory = PopupFactory.getSharedInstance();
|
PopupFactory popupFactory = PopupFactory.getSharedInstance();
|
||||||
popup = popupFactory.getPopup( c, tip, tx, ty );
|
popup = popupFactory.getPopup( c, tip, tx, ty );
|
||||||
|
|||||||
@@ -309,6 +309,8 @@ public class FlatWindowsNativeWindowBorder
|
|||||||
WM_ENTERSIZEMOVE = 0x0231,
|
WM_ENTERSIZEMOVE = 0x0231,
|
||||||
WM_EXITSIZEMOVE = 0x0232,
|
WM_EXITSIZEMOVE = 0x0232,
|
||||||
|
|
||||||
|
WM_DPICHANGED = 0x02E0,
|
||||||
|
|
||||||
WM_DWMCOLORIZATIONCOLORCHANGED = 0x0320;
|
WM_DWMCOLORIZATIONCOLORCHANGED = 0x0320;
|
||||||
|
|
||||||
// WM_SIZE wParam
|
// WM_SIZE wParam
|
||||||
@@ -501,6 +503,22 @@ public class FlatWindowsNativeWindowBorder
|
|||||||
isMoving = true;
|
isMoving = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case WM_DPICHANGED:
|
||||||
|
LRESULT lResult = User32Ex.INSTANCE.CallWindowProc( defaultWndProc, hwnd, uMsg, wParam, lParam );
|
||||||
|
|
||||||
|
// if window is maximized and DPI/scaling changed, then Windows
|
||||||
|
// does not send a subsequent WM_SIZE message and Java window bounds,
|
||||||
|
// which depend on scale factor, are not updated
|
||||||
|
boolean isMaximized = User32Ex.INSTANCE.IsZoomed( hwnd );
|
||||||
|
if( isMaximized ) {
|
||||||
|
MyRECT r = new MyRECT( new Pointer( lParam.longValue() ) );
|
||||||
|
int width = r.right - r.left;
|
||||||
|
int height = r.bottom - r.top;
|
||||||
|
User32Ex.INSTANCE.CallWindowProc( defaultWndProc, hwnd, WM_SIZE, new WPARAM( SIZE_MAXIMIZED ), MAKELPARAM( width, height ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return lResult;
|
||||||
|
|
||||||
case WM_ERASEBKGND:
|
case WM_ERASEBKGND:
|
||||||
// do not erase background while the user is moving the window,
|
// do not erase background while the user is moving the window,
|
||||||
// otherwise there may be rendering artifacts on HiDPI screens with Java 9+
|
// otherwise there may be rendering artifacts on HiDPI screens with Java 9+
|
||||||
@@ -818,6 +836,13 @@ public class FlatWindowsNativeWindowBorder
|
|||||||
return (low & 0xffff) | ((high & 0xffff) << 16);
|
return (low & 0xffff) | ((high & 0xffff) << 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same implementation as MAKELPARAM(l, h) macro in winuser.h.
|
||||||
|
*/
|
||||||
|
private LPARAM MAKELPARAM( int low, int high ) {
|
||||||
|
return new LPARAM( MAKELONG( low, high ) );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Same implementation as RGB(r,g,b) macro in wingdi.h.
|
* Same implementation as RGB(r,g,b) macro in wingdi.h.
|
||||||
*/
|
*/
|
||||||
@@ -937,6 +962,23 @@ public class FlatWindowsNativeWindowBorder
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---- class MyRECT -------------------------------------------------------
|
||||||
|
|
||||||
|
@FieldOrder( { "left", "top", "right", "bottom" } )
|
||||||
|
public static class MyRECT
|
||||||
|
extends Structure
|
||||||
|
{
|
||||||
|
public int left;
|
||||||
|
public int top;
|
||||||
|
public int right;
|
||||||
|
public int bottom;
|
||||||
|
|
||||||
|
public MyRECT( Pointer pointer ) {
|
||||||
|
super( pointer );
|
||||||
|
read();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//---- class MENUITEMINFO -------------------------------------------------
|
//---- class MENUITEMINFO -------------------------------------------------
|
||||||
|
|
||||||
@FieldOrder( { "cbSize", "fMask", "fType", "fState", "wID", "hSubMenu",
|
@FieldOrder( { "cbSize", "fMask", "fType", "fState", "wID", "hSubMenu",
|
||||||
|
|||||||
@@ -19,3 +19,32 @@ The DLLs were built on a GitHub server with the help of GitHub Actions. See:
|
|||||||
[Native Libraries](https://github.com/JFormDesigner/FlatLaf/actions/workflows/natives.yml)
|
[Native Libraries](https://github.com/JFormDesigner/FlatLaf/actions/workflows/natives.yml)
|
||||||
workflow. Then the produced Artifacts ZIP was downloaded, signed DLLs with
|
workflow. Then the produced Artifacts ZIP was downloaded, signed DLLs with
|
||||||
FormDev Software code signing certificate and committed the DLLs to Git.
|
FormDev Software code signing certificate and committed the DLLs to Git.
|
||||||
|
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
To build the library on Windows using Gradle, (parts of)
|
||||||
|
[Visual Studio Community
|
||||||
|
2022](https://visualstudio.microsoft.com/downloads/)
|
||||||
|
needs to be installed. After downloading and running `VisualStudioSetup.exe` the
|
||||||
|
**Visual Studio Installer** is installed and started. Once running, it shows the
|
||||||
|
**Workloads** tab that allows you to install additional packages. Either choose
|
||||||
|
**Desktop development with C++**, or to save some disk space switch to the
|
||||||
|
**Single Components** tab and choose following components (newest versions):
|
||||||
|
|
||||||
|
- MSVC v143 - VS 2022 C++ x64/x86 Buildtools
|
||||||
|
- MSVC v143 - VS 2022 C++ ARM64/ARM64EC Buildtools
|
||||||
|
- Windows 11 SDK
|
||||||
|
|
||||||
|
Note that the Visual Studio Installer shows many similar named components for
|
||||||
|
MSVC. Make sure to choose exactly those components listed above.
|
||||||
|
|
||||||
|
Using
|
||||||
|
[Build Tools for Visual Studio 2022](https://visualstudio.microsoft.com/downloads/#remote-tools-for-visual-studio-2022)
|
||||||
|
(installs only compiler and SDKs) instead of
|
||||||
|
[Visual Studio Community
|
||||||
|
2022](https://visualstudio.microsoft.com/downloads/)
|
||||||
|
does not work with Gradle.
|
||||||
|
|
||||||
|
[Visual Studio Code](https://code.visualstudio.com/) with **C/C++** extension
|
||||||
|
can be used for C++ code editing.
|
||||||
|
|||||||
@@ -288,6 +288,23 @@ LRESULT CALLBACK FlatWndProc::WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, L
|
|||||||
isMoving = true;
|
isMoving = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case WM_DPICHANGED: {
|
||||||
|
LRESULT lResult = ::CallWindowProc( defaultWndProc, hwnd, uMsg, wParam, lParam );
|
||||||
|
|
||||||
|
// if window is maximized and DPI/scaling changed, then Windows
|
||||||
|
// does not send a subsequent WM_SIZE message and Java window bounds,
|
||||||
|
// which depend on scale factor, are not updated
|
||||||
|
bool isMaximized = ::IsZoomed( hwnd );
|
||||||
|
if( isMaximized ) {
|
||||||
|
RECT* r = reinterpret_cast<RECT*>( lParam );
|
||||||
|
int width = r->right - r->left;
|
||||||
|
int height = r->bottom - r->top;
|
||||||
|
::CallWindowProc( defaultWndProc, hwnd, WM_SIZE, SIZE_MAXIMIZED, MAKELPARAM( width, height ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return lResult;
|
||||||
|
}
|
||||||
|
|
||||||
case WM_ERASEBKGND:
|
case WM_ERASEBKGND:
|
||||||
// do not erase background while the user is moving the window,
|
// do not erase background while the user is moving the window,
|
||||||
// otherwise there may be rendering artifacts on HiDPI screens with Java 9+
|
// otherwise there may be rendering artifacts on HiDPI screens with Java 9+
|
||||||
|
|||||||
@@ -30,12 +30,26 @@ HWND getWindowHandle( JNIEnv* env, jobject window );
|
|||||||
|
|
||||||
//---- Utility ----------------------------------------------------------------
|
//---- Utility ----------------------------------------------------------------
|
||||||
|
|
||||||
|
typedef LONG (WINAPI *RtlGetVersion_Type)( OSVERSIONINFO* );
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
JNIEXPORT jlong JNICALL Java_com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_getOSBuildNumberImpl
|
JNIEXPORT jlong JNICALL Java_com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_getOSBuildNumberImpl
|
||||||
( JNIEnv* env, jclass cls )
|
( JNIEnv* env, jclass cls )
|
||||||
{
|
{
|
||||||
OSVERSIONINFO info;
|
OSVERSIONINFO info;
|
||||||
info.dwOSVersionInfoSize = sizeof( info );
|
info.dwOSVersionInfoSize = sizeof( info );
|
||||||
|
info.dwBuildNumber = 0;
|
||||||
|
|
||||||
|
// use RtlGetVersion for the case that app manifest does not specify Windows 10+ compatibility
|
||||||
|
// https://www.codeproject.com/Articles/5336372/Windows-Version-Detection
|
||||||
|
HMODULE ntdllModule = ::GetModuleHandleA( "ntdll.dll" );
|
||||||
|
if( ntdllModule != NULL ) {
|
||||||
|
RtlGetVersion_Type pRtlGetVersion = (RtlGetVersion_Type) ::GetProcAddress( ntdllModule, "RtlGetVersion" );
|
||||||
|
if( pRtlGetVersion != NULL && pRtlGetVersion( &info ) == 0 )
|
||||||
|
return info.dwBuildNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fallback
|
||||||
if( !::GetVersionEx( &info ) )
|
if( !::GetVersionEx( &info ) )
|
||||||
return 0;
|
return 0;
|
||||||
return info.dwBuildNumber;
|
return info.dwBuildNumber;
|
||||||
|
|||||||
@@ -59,6 +59,11 @@ public class FlatComponentsTest
|
|||||||
};
|
};
|
||||||
for( JSlider slider : allSliders )
|
for( JSlider slider : allSliders )
|
||||||
slider.addChangeListener( sliderChanged );
|
slider.addChangeListener( sliderChanged );
|
||||||
|
|
||||||
|
UIManager.addPropertyChangeListener( e -> {
|
||||||
|
if( "lookAndFeel".equals( e.getPropertyName() ) && hideArrowButtonCheckBox.isSelected() )
|
||||||
|
SwingUtilities.invokeLater( () -> hideArrowButton() );
|
||||||
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void changeProgress() {
|
private void changeProgress() {
|
||||||
@@ -127,6 +132,18 @@ public class FlatComponentsTest
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void hideArrowButton() {
|
||||||
|
boolean hideArrowButton = hideArrowButtonCheckBox.isSelected();
|
||||||
|
|
||||||
|
for( Component c : getComponents() ) {
|
||||||
|
if( c instanceof JComboBox ) {
|
||||||
|
Component b = ((JComboBox<?>)c).getComponent( 0 );
|
||||||
|
if( b instanceof AbstractButton )
|
||||||
|
b.setVisible( !hideArrowButton );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void roundRectChanged() {
|
private void roundRectChanged() {
|
||||||
Boolean roundRect = roundRectCheckBox.isSelected() ? true : null;
|
Boolean roundRect = roundRectCheckBox.isSelected() ? true : null;
|
||||||
|
|
||||||
@@ -380,6 +397,7 @@ public class FlatComponentsTest
|
|||||||
magentaOutlineRadioButton = new JRadioButton();
|
magentaOutlineRadioButton = new JRadioButton();
|
||||||
magentaCyanOutlineRadioButton = new JRadioButton();
|
magentaCyanOutlineRadioButton = new JRadioButton();
|
||||||
focusPaintedCheckBox = new JCheckBox();
|
focusPaintedCheckBox = new JCheckBox();
|
||||||
|
hideArrowButtonCheckBox = new JCheckBox();
|
||||||
JLabel scrollBarLabel = new JLabel();
|
JLabel scrollBarLabel = new JLabel();
|
||||||
JScrollBar scrollBar1 = new JScrollBar();
|
JScrollBar scrollBar1 = new JScrollBar();
|
||||||
JScrollBar scrollBar4 = new JScrollBar();
|
JScrollBar scrollBar4 = new JScrollBar();
|
||||||
@@ -1234,9 +1252,10 @@ public class FlatComponentsTest
|
|||||||
"[]" +
|
"[]" +
|
||||||
"[]",
|
"[]",
|
||||||
// rows
|
// rows
|
||||||
"[]" +
|
"[]0" +
|
||||||
"[]" +
|
"[]0" +
|
||||||
"[]" +
|
"[]0" +
|
||||||
|
"[]0" +
|
||||||
"[]"));
|
"[]"));
|
||||||
|
|
||||||
//---- buttonTypeComboBox ----
|
//---- buttonTypeComboBox ----
|
||||||
@@ -1290,13 +1309,18 @@ public class FlatComponentsTest
|
|||||||
magentaCyanOutlineRadioButton.addActionListener(e -> outlineChanged());
|
magentaCyanOutlineRadioButton.addActionListener(e -> outlineChanged());
|
||||||
panel4.add(magentaCyanOutlineRadioButton);
|
panel4.add(magentaCyanOutlineRadioButton);
|
||||||
}
|
}
|
||||||
panel5.add(panel4, "cell 0 2 1 2");
|
panel5.add(panel4, "cell 0 2 1 3");
|
||||||
|
|
||||||
//---- focusPaintedCheckBox ----
|
//---- focusPaintedCheckBox ----
|
||||||
focusPaintedCheckBox.setText("focusPainted");
|
focusPaintedCheckBox.setText("focusPainted");
|
||||||
focusPaintedCheckBox.setSelected(true);
|
focusPaintedCheckBox.setSelected(true);
|
||||||
focusPaintedCheckBox.addActionListener(e -> focusPaintedChanged());
|
focusPaintedCheckBox.addActionListener(e -> focusPaintedChanged());
|
||||||
panel5.add(focusPaintedCheckBox, "cell 1 2");
|
panel5.add(focusPaintedCheckBox, "cell 1 2");
|
||||||
|
|
||||||
|
//---- hideArrowButtonCheckBox ----
|
||||||
|
hideArrowButtonCheckBox.setText("hide arrow button");
|
||||||
|
hideArrowButtonCheckBox.addActionListener(e -> hideArrowButton());
|
||||||
|
panel5.add(hideArrowButtonCheckBox, "cell 1 3");
|
||||||
}
|
}
|
||||||
add(panel5, "cell 5 13 2 10,grow");
|
add(panel5, "cell 5 13 2 10,grow");
|
||||||
|
|
||||||
@@ -1703,6 +1727,7 @@ public class FlatComponentsTest
|
|||||||
private JRadioButton magentaOutlineRadioButton;
|
private JRadioButton magentaOutlineRadioButton;
|
||||||
private JRadioButton magentaCyanOutlineRadioButton;
|
private JRadioButton magentaCyanOutlineRadioButton;
|
||||||
private JCheckBox focusPaintedCheckBox;
|
private JCheckBox focusPaintedCheckBox;
|
||||||
|
private JCheckBox hideArrowButtonCheckBox;
|
||||||
private JSlider slider1;
|
private JSlider slider1;
|
||||||
private JSlider slider6;
|
private JSlider slider6;
|
||||||
private JCheckBox sliderPaintTrackCheckBox;
|
private JCheckBox sliderPaintTrackCheckBox;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
JFDML JFormDesigner: "7.0.5.0.404" Java: "17.0.2" encoding: "UTF-8"
|
JFDML JFormDesigner: "8.3" encoding: "UTF-8"
|
||||||
|
|
||||||
new FormModel {
|
new FormModel {
|
||||||
contentType: "form/swing"
|
contentType: "form/swing"
|
||||||
@@ -993,7 +993,7 @@ new FormModel {
|
|||||||
} )
|
} )
|
||||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||||
"$columnConstraints": "[][]"
|
"$columnConstraints": "[][]"
|
||||||
"$rowConstraints": "[][][][]"
|
"$rowConstraints": "[]0[]0[]0[]0[]"
|
||||||
"$layoutConstraints": "ltr,insets dialog,hidemode 3"
|
"$layoutConstraints": "ltr,insets dialog,hidemode 3"
|
||||||
} ) {
|
} ) {
|
||||||
name: "panel5"
|
name: "panel5"
|
||||||
@@ -1092,7 +1092,7 @@ new FormModel {
|
|||||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "outlineChanged", false ) )
|
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "outlineChanged", false ) )
|
||||||
} )
|
} )
|
||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
"value": "cell 0 2 1 2"
|
"value": "cell 0 2 1 3"
|
||||||
} )
|
} )
|
||||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||||
name: "focusPaintedCheckBox"
|
name: "focusPaintedCheckBox"
|
||||||
@@ -1105,6 +1105,16 @@ new FormModel {
|
|||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
"value": "cell 1 2"
|
"value": "cell 1 2"
|
||||||
} )
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||||
|
name: "hideArrowButtonCheckBox"
|
||||||
|
"text": "hide arrow button"
|
||||||
|
auxiliary() {
|
||||||
|
"JavaCodeGenerator.variableLocal": false
|
||||||
|
}
|
||||||
|
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "hideArrowButton", false ) )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 1 3"
|
||||||
|
} )
|
||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
"value": "cell 5 13 2 10,grow"
|
"value": "cell 5 13 2 10,grow"
|
||||||
} )
|
} )
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import java.awt.event.MouseAdapter;
|
|||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.border.*;
|
import javax.swing.border.*;
|
||||||
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
import com.formdev.flatlaf.demo.ScrollablePanel;
|
import com.formdev.flatlaf.demo.ScrollablePanel;
|
||||||
import net.miginfocom.swing.*;
|
import net.miginfocom.swing.*;
|
||||||
|
|
||||||
@@ -63,6 +64,15 @@ public class FlatOptionPaneTest
|
|||||||
UIManager.put( "OptionPane.showIcon", showTitleBarIconCheckBox.isSelected() );
|
UIManager.put( "OptionPane.showIcon", showTitleBarIconCheckBox.isSelected() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void showWithCustomIcon() {
|
||||||
|
JOptionPane optionPane = new JOptionPane( "Hello world." );
|
||||||
|
JDialog dialog = optionPane.createDialog( "With Custom Icon" );
|
||||||
|
dialog.getRootPane().putClientProperty( FlatClientProperties.TITLE_BAR_SHOW_ICON, true );
|
||||||
|
dialog.setIconImage( new ImageIcon( FlatOptionPaneTest.class.getResource( "/com/formdev/flatlaf/testing/test32.png" ) ).getImage() );
|
||||||
|
dialog.setVisible( true );
|
||||||
|
dialog.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
private void initComponents() {
|
private void initComponents() {
|
||||||
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
|
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
|
||||||
ScrollablePanel panel9 = new ScrollablePanel();
|
ScrollablePanel panel9 = new ScrollablePanel();
|
||||||
@@ -75,6 +85,7 @@ public class FlatOptionPaneTest
|
|||||||
JPanel panel2 = new JPanel();
|
JPanel panel2 = new JPanel();
|
||||||
JOptionPane errorOptionPane = new JOptionPane();
|
JOptionPane errorOptionPane = new JOptionPane();
|
||||||
errorShowDialogLabel = new FlatOptionPaneTest.ShowDialogLinkLabel();
|
errorShowDialogLabel = new FlatOptionPaneTest.ShowDialogLinkLabel();
|
||||||
|
JButton showWithCustomIconButton = new JButton();
|
||||||
JLabel informationLabel = new JLabel();
|
JLabel informationLabel = new JLabel();
|
||||||
JPanel panel3 = new JPanel();
|
JPanel panel3 = new JPanel();
|
||||||
JOptionPane informationOptionPane = new JOptionPane();
|
JOptionPane informationOptionPane = new JOptionPane();
|
||||||
@@ -173,6 +184,11 @@ public class FlatOptionPaneTest
|
|||||||
errorShowDialogLabel.setOptionPane(errorOptionPane);
|
errorShowDialogLabel.setOptionPane(errorOptionPane);
|
||||||
panel9.add(errorShowDialogLabel, "cell 1 1");
|
panel9.add(errorShowDialogLabel, "cell 1 1");
|
||||||
|
|
||||||
|
//---- showWithCustomIconButton ----
|
||||||
|
showWithCustomIconButton.setText("Show with custom icon");
|
||||||
|
showWithCustomIconButton.addActionListener(e -> showWithCustomIcon());
|
||||||
|
panel9.add(showWithCustomIconButton, "cell 2 1");
|
||||||
|
|
||||||
//---- informationLabel ----
|
//---- informationLabel ----
|
||||||
informationLabel.setText("Information");
|
informationLabel.setText("Information");
|
||||||
panel9.add(informationLabel, "cell 0 2");
|
panel9.add(informationLabel, "cell 0 2");
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
JFDML JFormDesigner: "7.0.4.0.360" Java: "16" encoding: "UTF-8"
|
JFDML JFormDesigner: "8.2.3.0.386" Java: "21" encoding: "UTF-8"
|
||||||
|
|
||||||
new FormModel {
|
new FormModel {
|
||||||
contentType: "form/swing"
|
contentType: "form/swing"
|
||||||
@@ -83,6 +83,13 @@ new FormModel {
|
|||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
"value": "cell 1 1"
|
"value": "cell 1 1"
|
||||||
} )
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JButton" ) {
|
||||||
|
name: "showWithCustomIconButton"
|
||||||
|
"text": "Show with custom icon"
|
||||||
|
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showWithCustomIcon", false ) )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 2 1"
|
||||||
|
} )
|
||||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||||
name: "informationLabel"
|
name: "informationLabel"
|
||||||
"text": "Information"
|
"text": "Information"
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ import java.util.Arrays;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.border.TitledBorder;
|
import javax.swing.border.TitledBorder;
|
||||||
import com.formdev.flatlaf.FlatClientProperties;
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
@@ -74,6 +76,7 @@ public class FlatWindowDecorationsTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
private List<Image> images;
|
private List<Image> images;
|
||||||
|
private Timer refreshStateTimer;
|
||||||
|
|
||||||
FlatWindowDecorationsTest() {
|
FlatWindowDecorationsTest() {
|
||||||
initComponents();
|
initComponents();
|
||||||
@@ -127,8 +130,54 @@ public class FlatWindowDecorationsTest
|
|||||||
+ " @ " + bounds.x + ", " + bounds.y );
|
+ " @ " + bounds.x + ", " + bounds.y );
|
||||||
} else
|
} else
|
||||||
fullWindowContentButtonsBoundsField.setText( "null" );
|
fullWindowContentButtonsBoundsField.setText( "null" );
|
||||||
|
|
||||||
|
fullWindowContentButtonsBoundsLabel.setEnabled( bounds != null );
|
||||||
|
fullWindowContentButtonsBoundsField.setEnabled( bounds != null );
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( window instanceof Frame ) {
|
||||||
|
AtomicInteger lastState = new AtomicInteger( -1 );
|
||||||
|
AtomicReference<Window> lastFullScreenWindow = new AtomicReference<>();
|
||||||
|
refreshStateTimer = new Timer( 500, e -> {
|
||||||
|
Frame frame = (Frame) window;
|
||||||
|
int state = frame.getExtendedState();
|
||||||
|
Window fullScreenWindow = window.getGraphicsConfiguration().getDevice().getFullScreenWindow();
|
||||||
|
if( state != lastState.get() || fullScreenWindow != lastFullScreenWindow.get() ) {
|
||||||
|
lastState.set( state );
|
||||||
|
lastFullScreenWindow.set( fullScreenWindow );
|
||||||
|
|
||||||
|
String s = "";
|
||||||
|
if( (state & Frame.ICONIFIED) != 0 )
|
||||||
|
s += "iconified ";
|
||||||
|
if( (state & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_BOTH )
|
||||||
|
s += "maximized ";
|
||||||
|
else {
|
||||||
|
if( (state & Frame.MAXIMIZED_HORIZ) != 0 )
|
||||||
|
s += "maximized-horizontal ";
|
||||||
|
if( (state & Frame.MAXIMIZED_VERT) != 0 )
|
||||||
|
s += "maximized-vertical ";
|
||||||
|
}
|
||||||
|
if( fullScreenWindow == window )
|
||||||
|
s += "full-screen ";
|
||||||
|
if( s.isEmpty() )
|
||||||
|
s = "normal";
|
||||||
|
|
||||||
|
frameStateField.setText( s );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
refreshStateTimer.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeNotify() {
|
||||||
|
super.removeNotify();
|
||||||
|
|
||||||
|
if( refreshStateTimer != null ) {
|
||||||
|
refreshStateTimer.stop();
|
||||||
|
refreshStateTimer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateDecorationStyleRadioButtons( JRootPane rootPane ) {
|
private void updateDecorationStyleRadioButtons( JRootPane rootPane ) {
|
||||||
@@ -189,6 +238,7 @@ public class FlatWindowDecorationsTest
|
|||||||
|
|
||||||
if( rightCompCheckBox.isSelected() ) {
|
if( rightCompCheckBox.isSelected() ) {
|
||||||
rightStretchCompCheckBox.setSelected( false );
|
rightStretchCompCheckBox.setSelected( false );
|
||||||
|
tallCompCheckBox.setSelected( false );
|
||||||
|
|
||||||
JButton myButton = new JButton( "?" );
|
JButton myButton = new JButton( "?" );
|
||||||
myButton.putClientProperty( "JButton.buttonType", "toolBarButton" );
|
myButton.putClientProperty( "JButton.buttonType", "toolBarButton" );
|
||||||
@@ -207,6 +257,7 @@ public class FlatWindowDecorationsTest
|
|||||||
|
|
||||||
if( rightStretchCompCheckBox.isSelected() ) {
|
if( rightStretchCompCheckBox.isSelected() ) {
|
||||||
rightCompCheckBox.setSelected( false );
|
rightCompCheckBox.setSelected( false );
|
||||||
|
tallCompCheckBox.setSelected( false );
|
||||||
|
|
||||||
menuBar.add( Box.createGlue() );
|
menuBar.add( Box.createGlue() );
|
||||||
menuBar.add( new JProgressBar() );
|
menuBar.add( new JProgressBar() );
|
||||||
@@ -216,6 +267,20 @@ public class FlatWindowDecorationsTest
|
|||||||
menuBar.repaint();
|
menuBar.repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void tallCompChanged() {
|
||||||
|
removeNonMenusFromMenuBar();
|
||||||
|
|
||||||
|
if( tallCompCheckBox.isSelected() ) {
|
||||||
|
rightCompCheckBox.setSelected( false );
|
||||||
|
rightStretchCompCheckBox.setSelected( false );
|
||||||
|
|
||||||
|
menuBar.add( new JButton( "<html>large<br>button<br>large<br>button</html>" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
menuBar.revalidate();
|
||||||
|
menuBar.repaint();
|
||||||
|
}
|
||||||
|
|
||||||
private void removeNonMenusFromMenuBar() {
|
private void removeNonMenusFromMenuBar() {
|
||||||
Component[] components = menuBar.getComponents();
|
Component[] components = menuBar.getComponents();
|
||||||
for( int i = components.length - 1; i >= 0; i-- ) {
|
for( int i = components.length - 1; i >= 0; i-- ) {
|
||||||
@@ -546,6 +611,16 @@ debug*/
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void titleBarHeightChanged() {
|
||||||
|
JRootPane rootPane = getWindowRootPane();
|
||||||
|
if( rootPane != null ) {
|
||||||
|
boolean enabled = titleBarHeightCheckBox.isSelected();
|
||||||
|
titleBarHeightField.setEnabled( enabled );
|
||||||
|
|
||||||
|
rootPane.putClientProperty( FlatClientProperties.TITLE_BAR_HEIGHT, enabled ? titleBarHeightField.getValue() : null );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private JRootPane getWindowRootPane() {
|
private JRootPane getWindowRootPane() {
|
||||||
Window window = SwingUtilities.windowForComponent( this );
|
Window window = SwingUtilities.windowForComponent( this );
|
||||||
return (window instanceof RootPaneContainer)
|
return (window instanceof RootPaneContainer)
|
||||||
@@ -572,12 +647,14 @@ debug*/
|
|||||||
maximizedBoundsCheckBox = new JCheckBox();
|
maximizedBoundsCheckBox = new JCheckBox();
|
||||||
JPanel panel4 = new JPanel();
|
JPanel panel4 = new JPanel();
|
||||||
showIconCheckBox = new FlatTriStateCheckBox();
|
showIconCheckBox = new FlatTriStateCheckBox();
|
||||||
|
titleBarHeightCheckBox = new JCheckBox();
|
||||||
showTitleCheckBox = new JCheckBox();
|
showTitleCheckBox = new JCheckBox();
|
||||||
|
titleBarHeightField = new JSpinner();
|
||||||
showIconifyCheckBox = new JCheckBox();
|
showIconifyCheckBox = new JCheckBox();
|
||||||
showMaximizeCheckBox = new JCheckBox();
|
showMaximizeCheckBox = new JCheckBox();
|
||||||
showCloseCheckBox = new JCheckBox();
|
showCloseCheckBox = new JCheckBox();
|
||||||
fullWindowContentCheckBox = new JCheckBox();
|
fullWindowContentCheckBox = new JCheckBox();
|
||||||
JLabel fullWindowContentButtonsBoundsLabel = new JLabel();
|
fullWindowContentButtonsBoundsLabel = new JLabel();
|
||||||
fullWindowContentButtonsBoundsField = new JLabel();
|
fullWindowContentButtonsBoundsField = new JLabel();
|
||||||
JPanel panel6 = new JPanel();
|
JPanel panel6 = new JPanel();
|
||||||
menuBarCheckBox = new JCheckBox();
|
menuBarCheckBox = new JCheckBox();
|
||||||
@@ -585,6 +662,7 @@ debug*/
|
|||||||
menuBarVisibleCheckBox = new JCheckBox();
|
menuBarVisibleCheckBox = new JCheckBox();
|
||||||
rightCompCheckBox = new JCheckBox();
|
rightCompCheckBox = new JCheckBox();
|
||||||
rightStretchCompCheckBox = new JCheckBox();
|
rightStretchCompCheckBox = new JCheckBox();
|
||||||
|
tallCompCheckBox = new JCheckBox();
|
||||||
JPanel panel3 = new JPanel();
|
JPanel panel3 = new JPanel();
|
||||||
addMenuButton = new JButton();
|
addMenuButton = new JButton();
|
||||||
addGlueButton = new JButton();
|
addGlueButton = new JButton();
|
||||||
@@ -621,6 +699,9 @@ debug*/
|
|||||||
typeUtilityRadioButton = new JRadioButton();
|
typeUtilityRadioButton = new JRadioButton();
|
||||||
typeSmallRadioButton = new JRadioButton();
|
typeSmallRadioButton = new JRadioButton();
|
||||||
showRectanglesCheckBox = new JCheckBox();
|
showRectanglesCheckBox = new JCheckBox();
|
||||||
|
JPanel hSpacer1 = new JPanel(null);
|
||||||
|
JLabel frameStateLabel = new JLabel();
|
||||||
|
frameStateField = new JLabel();
|
||||||
menuBar = new JMenuBar();
|
menuBar = new JMenuBar();
|
||||||
JMenu fileMenu = new JMenu();
|
JMenu fileMenu = new JMenu();
|
||||||
JMenuItem newMenuItem = new JMenuItem();
|
JMenuItem newMenuItem = new JMenuItem();
|
||||||
@@ -660,7 +741,8 @@ debug*/
|
|||||||
"[fill]" +
|
"[fill]" +
|
||||||
"[fill]" +
|
"[fill]" +
|
||||||
"[]" +
|
"[]" +
|
||||||
"[]"));
|
"[]" +
|
||||||
|
"[40]"));
|
||||||
|
|
||||||
//======== panel7 ========
|
//======== panel7 ========
|
||||||
{
|
{
|
||||||
@@ -711,7 +793,8 @@ debug*/
|
|||||||
panel4.setLayout(new MigLayout(
|
panel4.setLayout(new MigLayout(
|
||||||
"ltr,hidemode 3,gap 0 0",
|
"ltr,hidemode 3,gap 0 0",
|
||||||
// columns
|
// columns
|
||||||
"[grow,left]",
|
"[grow,left]" +
|
||||||
|
"[fill]",
|
||||||
// rows
|
// rows
|
||||||
"[]" +
|
"[]" +
|
||||||
"[]" +
|
"[]" +
|
||||||
@@ -726,12 +809,23 @@ debug*/
|
|||||||
showIconCheckBox.addActionListener(e -> showIconChanged());
|
showIconCheckBox.addActionListener(e -> showIconChanged());
|
||||||
panel4.add(showIconCheckBox, "cell 0 0");
|
panel4.add(showIconCheckBox, "cell 0 0");
|
||||||
|
|
||||||
|
//---- titleBarHeightCheckBox ----
|
||||||
|
titleBarHeightCheckBox.setText("Height:");
|
||||||
|
titleBarHeightCheckBox.addActionListener(e -> titleBarHeightChanged());
|
||||||
|
panel4.add(titleBarHeightCheckBox, "cell 1 0");
|
||||||
|
|
||||||
//---- showTitleCheckBox ----
|
//---- showTitleCheckBox ----
|
||||||
showTitleCheckBox.setText("show title");
|
showTitleCheckBox.setText("show title");
|
||||||
showTitleCheckBox.setSelected(true);
|
showTitleCheckBox.setSelected(true);
|
||||||
showTitleCheckBox.addActionListener(e -> showTitleChanged());
|
showTitleCheckBox.addActionListener(e -> showTitleChanged());
|
||||||
panel4.add(showTitleCheckBox, "cell 0 1");
|
panel4.add(showTitleCheckBox, "cell 0 1");
|
||||||
|
|
||||||
|
//---- titleBarHeightField ----
|
||||||
|
titleBarHeightField.setEnabled(false);
|
||||||
|
titleBarHeightField.setModel(new SpinnerNumberModel(44, null, null, 2));
|
||||||
|
titleBarHeightField.addChangeListener(e -> titleBarHeightChanged());
|
||||||
|
panel4.add(titleBarHeightField, "cell 1 1");
|
||||||
|
|
||||||
//---- showIconifyCheckBox ----
|
//---- showIconifyCheckBox ----
|
||||||
showIconifyCheckBox.setText("show iconfiy");
|
showIconifyCheckBox.setText("show iconfiy");
|
||||||
showIconifyCheckBox.setSelected(true);
|
showIconifyCheckBox.setSelected(true);
|
||||||
@@ -757,10 +851,12 @@ debug*/
|
|||||||
|
|
||||||
//---- fullWindowContentButtonsBoundsLabel ----
|
//---- fullWindowContentButtonsBoundsLabel ----
|
||||||
fullWindowContentButtonsBoundsLabel.setText("Buttons bounds:");
|
fullWindowContentButtonsBoundsLabel.setText("Buttons bounds:");
|
||||||
|
fullWindowContentButtonsBoundsLabel.setEnabled(false);
|
||||||
panel4.add(fullWindowContentButtonsBoundsLabel, "cell 0 6");
|
panel4.add(fullWindowContentButtonsBoundsLabel, "cell 0 6");
|
||||||
|
|
||||||
//---- fullWindowContentButtonsBoundsField ----
|
//---- fullWindowContentButtonsBoundsField ----
|
||||||
fullWindowContentButtonsBoundsField.setText("null");
|
fullWindowContentButtonsBoundsField.setText("null");
|
||||||
|
fullWindowContentButtonsBoundsField.setEnabled(false);
|
||||||
panel4.add(fullWindowContentButtonsBoundsField, "cell 0 6");
|
panel4.add(fullWindowContentButtonsBoundsField, "cell 0 6");
|
||||||
}
|
}
|
||||||
add(panel4, "cell 1 0");
|
add(panel4, "cell 1 0");
|
||||||
@@ -777,6 +873,7 @@ debug*/
|
|||||||
"[]" +
|
"[]" +
|
||||||
"[]" +
|
"[]" +
|
||||||
"[]" +
|
"[]" +
|
||||||
|
"[]" +
|
||||||
"[]"));
|
"[]"));
|
||||||
|
|
||||||
//---- menuBarCheckBox ----
|
//---- menuBarCheckBox ----
|
||||||
@@ -806,6 +903,11 @@ debug*/
|
|||||||
rightStretchCompCheckBox.setText("right aligned stretching component");
|
rightStretchCompCheckBox.setText("right aligned stretching component");
|
||||||
rightStretchCompCheckBox.addActionListener(e -> rightStretchCompChanged());
|
rightStretchCompCheckBox.addActionListener(e -> rightStretchCompChanged());
|
||||||
panel6.add(rightStretchCompCheckBox, "cell 0 4");
|
panel6.add(rightStretchCompCheckBox, "cell 0 4");
|
||||||
|
|
||||||
|
//---- tallCompCheckBox ----
|
||||||
|
tallCompCheckBox.setText("tall component");
|
||||||
|
tallCompCheckBox.addActionListener(e -> tallCompChanged());
|
||||||
|
panel6.add(tallCompCheckBox, "cell 0 5");
|
||||||
}
|
}
|
||||||
add(panel6, "cell 2 0");
|
add(panel6, "cell 2 0");
|
||||||
|
|
||||||
@@ -1039,6 +1141,16 @@ debug*/
|
|||||||
showRectanglesCheckBox.setSelected(true);
|
showRectanglesCheckBox.setSelected(true);
|
||||||
showRectanglesCheckBox.addActionListener(e -> showRectangles());
|
showRectanglesCheckBox.addActionListener(e -> showRectangles());
|
||||||
add(showRectanglesCheckBox, "cell 0 3");
|
add(showRectanglesCheckBox, "cell 0 3");
|
||||||
|
add(hSpacer1, "cell 2 3 2 1");
|
||||||
|
|
||||||
|
//---- frameStateLabel ----
|
||||||
|
frameStateLabel.setText("Frame state:");
|
||||||
|
add(frameStateLabel, "cell 2 3 2 1,alignx right,growx 0");
|
||||||
|
|
||||||
|
//---- frameStateField ----
|
||||||
|
frameStateField.setText("n/a");
|
||||||
|
frameStateField.setFont(frameStateField.getFont().deriveFont(frameStateField.getFont().getStyle() | Font.BOLD));
|
||||||
|
add(frameStateField, "cell 2 3 2 1,alignx right,growx 0");
|
||||||
|
|
||||||
//======== menuBar ========
|
//======== menuBar ========
|
||||||
{
|
{
|
||||||
@@ -1243,17 +1355,21 @@ debug*/
|
|||||||
private JCheckBox fullScreenCheckBox;
|
private JCheckBox fullScreenCheckBox;
|
||||||
private JCheckBox maximizedBoundsCheckBox;
|
private JCheckBox maximizedBoundsCheckBox;
|
||||||
private FlatTriStateCheckBox showIconCheckBox;
|
private FlatTriStateCheckBox showIconCheckBox;
|
||||||
|
private JCheckBox titleBarHeightCheckBox;
|
||||||
private JCheckBox showTitleCheckBox;
|
private JCheckBox showTitleCheckBox;
|
||||||
|
private JSpinner titleBarHeightField;
|
||||||
private JCheckBox showIconifyCheckBox;
|
private JCheckBox showIconifyCheckBox;
|
||||||
private JCheckBox showMaximizeCheckBox;
|
private JCheckBox showMaximizeCheckBox;
|
||||||
private JCheckBox showCloseCheckBox;
|
private JCheckBox showCloseCheckBox;
|
||||||
private JCheckBox fullWindowContentCheckBox;
|
private JCheckBox fullWindowContentCheckBox;
|
||||||
|
private JLabel fullWindowContentButtonsBoundsLabel;
|
||||||
private JLabel fullWindowContentButtonsBoundsField;
|
private JLabel fullWindowContentButtonsBoundsField;
|
||||||
private JCheckBox menuBarCheckBox;
|
private JCheckBox menuBarCheckBox;
|
||||||
private JCheckBox menuBarEmbeddedCheckBox;
|
private JCheckBox menuBarEmbeddedCheckBox;
|
||||||
private JCheckBox menuBarVisibleCheckBox;
|
private JCheckBox menuBarVisibleCheckBox;
|
||||||
private JCheckBox rightCompCheckBox;
|
private JCheckBox rightCompCheckBox;
|
||||||
private JCheckBox rightStretchCompCheckBox;
|
private JCheckBox rightStretchCompCheckBox;
|
||||||
|
private JCheckBox tallCompCheckBox;
|
||||||
private JButton addMenuButton;
|
private JButton addMenuButton;
|
||||||
private JButton addGlueButton;
|
private JButton addGlueButton;
|
||||||
private JButton addCaptionButton;
|
private JButton addCaptionButton;
|
||||||
@@ -1284,6 +1400,7 @@ debug*/
|
|||||||
private JRadioButton typeUtilityRadioButton;
|
private JRadioButton typeUtilityRadioButton;
|
||||||
private JRadioButton typeSmallRadioButton;
|
private JRadioButton typeSmallRadioButton;
|
||||||
private JCheckBox showRectanglesCheckBox;
|
private JCheckBox showRectanglesCheckBox;
|
||||||
|
private JLabel frameStateField;
|
||||||
private JMenuBar menuBar;
|
private JMenuBar menuBar;
|
||||||
// JFormDesigner - End of variables declaration //GEN-END:variables
|
// JFormDesigner - End of variables declaration //GEN-END:variables
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
JFDML JFormDesigner: "8.2.1.0.348" Java: "21.0.1" encoding: "UTF-8"
|
JFDML JFormDesigner: "8.2.3.0.386" Java: "21" encoding: "UTF-8"
|
||||||
|
|
||||||
new FormModel {
|
new FormModel {
|
||||||
contentType: "form/swing"
|
contentType: "form/swing"
|
||||||
@@ -9,7 +9,7 @@ new FormModel {
|
|||||||
add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||||
"$layoutConstraints": "ltr,insets dialog,hidemode 3"
|
"$layoutConstraints": "ltr,insets dialog,hidemode 3"
|
||||||
"$columnConstraints": "[left][fill][fill][fill]"
|
"$columnConstraints": "[left][fill][fill][fill]"
|
||||||
"$rowConstraints": "[fill][fill][][]"
|
"$rowConstraints": "[fill][fill][][][40]"
|
||||||
} ) {
|
} ) {
|
||||||
name: "this"
|
name: "this"
|
||||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||||
@@ -76,7 +76,7 @@ new FormModel {
|
|||||||
} )
|
} )
|
||||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||||
"$layoutConstraints": "ltr,hidemode 3,gap 0 0"
|
"$layoutConstraints": "ltr,hidemode 3,gap 0 0"
|
||||||
"$columnConstraints": "[grow,left]"
|
"$columnConstraints": "[grow,left][fill]"
|
||||||
"$rowConstraints": "[][][][][]rel[]rel[]"
|
"$rowConstraints": "[][][][][]rel[]rel[]"
|
||||||
} ) {
|
} ) {
|
||||||
name: "panel4"
|
name: "panel4"
|
||||||
@@ -91,6 +91,16 @@ new FormModel {
|
|||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
"value": "cell 0 0"
|
"value": "cell 0 0"
|
||||||
} )
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||||
|
name: "titleBarHeightCheckBox"
|
||||||
|
"text": "Height:"
|
||||||
|
auxiliary() {
|
||||||
|
"JavaCodeGenerator.variableLocal": false
|
||||||
|
}
|
||||||
|
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "titleBarHeightChanged", false ) )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 1 0"
|
||||||
|
} )
|
||||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||||
name: "showTitleCheckBox"
|
name: "showTitleCheckBox"
|
||||||
"text": "show title"
|
"text": "show title"
|
||||||
@@ -102,6 +112,20 @@ new FormModel {
|
|||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
"value": "cell 0 1"
|
"value": "cell 0 1"
|
||||||
} )
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JSpinner" ) {
|
||||||
|
name: "titleBarHeightField"
|
||||||
|
"enabled": false
|
||||||
|
"model": new javax.swing.SpinnerNumberModel {
|
||||||
|
stepSize: 2
|
||||||
|
value: 44
|
||||||
|
}
|
||||||
|
auxiliary() {
|
||||||
|
"JavaCodeGenerator.variableLocal": false
|
||||||
|
}
|
||||||
|
addEvent( new FormEvent( "javax.swing.event.ChangeListener", "stateChanged", "titleBarHeightChanged", false ) )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 1 1"
|
||||||
|
} )
|
||||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||||
name: "showIconifyCheckBox"
|
name: "showIconifyCheckBox"
|
||||||
"text": "show iconfiy"
|
"text": "show iconfiy"
|
||||||
@@ -148,12 +172,17 @@ new FormModel {
|
|||||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||||
name: "fullWindowContentButtonsBoundsLabel"
|
name: "fullWindowContentButtonsBoundsLabel"
|
||||||
"text": "Buttons bounds:"
|
"text": "Buttons bounds:"
|
||||||
|
"enabled": false
|
||||||
|
auxiliary() {
|
||||||
|
"JavaCodeGenerator.variableLocal": false
|
||||||
|
}
|
||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
"value": "cell 0 6"
|
"value": "cell 0 6"
|
||||||
} )
|
} )
|
||||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||||
name: "fullWindowContentButtonsBoundsField"
|
name: "fullWindowContentButtonsBoundsField"
|
||||||
"text": "null"
|
"text": "null"
|
||||||
|
"enabled": false
|
||||||
auxiliary() {
|
auxiliary() {
|
||||||
"JavaCodeGenerator.variableLocal": false
|
"JavaCodeGenerator.variableLocal": false
|
||||||
}
|
}
|
||||||
@@ -166,7 +195,7 @@ new FormModel {
|
|||||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||||
"$layoutConstraints": "ltr,hidemode 3,gap 0 0"
|
"$layoutConstraints": "ltr,hidemode 3,gap 0 0"
|
||||||
"$columnConstraints": "[left]"
|
"$columnConstraints": "[left]"
|
||||||
"$rowConstraints": "[][][][][]"
|
"$rowConstraints": "[][][][][][]"
|
||||||
} ) {
|
} ) {
|
||||||
name: "panel6"
|
name: "panel6"
|
||||||
"border": new javax.swing.border.TitledBorder( "Menu Bar" )
|
"border": new javax.swing.border.TitledBorder( "Menu Bar" )
|
||||||
@@ -223,6 +252,16 @@ new FormModel {
|
|||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
"value": "cell 0 4"
|
"value": "cell 0 4"
|
||||||
} )
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||||
|
name: "tallCompCheckBox"
|
||||||
|
"text": "tall component"
|
||||||
|
auxiliary() {
|
||||||
|
"JavaCodeGenerator.variableLocal": false
|
||||||
|
}
|
||||||
|
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "tallCompChanged", false ) )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 5"
|
||||||
|
} )
|
||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
"value": "cell 2 0"
|
"value": "cell 2 0"
|
||||||
} )
|
} )
|
||||||
@@ -598,9 +637,30 @@ new FormModel {
|
|||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
"value": "cell 0 3"
|
"value": "cell 0 3"
|
||||||
} )
|
} )
|
||||||
|
add( new FormComponent( "com.jformdesigner.designer.wrapper.HSpacer" ) {
|
||||||
|
name: "hSpacer1"
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 2 3 2 1"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||||
|
name: "frameStateLabel"
|
||||||
|
"text": "Frame state:"
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 2 3 2 1,alignx right,growx 0"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||||
|
name: "frameStateField"
|
||||||
|
"text": "n/a"
|
||||||
|
"font": new com.jformdesigner.model.SwingDerivedFont( null, 1, 0, false )
|
||||||
|
auxiliary() {
|
||||||
|
"JavaCodeGenerator.variableLocal": false
|
||||||
|
}
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 2 3 2 1,alignx right,growx 0"
|
||||||
|
} )
|
||||||
}, new FormLayoutConstraints( null ) {
|
}, new FormLayoutConstraints( null ) {
|
||||||
"location": new java.awt.Point( 0, 0 )
|
"location": new java.awt.Point( 0, 0 )
|
||||||
"size": new java.awt.Dimension( 960, 495 )
|
"size": new java.awt.Dimension( 960, 570 )
|
||||||
} )
|
} )
|
||||||
add( new FormContainer( "javax.swing.JMenuBar", new FormLayoutManager( class javax.swing.JMenuBar ) ) {
|
add( new FormContainer( "javax.swing.JMenuBar", new FormLayoutManager( class javax.swing.JMenuBar ) ) {
|
||||||
name: "menuBar"
|
name: "menuBar"
|
||||||
@@ -766,23 +826,23 @@ new FormModel {
|
|||||||
} )
|
} )
|
||||||
} )
|
} )
|
||||||
}, new FormLayoutConstraints( null ) {
|
}, new FormLayoutConstraints( null ) {
|
||||||
"location": new java.awt.Point( 0, 515 )
|
"location": new java.awt.Point( 0, 585 )
|
||||||
"size": new java.awt.Dimension( 255, 30 )
|
"size": new java.awt.Dimension( 255, 30 )
|
||||||
} )
|
} )
|
||||||
add( new FormNonVisual( "javax.swing.ButtonGroup" ) {
|
add( new FormNonVisual( "javax.swing.ButtonGroup" ) {
|
||||||
name: "styleButtonGroup"
|
name: "styleButtonGroup"
|
||||||
}, new FormLayoutConstraints( null ) {
|
}, new FormLayoutConstraints( null ) {
|
||||||
"location": new java.awt.Point( 0, 565 )
|
"location": new java.awt.Point( 0, 635 )
|
||||||
} )
|
} )
|
||||||
add( new FormNonVisual( "javax.swing.ButtonGroup" ) {
|
add( new FormNonVisual( "javax.swing.ButtonGroup" ) {
|
||||||
name: "iconButtonGroup"
|
name: "iconButtonGroup"
|
||||||
}, new FormLayoutConstraints( null ) {
|
}, new FormLayoutConstraints( null ) {
|
||||||
"location": new java.awt.Point( 0, 615 )
|
"location": new java.awt.Point( 0, 685 )
|
||||||
} )
|
} )
|
||||||
add( new FormNonVisual( "javax.swing.ButtonGroup" ) {
|
add( new FormNonVisual( "javax.swing.ButtonGroup" ) {
|
||||||
name: "typeButtonGroup"
|
name: "typeButtonGroup"
|
||||||
}, new FormLayoutConstraints( null ) {
|
}, new FormLayoutConstraints( null ) {
|
||||||
"location": new java.awt.Point( 0, 669 )
|
"location": new java.awt.Point( 0, 740 )
|
||||||
} )
|
} )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,9 +23,11 @@ import java.awt.Color;
|
|||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.GraphicsConfiguration;
|
||||||
import java.awt.Insets;
|
import java.awt.Insets;
|
||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
import java.awt.Robot;
|
import java.awt.Robot;
|
||||||
|
import java.awt.Toolkit;
|
||||||
import java.awt.Window;
|
import java.awt.Window;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.EventQueue;
|
import java.awt.EventQueue;
|
||||||
@@ -97,16 +99,18 @@ class FlatColorPipette
|
|||||||
// macOS: windows with opacity smaller than 0.05 does not receive
|
// macOS: windows with opacity smaller than 0.05 does not receive
|
||||||
// mouse clicked/pressed/released events (but mouse moved events)
|
// mouse clicked/pressed/released events (but mouse moved events)
|
||||||
setOpacity( SystemInfo.isMacOS ? 0.05f : 0.005f );
|
setOpacity( SystemInfo.isMacOS ? 0.05f : 0.005f );
|
||||||
setBounds( owner.getGraphicsConfiguration().getBounds() );
|
GraphicsConfiguration gc = owner.getGraphicsConfiguration();
|
||||||
|
setBounds( (gc != null) ? gc.getBounds() : new Rectangle( Toolkit.getDefaultToolkit().getScreenSize() ) );
|
||||||
|
|
||||||
robot = new Robot( owner.getGraphicsConfiguration().getDevice() );
|
robot = (gc != null) ? new Robot( gc.getDevice() ) : new Robot();
|
||||||
magnifier = new Magnifier( this, robot );
|
magnifier = new Magnifier( this, robot );
|
||||||
|
|
||||||
MouseAdapter mouseListener = new MouseAdapter() {
|
MouseAdapter mouseListener = new MouseAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void mouseMoved( MouseEvent e ) {
|
public void mouseMoved( MouseEvent e ) {
|
||||||
lastX = e.getX();
|
// adding location of pick window is necessary for secondary screens
|
||||||
lastY = e.getY();
|
lastX = e.getX() + getX();
|
||||||
|
lastY = e.getY() + getY();
|
||||||
|
|
||||||
// get color at mouse location
|
// get color at mouse location
|
||||||
// (temporary change opacity to zero to get correct color from robot)
|
// (temporary change opacity to zero to get correct color from robot)
|
||||||
@@ -133,7 +137,7 @@ class FlatColorPipette
|
|||||||
// --> use last hover color on macOS
|
// --> use last hover color on macOS
|
||||||
color = SystemInfo.isMacOS
|
color = SystemInfo.isMacOS
|
||||||
? lastHoverColor
|
? lastHoverColor
|
||||||
: robot.getPixelColor( e.getX(), e.getY() );
|
: robot.getPixelColor( e.getX() + getX(), e.getY() + getY() );
|
||||||
}
|
}
|
||||||
pick( color );
|
pick( color );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -241,7 +241,7 @@ class FlatThemePropertiesSupport
|
|||||||
}
|
}
|
||||||
|
|
||||||
static boolean isDark( String baseTheme ) {
|
static boolean isDark( String baseTheme ) {
|
||||||
return "dark".equals( baseTheme ) || "darcula".equals( baseTheme );
|
return "dark".equals( baseTheme ) || "darcula".equals( baseTheme ) || "macdark".equals( baseTheme );
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getBaseTheme() {
|
private String getBaseTheme() {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
|
|
||||||
flatlaf.releaseVersion = 3.5
|
flatlaf.releaseVersion = 3.5.3
|
||||||
flatlaf.developmentVersion = 3.6-SNAPSHOT
|
flatlaf.developmentVersion = 3.6-SNAPSHOT
|
||||||
|
|
||||||
org.gradle.parallel = true
|
org.gradle.parallel = true
|
||||||
|
|||||||
@@ -46,8 +46,8 @@ glazedlists = "com.glazedlists:glazedlists:1.11.0"
|
|||||||
netbeans-api-awt = "org.netbeans.api:org-openide-awt:RELEASE112"
|
netbeans-api-awt = "org.netbeans.api:org-openide-awt:RELEASE112"
|
||||||
|
|
||||||
# flatlaf-natives-jna
|
# flatlaf-natives-jna
|
||||||
jna = "net.java.dev.jna:jna:5.12.1"
|
jna = "net.java.dev.jna:jna:5.15.0"
|
||||||
jna-platform = "net.java.dev.jna:jna-platform:5.12.1"
|
jna-platform = "net.java.dev.jna:jna-platform:5.15.0"
|
||||||
|
|
||||||
# junit
|
# junit
|
||||||
junit = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit" }
|
junit = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit" }
|
||||||
|
|||||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|||||||
7
gradlew
vendored
7
gradlew
vendored
@@ -15,6 +15,8 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
#
|
#
|
||||||
@@ -55,7 +57,7 @@
|
|||||||
# Darwin, MinGW, and NonStop.
|
# Darwin, MinGW, and NonStop.
|
||||||
#
|
#
|
||||||
# (3) This script is generated from the Groovy template
|
# (3) This script is generated from the Groovy template
|
||||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
# within the Gradle project.
|
# within the Gradle project.
|
||||||
#
|
#
|
||||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
@@ -84,7 +86,8 @@ done
|
|||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
APP_BASE_NAME=${0##*/}
|
APP_BASE_NAME=${0##*/}
|
||||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
||||||
|
' "$PWD" ) || exit
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD=maximum
|
MAX_FD=maximum
|
||||||
|
|||||||
2
gradlew.bat
vendored
2
gradlew.bat
vendored
@@ -13,6 +13,8 @@
|
|||||||
@rem See the License for the specific language governing permissions and
|
@rem See the License for the specific language governing permissions and
|
||||||
@rem limitations under the License.
|
@rem limitations under the License.
|
||||||
@rem
|
@rem
|
||||||
|
@rem SPDX-License-Identifier: Apache-2.0
|
||||||
|
@rem
|
||||||
|
|
||||||
@if "%DEBUG%"=="" @echo off
|
@if "%DEBUG%"=="" @echo off
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
|
|||||||
Binary file not shown.
BIN
images/none-sponsors.png
Normal file
BIN
images/none-sponsors.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.7 KiB |
Reference in New Issue
Block a user