Compare commits

..

80 Commits

Author SHA1 Message Date
Karl Tauber
78a8035b92 Linux: rounded borders for popups (issue #949) 2025-01-27 17:15:38 +01:00
Karl Tauber
c32c00a5eb Linux with FlatLaf window decorations:
- moved window resizer components from layered pane to rootpane so that border is included in area where user can resize window
- scale border thickness
2025-01-26 17:48:19 +01:00
Karl Tauber
3a8a55a545 Linux with FlatLaf window decorations: right and bottom window resize drag areas were 2px smaller than at left and top sides 2025-01-26 17:23:59 +01:00
Karl Tauber
6c49b8bc4d Linux: hide popups when window is moved, resized, maximized, restored, iconified or switched to another window (issue #962) 2025-01-25 09:48:52 +01:00
Karl Tauber
cca9707f6b Popup: on Windows 10, update drop shadow of heavy-weight popup if popup moved/resized (issue #942) 2025-01-25 07:45:57 +01:00
Karl Tauber
f30dd876e4 Linux: updated libflatlaf-linux-arm64.so for Linux on ARM64; now built on ARM64 Linux (ubuntu-24.04-arm); previous was cross-compiled on X86_64 Linux (issue #899)
built by GitHub Actions: https://github.com/JFormDesigner/FlatLaf/actions/runs/12932258675
2025-01-23 16:38:16 +01:00
Karl Tauber
c6872d48b3 GitHub Actions:
- build Linux ARM64 native library on ubuntu-24.04-arm
- build on various Java versions only if build on Java 11 succeeded
- build Java version matrix only on main repo
2025-01-23 16:15:22 +01:00
Karl Tauber
5e78b21df7 macOS native rounded borders: (PR #772)
- removed opacity from contentView.layer
- catch and log exceptions
2025-01-21 11:59:40 +01:00
Karl Tauber
2ef87dc789 macOS: re-enabled rounded popup border (see PR #772) on macOS 14.4+ (was disabled in 3.5.x)
deferred rounded border setup, if popup window is not yet created, could make a difference (see commit 656d25b75e)
2025-01-20 19:42:55 +01:00
Karl Tauber
28904c34cc Linux: added libflatlaf-linux-arm64.so for Linux on ARM64 (issue #899)
built by GitHub Actions: https://github.com/JFormDesigner/FlatLaf/actions/runs/12845430366
2025-01-18 17:09:32 +01:00
Karl Tauber
91f19bf94c Native Libraries:
- Linux: added dumps
- macOS: replaced deprecated Gradle `exec`
2025-01-18 16:53:30 +01:00
Karl Tauber
0ea188f8db Linux: support cross-compile native library for ARM64 on x86_64 Linux (issue #899) 2025-01-18 14:50:42 +01:00
Karl Tauber
6c77b81277 Linux: support building native library for ARM64 when Gradle build runs on ARM64 Linux (issue #899) 2025-01-16 20:10:57 +01:00
Karl Tauber
ddee4ef526 GitHub Actions: natives.yml: install libxt-dev to fix build error on ubuntu 24.04 (did work without this on ubuntu 22.04) 2025-01-09 15:57:46 +01:00
Karl Tauber
f11f68282b update to Gradle 8.12 2025-01-09 15:39:27 +01:00
Karl Tauber
ac0cceb09b added Exocharts as Gold sponsor 2025-01-09 15:19:47 +01:00
Karl Tauber
a238fd4505 Button: fixed background and foreground colors for borderless and toolBarButton style default buttons (JButton.isDefaultButton() is true) (issue #947) 2025-01-09 14:38:36 +01:00
Karl Tauber
8dc6242889 FlatLaf window decorations: minimize and maximize icons were not shown for custom scale factors less than 100% (e.g. `-Dflatlaf.uiScale=75%) (issue #951) 2025-01-09 14:19:44 +01:00
Karl Tauber
d17fffb82a PopupFactory: fixed NPE on Windows 10 when owner is null (issue #952) 2025-01-09 12:26:57 +01:00
Karl Tauber
0ad3180b10 FileChooser: improved performance when navigating to large directories with thousands of files (issue #953) 2025-01-09 12:04:25 +01:00
Karl Tauber
80ba75fdeb List:
- fixed wrong x/width bounds of alternating rows for multi-column lists (PR #939)
- Demo: added "alternating rows" checkboxes to "Data Components" page
2024-12-18 12:22:04 +01:00
Karl Tauber
7027821c00 Merge PR #939: Support for alternate row color in JList 2024-12-18 00:30:01 +01:00
Karl Tauber
a3a49cef73 Merge PR #936: CheckBox: support styling indeterminate state of tri-state check boxes 2024-12-17 23:46:12 +01:00
Dar
abf77d5399 mod: code format 2024-12-16 15:55:40 +01:00
Dar
6404b8de2a fix: filter combobox by name 2024-12-16 15:49:19 +01:00
Dar
19055d5a18 mod: combobox does not support alternate row color 2024-12-13 09:21:14 +01:00
Dar
c12adf12e7 new: support for alternate row color in JList 2024-12-13 09:20:23 +01:00
Karl Tauber
b9c68fbe77 CheckBox: support styling indeterminate state of tri-state check boxes (issue #919) 2024-12-11 16:54:03 +01:00
Karl Tauber
7bdfd49921 Merge PR #935: Tree: support wide cell renderer 2024-12-11 13:33:03 +01:00
Karl Tauber
58fa2a5085 Demo, Testing, Theme Editor: re-generated UI code using JFormDesigner 8.3, which now supports class FlatClientProperties 2024-12-10 19:49:46 +01:00
Karl Tauber
a400799db5 Extras: use default activation keys if passing null to FlatInspector.install() or to FlatUIDefaultsInspector.install() 2024-12-09 23:55:02 +01:00
Karl Tauber
2a8e487c1f Tree: support wide cell renderer (issue #922) 2024-12-09 19:50:00 +01:00
Karl Tauber
145631fd43 FlatComponentsTest: added "transparent background" checkbox 2024-12-09 17:10:33 +01:00
Karl Tauber
6a774d8c70 GitHub Actions: use lftp directly to upload FlatLaf demo and theme editor
previously used github action `sebastianpopp/ftp-action`, which uses Docker, was very slow (about two minutes to upload one file)
2024-12-09 13:44:54 +01:00
Karl Tauber
bfd746f981 GitHub Actions: no longer upload theme editor snapshot; update gradle wrapper validation action 2024-12-09 01:23:55 +01:00
Karl Tauber
3af54b7215 Merge branch 'flatlaf-3.5.4' into main 2024-12-09 01:12:27 +01:00
Karl Tauber
3ba9fc6c1c release 3.5.4 2024-12-09 00:44:57 +01:00
Karl Tauber
0a9ecd66a9 Linux: fixed NPE when using FlatLaf window decorations and switching theme (issue #933; regression in 3.5.3)
caused by fix for #907; commit d471f08b15
2024-12-09 00:43:44 +01:00
Karl Tauber
6991d6729e Merge PR #931: Fixing NPE when using HTML text on a component with null font
(cherry picked from commit 41332de275)
2024-12-08 23:01:00 +01:00
Karl Tauber
304cb0d57b Merge PR #903: Support for alternate row color in JTree 2024-12-08 13:44:58 +01:00
Karl Tauber
41332de275 Merge PR #931: Fixing NPE when using HTML text on a component with null font 2024-12-08 13:37:02 +01:00
Karl Tauber
ef61ae504b FlatSVGIcon: color filters now can access painting component to implement component state based color mappings (PR #906) 2024-12-07 19:52:23 +01:00
Eduwardo Horibe
f96baf1bc2 Fixing NPE when using HTML text on a component with null font 2024-12-06 18:52:14 -03:00
Karl Tauber
1462636e97 release 3.5.3 2024-12-06 12:42:15 +01:00
Karl Tauber
7e59a7f4af FlatPropertiesLaf: support macOS themes as base themes 2024-12-04 23:56:01 +01:00
Karl Tauber
e9a21848bc ComboBox: do not paint arrow button background if it is hidden (issue #915) 2024-12-04 19:24:10 +01:00
Karl Tauber
1dcb251ecb FlatLaf window decorations: fixed sometimes broken window moving with SplitPane in window title area in "full window content" mode (issue #926) 2024-12-04 18:21:06 +01:00
Karl Tauber
3f33543cee 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)
the removed use of floating point font size is similar to what is done in JDK for GTK Look and Feel:
- https://bugs.openjdk.org/browse/JDK-6979979
- 306f12db9e
2024-12-04 17:18:33 +01:00
Karl Tauber
84bd2088f2 FlatSystemProperties: javadoc fixes 2024-12-04 13:06:37 +01:00
Karl Tauber
4f4a3132c5 UIScale:
- do not use "defaultFont" if current Laf is not FlatLaf
- support custom font size divider to calculate user scale factor from font size

(for special use in JFormDesigner)
2024-12-04 13:06:11 +01:00
Karl Tauber
e064c934cb Windows: fixed detection of Windows 11 if custom exe launcher does not specify Windows 10+ compatibility in application manifest (issue #916)
Windows binaries built and signed locally in clean workspace
2024-11-28 14:12:56 +01:00
Karl Tauber
16fc3cabf2 Popup: fixed NPE if GraphicsConfiguration is null on Windows (issue #921)
also check for null GraphicsConfiguration in other classes
2024-11-27 19:27:47 +01:00
Karl Tauber
7e002ff6c2 Theme Editor: fixed using color picker on secondary screen 2024-11-27 19:02:13 +01:00
Karl Tauber
323c0c62c3 update to Gradle 8.11.1 2024-11-20 20:11:34 +01:00
Karl Tauber
ff5bd301cc Popup: on Windows 10, fixed misplaced popup drop shadow (issue #911; regression in 3.5 since commit a311bac89b) 2024-11-19 23:25:50 +01:00
Karl Tauber
c37712b0f0 Windows: fixed wrong layout in maximized frame after changing screen scale factor (issue #904)
Windows binaries built and signed locally in clean workspace
2024-11-17 19:41:54 +01:00
Karl Tauber
ee9e238592 Windows: fixed possible deadlock with TabbedPane in window title area in "full window content" mode (issue #909) 2024-11-14 19:34:31 +01:00
Karl Tauber
da5d6fa157 update to Gradle 8.11 2024-11-14 18:39:37 +01:00
Karl Tauber
d471f08b15 Linux: fixed continuous cursor toggling between resize and standard cursor when resizing window with FlatLaf window decorations (issue #907) 2024-11-14 18:34:55 +01:00
Karl Tauber
b97424f767 HTML: fixed wrong rendering if HTML text contains <style> tag with attributes (e.g. <style type='text/css'>) (issue #905; regression in 3.5) 2024-11-10 13:28:02 +01:00
Dar
a20cfa6db3 mod: style tester 2024-10-23 15:36:17 +02:00
Dar
6ac6698ecf mod: added 3.6 tag 2024-10-23 15:32:16 +02:00
Dar
8004d2761a fix: respect the selection arc 2024-10-23 15:30:06 +02:00
Dar
25c2bbc851 fix: alternate row color paint 2024-10-22 18:05:14 +02:00
Dar
33e37a7167 new: support for alternate row color in jtree
see: https://github.com/JFormDesigner/FlatLaf/issues/900
2024-10-22 16:46:30 +02:00
Karl Tauber
c29a276188 release 3.5.2 2024-10-18 13:28:53 +02:00
Karl Tauber
d1694aa8bd FlatClientProperties and FlatSystemProperties: javadoc fixes 2024-10-18 13:28:07 +02:00
Karl Tauber
570cf6fc51 FlatLaf window decorations: added client property JRootPane.titleBarHeight to allow specifying a (larger) preferred height for the title bar (issue #897) 2024-10-17 19:58:58 +02:00
Karl Tauber
8eab86e489 FlatLaf window decorations: strech iconify/maximize/close buttons to always fill whole title bar height (issue #897) 2024-10-17 19:49:51 +02:00
Karl Tauber
566568f61a Windows: fixed repaint issues (ghosting) on some systems by setting sun.java2d.d3d.onscreen to false (issue #887) 2024-10-17 13:19:04 +02:00
Karl Tauber
56a73a4d17 Popup: added system property flatlaf.useRoundedPopupBorder to allow disabling native rounded popup borders (PRs #643 and #772) 2024-10-15 00:29:15 +02:00
Karl Tauber
656d25b75e Popup: setup rounded popup border after window was created (no longer create window ourself using addNotify()) to (hopefully) fix repaint issues on some Windows 11 systems after first showing a popup (issue #887, PR #643) 2024-10-12 23:25:59 +02:00
Karl Tauber
dcdc80ade3 Testing: FlatOptionPaneTest: test option pane with custom title bar icon (issue #886) 2024-10-12 00:28:19 +02:00
Karl Tauber
09f2d65d5e change snapshot version from 3.6-SNAPSHOT to 3.5.2-SNAPSHOT 2024-10-11 19:27:23 +02:00
Karl Tauber
b304d46f7e TextComponents: fixed too fast scrolling in multi-line text components when using touchpads (e.g. on macOS) (issue #892) 2024-10-11 19:18:00 +02:00
Karl Tauber
3391f971ec GitHub Actions: build using Java 23 2024-10-11 15:16:49 +02:00
Karl Tauber
778fed27a5 update to Gradle 8.10.2 2024-10-11 15:14:11 +02:00
Karl Tauber
1755dbc877 README.md updated 2024-10-11 15:11:56 +02:00
Karl Tauber
4e6f538519 ToolBar: fixed endless loop if button in Toolbar has focus and is made invisible (issue #884) 2024-09-29 19:26:37 +02:00
Karl Tauber
a6ecb0ef85 FlatLaf window decorations on 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) 2024-09-04 00:48:42 +02:00
116 changed files with 3164 additions and 747 deletions

View File

@@ -20,47 +20,29 @@ on:
jobs:
build:
name: build (11)
runs-on: ubuntu-latest
strategy:
matrix:
# test against
# - Java 8 (minimum requirement)
# - Java LTS versions (11, 17, ...)
# - latest Java version(s)
java:
- 8
- 11 # LTS
- 17 # LTS
- 21 # LTS
toolchain: [""]
include:
- java: 21
toolchain: 22 # latest
steps:
- uses: actions/checkout@v4
- uses: gradle/wrapper-validation-action@v2
if: matrix.java == '8'
- uses: gradle/actions/wrapper-validation@v4
- name: Setup Java ${{ matrix.java }}
- name: Setup Java 11
uses: actions/setup-java@v4
with:
java-version: ${{ matrix.java }}
distribution: temurin # Java 8, 11, 17 and 21 are pre-installed on ubuntu-latest
java-version: 11
distribution: temurin # pre-installed on ubuntu-latest
cache: gradle
- name: Check with Error Prone
if: matrix.java == '11'
run: ./gradlew errorprone clean -Dtoolchain=${{ matrix.toolchain }}
run: ./gradlew errorprone clean
- name: Build with Gradle
run: ./gradlew build -Dtoolchain=${{ matrix.toolchain }}
run: ./gradlew build
- name: Upload artifacts
uses: actions/upload-artifact@v4
if: matrix.java == '11'
with:
name: FlatLaf-build-artifacts
path: |
@@ -70,9 +52,44 @@ jobs:
!**/*-sources.jar
snapshot:
build-on:
runs-on: ubuntu-latest
needs: build
if: github.repository == 'JFormDesigner/FlatLaf'
strategy:
matrix:
# test against
# - Java 8 (minimum requirement)
# - Java LTS versions (11, 17, ...)
# - latest Java version(s)
java:
- 8
- 17 # LTS
- 21 # LTS
- 23 # latest
toolchain: [""]
# include:
# - java: 21
# toolchain: 22 # latest
steps:
- uses: actions/checkout@v4
- name: Setup Java ${{ matrix.java }}
uses: actions/setup-java@v4
with:
java-version: ${{ matrix.java }}
distribution: temurin # Java 8, 11, 17 and 21 are pre-installed on ubuntu-latest
cache: gradle
- name: Build with Gradle
run: ./gradlew build -Dtoolchain=${{ matrix.toolchain }}
snapshot:
runs-on: ubuntu-latest
needs: build-on
if: |
github.event_name == 'push' &&
(github.ref == 'refs/heads/main' || startsWith( github.ref, 'refs/heads/develop-' )) &&
@@ -89,26 +106,15 @@ jobs:
cache: gradle
- name: Publish snapshot to oss.sonatype.org
run: ./gradlew publish :flatlaf-theme-editor:build -PskipFonts -Dorg.gradle.internal.publish.checksums.insecure=true -Dorg.gradle.parallel=false
run: ./gradlew publish -PskipFonts -Dorg.gradle.internal.publish.checksums.insecure=true -Dorg.gradle.parallel=false
env:
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
- name: Upload theme editor
uses: sebastianpopp/ftp-action@releases/v2
with:
host: ${{ secrets.FTP_SERVER }}
user: ${{ secrets.FTP_USERNAME }}
password: ${{ secrets.FTP_PASSWORD }}
forceSsl: true
localDir: "flatlaf-theme-editor/build/libs"
remoteDir: "snapshots"
options: "--only-newer --no-recursion --verbose=1"
release:
runs-on: ubuntu-latest
needs: build
needs: build-on
if: |
github.event_name == 'push' &&
startsWith( github.ref, 'refs/tags/' ) &&
@@ -132,24 +138,12 @@ jobs:
SIGNING_KEY: ${{ secrets.SIGNING_KEY }}
SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }}
- name: Upload demo
uses: sebastianpopp/ftp-action@releases/v2
with:
host: ${{ secrets.FTP_SERVER }}
user: ${{ secrets.FTP_USERNAME }}
password: ${{ secrets.FTP_PASSWORD }}
forceSsl: true
localDir: "flatlaf-demo/build/libs"
remoteDir: "."
options: "--only-newer --no-recursion --verbose=1"
- name: Install lftp
run: sudo apt-get -y install lftp
- name: Upload theme editor
uses: sebastianpopp/ftp-action@releases/v2
with:
host: ${{ secrets.FTP_SERVER }}
user: ${{ secrets.FTP_USERNAME }}
password: ${{ secrets.FTP_PASSWORD }}
forceSsl: true
localDir: "flatlaf-theme-editor/build/libs"
remoteDir: "."
options: "--only-newer --no-recursion --verbose=1"
- name: Upload demo and theme editor
run: >
lftp -c "set ftp:ssl-force true;
open -u ${{ secrets.FTP_USERNAME }},${{ secrets.FTP_PASSWORD }} ${{ secrets.FTP_SERVER }};
mput flatlaf-demo/build/libs/flatlaf-demo-*.jar;
mput flatlaf-theme-editor/build/libs/flatlaf-theme-editor-*.jar"

View File

@@ -21,16 +21,25 @@ jobs:
strategy:
matrix:
os:
- windows
- macos
- ubuntu
- windows-latest
- macos-latest
- ubuntu-latest
- ubuntu-24.04-arm
runs-on: ${{ matrix.os }}-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: gradle/wrapper-validation-action@v2
- uses: gradle/actions/wrapper-validation@v4
- name: install libxt-dev
if: matrix.os == 'ubuntu-latest' || matrix.os == 'ubuntu-24.04-arm'
run: sudo apt install libxt-dev
- name: install g++-aarch64-linux-gnu
if: matrix.os == 'ubuntu-latest'
run: sudo apt install g++-aarch64-linux-gnu
- name: Setup Java 11
uses: actions/setup-java@v4

View File

@@ -1,6 +1,112 @@
FlatLaf Change Log
==================
## 3.6-SNAPSHOT
#### New features and improvements
- macOS: Re-enabled rounded popup border (see PR #772) on macOS 14.4+ (was
disabled in 3.5.x).
- CheckBox: Support styling indeterminate state of
[tri-state check boxes](https://www.javadoc.io/doc/com.formdev/flatlaf-extras/latest/com/formdev/flatlaf/extras/components/FlatTriStateCheckBox.html).
(PR #936; issue #919)
- List: Support for alternate row highlighting. (PR #939)
- Tree: Support for alternate row highlighting. (PR #903)
- Tree: Support wide cell renderer. (issue #922)
- Extras: `FlatSVGIcon` color filters now can access painting component to
implement component state based color mappings. (issue #906)
- Linux: Added `libflatlaf-linux-arm64.so` for Linux on ARM64. (issue #899)
#### Fixed bugs
- Button: Fixed background and foreground colors for `borderless` and
`toolBarButton` style default buttons (`JButton.isDefaultButton()` is `true`).
(issue #947)
- FileChooser: Improved performance when navigating to large directories with
thousands of files. (issue #953)
- PopupFactory: Fixed NPE on Windows 10 when `owner` is `null`. (issue #952)
- Popup: On Windows 10, drop shadow of heavy-weight popup was not updated if
popup moved/resized. (issue #942)
- FlatLaf window decorations: Minimize and maximize icons were not shown for
custom scale factors less than 100% (e.g. `-Dflatlaf.uiScale=75%`). (issue
#951)
- Linux: Popups (menus and combobox lists) were not hidden when window is moved,
resized, maximized, restored, iconified or switched to another window. (issue
#962)
## 3.5.4
#### Fixed bugs
- HTML: Fixed NPE when using HTML text on a component with `null` font. (issue
#930; PR #931; regression in 3.5)
- Linux: Fixed NPE when using FlatLaf window decorations and switching theme.
(issue #933; regression in 3.5.3)
## 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

View File

@@ -33,14 +33,22 @@ FlatLaf can use 3rd party themes created for IntelliJ Platform (see
Sponsors
--------
### Current Sponsors
<a href="https://exocharts.com/"><img src="https://www.formdev.com/flatlaf/sponsor/Exocharts.png" width="200" alt="Exocharts" title="Exocharts - Professional Grade OrderFlow"></a>
<!-- [![None Sponsors](images/none-sponsors.png)](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>
&nbsp; &nbsp; &nbsp; &nbsp;
<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>
&nbsp; &nbsp; &nbsp; &nbsp;
<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
----

View File

@@ -156,5 +156,6 @@ flatlafPublish {
NativeArtifact( "${natives}/libflatlaf-macos-arm64.dylib", "macos-arm64", "dylib" ),
NativeArtifact( "${natives}/libflatlaf-macos-x86_64.dylib", "macos-x86_64", "dylib" ),
NativeArtifact( "${natives}/libflatlaf-linux-x86_64.so", "linux-x86_64", "so" ),
NativeArtifact( "${natives}/libflatlaf-linux-arm64.so", "linux-arm64", "so" ),
)
}

View File

@@ -1,5 +1,5 @@
#Signature file v4.1
#Version 3.5.1
#Version 3.5.2
CLSS public abstract interface com.formdev.flatlaf.FlatClientProperties
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 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_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_ICON = "JRootPane.titleBarShowIcon"
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.function.Function<java.lang.String,java.awt.Color> getSystemColorGetter()
meth public static javax.swing.UIDefaults$ActiveValue createActiveFontValue(float)
meth public static void disableWindowsD3Donscreen()
meth public static void hideMnemonics()
meth public static void initIconColors(javax.swing.UIDefaults,boolean)
meth public static void installLafInfo(java.lang.String,java.lang.Class<? extends javax.swing.LookAndFeel>)
@@ -296,6 +298,7 @@ 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"
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_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_UBUNTU_FONT = "flatlaf.useUbuntuFont"

View File

@@ -384,6 +384,7 @@ public interface FlatClientProperties
* If this value is {@code 1 - 4}, then {@code DWMWCP_ROUNDSMALL} is used.
* If it is {@code >= 5}, then {@code DWMWCP_ROUND} is used.
* <li><strong>macOS</strong> (10.14 and later): Any corner radius is supported.
* <li><strong>Linux</strong> (since FlatLaf 3.6): Any corner radius is supported.
* </ul>
* <strong>Component</strong> {@link javax.swing.JComponent}<br>
* <strong>Value type</strong> {@link java.lang.Integer}<br>
@@ -402,6 +403,7 @@ public interface FlatClientProperties
* Supported platforms:
* <ul>
* <li><strong>macOS</strong> (10.14 and later)
* <li><strong>Linux</strong> (since FlatLaf 3.6)
* </ul>
* <strong>Component</strong> {@link javax.swing.JComponent}<br>
* <strong>Value type</strong> {@link java.lang.Integer} or {@link java.lang.Float}<br>
@@ -461,7 +463,7 @@ public interface FlatClientProperties
* {@link FlatSystemProperties#USE_WINDOW_DECORATIONS}, but higher priority
* than UI default {@code TitlePane.useWindowDecorations}.
* <p>
* (requires Window 10)
* (requires Windows 10/11)
* <p>
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
@@ -481,7 +483,7 @@ public interface FlatClientProperties
* {@link FlatSystemProperties#MENUBAR_EMBEDDED}, but higher priority
* than UI default {@code TitlePane.menuBarEmbedded}.
* <p>
* (requires Window 10)
* (requires Windows 10/11)
* <p>
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
@@ -507,6 +509,8 @@ public interface FlatClientProperties
* 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).
* <p>
* (requires Windows 10/11)
* <p>
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
*
@@ -537,7 +541,7 @@ public interface FlatClientProperties
* <p>
* This client property has higher priority than UI default {@code TitlePane.showIcon}.
* <p>
* (requires Window 10)
* (requires Windows 10/11)
* <p>
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
@@ -553,6 +557,8 @@ public interface FlatClientProperties
* Setting this shows/hides the windows title
* for the {@code JFrame} or {@code JDialog} that contains the root pane.
* <p>
* (requires Windows 10/11)
* <p>
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
*
@@ -567,6 +573,8 @@ public interface FlatClientProperties
* Setting this shows/hides the "iconify" button
* for the {@code JFrame} that contains the root pane.
* <p>
* (requires Windows 10/11)
* <p>
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
*
@@ -581,6 +589,8 @@ public interface FlatClientProperties
* Setting this shows/hides the "maximize/restore" button
* for the {@code JFrame} that contains the root pane.
* <p>
* (requires Windows 10/11)
* <p>
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
*
@@ -595,6 +605,8 @@ public interface FlatClientProperties
* Setting this shows/hides the "close" button
* for the {@code JFrame} or {@code JDialog} that contains the root pane.
* <p>
* (requires Windows 10/11)
* <p>
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
*
@@ -605,7 +617,7 @@ public interface FlatClientProperties
/**
* Background color of window title bar (requires enabled window decorations).
* <p>
* (requires Window 10)
* (requires Windows 10/11)
* <p>
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
* <strong>Value type</strong> {@link java.awt.Color}
@@ -617,7 +629,7 @@ public interface FlatClientProperties
/**
* Foreground color of window title bar (requires enabled window decorations).
* <p>
* (requires Window 10)
* (requires Windows 10/11)
* <p>
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
* <strong>Value type</strong> {@link java.awt.Color}
@@ -626,10 +638,24 @@ public interface FlatClientProperties
*/
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,
* if FlatLaf window decorations are enabled. Default is {@code false}.
* <p>
* (requires Windows 10/11)
* <p>
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
*
@@ -1386,13 +1412,23 @@ public interface FlatClientProperties
//---- JTree --------------------------------------------------------------
/**
* Override if a tree shows a wide selection. Default is {@code true}.
* Specifies whether tree shows a wide selection. Default is {@code true}.
* <p>
* <strong>Component</strong> {@link javax.swing.JTree}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
*/
String TREE_WIDE_SELECTION = "JTree.wideSelection";
/**
* Specifies whether tree uses a wide cell renderer. Default is {@code false}.
* <p>
* <strong>Component</strong> {@link javax.swing.JTree}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
*
* @since 3.6
*/
String TREE_WIDE_CELL_RENDERER = "JTree.wideCellRenderer";
/**
* Specifies whether tree item selection is painted. Default is {@code true}.
* If set to {@code false}, then the tree cell renderer is responsible for painting selection.

View File

@@ -20,6 +20,7 @@ import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.Toolkit;
@@ -110,6 +111,7 @@ public abstract class FlatLaf
private PopupFactory oldPopupFactory;
private MnemonicHandler mnemonicHandler;
private boolean subMenuUsabilityHelperInstalled;
private LinuxPopupMenuCanceler linuxPopupMenuCanceler;
private Consumer<UIDefaults> postInitialization;
private List<Function<Object, Object>> uiDefaultsGetters;
@@ -119,6 +121,46 @@ public abstract class FlatLaf
private static String preferredSemiboldFontFamily;
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
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
@@ -264,6 +306,10 @@ public abstract class FlatLaf
// install submenu usability helper
subMenuUsabilityHelperInstalled = SubMenuUsabilityHelper.install();
// install Linux popup menu canceler
if( SystemInfo.isLinux )
linuxPopupMenuCanceler = new LinuxPopupMenuCanceler();
// listen to desktop property changes to update UI if system font or scaling changes
if( SystemInfo.isWindows ) {
// Windows 10 allows increasing font size independent of scaling:
@@ -356,6 +402,12 @@ public abstract class FlatLaf
subMenuUsabilityHelperInstalled = false;
}
// uninstall Linux popup menu canceler
if( linuxPopupMenuCanceler != null ) {
linuxPopupMenuCanceler.uninstall();
linuxPopupMenuCanceler = null;
}
// restore default link color
new HTMLEditorKit().getStyleSheet().addRule( "a, address { color: blue; }" );
postInitialization = null;

View File

@@ -23,13 +23,15 @@ import java.io.InputStream;
import java.util.ArrayList;
import java.util.Locale;
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.
* <p>
* Specify the base theme in the properties with {@code @baseTheme=<baseTheme>}.
* 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>
* The properties are applied after loading the base theme and may overwrite base properties.
* All features of FlatLaf properties files are available.
@@ -71,7 +73,8 @@ public class FlatPropertiesLaf
this.properties = properties;
baseTheme = properties.getProperty( "@baseTheme", "light" );
dark = "dark".equalsIgnoreCase( baseTheme ) || "darcula".equalsIgnoreCase( baseTheme );
dark = "dark".equalsIgnoreCase( baseTheme ) || "darcula".equalsIgnoreCase( baseTheme ) ||
"macdark".equalsIgnoreCase( baseTheme );
}
@Override
@@ -116,6 +119,16 @@ public class FlatPropertiesLaf
lafClasses.add( FlatDarkLaf.class );
lafClasses.add( FlatDarculaLaf.class );
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;
}

View File

@@ -82,7 +82,7 @@ public interface FlatSystemProperties
* {@link FlatClientProperties#USE_WINDOW_DECORATIONS} and
* UI default {@code TitlePane.useWindowDecorations}.
* <p>
* (requires Window 10/11)
* (requires Windows 10/11)
* <p>
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
* <strong>Default</strong> none
@@ -99,7 +99,7 @@ public interface FlatSystemProperties
* Setting this to {@code false} disables using JetBrains Runtime custom window decorations.
* Then FlatLaf native window decorations are used.
* <p>
* (requires Window 10/11)
* (requires Windows 10/11)
* <p>
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
* <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
* UI default {@code TitlePane.menuBarEmbedded}.
* <p>
* (requires Window 10/11)
* (requires Windows 10/11)
* <p>
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
* <strong>Default</strong> none
@@ -135,6 +135,18 @@ public interface FlatSystemProperties
*/
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 in FlatLaf 3.5.x on macOS 14.4+ where it was {@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.
* <p>
@@ -209,6 +221,7 @@ public interface FlatSystemProperties
* <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";

View File

@@ -111,7 +111,7 @@ class LinuxFontPolicy
if( logicalFamily != null )
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.
* 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(;;) {
Font font = createFont( family, style, size, dsize );
Font font = FlatLaf.createCompositeFont( family, style, size );
if( Font.DIALOG.equals( family ) )
return font;
@@ -135,7 +135,7 @@ class LinuxFontPolicy
// - character width is zero (e.g. font Cantarell; Fedora; Oracle Java 8)
FontMetrics fm = StyleContext.getDefaultStyleContext().getFontMetrics( font );
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;
}
@@ -143,7 +143,7 @@ class LinuxFontPolicy
// find last word in family
int index = family.lastIndexOf( ' ' );
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)
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() {
// do not scale font here if JRE scales
if( isSystemScaling() )
@@ -257,7 +248,7 @@ class LinuxFontPolicy
if( size < 1 )
size = 1;
return createFont( family, style, size, dsize );
return FlatLaf.createCompositeFont( family, style, size );
}
@SuppressWarnings( "MixedMutabilityReturnType" ) // Error Prone

View File

@@ -0,0 +1,164 @@
/*
* Copyright 2025 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;
import java.awt.Component;
import java.awt.Window;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JPopupMenu;
import javax.swing.MenuElement;
import javax.swing.MenuSelectionManager;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
/**
* Cancels (hides) popup menus on Linux.
* <p>
* On Linux, popups are not hidden under following conditions, which results in
* misplaced popups:
* <ul>
* <li>window moved or resized
* <li>window maximized or restored
* <li>window iconified
* <li>window deactivated (e.g. activated other application)
* </ul>
*
* On Windows and macOS, popups are automatically hidden.
* <p>
* The implementation is similar to what's done in
* {@code javax.swing.plaf.basic.BasicPopupMenuUI.MouseGrabber},
* but only hides popup in some conditions.
*
* @author Karl Tauber
*/
class LinuxPopupMenuCanceler
extends WindowAdapter
implements ChangeListener, ComponentListener
{
private MenuElement[] lastPathSelectedPath;
private Window window;
LinuxPopupMenuCanceler() {
MenuSelectionManager msm = MenuSelectionManager.defaultManager();
msm.addChangeListener( this );
lastPathSelectedPath = msm.getSelectedPath();
if( lastPathSelectedPath.length > 0 )
addWindowListeners( lastPathSelectedPath[0] );
}
void uninstall() {
MenuSelectionManager.defaultManager().removeChangeListener( this );
}
private void addWindowListeners( MenuElement selected ) {
// see BasicPopupMenuUI.MouseGrabber.grabWindow()
Component invoker = selected.getComponent();
if( invoker instanceof JPopupMenu )
invoker = ((JPopupMenu)invoker).getInvoker();
window = (invoker instanceof Window)
? (Window) invoker
: SwingUtilities.windowForComponent( invoker );
if( window != null ) {
window.addWindowListener( this );
window.addComponentListener( this );
}
}
private void removeWindowListeners() {
if( window != null ) {
window.removeWindowListener( this );
window.removeComponentListener( this );
window = null;
}
}
private void cancelPopupMenu() {
try {
MenuSelectionManager msm = MenuSelectionManager.defaultManager();
MenuElement[] selectedPath = msm.getSelectedPath();
for( MenuElement e : selectedPath ) {
if( e instanceof JPopupMenu )
((JPopupMenu)e).putClientProperty( "JPopupMenu.firePopupMenuCanceled", true );
}
msm.clearSelectedPath();
} catch( RuntimeException ex ) {
removeWindowListeners();
throw ex;
} catch( Error ex ) {
removeWindowListeners();
throw ex;
}
}
//---- ChangeListener ----
@Override
public void stateChanged( ChangeEvent e ) {
MenuElement[] selectedPath = MenuSelectionManager.defaultManager().getSelectedPath();
if( selectedPath.length == 0 )
removeWindowListeners();
else if( lastPathSelectedPath.length == 0 )
addWindowListeners( selectedPath[0] );
lastPathSelectedPath = selectedPath;
}
//---- WindowListener ----
@Override
public void windowIconified( WindowEvent e ) {
cancelPopupMenu();
}
@Override
public void windowDeactivated( WindowEvent e ) {
cancelPopupMenu();
}
@Override
public void windowClosing( WindowEvent e ) {
cancelPopupMenu();
}
//---- ComponentListener ----
@Override
public void componentResized( ComponentEvent e ) {
cancelPopupMenu();
}
@Override
public void componentMoved( ComponentEvent e ) {
cancelPopupMenu();
}
@Override
public void componentShown( ComponentEvent e ) {
}
@Override
public void componentHidden( ComponentEvent e ) {
cancelPopupMenu();
}
}

View File

@@ -57,6 +57,8 @@ public abstract class FlatAbstractIcon
// g2.setColor( Color.blue );
// g2.drawRect( x, y, getIconWidth() - 1, getIconHeight() - 1 );
paintBackground( c, g2, x, y );
g2.translate( x, y );
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
public int getIconWidth() {

View File

@@ -17,6 +17,7 @@
package com.formdev.flatlaf.icons;
import static com.formdev.flatlaf.FlatClientProperties.*;
import static com.formdev.flatlaf.ui.FlatUIUtils.stateColor;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
@@ -48,6 +49,8 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
* @uiDefault CheckBox.icon.borderWidth int or float optional; defaults to Component.borderWidth
* @uiDefault CheckBox.icon.selectedBorderWidth int or float optional; defaults to CheckBox.icon.borderWidth
* @uiDefault CheckBox.icon.disabledSelectedBorderWidth int or float optional; defaults to CheckBox.icon.selectedBorderWidth
* @uiDefault CheckBox.icon.indeterminateBorderWidth int or float optional; defaults to CheckBox.icon.selectedBorderWidth
* @uiDefault CheckBox.icon.disabledIndeterminateBorderWidth int or float optional; defaults to CheckBox.icon.disabledSelectedBorderWidth
* @uiDefault CheckBox.arc int
*
* @uiDefault CheckBox.icon.focusColor Color optional; defaults to Component.focusColor
@@ -56,30 +59,45 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
* @uiDefault CheckBox.icon.selectedBorderColor Color
* @uiDefault CheckBox.icon.selectedBackground Color
* @uiDefault CheckBox.icon.checkmarkColor Color
* @uiDefault CheckBox.icon.indeterminateBorderColor Color optional; defaults to CheckBox.icon.selectedBorderColor
* @uiDefault CheckBox.icon.indeterminateBackground Color optional; defaults to CheckBox.icon.selectedBackground
* @uiDefault CheckBox.icon.indeterminateCheckmarkColor Color optional; defaults to CheckBox.icon.checkmarkColor
*
* @uiDefault CheckBox.icon.disabledBorderColor Color
* @uiDefault CheckBox.icon.disabledBackground Color
* @uiDefault CheckBox.icon.disabledSelectedBorderColor Color optional; CheckBox.icon.disabledBorderColor is used if not specified
* @uiDefault CheckBox.icon.disabledSelectedBackground Color optional; CheckBox.icon.disabledBackground is used if not specified
* @uiDefault CheckBox.icon.disabledCheckmarkColor Color
* @uiDefault CheckBox.icon.disabledBorderColor Color
* @uiDefault CheckBox.icon.disabledBackground Color
* @uiDefault CheckBox.icon.disabledSelectedBorderColor Color optional; defaults to CheckBox.icon.disabledBorderColor
* @uiDefault CheckBox.icon.disabledSelectedBackground Color optional; defaults to CheckBox.icon.disabledBackground
* @uiDefault CheckBox.icon.disabledCheckmarkColor Color
* @uiDefault CheckBox.icon.disabledIndeterminateBorderColor Color optional; defaults to CheckBox.icon.disabledSelectedBorderColor
* @uiDefault CheckBox.icon.disabledIndeterminateBackground Color optional; defaults to CheckBox.icon.disabledSelectedBackground
* @uiDefault CheckBox.icon.disabledIndeterminateCheckmarkColor Color optional; defaults to CheckBox.icon.disabledCheckmarkColor
*
* @uiDefault CheckBox.icon.focusedBorderColor Color optional
* @uiDefault CheckBox.icon.focusedBackground Color optional
* @uiDefault CheckBox.icon.focusedSelectedBorderColor Color optional; CheckBox.icon.focusedBorderColor is used if not specified
* @uiDefault CheckBox.icon.focusedSelectedBackground Color optional; CheckBox.icon.focusedBackground is used if not specified
* @uiDefault CheckBox.icon.focusedCheckmarkColor Color optional; CheckBox.icon.checkmarkColor is used if not specified
* @uiDefault CheckBox.icon.focusedBorderColor Color optional
* @uiDefault CheckBox.icon.focusedBackground Color optional
* @uiDefault CheckBox.icon.focusedSelectedBorderColor Color optional; defaults to CheckBox.icon.focusedBorderColor
* @uiDefault CheckBox.icon.focusedSelectedBackground Color optional; defaults to CheckBox.icon.focusedBackground
* @uiDefault CheckBox.icon.focusedCheckmarkColor Color optional; defaults to CheckBox.icon.checkmarkColor
* @uiDefault CheckBox.icon.focusedIndeterminateBorderColor Color optional; defaults to CheckBox.icon.focusedSelectedBorderColor
* @uiDefault CheckBox.icon.focusedIndeterminateBackground Color optional; defaults to CheckBox.icon.focusedSelectedBackground
* @uiDefault CheckBox.icon.focusedIndeterminateCheckmarkColor Color optional; defaults to CheckBox.icon.focusedCheckmarkColor
*
* @uiDefault CheckBox.icon.hoverBorderColor Color optional
* @uiDefault CheckBox.icon.hoverBackground Color optional
* @uiDefault CheckBox.icon.hoverSelectedBorderColor Color optional; CheckBox.icon.hoverBorderColor is used if not specified
* @uiDefault CheckBox.icon.hoverSelectedBackground Color optional; CheckBox.icon.hoverBackground is used if not specified
* @uiDefault CheckBox.icon.hoverCheckmarkColor Color optional; CheckBox.icon.checkmarkColor is used if not specified
* @uiDefault CheckBox.icon.hoverBorderColor Color optional
* @uiDefault CheckBox.icon.hoverBackground Color optional
* @uiDefault CheckBox.icon.hoverSelectedBorderColor Color optional; defaults to CheckBox.icon.hoverBorderColor
* @uiDefault CheckBox.icon.hoverSelectedBackground Color optional; defaults to CheckBox.icon.hoverBackground
* @uiDefault CheckBox.icon.hoverCheckmarkColor Color optional; defaults to CheckBox.icon.checkmarkColor
* @uiDefault CheckBox.icon.hoverIndeterminateBorderColor Color optional; defaults to CheckBox.icon.hoverSelectedBorderColor
* @uiDefault CheckBox.icon.hoverIndeterminateBackground Color optional; defaults to CheckBox.icon.hoverSelectedBackground
* @uiDefault CheckBox.icon.hoverIndeterminateCheckmarkColor Color optional; defaults to CheckBox.icon.hoverCheckmarkColor
*
* @uiDefault CheckBox.icon.pressedBorderColor Color optional
* @uiDefault CheckBox.icon.pressedBackground Color optional
* @uiDefault CheckBox.icon.pressedSelectedBorderColor Color optional; CheckBox.icon.pressedBorderColor is used if not specified
* @uiDefault CheckBox.icon.pressedSelectedBackground Color optional; CheckBox.icon.pressedBackground is used if not specified
* @uiDefault CheckBox.icon.pressedCheckmarkColor Color optional; CheckBox.icon.checkmarkColor is used if not specified
* @uiDefault CheckBox.icon.pressedBorderColor Color optional
* @uiDefault CheckBox.icon.pressedBackground Color optional
* @uiDefault CheckBox.icon.pressedSelectedBorderColor Color optional; defaults to CheckBox.icon.pressedBorderColor
* @uiDefault CheckBox.icon.pressedSelectedBackground Color optional; defaults to CheckBox.icon.pressedBackground
* @uiDefault CheckBox.icon.pressedCheckmarkColor Color optional; defaults to CheckBox.icon.checkmarkColor
* @uiDefault CheckBox.icon.pressedIndeterminateBorderColor Color optional; defaults to CheckBox.icon.pressedSelectedBorderColor
* @uiDefault CheckBox.icon.pressedIndeterminateBackground Color optional; defaults to CheckBox.icon.pressedSelectedBackground
* @uiDefault CheckBox.icon.pressedIndeterminateCheckmarkColor Color optional; defaults to CheckBox.icon.pressedCheckmarkColor
*
* @author Karl Tauber
*/
@@ -92,6 +110,8 @@ public class FlatCheckBoxIcon
/** @since 2 */ @Styleable protected float borderWidth = getUIFloat( "CheckBox.icon.borderWidth", FlatUIUtils.getUIFloat( "Component.borderWidth", 1 ), style );
/** @since 2 */ @Styleable protected float selectedBorderWidth = getUIFloat( "CheckBox.icon.selectedBorderWidth", Float.MIN_VALUE, style );
/** @since 2 */ @Styleable protected float disabledSelectedBorderWidth = getUIFloat( "CheckBox.icon.disabledSelectedBorderWidth", Float.MIN_VALUE, style );
/** @since 3.6 */ @Styleable protected float indeterminateBorderWidth = getUIFloat( "CheckBox.icon.indeterminateBorderWidth", Float.MIN_VALUE, style );
/** @since 3.6 */ @Styleable protected float disabledIndeterminateBorderWidth = getUIFloat( "CheckBox.icon.disabledIndeterminateBorderWidth", Float.MIN_VALUE, style );
@Styleable protected int arc = FlatUIUtils.getUIInt( "CheckBox.arc", 2 );
// enabled
@@ -100,6 +120,9 @@ public class FlatCheckBoxIcon
@Styleable protected Color selectedBorderColor = getUIColor( "CheckBox.icon.selectedBorderColor", style );
@Styleable protected Color selectedBackground = getUIColor( "CheckBox.icon.selectedBackground", style );
@Styleable protected Color checkmarkColor = getUIColor( "CheckBox.icon.checkmarkColor", style );
/** @since 3.6 */ @Styleable protected Color indeterminateBorderColor = getUIColor( "CheckBox.icon.indeterminateBorderColor", style );
/** @since 3.6 */ @Styleable protected Color indeterminateBackground = getUIColor( "CheckBox.icon.indeterminateBackground", style );
/** @since 3.6 */ @Styleable protected Color indeterminateCheckmarkColor = getUIColor( "CheckBox.icon.indeterminateCheckmarkColor", style );
// disabled
@Styleable protected Color disabledBorderColor = getUIColor( "CheckBox.icon.disabledBorderColor", style );
@@ -107,6 +130,9 @@ public class FlatCheckBoxIcon
/** @since 2 */ @Styleable protected Color disabledSelectedBorderColor = getUIColor( "CheckBox.icon.disabledSelectedBorderColor", style );
/** @since 2 */ @Styleable protected Color disabledSelectedBackground = getUIColor( "CheckBox.icon.disabledSelectedBackground", style );
@Styleable protected Color disabledCheckmarkColor = getUIColor( "CheckBox.icon.disabledCheckmarkColor", style );
/** @since 3.6 */ @Styleable protected Color disabledIndeterminateBorderColor = getUIColor( "CheckBox.icon.disabledIndeterminateBorderColor", style );
/** @since 3.6 */ @Styleable protected Color disabledIndeterminateBackground = getUIColor( "CheckBox.icon.disabledIndeterminateBackground", style );
/** @since 3.6 */ @Styleable protected Color disabledIndeterminateCheckmarkColor = getUIColor( "CheckBox.icon.disabledIndeterminateCheckmarkColor", style );
// focused
@Styleable protected Color focusedBorderColor = getUIColor( "CheckBox.icon.focusedBorderColor", style );
@@ -114,6 +140,9 @@ public class FlatCheckBoxIcon
/** @since 2 */ @Styleable protected Color focusedSelectedBorderColor = getUIColor( "CheckBox.icon.focusedSelectedBorderColor", style );
/** @since 2 */ @Styleable protected Color focusedSelectedBackground = getUIColor( "CheckBox.icon.focusedSelectedBackground", style );
/** @since 2 */ @Styleable protected Color focusedCheckmarkColor = getUIColor( "CheckBox.icon.focusedCheckmarkColor", style );
/** @since 3.6 */ @Styleable protected Color focusedIndeterminateBorderColor = getUIColor( "CheckBox.icon.focusedIndeterminateBorderColor", style );
/** @since 3.6 */ @Styleable protected Color focusedIndeterminateBackground = getUIColor( "CheckBox.icon.focusedIndeterminateBackground", style );
/** @since 3.6 */ @Styleable protected Color focusedIndeterminateCheckmarkColor = getUIColor( "CheckBox.icon.focusedIndeterminateCheckmarkColor", style );
// hover
@Styleable protected Color hoverBorderColor = getUIColor( "CheckBox.icon.hoverBorderColor", style );
@@ -121,6 +150,9 @@ public class FlatCheckBoxIcon
/** @since 2 */ @Styleable protected Color hoverSelectedBorderColor = getUIColor( "CheckBox.icon.hoverSelectedBorderColor", style );
/** @since 2 */ @Styleable protected Color hoverSelectedBackground = getUIColor( "CheckBox.icon.hoverSelectedBackground", style );
/** @since 2 */ @Styleable protected Color hoverCheckmarkColor = getUIColor( "CheckBox.icon.hoverCheckmarkColor", style );
/** @since 3.6 */ @Styleable protected Color hoverIndeterminateBorderColor = getUIColor( "CheckBox.icon.hoverIndeterminateBorderColor", style );
/** @since 3.6 */ @Styleable protected Color hoverIndeterminateBackground = getUIColor( "CheckBox.icon.hoverIndeterminateBackground", style );
/** @since 3.6 */ @Styleable protected Color hoverIndeterminateCheckmarkColor = getUIColor( "CheckBox.icon.hoverIndeterminateCheckmarkColor", style );
// pressed
/** @since 2 */ @Styleable protected Color pressedBorderColor = getUIColor( "CheckBox.icon.pressedBorderColor", style );
@@ -128,6 +160,9 @@ public class FlatCheckBoxIcon
/** @since 2 */ @Styleable protected Color pressedSelectedBorderColor = getUIColor( "CheckBox.icon.pressedSelectedBorderColor", style );
/** @since 2 */ @Styleable protected Color pressedSelectedBackground = getUIColor( "CheckBox.icon.pressedSelectedBackground", style );
/** @since 2 */ @Styleable protected Color pressedCheckmarkColor = getUIColor( "CheckBox.icon.pressedCheckmarkColor", style );
/** @since 3.6 */ @Styleable protected Color pressedIndeterminateBorderColor = getUIColor( "CheckBox.icon.pressedIndeterminateBorderColor", style );
/** @since 3.6 */ @Styleable protected Color pressedIndeterminateBackground = getUIColor( "CheckBox.icon.pressedIndeterminateBackground", style );
/** @since 3.6 */ @Styleable protected Color pressedIndeterminateCheckmarkColor = getUIColor( "CheckBox.icon.pressedIndeterminateCheckmarkColor", style );
protected String getPropertyPrefix() {
return "CheckBox.";
@@ -182,11 +217,17 @@ public class FlatCheckBoxIcon
boolean indeterminate = isIndeterminate( c );
boolean selected = indeterminate || isSelected( c );
boolean isFocused = FlatUIUtils.isPermanentFocusOwner( c );
float bw = selected
? (disabledSelectedBorderWidth != Float.MIN_VALUE && !c.isEnabled()
? disabledSelectedBorderWidth
: (selectedBorderWidth != Float.MIN_VALUE ? selectedBorderWidth : borderWidth))
: borderWidth;
float bw = Float.MIN_VALUE;
if( !c.isEnabled() ) {
bw = (indeterminate && disabledIndeterminateBorderWidth != Float.MIN_VALUE)
? disabledIndeterminateBorderWidth
: (selected ? disabledSelectedBorderWidth : selectedBorderWidth);
}
if( bw == Float.MIN_VALUE ) {
bw = (indeterminate && indeterminateBorderWidth != Float.MIN_VALUE)
? indeterminateBorderWidth
: ((selected && selectedBorderWidth != Float.MIN_VALUE) ? selectedBorderWidth : borderWidth);
}
// paint focused border
if( isFocused && focusWidth > 0 && FlatButtonUI.isFocusPainted( c ) ) {
@@ -195,15 +236,15 @@ public class FlatCheckBoxIcon
}
// paint border
g.setColor( getBorderColor( c, selected ) );
g.setColor( getBorderColor( c, selected, indeterminate ) );
paintBorder( c, g, bw );
// paint background
Color bg = FlatUIUtils.deriveColor( getBackground( c, selected ),
selected ? selectedBackground : background );
Color baseBg = stateColor( indeterminate, indeterminateBackground, selected, selectedBackground, background );
Color bg = FlatUIUtils.deriveColor( getBackground( c, selected, indeterminate ), baseBg );
if( bg.getAlpha() < 255 ) {
// fill background with default color before filling with non-opaque background
g.setColor( selected ? selectedBackground : background );
g.setColor( baseBg );
paintBackground( c, g, bw );
}
g.setColor( bg );
@@ -211,7 +252,7 @@ public class FlatCheckBoxIcon
// paint checkmark
if( selected ) {
g.setColor( getCheckmarkColor( c ) );
g.setColor( getCheckmarkColor( c, indeterminate ) );
if( indeterminate )
paintIndeterminate( c, g );
else
@@ -272,30 +313,33 @@ public class FlatCheckBoxIcon
return focusColor;
}
protected Color getBorderColor( Component c, boolean selected ) {
/** @since 3.6 */
protected Color getBorderColor( Component c, boolean selected, boolean indeterminate ) {
return FlatButtonUI.buttonStateColor( c,
selected ? selectedBorderColor : borderColor,
(selected && disabledSelectedBorderColor != null) ? disabledSelectedBorderColor : disabledBorderColor,
(selected && focusedSelectedBorderColor != null) ? focusedSelectedBorderColor : focusedBorderColor,
(selected && hoverSelectedBorderColor != null) ? hoverSelectedBorderColor : hoverBorderColor,
(selected && pressedSelectedBorderColor != null) ? pressedSelectedBorderColor : pressedBorderColor );
stateColor( indeterminate, indeterminateBorderColor, selected, selectedBorderColor, borderColor ),
stateColor( indeterminate, disabledIndeterminateBorderColor, selected, disabledSelectedBorderColor, disabledBorderColor ),
stateColor( indeterminate, focusedIndeterminateBorderColor, selected, focusedSelectedBorderColor, focusedBorderColor ),
stateColor( indeterminate, hoverIndeterminateBorderColor, selected, hoverSelectedBorderColor, hoverBorderColor ),
stateColor( indeterminate, pressedIndeterminateBorderColor, selected, pressedSelectedBorderColor, pressedBorderColor ) );
}
protected Color getBackground( Component c, boolean selected ) {
/** @since 3.6 */
protected Color getBackground( Component c, boolean selected, boolean indeterminate ) {
return FlatButtonUI.buttonStateColor( c,
selected ? selectedBackground : background,
(selected && disabledSelectedBackground != null) ? disabledSelectedBackground : disabledBackground,
(selected && focusedSelectedBackground != null) ? focusedSelectedBackground : focusedBackground,
(selected && hoverSelectedBackground != null) ? hoverSelectedBackground : hoverBackground,
(selected && pressedSelectedBackground != null) ? pressedSelectedBackground : pressedBackground );
stateColor( indeterminate, indeterminateBackground, selected, selectedBackground, background ),
stateColor( indeterminate, disabledIndeterminateBackground, selected, disabledSelectedBackground, disabledBackground ),
stateColor( indeterminate, focusedIndeterminateBackground, selected, focusedSelectedBackground, focusedBackground ),
stateColor( indeterminate, hoverIndeterminateBackground, selected, hoverSelectedBackground, hoverBackground ),
stateColor( indeterminate, pressedIndeterminateBackground, selected, pressedSelectedBackground, pressedBackground ) );
}
protected Color getCheckmarkColor( Component c ) {
/** @since 3.6 */
protected Color getCheckmarkColor( Component c, boolean indeterminate ) {
return FlatButtonUI.buttonStateColor( c,
checkmarkColor,
disabledCheckmarkColor,
focusedCheckmarkColor,
hoverCheckmarkColor,
pressedCheckmarkColor );
stateColor( indeterminate, indeterminateCheckmarkColor, checkmarkColor ),
stateColor( indeterminate, disabledIndeterminateCheckmarkColor, disabledCheckmarkColor ),
stateColor( indeterminate, focusedIndeterminateCheckmarkColor, focusedCheckmarkColor ),
stateColor( indeterminate, hoverIndeterminateCheckmarkColor, hoverCheckmarkColor ),
stateColor( indeterminate, pressedIndeterminateCheckmarkColor, pressedCheckmarkColor ) );
}
}

View File

@@ -60,23 +60,24 @@ public abstract class FlatWindowAbstractIcon
@Override
protected void paintIcon( Component c, Graphics2D g ) {
paintBackground( c, g );
g.setColor( getForeground( c ) );
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 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 );
if( background != null ) {
// 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 );
g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF );
// fill background of whole component
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 );
}

View File

@@ -63,7 +63,7 @@ public class FlatWindowCloseIcon
int iy = y + ((height - iwh) / 2);
int ix2 = ix + iwh - 1;
int iy2 = iy + iwh - 1;
float thickness = SystemInfo.isWindows_11_orLater ? (float) scaleFactor : (int) scaleFactor;
float thickness = Math.max( SystemInfo.isWindows_11_orLater ? (float) scaleFactor : (int) scaleFactor, 1 );
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD, 4 );
path.moveTo( ix, iy );

View File

@@ -38,7 +38,7 @@ public class FlatWindowIconifyIcon
@Override
protected void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
int iw = (int) (getSymbolHeight() * scaleFactor);
int ih = (int) scaleFactor;
int ih = Math.max( (int) scaleFactor, 1 );
int ix = x + ((width - iw) / 2);
int iy = y + ((height - ih) / 2);

View File

@@ -42,7 +42,7 @@ public class FlatWindowMaximizeIcon
int iwh = (int) (getSymbolHeight() * scaleFactor);
int ix = x + ((width - iwh) / 2);
int iy = y + ((height - iwh) / 2);
float thickness = SystemInfo.isWindows_11_orLater ? (float) scaleFactor : (int) scaleFactor;
float thickness = Math.max( SystemInfo.isWindows_11_orLater ? (float) scaleFactor : (int) scaleFactor, 1 );
int arc = Math.max( (int) (1.5 * scaleFactor), 2 );
g.fill( SystemInfo.isWindows_11_orLater

View File

@@ -45,7 +45,7 @@ public class FlatWindowRestoreIcon
int iwh = (int) (getSymbolHeight() * scaleFactor);
int ix = x + ((width - iwh) / 2);
int iy = y + ((height - iwh) / 2);
float thickness = SystemInfo.isWindows_11_orLater ? (float) scaleFactor : (int) scaleFactor;
float thickness = Math.max( SystemInfo.isWindows_11_orLater ? (float) scaleFactor : (int) scaleFactor, 1 );
int arc = Math.max( (int) (1.5 * scaleFactor), 2 );
int arcOuter = (int) (arc + (1.5 * scaleFactor));

View File

@@ -653,7 +653,8 @@ public class FlatButtonUI
}
protected Color getBackground( JComponent c ) {
boolean toolBarButton = isToolBarButton( c ) || isBorderlessButton( c );
boolean def = isDefaultButton( c );
boolean toolBarButton = !def && (isToolBarButton( c ) || isBorderlessButton( c ));
// selected state
if( ((AbstractButton)c).isSelected() ) {
@@ -681,7 +682,6 @@ public class FlatButtonUI
toolbarPressedBackground );
}
boolean def = isDefaultButton( c );
return buttonStateColor( c,
getBackgroundBase( c, def ),
disabledBackground,
@@ -733,7 +733,8 @@ public class FlatButtonUI
protected Color getForeground( JComponent c ) {
Color fg = c.getForeground();
boolean toolBarButton = isToolBarButton( c ) || isBorderlessButton( c );
boolean def = isDefaultButton( c );
boolean toolBarButton = !def && (isToolBarButton( c ) || isBorderlessButton( c ));
// selected state
if( ((AbstractButton)c).isSelected() ) {
@@ -759,7 +760,6 @@ public class FlatButtonUI
toolbarPressedForeground );
}
boolean def = isDefaultButton( c );
return buttonStateColor( c,
getForegroundBase( c, def ),
disabledText,

View File

@@ -585,7 +585,7 @@ public class FlatComboBoxUI
FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc );
// paint arrow button background
if( enabled && !isCellRenderer ) {
if( enabled && !isCellRenderer && arrowButton.isVisible() ) {
Color buttonColor = paintButton
? buttonEditableBackground
: (buttonFocusedBackground != null || focusedBackground != null) && isPermanentFocusOwner( comboBox )
@@ -612,7 +612,7 @@ public class FlatComboBoxUI
}
// paint vertical line between value and arrow button
if( paintButton ) {
if( paintButton && arrowButton.isVisible() ) {
Color separatorColor = enabled ? buttonSeparatorColor : buttonDisabledSeparatorColor;
if( separatorColor != null && buttonSeparatorWidth > 0 ) {
g2.setColor( separatorColor );

View File

@@ -74,7 +74,7 @@ public class FlatDropShadowBorder
this.shadowColor = shadowColor;
this.shadowInsets = shadowInsets;
this.shadowOpacity = shadowOpacity;
this.shadowOpacity = Math.min( Math.max( shadowOpacity, 0f ), 1f );
shadowSize = maxInset( shadowInsets );
}

View File

@@ -376,31 +376,68 @@ public class FlatFileChooserUI
if( icon != null )
return icon;
// get system icon
if( f != null ) {
try {
icon = getFileChooser().getFileSystemView().getSystemIcon( f );
} catch( NullPointerException ex ) {
// Java 21 may throw a NPE for exe files that use default Windows exe icon
}
// new proxy icon
//
// Note: Since this is a super light weight icon object, we do not add it
// to the icon cache here. This keeps cache small in case of large directories
// with thousands of files when icons of all files are only needed to compute
// the layout of list/table, but never painted because located outside of visible area.
// When an icon needs to be painted, the proxy adds it to the icon cache
// and loads the real icon.
return new FlatFileViewIcon( f );
}
if( icon != null ) {
if( icon instanceof ImageIcon )
icon = new ScaledImageIcon( (ImageIcon) icon );
cacheIcon( f, icon );
return icon;
}
//---- class FlatFileViewIcon -----------------------------------------
/**
* A proxy icon that has a fixed (scaled) width/height (16x16) and
* gets/loads the real (system) icon only for painting.
* Avoids unnecessary getting/loading system icons.
*/
private class FlatFileViewIcon
implements Icon
{
private final File f;
private Icon realIcon;
FlatFileViewIcon( File f ) {
this.f = f;
}
// get default icon
icon = super.getIcon( f );
if( icon instanceof ImageIcon ) {
icon = new ScaledImageIcon( (ImageIcon) icon );
cacheIcon( f, icon );
@Override
public int getIconWidth() {
return UIScale.scale( 16 );
}
return icon;
@Override
public int getIconHeight() {
return UIScale.scale( 16 );
}
@Override
public void paintIcon( Component c, Graphics g, int x, int y ) {
// get icon on demand
if( realIcon == null ) {
// get system icon
try {
if( f != null )
realIcon = getFileChooser().getFileSystemView().getSystemIcon( f );
} catch( NullPointerException ex ) {
// Java 21 may throw a NPE for exe files that use default Windows exe icon
}
// get default icon
if( realIcon == null )
realIcon = FlatFileView.super.getIcon( f );
if( realIcon instanceof ImageIcon )
realIcon = new ScaledImageIcon( (ImageIcon) realIcon );
cacheIcon( f, this );
}
realIcon.paintIcon( c, g, x, y );
}
}
}

View File

@@ -17,12 +17,13 @@
package com.formdev.flatlaf.ui;
import java.awt.Color;
import java.awt.Font;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import java.util.function.BiConsumer;
import javax.swing.AbstractButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
@@ -74,9 +75,9 @@ public class FlatHTML
for( int i = 1; i <= 7; i++ )
System.out.println( i+": "+ styleSheet.getPointSize( i ) );
debug*/
int fontBaseSize = c.getFont().getSize();
Font font = c.getFont();
if( styleSheet.getPointSize( 7 ) != 36f ||
styleSheet.getPointSize( 4 ) == fontBaseSize )
font == null || styleSheet.getPointSize( 4 ) == font.getSize() )
return;
// check whether view uses "absolute-size" keywords (e.g. "x-large") for font-size
@@ -93,23 +94,22 @@ debug*/
text = ((JToolTip)c).getTipText();
else
return;
if( text == null )
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 style = "<style>BASE_SIZE " + font.getSize() + "</style>";
String openTag = "";
String closeTag = "";
String lowerText = text.toLowerCase( Locale.ENGLISH );
int headIndex;
int styleIndex;
int insertIndex;
if( (headIndex = lowerText.indexOf( "<head>" )) >= 0 ) {
if( (headIndex = indexOfTag( text, "head", true )) >= 0 ) {
// there is a <head> tag --> insert after <head> tag
insertIndex = headIndex + "<head>".length();
} else if( (styleIndex = lowerText.indexOf( "<style>" )) >= 0 ) {
insertIndex = headIndex;
} else if( (styleIndex = indexOfTag( text, "style", false )) >= 0 ) {
// there is a <style> tag --> insert before <style> tag
insertIndex = styleIndex;
} else {
@@ -124,6 +124,41 @@ debug*/
+ 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(

View File

@@ -57,6 +57,7 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault List.foreground Color
* @uiDefault List.selectionBackground Color
* @uiDefault List.selectionForeground Color
* @uiDefault List.alternateRowColor Color
* @uiDefault List.dropLineColor Color
* @uiDefault List.border Border
* @uiDefault List.cellRenderer ListCellRenderer
@@ -93,6 +94,7 @@ public class FlatListUI
@Styleable protected Color selectionForeground;
@Styleable protected Color selectionInactiveBackground;
@Styleable protected Color selectionInactiveForeground;
/** @since 3.6 */ @Styleable protected Color alternateRowColor;
/** @since 3 */ @Styleable protected Insets selectionInsets;
/** @since 3 */ @Styleable protected int selectionArc;
@@ -129,6 +131,7 @@ public class FlatListUI
selectionForeground = UIManager.getColor( "List.selectionForeground" );
selectionInactiveBackground = UIManager.getColor( "List.selectionInactiveBackground" );
selectionInactiveForeground = UIManager.getColor( "List.selectionInactiveForeground" );
alternateRowColor = UIManager.getColor( "List.alternateRowColor" );
selectionInsets = UIManager.getInsets( "List.selectionInsets" );
selectionArc = UIManager.getInt( "List.selectionArc" );
@@ -143,6 +146,7 @@ public class FlatListUI
selectionForeground = null;
selectionInactiveBackground = null;
selectionInactiveForeground = null;
alternateRowColor = null;
oldStyleValues = null;
}
@@ -299,13 +303,24 @@ public class FlatListUI
{
boolean isSelected = selModel.isSelectedIndex( row );
// paint alternating rows
if( alternateRowColor != null && row % 2 != 0 &&
!"ComboBox.list".equals( list.getName() ) ) // combobox does not support alternate row color
{
g.setColor( alternateRowColor );
float arc = UIScale.scale( selectionArc / 2f );
FlatUIUtils.paintSelection( (Graphics2D) g, rowBounds.x, rowBounds.y, rowBounds.width, rowBounds.height,
UIScale.scale( selectionInsets ), arc, arc, arc, arc, 0 );
}
// get renderer component
@SuppressWarnings( "unchecked" )
Component rendererComponent = cellRenderer.getListCellRendererComponent( list,
dataModel.getElementAt( row ), row, isSelected,
FlatUIUtils.isPermanentFocusOwner( list ) && (row == leadIndex) );
//
// use smaller cell width if list is used in JFileChooser
boolean isFileList = Boolean.TRUE.equals( list.getClientProperty( "List.isFileList" ) );
int cx, cw;
if( isFileList ) {

View File

@@ -90,10 +90,10 @@ class FlatNativeLibrary
classifier = SystemInfo.isAARCH64 ? "macos-arm64" : "macos-x86_64";
ext = "dylib";
} else if( SystemInfo.isLinux && SystemInfo.isX86_64 ) {
// Linux: requires x86_64
} else if( SystemInfo.isLinux && (SystemInfo.isX86_64 || SystemInfo.isAARCH64)) {
// Linux: requires x86_64 or aarch64
classifier = "linux-x86_64";
classifier = SystemInfo.isAARCH64 ? "linux-arm64" : "linux-x86_64";
ext = "so";
// Load libjawt.so (part of JRE) explicitly because it is not found

View File

@@ -16,6 +16,7 @@
package com.formdev.flatlaf.ui;
import java.awt.GraphicsConfiguration;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.Window;
@@ -96,7 +97,11 @@ class FlatNativeLinuxLibrary
}
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 y = (int) Math.round( pt.y * transform.getScaleY() );
return new Point( x, y );

View File

@@ -25,6 +25,7 @@ import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsDevice.WindowTranslucency;
import java.awt.GraphicsEnvironment;
import java.awt.Insets;
import java.awt.MouseInfo;
@@ -36,6 +37,8 @@ import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.awt.event.MouseEvent;
import java.awt.event.WindowFocusListener;
import java.lang.invoke.MethodHandle;
@@ -43,6 +46,7 @@ import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicReference;
import javax.swing.JComponent;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
@@ -60,6 +64,7 @@ import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.plaf.basic.BasicComboPopup;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatSystemProperties;
import com.formdev.flatlaf.util.SystemInfo;
import com.formdev.flatlaf.util.UIScale;
@@ -113,14 +118,8 @@ public class FlatPopupFactory
// macOS and Linux adds drop shadow to heavy weight popups
if( SystemInfo.isMacOS || SystemInfo.isLinux ) {
NonFlashingPopup popup = new NonFlashingPopup( getPopupForScreenOfOwner( owner, contents, x, y, true ), owner, contents );
if( popup.popupWindow != null && SystemInfo.isMacOS &&
// 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 );
if( popup.popupWindow != null && (isMacOSBorderSupported() || isLinuxBorderSupported( popup.popupWindow )) )
setupRoundedBorder( popup, popup.popupWindow, owner, contents );
return popup;
}
@@ -130,7 +129,7 @@ public class FlatPopupFactory
{
NonFlashingPopup popup = new NonFlashingPopup( getPopupForScreenOfOwner( owner, contents, x, y, true ), owner, contents );
if( popup.popupWindow != null )
setupRoundedBorder( popup.popupWindow, owner, contents );
setupRoundedBorder( popup, popup.popupWindow, owner, contents );
return popup;
}
@@ -140,7 +139,8 @@ public class FlatPopupFactory
// create drop shadow popup
Popup popupForScreenOfOwner = getPopupForScreenOfOwner( owner, contents, x, y, forceHeavyWeight );
return owner.getGraphicsConfiguration().isTranslucencyCapable()
GraphicsConfiguration gc = (owner != null) ? owner.getGraphicsConfiguration() : null;
return (gc != null && gc.isTranslucencyCapable())
? new DropShadowPopup( popupForScreenOfOwner, owner, contents )
: new NonFlashingPopup( popupForScreenOfOwner, owner, contents );
}
@@ -307,7 +307,7 @@ public class FlatPopupFactory
break;
}
}
if( gc == null )
if( gc == null && owner != null )
gc = owner.getGraphicsConfiguration();
if( gc == null )
return null;
@@ -360,19 +360,31 @@ public class FlatPopupFactory
//---- native rounded border ----------------------------------------------
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 void setupRoundedBorder( Window popupWindow, Component owner, Component contents ) {
// make sure that the native window is created
if( !popupWindow.isDisplayable() )
popupWindow.addNotify();
private static boolean isMacOSBorderSupported() {
return SystemInfo.isMacOS &&
FlatSystemProperties.getBoolean( FlatSystemProperties.USE_ROUNDED_POPUP_BORDER, true ) &&
FlatNativeMacLibrary.isLoaded();
}
private static boolean isLinuxBorderSupported( Window window ) {
return SystemInfo.isLinux &&
FlatSystemProperties.getBoolean( FlatSystemProperties.USE_ROUNDED_POPUP_BORDER, true ) &&
window.getGraphicsConfiguration().getDevice().isWindowTranslucencySupported( WindowTranslucency.PERPIXEL_TRANSPARENT );
}
private static void setupRoundedBorder( NonFlashingPopup popup,
Window popupWindow, Component owner, Component contents )
{
int borderCornerRadius = getBorderCornerRadius( owner, contents );
float borderWidth = getRoundedBorderWidth( owner, contents );
// get Swing border color
Color borderColor = null; // use system default color
Color borderColor;
if( contents instanceof JComponent ) {
Border border = ((JComponent)contents).getBorder();
border = FlatUIUtils.unwrapNonUIResourceBorder( border );
@@ -384,11 +396,35 @@ public class FlatPopupFactory
borderColor = ((LineBorder)border).getLineColor();
else if( border instanceof EmptyBorder )
borderColor = FlatNativeWindowsLibrary.COLOR_NONE; // do not paint border
else
borderColor = null; // use system default color
// avoid that FlatLineBorder paints the Swing border
((JComponent)contents).putClientProperty( KEY_POPUP_USES_NATIVE_BORDER, true );
}
} else
borderColor = null; // use system default color
if( popupWindow.isDisplayable() ) {
// native window already created
setupRoundedBorderImpl( popup, 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( popup, popupWindow, borderCornerRadius, borderWidth, borderColor );
popupWindow.removeHierarchyListener( l.get() );
}
} );
popupWindow.addHierarchyListener( l.get() );
}
}
private static void setupRoundedBorderImpl( NonFlashingPopup popup,
Window popupWindow, int borderCornerRadius, float borderWidth, Color borderColor )
{
if( SystemInfo.isWindows ) {
// get native window handle
long hwnd = FlatNativeWindowsLibrary.getHWND( popupWindow );
@@ -408,6 +444,12 @@ public class FlatPopupFactory
// set corner radius, border width and color
FlatNativeMacLibrary.setWindowRoundedBorder( popupWindow, borderCornerRadius,
borderWidth, (borderColor != null) ? borderColor.getRGB() : 0 );
} else if( SystemInfo.isLinux ) {
if( popupWindow instanceof RootPaneContainer ) {
popup.windowRoundedBorder = new FlatWindowRoundedBorder(
((RootPaneContainer)popupWindow).getRootPane(),
borderCornerRadius, borderWidth, borderColor );
}
}
}
@@ -440,7 +482,7 @@ public class FlatPopupFactory
"Popup.roundedBorderWidth";
Object value = getOption( owner, contents, FlatClientProperties.POPUP_ROUNDED_BORDER_WIDTH, uiKey );
return (value instanceof Number) ? ((Number)value).floatValue() : 0;
return (value instanceof Number) ? ((Number)value).floatValue() : 1;
}
//---- fixes --------------------------------------------------------------
@@ -553,6 +595,7 @@ public class FlatPopupFactory
// heavy weight
Window popupWindow;
private Color oldPopupWindowBackground;
private FlatWindowRoundedBorder windowRoundedBorder;
private boolean disposed;
@@ -578,6 +621,7 @@ public class FlatPopupFactory
contents = reusePopup.contents;
popupWindow = reusePopup.popupWindow;
oldPopupWindowBackground = reusePopup.oldPopupWindowBackground;
windowRoundedBorder = reusePopup.windowRoundedBorder;
}
NonFlashingPopup cloneForReuse() {
@@ -649,6 +693,11 @@ public class FlatPopupFactory
contents = null;
}
if( windowRoundedBorder != null ) {
windowRoundedBorder.uninstall();
windowRoundedBorder = null;
}
if( popupWindow != null ) {
// restore background so that it can not affect other LaFs (when switching)
// because popup windows are cached and reused
@@ -665,8 +714,6 @@ public class FlatPopupFactory
Container contentPane = ((JWindow)popupWindow).getContentPane();
contentPane.removeAll();
contentPane.add( contents, BorderLayout.CENTER );
popupWindow.invalidate();
popupWindow.validate();
popupWindow.pack();
// update client property on contents
@@ -686,6 +733,7 @@ public class FlatPopupFactory
private class DropShadowPopup
extends NonFlashingPopup
implements ComponentListener
{
// light weight
private JComponent lightComp;
@@ -745,7 +793,7 @@ public class FlatPopupFactory
}
// Windows 11: reset corner preference on reused heavy weight popups
if( isWindows11BorderSupported() ) {
if( SystemInfo.isWindows_11_orLater && FlatNativeWindowsLibrary.isLoaded() ) {
resetWindows11Border( popupWindow );
if( dropShadowWindow != null )
resetWindows11Border( dropShadowWindow );
@@ -815,10 +863,18 @@ public class FlatPopupFactory
if( insets.left != 0 || insets.top != 0 )
lightComp.setLocation( lightComp.getX() - insets.left, lightComp.getY() - insets.top );
}
if( popupWindow != null ) {
removeAllPopupWindowComponentListeners();
popupWindow.addComponentListener( this );
}
}
@Override
void hideImpl() {
if( popupWindow != null )
removeAllPopupWindowComponentListeners();
if( dropShadowDelegate != null ) {
dropShadowDelegate.hide();
dropShadowDelegate = null;
@@ -918,22 +974,55 @@ public class FlatPopupFactory
@Override
void reset( Component contents, int ownerX, int ownerY ) {
if( popupWindow != null )
removeAllPopupWindowComponentListeners();
super.reset( contents, ownerX, ownerY );
if( dropShadowWindow != null ) {
// set preferred size of drop shadow panel
Dimension prefSize = popupWindow.getPreferredSize();
Insets insets = dropShadowPanel2.getInsets();
int w = prefSize.width + insets.left + insets.right;
int h = prefSize.height + insets.top + insets.bottom;
dropShadowPanel2.setPreferredSize( new Dimension( w, h ) );
updateDropShadowWindowBounds();
}
// update drop shadow popup window location and size
int x = popupWindow.getX() - insets.left;
int y = popupWindow.getY() - insets.top;
dropShadowWindow.setBounds( x, y, w, h );
dropShadowWindow.pack();
private void updateDropShadowWindowBounds() {
if( dropShadowWindow == null )
return;
// calculate size of drop shadow window
Dimension size = popupWindow.getSize();
Insets insets = dropShadowPanel2.getInsets();
int w = size.width + insets.left + insets.right;
int h = size.height + insets.top + insets.bottom;
// update drop shadow popup window bounds
int x = popupWindow.getX() - insets.left;
int y = popupWindow.getY() - insets.top;
dropShadowWindow.setBounds( x, y, w, h );
dropShadowWindow.validate();
}
private void removeAllPopupWindowComponentListeners() {
// make sure that there is no old component listener
// necessary because this class is cloned if reusing popup windows
for( ComponentListener l : popupWindow.getComponentListeners() ) {
if( l instanceof DropShadowPopup )
popupWindow.removeComponentListener( l );
}
}
//---- interface ComponentListener ----
@Override
public void componentResized( ComponentEvent e ) {
if( e.getSource() == popupWindow )
updateDropShadowWindowBounds();
}
@Override
public void componentMoved( ComponentEvent e ) {
if( e.getSource() == popupWindow )
updateDropShadowWindowBounds();
}
@Override public void componentShown( ComponentEvent e ) {}
@Override public void componentHidden( ComponentEvent e ) {}
}
}

View File

@@ -239,11 +239,13 @@ public class FlatPopupMenuUI
if( gc == null && popupMenu.getInvoker() != null )
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
// the popup can overlap the taskbar; see JPopupMenu.canPopupOverlapTaskBar())
Toolkit toolkit = Toolkit.getDefaultToolkit();
Rectangle screenBounds = (gc != null) ? gc.getBounds() : new Rectangle( toolkit.getScreenSize() );
Rectangle screenBounds = gc.getBounds();
Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets( gc );
return FlatUIUtils.subtractInsets( screenBounds, screenInsets );
}

View File

@@ -448,6 +448,11 @@ public class FlatRootPaneUI
titlePane.titleBarColorsChanged();
break;
case FlatClientProperties.TITLE_BAR_HEIGHT:
if( titlePane != null )
titlePane.revalidate();
break;
case FlatClientProperties.FULL_WINDOW_CONTENT:
if( titlePane != null ) {
rootPane.getLayeredPane().setLayer( titlePane, getLayerForTitlePane() );
@@ -679,7 +684,7 @@ public class FlatRootPaneUI
* Window border used for non-native window decorations.
*/
public static class FlatWindowBorder
extends BorderUIResource.EmptyBorderUIResource
extends FlatEmptyBorder
{
protected final Color activeBorderColor = UIManager.getColor( "RootPane.activeBorderColor" );
protected final Color inactiveBorderColor = UIManager.getColor( "RootPane.inactiveBorderColor" );
@@ -712,7 +717,10 @@ public class FlatRootPaneUI
}
private void paintImpl( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
g.drawRect( x, y, width - 1, height - 1 );
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g );
float lineWidth = (float) (UIScale.scale( 1f ) * scaleFactor);
g.fill( FlatUIUtils.createRectangle( x, y, width, height, lineWidth ) );
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
}
protected boolean isWindowMaximized( Component c ) {

View File

@@ -210,7 +210,7 @@ public class FlatScrollPaneUI
// Use (0, 0) view position to obtain a constant unit increment of first 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 );
if( unitIncrement > 0 ) {

View File

@@ -2306,8 +2306,23 @@ debug*/
/** @since 3.4 */
@Override
public Boolean isTitleBarCaptionAt( int x, int y ) {
if( tabForCoordinate( tabPane, x, y ) >= 0 )
return false;
// Note: not using tabForCoordinate() here because this may validate layout and cause dead lock
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
}

View File

@@ -359,6 +359,10 @@ public class FlatTitlePane
@Override
public Dimension 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() ) ) {
// make title pane height smaller when frame is maximized
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
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.setContentAreaFilled( false );
@@ -814,7 +824,8 @@ public class FlatTitlePane
Rectangle oldMaximizedBounds = frame.getMaximizedBounds();
if( !hasNativeCustomDecoration() &&
(oldMaximizedBounds == null ||
Objects.equals( oldMaximizedBounds, rootPane.getClientProperty( "_flatlaf.maximizedBounds" ) )) )
Objects.equals( oldMaximizedBounds, rootPane.getClientProperty( "_flatlaf.maximizedBounds" ) )) &&
window.getGraphicsConfiguration() != null )
{
GraphicsConfiguration gc = window.getGraphicsConfiguration();
@@ -1048,10 +1059,11 @@ public class FlatTitlePane
* <p>
* Note:
* <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.
* <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>
*/
private boolean captionHitTest( Point pt ) {
@@ -1079,7 +1091,7 @@ public class FlatTitlePane
}
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
if( c.isEnabled() &&
@@ -1097,8 +1109,18 @@ public class FlatTitlePane
// if component is not fully layouted, do not invoke function
// because it is too dangerous that the function tries to layout the component,
// 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
}
if( caption instanceof Function ) {
// check client property function value
@@ -1131,6 +1153,16 @@ public class FlatTitlePane
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 lastCaptionHitTestY;
private long lastCaptionHitTestTime;
@@ -1558,6 +1590,15 @@ debug*/
* 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
* 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
* {@code false} if the component wants process mouse input at the given location

View File

@@ -531,8 +531,11 @@ public class FlatToolBarUI
private Component getRecentComponent( Container aContainer, boolean first ) {
// if moving focus into the toolbar, focus recently focused toolbar button
if( focusedCompIndex >= 0 && focusedCompIndex < toolBar.getComponentCount() )
return toolBar.getComponent( focusedCompIndex );
if( focusedCompIndex >= 0 && focusedCompIndex < toolBar.getComponentCount() ) {
Component c = toolBar.getComponent( focusedCompIndex );
if( accept( c ) )
return c;
}
return first
? super.getFirstComponent( aContainer )

View File

@@ -102,9 +102,11 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault Tree.selectionForeground Color
* @uiDefault Tree.selectionInactiveBackground Color
* @uiDefault Tree.selectionInactiveForeground Color
* @uiDefault Tree.alternateRowColor Color
* @uiDefault Tree.selectionInsets Insets
* @uiDefault Tree.selectionArc int
* @uiDefault Tree.wideSelection boolean
* @uiDefault Tree.wideCellRenderer boolean
* @uiDefault Tree.showCellFocusIndicator boolean
* @uiDefault Tree.showDefaultIcons boolean
*
@@ -141,9 +143,11 @@ public class FlatTreeUI
@Styleable protected Color selectionInactiveBackground;
@Styleable protected Color selectionInactiveForeground;
@Styleable protected Color selectionBorderColor;
/** @since 3.6 */ @Styleable protected Color alternateRowColor;
/** @since 3 */ @Styleable protected Insets selectionInsets;
/** @since 3 */ @Styleable protected int selectionArc;
@Styleable protected boolean wideSelection;
/** @since 3.6 */ @Styleable protected boolean wideCellRenderer;
@Styleable protected boolean showCellFocusIndicator;
/** @since 3 */ protected boolean showDefaultIcons;
@@ -192,9 +196,11 @@ public class FlatTreeUI
selectionInactiveBackground = UIManager.getColor( "Tree.selectionInactiveBackground" );
selectionInactiveForeground = UIManager.getColor( "Tree.selectionInactiveForeground" );
selectionBorderColor = UIManager.getColor( "Tree.selectionBorderColor" );
alternateRowColor = UIManager.getColor( "Tree.alternateRowColor" );
selectionInsets = UIManager.getInsets( "Tree.selectionInsets" );
selectionArc = UIManager.getInt( "Tree.selectionArc" );
wideSelection = UIManager.getBoolean( "Tree.wideSelection" );
wideCellRenderer = UIManager.getBoolean( "Tree.wideCellRenderer" );
showCellFocusIndicator = UIManager.getBoolean( "Tree.showCellFocusIndicator" );
showDefaultIcons = UIManager.getBoolean( "Tree.showDefaultIcons" );
@@ -227,6 +233,7 @@ public class FlatTreeUI
selectionInactiveBackground = null;
selectionInactiveForeground = null;
selectionBorderColor = null;
alternateRowColor = null;
defaultLeafIcon = null;
defaultClosedIcon = null;
@@ -310,6 +317,7 @@ public class FlatTreeUI
if( e.getSource() == tree ) {
switch( e.getPropertyName() ) {
case TREE_WIDE_SELECTION:
case TREE_WIDE_CELL_RENDERER:
case TREE_PAINT_SELECTION:
HiDPIUtils.repaint( tree );
break;
@@ -571,6 +579,27 @@ public class FlatTreeUI
boolean isDropRow = isDropRow( row );
boolean needsSelectionPainting = (isSelected || isDropRow) && isPaintSelection();
// paint alternating rows
if( alternateRowColor != null && row % 2 != 0 ) {
g.setColor( alternateRowColor );
float arc = UIScale.scale( selectionArc / 2f );
FlatUIUtils.paintSelection( (Graphics2D) g, 0, bounds.y, tree.getWidth(), bounds.height,
UIScale.scale( selectionInsets ), arc, arc, arc, arc, 0 );
}
// update bounds for wide cell renderer
if( isWideSelection() && isWideCellRenderer() ) {
Rectangle wideBounds = new Rectangle( bounds );
if( tree.getComponentOrientation().isLeftToRight() )
wideBounds.width = tree.getWidth() - bounds.x - insets.right;
else {
wideBounds.x = insets.left;
wideBounds.width = bounds.x + bounds.width - insets.left;
}
bounds = wideBounds;
}
// do not paint row if editing
if( isEditing ) {
// paint wide selection
@@ -795,6 +824,11 @@ public class FlatTreeUI
return clientPropertyBoolean( tree, TREE_WIDE_SELECTION, wideSelection );
}
/** @since 3.6 */
protected boolean isWideCellRenderer() {
return clientPropertyBoolean( tree, TREE_WIDE_CELL_RENDERER, wideCellRenderer );
}
protected boolean isPaintSelection() {
return clientPropertyBoolean( tree, TREE_PAINT_SELECTION, paintSelection );
}

View File

@@ -129,6 +129,20 @@ public class FlatUIUtils
return insets.top == 0 && insets.left == 0 && insets.bottom == 0 && insets.right == 0;
}
/** @since 3.6 */
public static Color stateColor( boolean state, Color stateColor, Color defaultColor ) {
return (state && stateColor != null) ? stateColor : defaultColor;
}
/** @since 3.6 */
public static Color stateColor( boolean state1, Color state1Color,
boolean state2, Color state2Color, Color defaultColor )
{
return (state1 && state1Color != null)
? state1Color
: ((state2 && state2Color != null) ? state2Color : defaultColor);
}
public static Color getUIColor( String key, int defaultColorRGB ) {
Color color = UIManager.getColor( key );
return (color != null) ? color : new Color( defaultColorRGB );
@@ -397,7 +411,8 @@ public class FlatUIUtils
GraphicsConfiguration gc = c.getGraphicsConfiguration();
GraphicsDevice gd = (gc != null) ? gc.getDevice() : null;
Window fullScreenWindow = (gd != null) ? gd.getFullScreenWindow() : null;
return (fullScreenWindow != null && fullScreenWindow == SwingUtilities.windowForComponent( c ));
return (fullScreenWindow != null &&
(fullScreenWindow == c || fullScreenWindow == SwingUtilities.windowForComponent( c )));
}
public static Boolean isRoundRect( Component c ) {

View File

@@ -41,7 +41,7 @@ import java.util.function.Supplier;
import javax.swing.DesktopManager;
import javax.swing.JComponent;
import javax.swing.JInternalFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
@@ -59,8 +59,6 @@ import com.formdev.flatlaf.util.UIScale;
public abstract class FlatWindowResizer
implements PropertyChangeListener, ComponentListener
{
protected final static Integer WINDOW_RESIZER_LAYER = JLayeredPane.DRAG_LAYER + 1;
protected final JComponent resizeComp;
protected final int borderDragThickness = FlatUIUtils.getUIInt( "RootPane.borderDragThickness", 5 );
@@ -81,12 +79,12 @@ public abstract class FlatWindowResizer
leftDragComp = createDragBorderComponent( NW_RESIZE_CURSOR, W_RESIZE_CURSOR, SW_RESIZE_CURSOR );
rightDragComp = createDragBorderComponent( NE_RESIZE_CURSOR, E_RESIZE_CURSOR, SE_RESIZE_CURSOR );
Container cont = (resizeComp instanceof JRootPane) ? ((JRootPane)resizeComp).getLayeredPane() : resizeComp;
Object cons = (cont instanceof JLayeredPane) ? WINDOW_RESIZER_LAYER : null;
cont.add( topDragComp, cons, 0 );
cont.add( bottomDragComp, cons, 1 );
cont.add( leftDragComp, cons, 2 );
cont.add( rightDragComp, cons, 3 );
// for rootpanes, add after glasspane
int insertIndex = (resizeComp instanceof JRootPane) ? 1 : 0;
resizeComp.add( topDragComp, insertIndex++ );
resizeComp.add( bottomDragComp, insertIndex++ );
resizeComp.add( leftDragComp, insertIndex++ );
resizeComp.add( rightDragComp, insertIndex++ );
resizeComp.addComponentListener( this );
resizeComp.addPropertyChangeListener( "ancestor", this );
@@ -105,11 +103,10 @@ public abstract class FlatWindowResizer
resizeComp.removeComponentListener( this );
resizeComp.removePropertyChangeListener( "ancestor", this );
Container cont = topDragComp.getParent();
cont.remove( topDragComp );
cont.remove( bottomDragComp );
cont.remove( leftDragComp );
cont.remove( rightDragComp );
resizeComp.remove( topDragComp );
resizeComp.remove( bottomDragComp );
resizeComp.remove( leftDragComp );
resizeComp.remove( rightDragComp );
}
public void doLayout() {
@@ -120,7 +117,7 @@ public abstract class FlatWindowResizer
int y = 0;
int width = resizeComp.getWidth();
int height = resizeComp.getHeight();
if( width == 0 || height == 0 )
if( width <= 0 || height <= 0 )
return;
Insets resizeInsets = getResizeInsets();
@@ -191,7 +188,7 @@ public abstract class FlatWindowResizer
protected abstract Dimension getWindowMinimumSize();
protected abstract Dimension getWindowMaximumSize();
protected void beginResizing( int direction ) {}
protected void beginResizing( int resizeDir ) {}
protected void endResizing() {}
//---- interface PropertyChangeListener ----
@@ -234,17 +231,45 @@ public abstract class FlatWindowResizer
{
protected Window window;
private final JComponent centerComp;
private final boolean limitResizeToScreenBounds;
public WindowResizer( JRootPane 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 );
rootPane.add( centerComp, 5 );
// On Linux, limit window resizing to screen bounds because otherwise
// there would be a strange effect when the mouse is moved over a sidebar
// while resizing and the opposite window side is also resized.
limitResizeToScreenBounds = SystemInfo.isLinux;
}
@Override
public void uninstall() {
resizeComp.remove( centerComp );
super.uninstall();
}
@Override
public void doLayout() {
super.doLayout();
if( centerComp != null && centerComp.isVisible() )
centerComp.setBounds( 0, 0, resizeComp.getWidth(), resizeComp.getHeight() );
}
@Override
protected void addNotify() {
Container parent = resizeComp.getParent();
@@ -299,20 +324,17 @@ public abstract class FlatWindowResizer
@Override
protected boolean limitToParentBounds() {
return limitResizeToScreenBounds && window != null;
return limitResizeToScreenBounds && window != null && window.getGraphicsConfiguration() != null;
}
@Override
protected Rectangle getParentBounds() {
if( limitResizeToScreenBounds && window != null ) {
GraphicsConfiguration gc = window.getGraphicsConfiguration();
Rectangle bounds = gc.getBounds();
Insets insets = window.getToolkit().getScreenInsets( gc );
return new Rectangle( bounds.x + insets.left, bounds.y + insets.top,
bounds.width - insets.left - insets.right,
bounds.height - insets.top - insets.bottom );
}
return null;
GraphicsConfiguration gc = window.getGraphicsConfiguration();
Rectangle bounds = gc.getBounds();
Insets insets = window.getToolkit().getScreenInsets( gc );
return new Rectangle( bounds.x + insets.left, bounds.y + insets.top,
bounds.width - insets.left - insets.right,
bounds.height - insets.top - insets.bottom );
}
@Override
@@ -346,6 +368,19 @@ public abstract class FlatWindowResizer
public void windowStateChanged( WindowEvent e ) {
updateVisibility();
}
@Override
protected void beginResizing( int resizeDir ) {
centerComp.setBounds( 0, 0, resizeComp.getWidth(), resizeComp.getHeight() );
centerComp.setCursor( getPredefinedCursor( resizeDir ) );
centerComp.setVisible( true );
}
@Override
protected void endResizing() {
centerComp.setVisible( false );
centerComp.setCursor( null );
}
}
//---- class InternalFrameResizer -----------------------------------------
@@ -427,7 +462,18 @@ public abstract class FlatWindowResizer
}
@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 );
}
@@ -535,18 +581,7 @@ debug*/
dragRightOffset = windowBounds.x + windowBounds.width - xOnScreen;
dragBottomOffset = windowBounds.y + windowBounds.height - yOnScreen;
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;
}
beginResizing( direction );
beginResizing( resizeDir );
}
@Override

View File

@@ -0,0 +1,361 @@
/*
* Copyright 2025 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 javax.swing.SwingConstants.*;
import java.awt.Color;
import java.awt.Container;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.IllegalComponentStateException;
import java.awt.Shape;
import java.awt.Window;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.geom.Area;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JComponent;
import javax.swing.JLayeredPane;
import javax.swing.JRootPane;
import com.formdev.flatlaf.util.UIScale;
/**
* Rounded border for {@link Window}.
* Used for popups and for FlatLaf window decorations.
* <p>
* Border is painted only if window is not maximized (in both directions) and
* not in full screen mode. If maximized in one direction (vertically or horizontally),
* then a square border is painted.
* <p>
* Note: The rootpane of the window should have a {@link FlatEmptyBorder} with
* same insets as border width used in this class.
*
* @author Karl Tauber
* @since 3.6
*/
public class FlatWindowRoundedBorder
implements PropertyChangeListener, ComponentListener
{
protected final JRootPane rootPane;
protected final int borderCornerRadius;
protected final float borderWidth;
protected final Color borderColor;
protected final Shape cornerShape;
// edges
protected final RoundedBorderComponent northComp;
protected final RoundedBorderComponent southComp;
protected final RoundedBorderComponent westComp;
protected final RoundedBorderComponent eastComp;
// corners
protected final RoundedBorderComponent northWestComp;
protected final RoundedBorderComponent northEastComp;
protected final RoundedBorderComponent southWestComp;
protected final RoundedBorderComponent southEastComp;
protected Window window;
protected boolean windowIsRounded;
public FlatWindowRoundedBorder( JRootPane rootPane, int borderCornerRadius,
float borderWidth, Color borderColor )
{
this.rootPane = rootPane;
this.borderCornerRadius = borderCornerRadius;
this.borderWidth = borderWidth;
this.borderColor = borderColor;
// create shape used to paint rounded corners
cornerShape = createCornerShape();
// create edges
northComp = new RoundedBorderComponent( NORTH );
southComp = new RoundedBorderComponent( SOUTH );
westComp = new RoundedBorderComponent( WEST );
eastComp = new RoundedBorderComponent( EAST );
// create corners
northWestComp = new RoundedBorderComponent( NORTH_WEST );
northEastComp = new RoundedBorderComponent( NORTH_EAST );
southWestComp = new RoundedBorderComponent( SOUTH_WEST );
southEastComp = new RoundedBorderComponent( SOUTH_EAST );
// insert before layered pane
int insertIndex = rootPane.getComponentCount() - 1;
JLayeredPane layeredPane = rootPane.getLayeredPane();
for( int i = insertIndex; i >= 0; i-- ) {
if( rootPane.getComponent( insertIndex ) == layeredPane )
break;
}
// add edges
rootPane.add( northComp, insertIndex++ );
rootPane.add( southComp, insertIndex++ );
rootPane.add( westComp, insertIndex++ );
rootPane.add( eastComp, insertIndex++ );
// add corners
rootPane.add( northWestComp, insertIndex++ );
rootPane.add( northEastComp, insertIndex++ );
rootPane.add( southWestComp, insertIndex++ );
rootPane.add( southEastComp, insertIndex++ );
// add listeners
rootPane.addComponentListener( this );
rootPane.addPropertyChangeListener( "ancestor", this );
if( rootPane.isDisplayable() )
addNotify();
else
updateVisibility();
}
public void uninstall() {
removeNotify();
// remove listeners
rootPane.removeComponentListener( this );
rootPane.removePropertyChangeListener( "ancestor", this );
// remove edges
rootPane.remove( northComp );
rootPane.remove( southComp );
rootPane.remove( westComp );
rootPane.remove( eastComp );
// remove corners
rootPane.remove( northWestComp );
rootPane.remove( northEastComp );
rootPane.remove( southWestComp );
rootPane.remove( southEastComp );
}
public void doLayout() {
if( !northComp.isVisible() )
return;
int x = 0;
int y = 0;
int width = rootPane.getWidth();
int height = rootPane.getHeight();
if( width <= 0 || height <= 0 )
return;
// for layout, round-up scaled border width and radius to ensure that components are large enough
int lineWidth = (int) Math.ceil( UIScale.scale( borderWidth ) );
int cornerSize = (windowIsRounded && lineWidth > 0)
? (int) Math.ceil( UIScale.scale( (float) borderCornerRadius ) )
: 0;
int cornerSize2x = cornerSize * 2;
// edges
northComp.setBounds( x + cornerSize, y, width - cornerSize2x, lineWidth );
southComp.setBounds( x + cornerSize, y + height - lineWidth, width - cornerSize2x, lineWidth );
westComp.setBounds( x, y + cornerSize, lineWidth, height - cornerSize2x );
eastComp.setBounds( x + width - lineWidth, y + cornerSize, lineWidth, height - cornerSize2x );
// corners
northWestComp.setBounds( x, y, cornerSize, cornerSize );
northEastComp.setBounds( x + width - cornerSize, y, cornerSize, cornerSize );
southWestComp.setBounds( x, y + height - cornerSize, cornerSize, cornerSize );
southEastComp.setBounds( x + width - cornerSize, y + height - cornerSize, cornerSize, cornerSize );
}
protected void addNotify() {
Container parent = rootPane.getParent();
window = (parent instanceof Window) ? (Window) parent : null;
updateVisibility();
updateWindowShape();
doLayout();
}
protected void removeNotify() {
if( window != null ) {
window.setShape( null );
window = null;
}
updateVisibility();
}
protected void updateVisibility() {
boolean visible = needsBorder();
if( visible == northComp.isVisible() )
return;
// edges
northComp.setVisible( visible );
southComp.setVisible( visible );
westComp.setVisible( visible );
eastComp.setVisible( visible );
// corners
northWestComp.setVisible( visible );
northEastComp.setVisible( visible );
southWestComp.setVisible( visible );
southEastComp.setVisible( visible );
}
protected boolean needsBorder() {
if( window == null || FlatUIUtils.isFullScreen( window ) )
return false;
if( window instanceof Frame )
return (((Frame)window).getExtendedState() & Frame.MAXIMIZED_BOTH) != Frame.MAXIMIZED_BOTH;
return true;
}
protected void updateWindowShape() {
windowIsRounded = false;
if( window == null )
return;
if( !northComp.isVisible() ||
(window instanceof Frame && (((Frame)window).getExtendedState() & Frame.MAXIMIZED_BOTH) != 0) )
{
window.setShape( null );
return;
}
int arc = UIScale.scale( borderCornerRadius * 2 );
// use a slightly smaller arc for the shape so that at least parts of
// the antialiased arc outside are shown
arc -= 2;
if( arc > 0 ) {
try {
window.setShape( new RoundRectangle2D.Float( 0, 0,
rootPane.getWidth(), rootPane.getHeight(), arc, arc ) );
windowIsRounded = true;
} catch( IllegalComponentStateException | UnsupportedOperationException ex ) {
window.setShape( null );
}
} else
window.setShape( null );
}
protected Shape createCornerShape() {
float lineWidth = UIScale.scale( borderWidth );
int arc = UIScale.scale( borderCornerRadius * 2 );
int wh = arc * 3;
float innerArc = arc - (lineWidth * 2);
float innerWH = wh - (lineWidth * 2);
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
path.append( new RoundRectangle2D.Float( 0, 0, wh, wh, arc, arc ), false );
path.append( new RoundRectangle2D.Float( lineWidth, lineWidth, innerWH, innerWH, innerArc, innerArc ), false );
Area area = new Area( path );
int cornerSize = (int) Math.ceil( UIScale.scale( (float) borderCornerRadius ) );
area.intersect( new Area( new Rectangle2D.Float( 0, 0, cornerSize, cornerSize ) ) );
return area;
}
//---- interface PropertyChangeListener ----
@Override
public void propertyChange( PropertyChangeEvent e ) {
switch( e.getPropertyName() ) {
case "ancestor":
if( e.getNewValue() != null )
addNotify();
else
removeNotify();
break;
}
}
//---- interface ComponentListener ----
@Override
public void componentResized( ComponentEvent e ) {
updateVisibility();
updateWindowShape();
doLayout();
}
@Override public void componentMoved( ComponentEvent e ) {}
@Override public void componentShown( ComponentEvent e ) {}
@Override public void componentHidden( ComponentEvent e ) {}
//---- class RoundedBorderComponent ---------------------------------------
protected class RoundedBorderComponent
extends JComponent
{
private final int position;
protected RoundedBorderComponent( int position ) {
this.position = position;
}
@Override
public void paint( Graphics g ) {
Graphics2D g2 = (Graphics2D) g;
int width = getWidth();
int height = getHeight();
float lineWidth = UIScale.scale( borderWidth );
/*debug
g.setColor( java.awt.Color.green );
g.drawRect( 0, 0, width - 1, height - 1 );
debug*/
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g );
g.setColor( borderColor );
switch( position ) {
case NORTH: g2.fill( new Rectangle2D.Float( 0, 0, width, lineWidth ) ); break;
case SOUTH: g2.fill( new Rectangle2D.Float( 0, height - lineWidth, width, lineWidth ) ); break;
case WEST: g2.fill( new Rectangle2D.Float( 0, 0, lineWidth, height ) ); break;
case EAST: g2.fill( new Rectangle2D.Float( width - lineWidth, 0, lineWidth, height ) ); break;
case NORTH_WEST:
g2.fill( cornerShape );
break;
case NORTH_EAST:
g2.translate( width, 0 );
g2.rotate( Math.toRadians( 90 ) );
g2.fill( cornerShape );
break;
case SOUTH_WEST:
g2.translate( 0, height );
g2.rotate( Math.toRadians( -90 ) );
g2.fill( cornerShape );
break;
case SOUTH_EAST:
g2.translate( width, height );
g2.rotate( Math.toRadians( 180 ) );
g2.fill( cornerShape );
break;
}
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
}
}
}

View File

@@ -33,6 +33,7 @@ import javax.swing.plaf.DimensionUIResource;
import javax.swing.plaf.FontUIResource;
import javax.swing.plaf.InsetsUIResource;
import javax.swing.plaf.UIResource;
import com.formdev.flatlaf.FlatLaf;
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
// that a larger font size is set by the current LaF
// (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 )
font = UIManager.getFont( "Label.font" );
@@ -244,6 +247,16 @@ public class UIScale
}
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
float fontSizeDivider = 12f;

View File

@@ -246,7 +246,6 @@ PasswordField.revealIconColor = @foreground
#---- Popup ----
[mac]Popup.roundedBorderWidth = 1
Popup.dropShadowColor = #000
Popup.dropShadowOpacity = 0.25

View File

@@ -289,7 +289,7 @@ ComboBox.popupInsets = 0,0,0,0
ComboBox.selectionInsets = 0,0,0,0
ComboBox.selectionArc = 0
ComboBox.borderCornerRadius = $Popup.borderCornerRadius
[mac]ComboBox.roundedBorderWidth = $Popup.roundedBorderWidth
ComboBox.roundedBorderWidth = $Popup.roundedBorderWidth
#---- Component ----
@@ -506,7 +506,7 @@ PasswordField.revealIcon = com.formdev.flatlaf.icons.FlatRevealIcon
#---- Popup ----
Popup.borderCornerRadius = 4
[mac]Popup.roundedBorderWidth = 0
Popup.roundedBorderWidth = 1
Popup.dropShadowPainted = true
Popup.dropShadowInsets = -4,-4,4,4
@@ -516,7 +516,7 @@ Popup.dropShadowInsets = -4,-4,4,4
PopupMenu.border = com.formdev.flatlaf.ui.FlatPopupMenuBorder
PopupMenu.borderInsets = 4,1,4,1
PopupMenu.borderCornerRadius = $Popup.borderCornerRadius
[mac]PopupMenu.roundedBorderWidth = $Popup.roundedBorderWidth
PopupMenu.roundedBorderWidth = $Popup.roundedBorderWidth
PopupMenu.background = @menuBackground
PopupMenu.scrollArrowColor = @buttonArrowColor
@@ -913,7 +913,7 @@ ToolTipManager.enableToolTipMode = activeApplication
#---- ToolTip ----
ToolTip.borderCornerRadius = $Popup.borderCornerRadius
[mac]ToolTip.roundedBorderWidth = $Popup.roundedBorderWidth
ToolTip.roundedBorderWidth = $Popup.roundedBorderWidth
#---- Tree ----
@@ -934,6 +934,7 @@ Tree.rendererMargins = 1,2,1,2
Tree.selectionInsets = 0,0,0,0
Tree.selectionArc = 0
Tree.wideSelection = true
Tree.wideCellRenderer = false
Tree.repaintWholeRow = true
Tree.paintLines = false
Tree.showCellFocusIndicator = false

View File

@@ -253,6 +253,7 @@ PasswordField.revealIconColor = tint(@foreground,40%)
#---- Popup ----
[mac]Popup.roundedBorderWidth = 0
Popup.dropShadowColor = #000
Popup.dropShadowOpacity = 0.15

View File

@@ -0,0 +1,123 @@
/*
* 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.assertDoesNotThrow;
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 );
}
@Test
void htmlOnComponentWithNullFont() {
assertDoesNotThrow( () -> {
JLabel label = new JLabel();
label.setFont( null );
label.setText( "<html>foo<br>bar</html>" );
} );
}
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;
}
}
}

View File

@@ -270,6 +270,7 @@ public class TestFlatStyleableInfo
"selectionForeground", Color.class,
"selectionInactiveBackground", Color.class,
"selectionInactiveForeground", Color.class,
"alternateRowColor", Color.class,
"selectionInsets", Insets.class,
"selectionArc", int.class,
@@ -517,6 +518,8 @@ public class TestFlatStyleableInfo
"icon.borderWidth", float.class,
"icon.selectedBorderWidth", float.class,
"icon.disabledSelectedBorderWidth", float.class,
"icon.indeterminateBorderWidth", float.class,
"icon.disabledIndeterminateBorderWidth", float.class,
"icon.arc", int.class,
// enabled
@@ -525,6 +528,9 @@ public class TestFlatStyleableInfo
"icon.selectedBorderColor", Color.class,
"icon.selectedBackground", Color.class,
"icon.checkmarkColor", Color.class,
"icon.indeterminateBorderColor", Color.class,
"icon.indeterminateBackground", Color.class,
"icon.indeterminateCheckmarkColor", Color.class,
// disabled
"icon.disabledBorderColor", Color.class,
@@ -532,6 +538,9 @@ public class TestFlatStyleableInfo
"icon.disabledSelectedBorderColor", Color.class,
"icon.disabledSelectedBackground", Color.class,
"icon.disabledCheckmarkColor", Color.class,
"icon.disabledIndeterminateBorderColor", Color.class,
"icon.disabledIndeterminateBackground", Color.class,
"icon.disabledIndeterminateCheckmarkColor", Color.class,
// focused
"icon.focusedBorderColor", Color.class,
@@ -539,6 +548,9 @@ public class TestFlatStyleableInfo
"icon.focusedSelectedBorderColor", Color.class,
"icon.focusedSelectedBackground", Color.class,
"icon.focusedCheckmarkColor", Color.class,
"icon.focusedIndeterminateBorderColor", Color.class,
"icon.focusedIndeterminateBackground", Color.class,
"icon.focusedIndeterminateCheckmarkColor", Color.class,
// hover
"icon.hoverBorderColor", Color.class,
@@ -546,13 +558,19 @@ public class TestFlatStyleableInfo
"icon.hoverSelectedBorderColor", Color.class,
"icon.hoverSelectedBackground", Color.class,
"icon.hoverCheckmarkColor", Color.class,
"icon.hoverIndeterminateBorderColor", Color.class,
"icon.hoverIndeterminateBackground", Color.class,
"icon.hoverIndeterminateCheckmarkColor", Color.class,
// pressed
"icon.pressedBorderColor", Color.class,
"icon.pressedBackground", Color.class,
"icon.pressedSelectedBorderColor", Color.class,
"icon.pressedSelectedBackground", Color.class,
"icon.pressedCheckmarkColor", Color.class
"icon.pressedCheckmarkColor", Color.class,
"icon.pressedIndeterminateBorderColor", Color.class,
"icon.pressedIndeterminateBackground", Color.class,
"icon.pressedIndeterminateCheckmarkColor", Color.class
);
}
@@ -965,9 +983,11 @@ public class TestFlatStyleableInfo
"selectionInactiveBackground", Color.class,
"selectionInactiveForeground", Color.class,
"selectionBorderColor", Color.class,
"alternateRowColor", Color.class,
"selectionInsets", Insets.class,
"selectionArc", int.class,
"wideSelection", boolean.class,
"wideCellRenderer", boolean.class,
"showCellFocusIndicator", boolean.class,
"paintSelection", boolean.class,
@@ -1144,6 +1164,8 @@ public class TestFlatStyleableInfo
"borderWidth", float.class,
"selectedBorderWidth", float.class,
"disabledSelectedBorderWidth", float.class,
"indeterminateBorderWidth", float.class,
"disabledIndeterminateBorderWidth", float.class,
"arc", int.class,
// enabled
@@ -1152,6 +1174,9 @@ public class TestFlatStyleableInfo
"selectedBorderColor", Color.class,
"selectedBackground", Color.class,
"checkmarkColor", Color.class,
"indeterminateBorderColor", Color.class,
"indeterminateBackground", Color.class,
"indeterminateCheckmarkColor", Color.class,
// disabled
"disabledBorderColor", Color.class,
@@ -1159,6 +1184,9 @@ public class TestFlatStyleableInfo
"disabledSelectedBorderColor", Color.class,
"disabledSelectedBackground", Color.class,
"disabledCheckmarkColor", Color.class,
"disabledIndeterminateBorderColor", Color.class,
"disabledIndeterminateBackground", Color.class,
"disabledIndeterminateCheckmarkColor", Color.class,
// focused
"focusedBorderColor", Color.class,
@@ -1166,6 +1194,9 @@ public class TestFlatStyleableInfo
"focusedSelectedBorderColor", Color.class,
"focusedSelectedBackground", Color.class,
"focusedCheckmarkColor", Color.class,
"focusedIndeterminateBorderColor", Color.class,
"focusedIndeterminateBackground", Color.class,
"focusedIndeterminateCheckmarkColor", Color.class,
// hover
"hoverBorderColor", Color.class,
@@ -1173,13 +1204,19 @@ public class TestFlatStyleableInfo
"hoverSelectedBorderColor", Color.class,
"hoverSelectedBackground", Color.class,
"hoverCheckmarkColor", Color.class,
"hoverIndeterminateBorderColor", Color.class,
"hoverIndeterminateBackground", Color.class,
"hoverIndeterminateCheckmarkColor", Color.class,
// pressed
"pressedBorderColor", Color.class,
"pressedBackground", Color.class,
"pressedSelectedBorderColor", Color.class,
"pressedSelectedBackground", Color.class,
"pressedCheckmarkColor", Color.class
"pressedCheckmarkColor", Color.class,
"pressedIndeterminateBorderColor", Color.class,
"pressedIndeterminateBackground", Color.class,
"pressedIndeterminateCheckmarkColor", Color.class
);
}

View File

@@ -370,6 +370,7 @@ public class TestFlatStyleableValue
testColor( c, ui, "selectionForeground", 0x123456 );
testColor( c, ui, "selectionInactiveBackground", 0x123456 );
testColor( c, ui, "selectionInactiveForeground", 0x123456 );
testColor( c, ui, "alternateRowColor", 0x123456 );
testInsets( c, ui, "selectionInsets", 1,2,3,4 );
testInteger( c, ui, "selectionArc", 123 );
@@ -938,9 +939,11 @@ public class TestFlatStyleableValue
testColor( c, ui, "selectionInactiveBackground", 0x123456 );
testColor( c, ui, "selectionInactiveForeground", 0x123456 );
testColor( c, ui, "selectionBorderColor", 0x123456 );
testColor( c, ui, "alternateRowColor", 0x123456 );
testInsets( c, ui, "selectionInsets", 1,2,3,4 );
testInteger( c, ui, "selectionArc", 123 );
testBoolean( c, ui, "wideSelection", true );
testBoolean( c, ui, "wideCellRenderer", true );
testBoolean( c, ui, "showCellFocusIndicator", true );
testBoolean( c, ui, "paintSelection", false );
@@ -1146,6 +1149,8 @@ public class TestFlatStyleableValue
testValue( icon, "borderWidth", 1.5f );
testValue( icon, "selectedBorderWidth", 1.5f );
testValue( icon, "disabledSelectedBorderWidth", 1.5f );
testValue( icon, "indeterminateBorderWidth", 1.5f );
testValue( icon, "disabledIndeterminateBorderWidth", 1.5f );
testValue( icon, "arc", 5 );
// enabled
@@ -1154,6 +1159,9 @@ public class TestFlatStyleableValue
testValue( icon, "selectedBorderColor", Color.WHITE );
testValue( icon, "selectedBackground", Color.WHITE );
testValue( icon, "checkmarkColor", Color.WHITE );
testValue( icon, "indeterminateBorderColor", Color.WHITE );
testValue( icon, "indeterminateBackground", Color.WHITE );
testValue( icon, "indeterminateCheckmarkColor", Color.WHITE );
// disabled
testValue( icon, "disabledBorderColor", Color.WHITE );
@@ -1161,6 +1169,9 @@ public class TestFlatStyleableValue
testValue( icon, "disabledSelectedBorderColor", Color.WHITE );
testValue( icon, "disabledSelectedBackground", Color.WHITE );
testValue( icon, "disabledCheckmarkColor", Color.WHITE );
testValue( icon, "disabledIndeterminateBorderColor", Color.WHITE );
testValue( icon, "disabledIndeterminateBackground", Color.WHITE );
testValue( icon, "disabledIndeterminateCheckmarkColor", Color.WHITE );
// focused
testValue( icon, "focusedBorderColor", Color.WHITE );
@@ -1168,6 +1179,9 @@ public class TestFlatStyleableValue
testValue( icon, "focusedSelectedBorderColor", Color.WHITE );
testValue( icon, "focusedSelectedBackground", Color.WHITE );
testValue( icon, "focusedCheckmarkColor", Color.WHITE );
testValue( icon, "focusedIndeterminateBorderColor", Color.WHITE );
testValue( icon, "focusedIndeterminateBackground", Color.WHITE );
testValue( icon, "focusedIndeterminateCheckmarkColor", Color.WHITE );
// hover
testValue( icon, "hoverBorderColor", Color.WHITE );
@@ -1175,6 +1189,9 @@ public class TestFlatStyleableValue
testValue( icon, "hoverSelectedBorderColor", Color.WHITE );
testValue( icon, "hoverSelectedBackground", Color.WHITE );
testValue( icon, "hoverCheckmarkColor", Color.WHITE );
testValue( icon, "hoverIndeterminateBorderColor", Color.WHITE );
testValue( icon, "hoverIndeterminateBackground", Color.WHITE );
testValue( icon, "hoverIndeterminateCheckmarkColor", Color.WHITE );
// pressed
testValue( icon, "pressedBorderColor", Color.WHITE );
@@ -1182,6 +1199,9 @@ public class TestFlatStyleableValue
testValue( icon, "pressedSelectedBorderColor", Color.WHITE );
testValue( icon, "pressedSelectedBackground", Color.WHITE );
testValue( icon, "pressedCheckmarkColor", Color.WHITE );
testValue( icon, "pressedIndeterminateBorderColor", Color.WHITE );
testValue( icon, "pressedIndeterminateBackground", Color.WHITE );
testValue( icon, "pressedIndeterminateCheckmarkColor", Color.WHITE );
}
@Test

View File

@@ -433,6 +433,7 @@ public class TestFlatStyling
ui.applyStyle( "selectionForeground: #fff" );
ui.applyStyle( "selectionInactiveBackground: #fff" );
ui.applyStyle( "selectionInactiveForeground: #fff" );
ui.applyStyle( "alternateRowColor: #fff" );
ui.applyStyle( "selectionInsets: 1,2,3,4" );
ui.applyStyle( "selectionArc: 8" );
@@ -1187,9 +1188,11 @@ public class TestFlatStyling
ui.applyStyle( "selectionInactiveBackground: #fff" );
ui.applyStyle( "selectionInactiveForeground: #fff" );
ui.applyStyle( "selectionBorderColor: #fff" );
ui.applyStyle( "alternateRowColor: #fff" );
ui.applyStyle( "selectionInsets: 1,2,3,4" );
ui.applyStyle( "selectionArc: 8" );
ui.applyStyle( "wideSelection: true" );
ui.applyStyle( "wideCellRenderer: true" );
ui.applyStyle( "showCellFocusIndicator: true" );
ui.applyStyle( "paintSelection: false" );
@@ -1388,6 +1391,8 @@ public class TestFlatStyling
icon.applyStyleProperty( "borderWidth", 1.5f );
icon.applyStyleProperty( "selectedBorderWidth", 1.5f );
icon.applyStyleProperty( "disabledSelectedBorderWidth", 1.5f );
icon.applyStyleProperty( "indeterminateBorderWidth", 1.5f );
icon.applyStyleProperty( "disabledIndeterminateBorderWidth", 1.5f );
icon.applyStyleProperty( "arc", 5 );
// enabled
@@ -1396,6 +1401,9 @@ public class TestFlatStyling
icon.applyStyleProperty( "selectedBorderColor", Color.WHITE );
icon.applyStyleProperty( "selectedBackground", Color.WHITE );
icon.applyStyleProperty( "checkmarkColor", Color.WHITE );
icon.applyStyleProperty( "indeterminateBorderColor", Color.WHITE );
icon.applyStyleProperty( "indeterminateBackground", Color.WHITE );
icon.applyStyleProperty( "indeterminateCheckmarkColor", Color.WHITE );
// disabled
icon.applyStyleProperty( "disabledBorderColor", Color.WHITE );
@@ -1403,6 +1411,9 @@ public class TestFlatStyling
icon.applyStyleProperty( "disabledSelectedBorderColor", Color.WHITE );
icon.applyStyleProperty( "disabledSelectedBackground", Color.WHITE );
icon.applyStyleProperty( "disabledCheckmarkColor", Color.WHITE );
icon.applyStyleProperty( "disabledIndeterminateBorderColor", Color.WHITE );
icon.applyStyleProperty( "disabledIndeterminateBackground", Color.WHITE );
icon.applyStyleProperty( "disabledIndeterminateCheckmarkColor", Color.WHITE );
// focused
icon.applyStyleProperty( "focusedBorderColor", Color.WHITE );
@@ -1410,6 +1421,9 @@ public class TestFlatStyling
icon.applyStyleProperty( "focusedSelectedBorderColor", Color.WHITE );
icon.applyStyleProperty( "focusedSelectedBackground", Color.WHITE );
icon.applyStyleProperty( "focusedCheckmarkColor", Color.WHITE );
icon.applyStyleProperty( "focusedIndeterminateBorderColor", Color.WHITE );
icon.applyStyleProperty( "focusedIndeterminateBackground", Color.WHITE );
icon.applyStyleProperty( "focusedIndeterminateCheckmarkColor", Color.WHITE );
// hover
icon.applyStyleProperty( "hoverBorderColor", Color.WHITE );
@@ -1417,6 +1431,9 @@ public class TestFlatStyling
icon.applyStyleProperty( "hoverSelectedBorderColor", Color.WHITE );
icon.applyStyleProperty( "hoverSelectedBackground", Color.WHITE );
icon.applyStyleProperty( "hoverCheckmarkColor", Color.WHITE );
icon.applyStyleProperty( "hoverIndeterminateBorderColor", Color.WHITE );
icon.applyStyleProperty( "hoverIndeterminateBackground", Color.WHITE );
icon.applyStyleProperty( "hoverIndeterminateCheckmarkColor", Color.WHITE );
// pressed
icon.applyStyleProperty( "pressedBorderColor", Color.WHITE );
@@ -1424,6 +1441,9 @@ public class TestFlatStyling
icon.applyStyleProperty( "pressedSelectedBorderColor", Color.WHITE );
icon.applyStyleProperty( "pressedSelectedBackground", Color.WHITE );
icon.applyStyleProperty( "pressedCheckmarkColor", Color.WHITE );
icon.applyStyleProperty( "pressedIndeterminateBorderColor", Color.WHITE );
icon.applyStyleProperty( "pressedIndeterminateBackground", Color.WHITE );
icon.applyStyleProperty( "pressedIndeterminateCheckmarkColor", Color.WHITE );
}
@Test

View File

@@ -6,7 +6,7 @@
# when the Demo window is activated.
# base theme (light, dark, intellij or darcula)
# base theme (light, dark, intellij, darcula, maclight or macdark)
@baseTheme = light
# add you theme defaults here

View File

@@ -277,22 +277,22 @@ class BasicComponentsPanel
//---- button5 ----
button5.setText("Square");
button5.putClientProperty("JButton.buttonType", "square");
button5.putClientProperty(FlatClientProperties.BUTTON_TYPE, FlatClientProperties.BUTTON_TYPE_SQUARE);
add(button5, "cell 3 1");
//---- button6 ----
button6.setText("Round");
button6.putClientProperty("JButton.buttonType", "roundRect");
button6.putClientProperty(FlatClientProperties.BUTTON_TYPE, FlatClientProperties.BUTTON_TYPE_ROUND_RECT);
add(button6, "cell 4 1");
//---- button3 ----
button3.setText("Help");
button3.putClientProperty("JButton.buttonType", "help");
button3.putClientProperty(FlatClientProperties.BUTTON_TYPE, FlatClientProperties.BUTTON_TYPE_HELP);
add(button3, "cell 4 1");
//---- button4 ----
button4.setText("Help");
button4.putClientProperty("JButton.buttonType", "help");
button4.putClientProperty(FlatClientProperties.BUTTON_TYPE, FlatClientProperties.BUTTON_TYPE_HELP);
button4.setEnabled(false);
add(button4, "cell 4 1");
@@ -432,7 +432,7 @@ class BasicComponentsPanel
//---- comboBox6 ----
comboBox6.setEditable(true);
comboBox6.putClientProperty("JTextField.placeholderText", "Placeholder");
comboBox6.putClientProperty(FlatClientProperties.PLACEHOLDER_TEXT, "Placeholder");
add(comboBox6, "cell 5 5,growx");
//---- textFieldLabel ----
@@ -463,7 +463,7 @@ class BasicComponentsPanel
add(textField4, "cell 4 6,growx");
//---- textField6 ----
textField6.putClientProperty("JTextField.placeholderText", "Placeholder");
textField6.putClientProperty(FlatClientProperties.PLACEHOLDER_TEXT, "Placeholder");
add(textField6, "cell 5 6,growx");
//---- formattedTextFieldLabel ----
@@ -494,7 +494,7 @@ class BasicComponentsPanel
add(formattedTextField4, "cell 4 7,growx");
//---- formattedTextField5 ----
formattedTextField5.putClientProperty("JTextField.placeholderText", "Placeholder");
formattedTextField5.putClientProperty(FlatClientProperties.PLACEHOLDER_TEXT, "Placeholder");
add(formattedTextField5, "cell 5 7,growx");
//---- passwordFieldLabel ----
@@ -522,7 +522,7 @@ class BasicComponentsPanel
add(passwordField4, "cell 4 8,growx");
//---- passwordField5 ----
passwordField5.putClientProperty("JTextField.placeholderText", "Placeholder");
passwordField5.putClientProperty(FlatClientProperties.PLACEHOLDER_TEXT, "Placeholder");
add(passwordField5, "cell 5 8,growx");
//---- textAreaLabel ----
@@ -703,11 +703,11 @@ class BasicComponentsPanel
add(errorHintsLabel, "cell 0 12");
//---- errorHintsTextField ----
errorHintsTextField.putClientProperty("JComponent.outline", "error");
errorHintsTextField.putClientProperty(FlatClientProperties.OUTLINE, FlatClientProperties.OUTLINE_ERROR);
add(errorHintsTextField, "cell 1 12,growx");
//---- errorHintsComboBox ----
errorHintsComboBox.putClientProperty("JComponent.outline", "error");
errorHintsComboBox.putClientProperty(FlatClientProperties.OUTLINE, FlatClientProperties.OUTLINE_ERROR);
errorHintsComboBox.setModel(new DefaultComboBoxModel<>(new String[] {
"Editable"
}));
@@ -715,7 +715,7 @@ class BasicComponentsPanel
add(errorHintsComboBox, "cell 2 12,growx");
//---- errorHintsSpinner ----
errorHintsSpinner.putClientProperty("JComponent.outline", "error");
errorHintsSpinner.putClientProperty(FlatClientProperties.OUTLINE, FlatClientProperties.OUTLINE_ERROR);
add(errorHintsSpinner, "cell 3 12,growx");
//---- warningHintsLabel ----
@@ -723,18 +723,18 @@ class BasicComponentsPanel
add(warningHintsLabel, "cell 0 13");
//---- warningHintsTextField ----
warningHintsTextField.putClientProperty("JComponent.outline", "warning");
warningHintsTextField.putClientProperty(FlatClientProperties.OUTLINE, FlatClientProperties.OUTLINE_WARNING);
add(warningHintsTextField, "cell 1 13,growx");
//---- warningHintsComboBox ----
warningHintsComboBox.putClientProperty("JComponent.outline", "warning");
warningHintsComboBox.putClientProperty(FlatClientProperties.OUTLINE, FlatClientProperties.OUTLINE_WARNING);
warningHintsComboBox.setModel(new DefaultComboBoxModel<>(new String[] {
"Not editable"
}));
add(warningHintsComboBox, "cell 2 13,growx");
//---- warningHintsSpinner ----
warningHintsSpinner.putClientProperty("JComponent.outline", "warning");
warningHintsSpinner.putClientProperty(FlatClientProperties.OUTLINE, FlatClientProperties.OUTLINE_WARNING);
add(warningHintsSpinner, "cell 3 13,growx");
//---- iconsLabel ----
@@ -765,53 +765,53 @@ class BasicComponentsPanel
//---- h00Label ----
h00Label.setText("H00");
h00Label.putClientProperty("FlatLaf.styleClass", "h00");
h00Label.putClientProperty(FlatClientProperties.STYLE_CLASS, "h00");
add(h00Label, "cell 1 16 5 1");
//---- h0Label ----
h0Label.setText("H0");
h0Label.putClientProperty("FlatLaf.styleClass", "h0");
h0Label.putClientProperty(FlatClientProperties.STYLE_CLASS, "h0");
add(h0Label, "cell 1 16 5 1");
//---- h1Label ----
h1Label.setText("H1");
h1Label.putClientProperty("FlatLaf.styleClass", "h1");
h1Label.putClientProperty(FlatClientProperties.STYLE_CLASS, "h1");
add(h1Label, "cell 1 16 5 1");
//---- h2Label ----
h2Label.setText("H2");
h2Label.putClientProperty("FlatLaf.styleClass", "h2");
h2Label.putClientProperty(FlatClientProperties.STYLE_CLASS, "h2");
add(h2Label, "cell 1 16 5 1");
//---- h3Label ----
h3Label.setText("H3");
h3Label.putClientProperty("FlatLaf.styleClass", "h3");
h3Label.putClientProperty(FlatClientProperties.STYLE_CLASS, "h3");
add(h3Label, "cell 1 16 5 1");
//---- h4Label ----
h4Label.setText("H4");
h4Label.putClientProperty("FlatLaf.styleClass", "h4");
h4Label.putClientProperty(FlatClientProperties.STYLE_CLASS, "h4");
add(h4Label, "cell 1 16 5 1");
//---- lightLabel ----
lightLabel.setText("light");
lightLabel.putClientProperty("FlatLaf.style", "font: 200% $light.font");
lightLabel.putClientProperty(FlatClientProperties.STYLE, "font: 200% $light.font");
add(lightLabel, "cell 1 16 5 1,gapx 30");
//---- semiboldLabel ----
semiboldLabel.setText("semibold");
semiboldLabel.putClientProperty("FlatLaf.style", "font: 200% $semibold.font");
semiboldLabel.putClientProperty(FlatClientProperties.STYLE, "font: 200% $semibold.font");
add(semiboldLabel, "cell 1 16 5 1");
//---- fontZoomLabel ----
fontZoomLabel.setText("(200%)");
fontZoomLabel.putClientProperty("FlatLaf.styleClass", "small");
fontZoomLabel.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
fontZoomLabel.setEnabled(false);
add(fontZoomLabel, "cell 1 16 5 1");
//---- largeLabel ----
largeLabel.setText("large");
largeLabel.putClientProperty("FlatLaf.styleClass", "large");
largeLabel.putClientProperty(FlatClientProperties.STYLE_CLASS, "large");
add(largeLabel, "cell 1 17 5 1");
//---- defaultLabel ----
@@ -820,22 +820,22 @@ class BasicComponentsPanel
//---- mediumLabel ----
mediumLabel.setText("medium");
mediumLabel.putClientProperty("FlatLaf.styleClass", "medium");
mediumLabel.putClientProperty(FlatClientProperties.STYLE_CLASS, "medium");
add(mediumLabel, "cell 1 17 5 1");
//---- smallLabel ----
smallLabel.setText("small");
smallLabel.putClientProperty("FlatLaf.styleClass", "small");
smallLabel.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
add(smallLabel, "cell 1 17 5 1");
//---- miniLabel ----
miniLabel.setText("mini");
miniLabel.putClientProperty("FlatLaf.styleClass", "mini");
miniLabel.putClientProperty(FlatClientProperties.STYLE_CLASS, "mini");
add(miniLabel, "cell 1 17 5 1");
//---- monospacedLabel ----
monospacedLabel.setText("monospaced");
monospacedLabel.putClientProperty("FlatLaf.styleClass", "monospaced");
monospacedLabel.putClientProperty(FlatClientProperties.STYLE_CLASS, "monospaced");
add(monospacedLabel, "cell 1 17 5 1,gapx 30");
//======== popupMenu1 ========

View File

@@ -22,6 +22,7 @@ import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import javax.swing.*;
import javax.swing.UIDefaults.ActiveValue;
import javax.swing.table.*;
import javax.swing.tree.*;
import com.formdev.flatlaf.FlatClientProperties;
@@ -65,6 +66,45 @@ class DataComponentsPanel
tree3.putClientProperty( FlatClientProperties.STYLE, "selectionInsets: 0,1,0,1; selectionArc: 6" );
}
private void listAlternatingRowsChanged() {
ActiveValue alternateRowColor = null;
if( listAlternatingRowsCheckBox.isSelected() ) {
alternateRowColor = table -> {
Color background = list1.getBackground();
return FlatLaf.isLafDark()
? ColorFunctions.lighten( background, 0.05f )
: ColorFunctions.darken( background, 0.05f );
};
}
UIManager.put( "List.alternateRowColor", alternateRowColor );
list1.updateUI();
list2.updateUI();
list3.updateUI();
}
private void treeWideSelectionChanged() {
boolean wideSelection = treeWideSelectionCheckBox.isSelected();
tree1.putClientProperty( FlatClientProperties.TREE_WIDE_SELECTION, wideSelection );
tree2.putClientProperty( FlatClientProperties.TREE_WIDE_SELECTION, wideSelection );
tree3.putClientProperty( FlatClientProperties.TREE_WIDE_SELECTION, wideSelection );
}
private void treeAlternatingRowsChanged() {
ActiveValue alternateRowColor = null;
if( treeAlternatingRowsCheckBox.isSelected() ) {
alternateRowColor = table -> {
Color background = tree1.getBackground();
return FlatLaf.isLafDark()
? ColorFunctions.lighten( background, 0.05f )
: ColorFunctions.darken( background, 0.05f );
};
}
UIManager.put( "Tree.alternateRowColor", alternateRowColor );
tree1.updateUI();
tree2.updateUI();
tree3.updateUI();
}
private void dndChanged() {
boolean dnd = dndCheckBox.isSelected();
DropMode dropMode = dnd ? DropMode.ON_OR_INSERT : DropMode.USE_SELECTION;
@@ -142,18 +182,20 @@ class DataComponentsPanel
}
private void alternatingRowsChanged() {
Color alternateRowColor = null;
ActiveValue alternateRowColor = null;
if( alternatingRowsCheckBox.isSelected() ) {
Color background = table1.getBackground();
alternateRowColor = FlatLaf.isLafDark()
? ColorFunctions.lighten( background, 0.05f )
: ColorFunctions.darken( background, 0.05f );
alternateRowColor = table -> {
Color background = table1.getBackground();
return FlatLaf.isLafDark()
? ColorFunctions.lighten( background, 0.05f )
: ColorFunctions.darken( background, 0.05f );
};
}
UIManager.put( "Table.alternateRowColor", alternateRowColor );
table1.repaint();
}
@SuppressWarnings( { "unchecked", "rawtypes" } )
@SuppressWarnings( { "rawtypes" } )
private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
JLabel label1 = new JLabel();
@@ -166,6 +208,8 @@ class DataComponentsPanel
list3 = new JList<>();
JScrollPane scrollPane2 = new JScrollPane();
list2 = new JList<>();
JPanel listOptionsPanel = new JPanel();
listAlternatingRowsCheckBox = new JCheckBox();
JLabel treeLabel = new JLabel();
JScrollPane scrollPane3 = new JScrollPane();
tree1 = new JTree();
@@ -173,6 +217,9 @@ class DataComponentsPanel
tree3 = new JTree();
JScrollPane scrollPane4 = new JScrollPane();
tree2 = new JTree();
JPanel treeOptionsPanel = new JPanel();
treeWideSelectionCheckBox = new JCheckBox();
treeAlternatingRowsCheckBox = new JCheckBox();
JLabel tableLabel = new JLabel();
JScrollPane scrollPane5 = new JScrollPane();
table1 = new JTable();
@@ -273,6 +320,22 @@ class DataComponentsPanel
}
add(scrollPane2, "cell 3 1");
//======== listOptionsPanel ========
{
listOptionsPanel.setLayout(new MigLayout(
"insets 0,hidemode 3",
// columns
"[fill]",
// rows
"[]"));
//---- listAlternatingRowsCheckBox ----
listAlternatingRowsCheckBox.setText("alternating rows");
listAlternatingRowsCheckBox.addActionListener(e -> listAlternatingRowsChanged());
listOptionsPanel.add(listAlternatingRowsCheckBox, "cell 0 0");
}
add(listOptionsPanel, "cell 4 1");
//---- treeLabel ----
treeLabel.setText("JTree:");
add(treeLabel, "cell 0 2,aligny top,growy 0");
@@ -334,6 +397,29 @@ class DataComponentsPanel
}
add(scrollPane4, "cell 3 2");
//======== treeOptionsPanel ========
{
treeOptionsPanel.setLayout(new MigLayout(
"insets 0,hidemode 3",
// columns
"[fill]",
// rows
"[]0" +
"[]"));
//---- treeWideSelectionCheckBox ----
treeWideSelectionCheckBox.setText("wide selection");
treeWideSelectionCheckBox.setSelected(true);
treeWideSelectionCheckBox.addActionListener(e -> treeWideSelectionChanged());
treeOptionsPanel.add(treeWideSelectionCheckBox, "cell 0 0");
//---- treeAlternatingRowsCheckBox ----
treeAlternatingRowsCheckBox.setText("alternating rows");
treeAlternatingRowsCheckBox.addActionListener(e -> treeAlternatingRowsChanged());
treeOptionsPanel.add(treeAlternatingRowsCheckBox, "cell 0 1");
}
add(treeOptionsPanel, "cell 4 2");
//---- tableLabel ----
tableLabel.setText("JTable:");
add(tableLabel, "cell 0 3,aligny top,growy 0");
@@ -379,7 +465,7 @@ class DataComponentsPanel
{
TableColumnModel cm = table1.getColumnModel();
cm.getColumn(2).setCellEditor(new DefaultCellEditor(
new JComboBox(new DefaultComboBoxModel(new String[] {
new JComboBox<>(new DefaultComboBoxModel<>(new String[] {
"January",
"February",
"March",
@@ -394,7 +480,7 @@ class DataComponentsPanel
"December"
}))));
cm.getColumn(3).setCellEditor(new DefaultCellEditor(
new JComboBox(new DefaultComboBoxModel(new String[] {
new JComboBox<>(new DefaultComboBoxModel<>(new String[] {
"January",
"February",
"March",
@@ -513,9 +599,12 @@ class DataComponentsPanel
private JList<String> list1;
private JList<String> list3;
private JList<String> list2;
private JCheckBox listAlternatingRowsCheckBox;
private JTree tree1;
private JTree tree3;
private JTree tree2;
private JCheckBox treeWideSelectionCheckBox;
private JCheckBox treeAlternatingRowsCheckBox;
private JTable table1;
private JCheckBox roundedSelectionCheckBox;
private JCheckBox showHorizontalLinesCheckBox;

View File

@@ -1,4 +1,4 @@
JFDML JFormDesigner: "8.2.0.0.331" Java: "21" encoding: "UTF-8"
JFDML JFormDesigner: "8.3" encoding: "UTF-8"
new FormModel {
contentType: "form/swing"
@@ -92,6 +92,25 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 3 1"
} )
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "insets 0,hidemode 3"
"$columnConstraints": "[fill]"
"$rowConstraints": "[]"
} ) {
name: "listOptionsPanel"
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "listAlternatingRowsCheckBox"
"text": "alternating rows"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "listAlternatingRowsChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 0"
} )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 4 1"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "treeLabel"
"text": "JTree:"
@@ -192,6 +211,36 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 3 2"
} )
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "insets 0,hidemode 3"
"$columnConstraints": "[fill]"
"$rowConstraints": "[]0[]"
} ) {
name: "treeOptionsPanel"
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "treeWideSelectionCheckBox"
"text": "wide selection"
"selected": true
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "treeWideSelectionChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 0"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "treeAlternatingRowsCheckBox"
"text": "alternating rows"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "treeAlternatingRowsChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 1"
} )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 4 2"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "tableLabel"
"text": "JTable:"

View File

@@ -19,6 +19,7 @@ package com.formdev.flatlaf.demo;
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
import com.formdev.flatlaf.FlatClientProperties;
import net.miginfocom.swing.*;
/**
@@ -176,12 +177,12 @@ class MoreComponentsPanel
add(scrollBar3, "cell 2 0 1 6,growy");
//---- scrollBar7 ----
scrollBar7.putClientProperty("JScrollBar.showButtons", true);
scrollBar7.putClientProperty(FlatClientProperties.SCROLL_BAR_SHOW_BUTTONS, true);
add(scrollBar7, "cell 2 0 1 6,growy");
//---- scrollBar8 ----
scrollBar8.setEnabled(false);
scrollBar8.putClientProperty("JScrollBar.showButtons", true);
scrollBar8.putClientProperty(FlatClientProperties.SCROLL_BAR_SHOW_BUTTONS, true);
add(scrollBar8, "cell 2 0 1 6,growy");
//---- separator2 ----
@@ -301,13 +302,13 @@ class MoreComponentsPanel
//---- scrollBar5 ----
scrollBar5.setOrientation(Adjustable.HORIZONTAL);
scrollBar5.putClientProperty("JScrollBar.showButtons", true);
scrollBar5.putClientProperty(FlatClientProperties.SCROLL_BAR_SHOW_BUTTONS, true);
add(scrollBar5, "cell 1 3,growx");
//---- scrollBar6 ----
scrollBar6.setOrientation(Adjustable.HORIZONTAL);
scrollBar6.setEnabled(false);
scrollBar6.putClientProperty("JScrollBar.showButtons", true);
scrollBar6.putClientProperty(FlatClientProperties.SCROLL_BAR_SHOW_BUTTONS, true);
add(scrollBar6, "cell 1 4,growx");
//---- separatorLabel ----
@@ -518,7 +519,7 @@ class MoreComponentsPanel
//======== panel5 ========
{
panel5.putClientProperty("FlatLaf.style", "arc: 16; background: darken($Panel.background,5%)");
panel5.putClientProperty(FlatClientProperties.STYLE, "arc: 16; background: darken($Panel.background,5%)");
panel5.setLayout(new BorderLayout());
//---- label9 ----
@@ -530,7 +531,7 @@ class MoreComponentsPanel
//======== panel4 ========
{
panel4.putClientProperty("FlatLaf.style", "border: 1,1,1,1,@disabledForeground,1,16; background: darken($Panel.background,5%)");
panel4.putClientProperty(FlatClientProperties.STYLE, "border: 1,1,1,1,@disabledForeground,1,16; background: darken($Panel.background,5%)");
panel4.setLayout(new BorderLayout());
//---- label8 ----
@@ -546,14 +547,14 @@ class MoreComponentsPanel
//---- label13 ----
label13.setText("rounded background");
label13.putClientProperty("FlatLaf.style", "arc: 999; border: 2,10,2,10");
label13.putClientProperty(FlatClientProperties.STYLE, "arc: 999; border: 2,10,2,10");
label13.setBackground(new Color(0xb8e4f3));
label13.setForeground(new Color(0x135b76));
add(label13, "cell 1 13 4 1");
//---- label10 ----
label10.setText("rounded border");
label10.putClientProperty("FlatLaf.style", "arc: 999; border: 2,10,2,10,#135b76");
label10.putClientProperty(FlatClientProperties.STYLE, "arc: 999; border: 2,10,2,10,#135b76");
label10.setBackground(new Color(0xb8e4f3));
label10.setForeground(new Color(0x135b76));
add(label10, "cell 1 13 4 1");

View File

@@ -16,6 +16,7 @@
package com.formdev.flatlaf.demo;
import com.formdev.flatlaf.FlatClientProperties;
import static com.formdev.flatlaf.FlatClientProperties.*;
import java.awt.*;
import java.awt.event.MouseEvent;
@@ -471,7 +472,7 @@ class TabsPanel
//---- tabPlacementLabel ----
tabPlacementLabel.setText("Tab placement");
tabPlacementLabel.putClientProperty("FlatLaf.styleClass", "h3");
tabPlacementLabel.putClientProperty(FlatClientProperties.STYLE_CLASS, "h3");
panel1.add(tabPlacementLabel, "cell 0 0");
//======== tabPlacementToolBar ========
@@ -482,38 +483,38 @@ class TabsPanel
//---- topPlacementButton ----
topPlacementButton.setText("top");
topPlacementButton.setSelected(true);
topPlacementButton.putClientProperty("FlatLaf.styleClass", "small");
topPlacementButton.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
topPlacementButton.addActionListener(e -> tabPlacementChanged());
tabPlacementToolBar.add(topPlacementButton);
//---- bottomPlacementButton ----
bottomPlacementButton.setText("bottom");
bottomPlacementButton.putClientProperty("FlatLaf.styleClass", "small");
bottomPlacementButton.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
bottomPlacementButton.addActionListener(e -> tabPlacementChanged());
tabPlacementToolBar.add(bottomPlacementButton);
//---- leftPlacementButton ----
leftPlacementButton.setText("left");
leftPlacementButton.putClientProperty("FlatLaf.styleClass", "small");
leftPlacementButton.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
leftPlacementButton.addActionListener(e -> tabPlacementChanged());
tabPlacementToolBar.add(leftPlacementButton);
//---- rightPlacementButton ----
rightPlacementButton.setText("right");
rightPlacementButton.putClientProperty("FlatLaf.styleClass", "small");
rightPlacementButton.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
rightPlacementButton.addActionListener(e -> tabPlacementChanged());
tabPlacementToolBar.add(rightPlacementButton);
tabPlacementToolBar.addSeparator();
//---- scrollButton ----
scrollButton.setText("scroll");
scrollButton.putClientProperty("FlatLaf.styleClass", "small");
scrollButton.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
scrollButton.addActionListener(e -> scrollChanged());
tabPlacementToolBar.add(scrollButton);
//---- borderButton ----
borderButton.setText("border");
borderButton.putClientProperty("FlatLaf.styleClass", "small");
borderButton.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
borderButton.addActionListener(e -> borderChanged());
tabPlacementToolBar.add(borderButton);
}
@@ -522,7 +523,7 @@ class TabsPanel
//---- tabLayoutLabel ----
tabLayoutLabel.setText("Tab layout");
tabLayoutLabel.putClientProperty("FlatLaf.styleClass", "h3");
tabLayoutLabel.putClientProperty(FlatClientProperties.STYLE_CLASS, "h3");
panel1.add(tabLayoutLabel, "cell 0 2");
//======== tabLayoutToolBar ========
@@ -533,13 +534,13 @@ class TabsPanel
//---- scrollTabLayoutButton ----
scrollTabLayoutButton.setText("scroll");
scrollTabLayoutButton.setSelected(true);
scrollTabLayoutButton.putClientProperty("FlatLaf.styleClass", "small");
scrollTabLayoutButton.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
scrollTabLayoutButton.addActionListener(e -> tabLayoutChanged());
tabLayoutToolBar.add(scrollTabLayoutButton);
//---- wrapTabLayoutButton ----
wrapTabLayoutButton.setText("wrap");
wrapTabLayoutButton.putClientProperty("FlatLaf.styleClass", "small");
wrapTabLayoutButton.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
wrapTabLayoutButton.addActionListener(e -> tabLayoutChanged());
tabLayoutToolBar.add(wrapTabLayoutButton);
}
@@ -548,20 +549,20 @@ class TabsPanel
//---- scrollLayoutNoteLabel ----
scrollLayoutNoteLabel.setText("(use mouse wheel to scroll; arrow button shows hidden tabs)");
scrollLayoutNoteLabel.setEnabled(false);
scrollLayoutNoteLabel.putClientProperty("FlatLaf.styleClass", "small");
scrollLayoutNoteLabel.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
panel1.add(scrollLayoutNoteLabel, "cell 0 3");
//---- wrapLayoutNoteLabel ----
wrapLayoutNoteLabel.setText("(probably better to use scroll layout?)");
wrapLayoutNoteLabel.setEnabled(false);
wrapLayoutNoteLabel.putClientProperty("FlatLaf.styleClass", "small");
wrapLayoutNoteLabel.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
panel1.add(wrapLayoutNoteLabel, "cell 0 3");
panel1.add(scrollLayoutTabbedPane, "cell 0 4");
panel1.add(wrapLayoutTabbedPane, "cell 0 4,width 100:100,height pref*2px");
//---- closableTabsLabel ----
closableTabsLabel.setText("Closable tabs");
closableTabsLabel.putClientProperty("FlatLaf.styleClass", "h3");
closableTabsLabel.putClientProperty(FlatClientProperties.STYLE_CLASS, "h3");
panel1.add(closableTabsLabel, "cell 0 5");
//======== closableTabsToolBar ========
@@ -572,19 +573,19 @@ class TabsPanel
//---- squareCloseButton ----
squareCloseButton.setText("square");
squareCloseButton.setSelected(true);
squareCloseButton.putClientProperty("FlatLaf.styleClass", "small");
squareCloseButton.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
squareCloseButton.addActionListener(e -> closeButtonStyleChanged());
closableTabsToolBar.add(squareCloseButton);
//---- circleCloseButton ----
circleCloseButton.setText("circle");
circleCloseButton.putClientProperty("FlatLaf.styleClass", "small");
circleCloseButton.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
circleCloseButton.addActionListener(e -> closeButtonStyleChanged());
closableTabsToolBar.add(circleCloseButton);
//---- redCrossCloseButton ----
redCrossCloseButton.setText("red cross");
redCrossCloseButton.putClientProperty("FlatLaf.styleClass", "small");
redCrossCloseButton.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
redCrossCloseButton.addActionListener(e -> closeButtonStyleChanged());
closableTabsToolBar.add(redCrossCloseButton);
}
@@ -593,7 +594,7 @@ class TabsPanel
//---- tabAreaComponentsLabel ----
tabAreaComponentsLabel.setText("Custom tab area components");
tabAreaComponentsLabel.putClientProperty("FlatLaf.styleClass", "h3");
tabAreaComponentsLabel.putClientProperty(FlatClientProperties.STYLE_CLASS, "h3");
panel1.add(tabAreaComponentsLabel, "cell 0 7");
//======== tabAreaComponentsToolBar ========
@@ -604,14 +605,14 @@ class TabsPanel
//---- leadingComponentButton ----
leadingComponentButton.setText("leading");
leadingComponentButton.setSelected(true);
leadingComponentButton.putClientProperty("FlatLaf.styleClass", "small");
leadingComponentButton.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
leadingComponentButton.addActionListener(e -> customComponentsChanged());
tabAreaComponentsToolBar.add(leadingComponentButton);
//---- trailingComponentButton ----
trailingComponentButton.setText("trailing");
trailingComponentButton.setSelected(true);
trailingComponentButton.putClientProperty("FlatLaf.styleClass", "small");
trailingComponentButton.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
trailingComponentButton.addActionListener(e -> customComponentsChanged());
tabAreaComponentsToolBar.add(trailingComponentButton);
}
@@ -642,13 +643,13 @@ class TabsPanel
//---- tabIconPlacementLabel ----
tabIconPlacementLabel.setText("Tab icon placement");
tabIconPlacementLabel.putClientProperty("FlatLaf.styleClass", "h3");
tabIconPlacementLabel.putClientProperty(FlatClientProperties.STYLE_CLASS, "h3");
panel2.add(tabIconPlacementLabel, "cell 0 0");
//---- tabIconPlacementNodeLabel ----
tabIconPlacementNodeLabel.setText("(top/bottom/leading/trailing)");
tabIconPlacementNodeLabel.setEnabled(false);
tabIconPlacementNodeLabel.putClientProperty("FlatLaf.styleClass", "small");
tabIconPlacementNodeLabel.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
panel2.add(tabIconPlacementNodeLabel, "cell 0 1");
panel2.add(iconTopTabbedPane, "cell 0 2");
panel2.add(iconBottomTabbedPane, "cell 0 3");
@@ -657,13 +658,13 @@ class TabsPanel
//---- tabAreaAlignmentLabel ----
tabAreaAlignmentLabel.setText("Tab area alignment");
tabAreaAlignmentLabel.putClientProperty("FlatLaf.styleClass", "h3");
tabAreaAlignmentLabel.putClientProperty(FlatClientProperties.STYLE_CLASS, "h3");
panel2.add(tabAreaAlignmentLabel, "cell 0 6");
//---- tabAreaAlignmentNoteLabel ----
tabAreaAlignmentNoteLabel.setText("(leading/center/trailing/fill)");
tabAreaAlignmentNoteLabel.setEnabled(false);
tabAreaAlignmentNoteLabel.putClientProperty("FlatLaf.styleClass", "small");
tabAreaAlignmentNoteLabel.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
panel2.add(tabAreaAlignmentNoteLabel, "cell 0 7");
panel2.add(alignLeadingTabbedPane, "cell 0 8");
panel2.add(alignCenterTabbedPane, "cell 0 9");
@@ -692,13 +693,13 @@ class TabsPanel
//---- tabWidthModeLabel ----
tabWidthModeLabel.setText("Tab width mode");
tabWidthModeLabel.putClientProperty("FlatLaf.styleClass", "h3");
tabWidthModeLabel.putClientProperty(FlatClientProperties.STYLE_CLASS, "h3");
panel3.add(tabWidthModeLabel, "cell 0 0");
//---- tabWidthModeNoteLabel ----
tabWidthModeNoteLabel.setText("(preferred/equal/compact)");
tabWidthModeNoteLabel.setEnabled(false);
tabWidthModeNoteLabel.putClientProperty("FlatLaf.styleClass", "small");
tabWidthModeNoteLabel.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
panel3.add(tabWidthModeNoteLabel, "cell 0 1");
panel3.add(widthPreferredTabbedPane, "cell 0 2");
panel3.add(widthEqualTabbedPane, "cell 0 3");
@@ -706,14 +707,14 @@ class TabsPanel
//---- minMaxTabWidthLabel ----
minMaxTabWidthLabel.setText("Minimum/maximum tab width");
minMaxTabWidthLabel.putClientProperty("FlatLaf.styleClass", "h3");
minMaxTabWidthLabel.putClientProperty(FlatClientProperties.STYLE_CLASS, "h3");
panel3.add(minMaxTabWidthLabel, "cell 0 5");
panel3.add(minimumTabWidthTabbedPane, "cell 0 6");
panel3.add(maximumTabWidthTabbedPane, "cell 0 7");
//---- tabAlignmentLabel ----
tabAlignmentLabel.setText("Tab title alignment");
tabAlignmentLabel.putClientProperty("FlatLaf.styleClass", "h3");
tabAlignmentLabel.putClientProperty(FlatClientProperties.STYLE_CLASS, "h3");
panel3.add(tabAlignmentLabel, "cell 0 8");
//======== panel5 ========
@@ -733,13 +734,13 @@ class TabsPanel
//---- tabAlignmentNoteLabel ----
tabAlignmentNoteLabel.setText("(leading/center/trailing)");
tabAlignmentNoteLabel.setEnabled(false);
tabAlignmentNoteLabel.putClientProperty("FlatLaf.styleClass", "small");
tabAlignmentNoteLabel.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
panel5.add(tabAlignmentNoteLabel, "cell 0 0");
//---- tabAlignmentNoteLabel2 ----
tabAlignmentNoteLabel2.setText("(trailing)");
tabAlignmentNoteLabel2.setEnabled(false);
tabAlignmentNoteLabel2.putClientProperty("FlatLaf.styleClass", "small");
tabAlignmentNoteLabel2.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
panel5.add(tabAlignmentNoteLabel2, "cell 1 0,alignx right,growx 0");
panel5.add(tabAlignLeadingTabbedPane, "cell 0 1");
@@ -787,19 +788,19 @@ class TabsPanel
//---- scrollAsNeededSingleButton ----
scrollAsNeededSingleButton.setText("asNeededSingle");
scrollAsNeededSingleButton.setSelected(true);
scrollAsNeededSingleButton.putClientProperty("FlatLaf.styleClass", "small");
scrollAsNeededSingleButton.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
scrollAsNeededSingleButton.addActionListener(e -> scrollButtonsPolicyChanged());
scrollButtonsPolicyToolBar.add(scrollAsNeededSingleButton);
//---- scrollAsNeededButton ----
scrollAsNeededButton.setText("asNeeded");
scrollAsNeededButton.putClientProperty("FlatLaf.styleClass", "small");
scrollAsNeededButton.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
scrollAsNeededButton.addActionListener(e -> scrollButtonsPolicyChanged());
scrollButtonsPolicyToolBar.add(scrollAsNeededButton);
//---- scrollNeverButton ----
scrollNeverButton.setText("never");
scrollNeverButton.putClientProperty("FlatLaf.styleClass", "small");
scrollNeverButton.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
scrollNeverButton.addActionListener(e -> scrollButtonsPolicyChanged());
scrollButtonsPolicyToolBar.add(scrollNeverButton);
}
@@ -817,13 +818,13 @@ class TabsPanel
//---- popupAsNeededButton ----
popupAsNeededButton.setText("asNeeded");
popupAsNeededButton.setSelected(true);
popupAsNeededButton.putClientProperty("FlatLaf.styleClass", "small");
popupAsNeededButton.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
popupAsNeededButton.addActionListener(e -> tabsPopupPolicyChanged());
tabsPopupPolicyToolBar.add(popupAsNeededButton);
//---- popupNeverButton ----
popupNeverButton.setText("never");
popupNeverButton.putClientProperty("FlatLaf.styleClass", "small");
popupNeverButton.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
popupNeverButton.addActionListener(e -> tabsPopupPolicyChanged());
tabsPopupPolicyToolBar.add(popupNeverButton);
}
@@ -846,13 +847,13 @@ class TabsPanel
//---- scrollBothButton ----
scrollBothButton.setText("both");
scrollBothButton.setSelected(true);
scrollBothButton.putClientProperty("FlatLaf.styleClass", "small");
scrollBothButton.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
scrollBothButton.addActionListener(e -> scrollButtonsPlacementChanged());
scrollButtonsPlacementToolBar.add(scrollBothButton);
//---- scrollTrailingButton ----
scrollTrailingButton.setText("trailing");
scrollTrailingButton.putClientProperty("FlatLaf.styleClass", "small");
scrollTrailingButton.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
scrollTrailingButton.addActionListener(e -> scrollButtonsPlacementChanged());
scrollButtonsPlacementToolBar.add(scrollTrailingButton);
}
@@ -869,13 +870,13 @@ class TabsPanel
//---- underlinedTabTypeButton ----
underlinedTabTypeButton.setText("underlined");
underlinedTabTypeButton.setSelected(true);
underlinedTabTypeButton.putClientProperty("FlatLaf.styleClass", "small");
underlinedTabTypeButton.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
underlinedTabTypeButton.addActionListener(e -> tabTypeChanged());
tabTypeToolBar.add(underlinedTabTypeButton);
//---- cardTabTypeButton ----
cardTabTypeButton.setText("card");
cardTabTypeButton.putClientProperty("FlatLaf.styleClass", "small");
cardTabTypeButton.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
cardTabTypeButton.addActionListener(e -> tabTypeChanged());
tabTypeToolBar.add(cardTabTypeButton);
}
@@ -893,25 +894,25 @@ class TabsPanel
//---- rotationNoneButton ----
rotationNoneButton.setText("none");
rotationNoneButton.setSelected(true);
rotationNoneButton.putClientProperty("FlatLaf.styleClass", "small");
rotationNoneButton.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
rotationNoneButton.addActionListener(e -> tabRotationChanged());
tabRotationToolBar.add(rotationNoneButton);
//---- rotationAutoButton ----
rotationAutoButton.setText("auto");
rotationAutoButton.putClientProperty("FlatLaf.styleClass", "small");
rotationAutoButton.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
rotationAutoButton.addActionListener(e -> tabRotationChanged());
tabRotationToolBar.add(rotationAutoButton);
//---- rotationLeftButton ----
rotationLeftButton.setText("left");
rotationLeftButton.putClientProperty("FlatLaf.styleClass", "small");
rotationLeftButton.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
rotationLeftButton.addActionListener(e -> tabRotationChanged());
tabRotationToolBar.add(rotationLeftButton);
//---- rotationRightButton ----
rotationRightButton.setText("right");
rotationRightButton.putClientProperty("FlatLaf.styleClass", "small");
rotationRightButton.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
rotationRightButton.addActionListener(e -> tabRotationChanged());
tabRotationToolBar.add(rotationRightButton);
}

View File

@@ -45,6 +45,7 @@ import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.event.*;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatDarculaLaf;
import com.formdev.flatlaf.FlatDarkLaf;
import com.formdev.flatlaf.FlatIntelliJLaf;
@@ -554,7 +555,7 @@ public class IJThemesPanel
"light",
"dark"
}));
filterComboBox.putClientProperty("JComponent.minimumWidth", 0);
filterComboBox.putClientProperty(FlatClientProperties.MINIMUM_WIDTH, 0);
filterComboBox.setFocusable(false);
filterComboBox.addActionListener(e -> filterChanged());
add(filterComboBox, "cell 0 0,alignx right,growx 0");

View File

@@ -24,6 +24,7 @@ import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GraphicsConfiguration;
import java.awt.Insets;
import java.awt.KeyboardFocusManager;
import java.awt.LayoutManager;
@@ -124,9 +125,12 @@ public class FlatInspector
* Installs a key listener into the application that allows enabling and disabling
* the UI inspector with the given keystroke (e.g. "ctrl shift alt X").
*
* @param activationKeys a keystroke (e.g. "ctrl shift alt X")
* @param activationKeys a keystroke (e.g. "ctrl shift alt X"), or {@code null} to use "ctrl shift alt X"
*/
public static void install( String activationKeys ) {
if( activationKeys == null )
activationKeys = "ctrl shift alt X";
KeyStroke keyStroke = KeyStroke.getKeyStroke( activationKeys );
Toolkit.getDefaultToolkit().addAWTEventListener( e -> {
if( e.getID() == KeyEvent.KEY_RELEASED &&
@@ -450,15 +454,18 @@ public class FlatInspector
Dimension size = tip.getPreferredSize();
// position the tip in the visible area
Rectangle visibleRect = rootPane.getGraphicsConfiguration().getBounds();
if( tx + size.width > visibleRect.x + visibleRect.width )
tx -= size.width + UIScale.scale( 16 );
if( ty + size.height > visibleRect.y + visibleRect.height )
ty -= size.height + UIScale.scale( 32 );
if( tx < visibleRect.x )
tx = visibleRect.x;
if( ty < visibleRect.y )
ty = visibleRect.y;
GraphicsConfiguration gc = rootPane.getGraphicsConfiguration();
if( gc != null ) {
Rectangle visibleRect = gc.getBounds();
if( tx + size.width > visibleRect.x + visibleRect.width )
tx -= size.width + UIScale.scale( 16 );
if( ty + size.height > visibleRect.y + visibleRect.height )
ty -= size.height + UIScale.scale( 32 );
if( tx < visibleRect.x )
tx = visibleRect.x;
if( ty < visibleRect.y )
ty = visibleRect.y;
}
PopupFactory popupFactory = PopupFactory.getSharedInstance();
popup = popupFactory.getPopup( c, tip, tx, ty );

View File

@@ -37,6 +37,7 @@ import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.Function;
import javax.swing.Icon;
import javax.swing.ImageIcon;
@@ -588,7 +589,12 @@ public class FlatSVGIcon
: GrayFilter.createDisabledIconFilter( dark );
}
Graphics2D g2 = new GraphicsFilter( (Graphics2D) g.create(), colorFilter, ColorFilter.getInstance(), grayFilter );
ColorFilter globalColorFilter = ColorFilter.getInstance();
globalColorFilter.c = c;
if( colorFilter != null )
colorFilter.c = c;
Graphics2D g2 = new GraphicsFilter( (Graphics2D) g.create(), colorFilter, globalColorFilter, grayFilter );
try {
setRenderingHints( g2 );
@@ -596,6 +602,10 @@ public class FlatSVGIcon
paintSvg( g2, x, y );
} finally {
g2.dispose();
globalColorFilter.c = null;
if( colorFilter != null )
colorFilter.c = null;
}
}
@@ -760,6 +770,8 @@ public class FlatSVGIcon
private Map<Color, Color> colorMap;
private Map<Color, Color> darkColorMap;
private Function<Color, Color> mapper;
private BiFunction<Component, Color, Color> mapperEx;
private Component c;
/**
* Returns the global ColorFilter that is applied to all icons.
@@ -800,6 +812,22 @@ public class FlatSVGIcon
setMapper( mapper );
}
/**
* Creates a color modifying function that changes painted colors.
* The {@link BiFunction} gets passed the component and
* the original color and returns a modified one.
* <p>
* Examples:
* A ColorFilter can be used to brighten colors of the icon (depending on component state if desired):
* <pre>new ColorFilter( (c, color) -&gt; c.isEnabled() ? color.brighter() : color );</pre>
*
* @param mapperEx The color mapper function
* @since 3.6
*/
public ColorFilter( BiFunction<Component, Color, Color> mapperEx ) {
setMapperEx( mapperEx );
}
/**
* Returns a color modifying function or {@code null}
*
@@ -821,12 +849,39 @@ public class FlatSVGIcon
* <pre>filter.setMapper( color -&gt; Color.RED );</pre>
*
* @param mapper The color mapper function
* @see #setMapperEx(BiFunction)
* @since 1.2
*/
public void setMapper( Function<Color, Color> mapper ) {
this.mapper = mapper;
}
/**
* Returns a color modifying function or {@code null}
*
* @since 3.6
*/
public BiFunction<Component, Color, Color> getMapperEx() {
return mapperEx;
}
/**
* Sets a color modifying function that changes painted colors.
* The {@link BiFunction} gets passed the component and
* the original color and returns a modified one.
* <p>
* Examples:
* A ColorFilter can be used to brighten colors of the icon (depending on component state if desired):
* <pre>filter.setMapperEx( (c, color) -&gt; c.isEnabled() ? color.brighter() : color );</pre>
*
* @param mapperEx The color mapper function
* @see #setMapper(Function)
* @since 3.6
*/
public void setMapperEx( BiFunction<Component, Color, Color> mapperEx ) {
this.mapperEx = mapperEx;
}
/**
* Returns the color mappings used for light themes.
*
@@ -936,6 +991,11 @@ public class FlatSVGIcon
}
public Color filter( Color color ) {
return filter( c, color );
}
/** @since 3.6 */
public Color filter( Component c, Color color ) {
// apply mappings
color = applyMappings( color );
@@ -943,6 +1003,10 @@ public class FlatSVGIcon
if( mapper != null )
color = mapper.apply( color );
// apply mapperEx function
if( mapperEx != null )
color = mapperEx.apply( c, color );
return color;
}
@@ -974,6 +1038,16 @@ public class FlatSVGIcon
return color;
}
/**
* Returns the component passed to {@link FlatSVGIcon#paintIcon(Component, Graphics, int, int)}.
* This allows color mapping depend on component state (e.g. enabled, selected, hover, etc).
*
* @since 3.6
*/
public Component getPaintingComponent() {
return c;
}
/**
* Creates a color modifying function that uses {@link RGBImageFilter#filterRGB(int, int, int)}.
* Can be set to a {@link ColorFilter} using {@link ColorFilter#setMapper(Function)}.

View File

@@ -85,9 +85,12 @@ public class FlatUIDefaultsInspector
* Installs a key listener into the application that allows enabling and disabling
* the UI inspector with the given keystroke (e.g. "ctrl shift alt Y").
*
* @param activationKeys a keystroke (e.g. "ctrl shift alt Y")
* @param activationKeys a keystroke (e.g. "ctrl shift alt Y"), or {@code null} to use "ctrl shift alt Y"
*/
public static void install( String activationKeys ) {
if( activationKeys == null )
activationKeys = "ctrl shift alt Y";
KeyStroke keyStroke = KeyStroke.getKeyStroke( activationKeys );
Toolkit.getDefaultToolkit().addAWTEventListener( e -> {
if( e.getID() == KeyEvent.KEY_RELEASED &&

View File

@@ -29,19 +29,37 @@ public class FlatTree
implements FlatComponentExtension, FlatStyleableComponent
{
/**
* Returns if the tree shows a wide selection
* Returns whether tree shows a wide selection
*/
public boolean isWideSelection() {
return getClientPropertyBoolean( TREE_WIDE_SELECTION, "Tree.wideSelection" );
}
/**
* Sets if the tree shows a wide selection
* Specifies whether tree shows a wide selection
*/
public void setWideSelection( boolean wideSelection ) {
putClientProperty( TREE_WIDE_SELECTION, wideSelection );
}
/**
* Returns whether tree uses a wide cell renderer.
*
* @since 3.6
*/
public boolean isWideCellRenderer() {
return getClientPropertyBoolean( TREE_WIDE_CELL_RENDERER, "Tree.wideCellRenderer" );
}
/**
* Specifies whether tree uses a wide cell renderer.
*
* @since 3.6
*/
public void setWideCellRenderer( boolean wideCellRenderer ) {
putClientProperty( TREE_WIDE_CELL_RENDERER, wideCellRenderer );
}
/**
* Returns whether tree item selection is painted. Default is {@code true}.
* If set to {@code false}, then the tree cell renderer is responsible for painting selection.

View File

@@ -62,6 +62,9 @@ CheckBox.icon.pressedBackground = CheckBox.icon.background
CheckBox.icon.focusedSelectedBackground = CheckBox.icon.selectedBackground
CheckBox.icon.hoverSelectedBackground = CheckBox.icon.selectedBackground
CheckBox.icon.pressedSelectedBackground = CheckBox.icon.selectedBackground
CheckBox.icon.focusedIndeterminateBackground = CheckBox.icon.indeterminateBackground
CheckBox.icon.hoverIndeterminateBackground = CheckBox.icon.indeterminateBackground
CheckBox.icon.pressedIndeterminateBackground = CheckBox.icon.indeterminateBackground
CheckBox.icon[filled].disabledBackground = CheckBox.icon[filled].background
CheckBox.icon[filled].focusedBackground = CheckBox.icon[filled].background
@@ -70,7 +73,9 @@ CheckBox.icon[filled].pressedBackground = CheckBox.icon[filled].background
CheckBox.icon[filled].focusedSelectedBackground = CheckBox.icon[filled].selectedBackground
CheckBox.icon[filled].hoverSelectedBackground = CheckBox.icon[filled].selectedBackground
CheckBox.icon[filled].pressedSelectedBackground = CheckBox.icon[filled].selectedBackground
CheckBox.icon[filled].focusedIndeterminateBackground = CheckBox.icon[filled].indeterminateBackground
CheckBox.icon[filled].hoverIndeterminateBackground = CheckBox.icon[filled].indeterminateBackground
CheckBox.icon[filled].pressedIndeterminateBackground = CheckBox.icon[filled].indeterminateBackground
#---- CheckBoxMenuItem ----

View File

@@ -23,6 +23,7 @@ import javax.swing.LookAndFeel;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.UIDefaults.ActiveValue;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatDefaultsAddon;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.jideoss.ui.FlatJidePainter;
@@ -55,8 +56,8 @@ public class FlatJideOssDefaultsAddon
public void afterDefaultsLoading( LookAndFeel laf, UIDefaults defaults ) {
// TristateCheckBox
defaults.put( "TristateCheckBox.icon", null );
defaults.put( "TristateCheckBox.setMixed.clientProperty", new Object[] { "JButton.selectedState", "indeterminate" } );
defaults.put( "TristateCheckBox.clearMixed.clientProperty", new Object[] { "JButton.selectedState", null } );
defaults.put( "TristateCheckBox.setMixed.clientProperty", new Object[] { FlatClientProperties.SELECTED_STATE, FlatClientProperties.SELECTED_STATE_INDETERMINATE } );
defaults.put( "TristateCheckBox.clearMixed.clientProperty", new Object[] { FlatClientProperties.SELECTED_STATE, null } );
}
@Override

View File

@@ -309,6 +309,8 @@ public class FlatWindowsNativeWindowBorder
WM_ENTERSIZEMOVE = 0x0231,
WM_EXITSIZEMOVE = 0x0232,
WM_DPICHANGED = 0x02E0,
WM_DWMCOLORIZATIONCOLORCHANGED = 0x0320;
// WM_SIZE wParam
@@ -501,6 +503,22 @@ public class FlatWindowsNativeWindowBorder
isMoving = true;
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:
// do not erase background while the user is moving the window,
// 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);
}
/**
* 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.
*/
@@ -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 -------------------------------------------------
@FieldOrder( { "cbSize", "fMask", "fType", "fState", "wID", "hSubMenu",

View File

@@ -5,12 +5,15 @@ This sub-project contains the source code for the FlatLaf Linux native library.
The native library can be built only on Linux and requires a C++ compiler.
The native library is available for following CPU architectures: `x86_64` (or
`amd64`) and `arm64` (or `aarch64`).
To be able to build FlatLaf on any platform, and without C++ compiler, the
pre-built native library is checked into Git at
pre-built native libraries are checked into Git at
[flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/](https://github.com/JFormDesigner/FlatLaf/tree/main/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives).
The native library was built on a GitHub server with the help of GitHub Actions.
See:
The native libraries were built on a GitHub server with the help of GitHub
Actions. See:
[Native Libraries](https://github.com/JFormDesigner/FlatLaf/actions/workflows/natives.yml)
workflow. Then the produced Artifacts ZIP was downloaded and the native library
checked into Git.
@@ -18,19 +21,27 @@ checked into Git.
## Development
To build the library on Linux, some packages needs to be installed.
To build the library on Linux, some packages needs to be installed:
- `build-essential` - GCC and development tools
- `libxt-dev` - X11 toolkit development headers
- `g++-aarch64-linux-gnu` - GNU C++ compiler for the arm64 architecture (only on
x86_64 Linux for cross-compiling for arm64 architecture)
### Ubuntu
`build-essential` contains GCC and development tools. `libxt-dev` contains the
X11 toolkit development headers.
~~~
sudo apt update
sudo apt install build-essential libxt-dev
~~~
Only on x86_64 Linux for cross-compiling for arm64 architecture:
~~~
sudo apt install g++-aarch64-linux-gnu
~~~
### CentOS

View File

@@ -14,6 +14,8 @@
* limitations under the License.
*/
import java.io.FileOutputStream
plugins {
`cpp-library`
`flatlaf-cpp-library`
@@ -28,11 +30,14 @@ flatlafJniHeaders {
}
library {
targetMachines = listOf( machines.linux.x86_64 )
targetMachines = listOf(
machines.linux.x86_64,
machines.linux.architecture( "aarch64" ),
)
}
var javaHome = System.getProperty( "java.home" )
if( javaHome.endsWith( "jre" ) )
if( javaHome.endsWith( "jre" ) && !file( "${javaHome}/include" ).exists() )
javaHome += "/.."
tasks {
@@ -40,8 +45,16 @@ tasks {
group = "build"
description = "Builds natives"
if( org.gradle.internal.os.OperatingSystem.current().isLinux )
dependsOn( "linkRelease" )
if( org.gradle.internal.os.OperatingSystem.current().isLinux ) {
val osArch = System.getProperty( "os.arch" )
if( osArch == "amd64" ) {
dependsOn( "linkReleaseX86-64" )
if( file( "/usr/bin/aarch64-linux-gnu-gcc" ).exists() )
dependsOn( "linkCrossAarch64" )
}
if( osArch == "aarch64" )
dependsOn( "linkReleaseAarch64" )
}
}
withType<CppCompile>().configureEach {
@@ -67,7 +80,7 @@ tasks {
onlyIf { name.contains( "Release" ) }
val nativesDir = project( ":flatlaf-core" ).projectDir.resolve( "src/main/resources/com/formdev/flatlaf/natives" )
val libraryName = "libflatlaf-linux-x86_64.so"
val libraryName = if( name.contains( "X86-64" ) ) "libflatlaf-linux-x86_64.so" else "libflatlaf-linux-arm64.so"
val jawt = "jawt"
var jawtPath = "${javaHome}/lib"
if( JavaVersion.current() == JavaVersion.VERSION_1_8 )
@@ -85,8 +98,103 @@ tasks {
copy {
from( linkedFile )
into( nativesDir )
rename( "libflatlaf-natives-linux.so", libraryName )
rename( linkedFile.get().asFile.name, libraryName )
}
// dump( linkedFile.asFile.get(), true )
}
}
if( org.gradle.internal.os.OperatingSystem.current().isLinux &&
System.getProperty( "os.arch" ) == "amd64" &&
file( "/usr/bin/aarch64-linux-gnu-gcc" ).exists() )
{
register<Exec>( "compileCrossAarch64Cpp" ) {
val include = layout.projectDirectory.dir( "src/main/headers" )
val src = layout.projectDirectory.dir( "src/main/cpp" )
workingDir = file( layout.buildDirectory.dir( "obj/main/release/aarch64-cross" ) )
doFirst {
workingDir.mkdirs()
}
commandLine = listOf(
"aarch64-linux-gnu-gcc",
"-c",
"-fPIC",
"-fvisibility=hidden",
"-O3",
"-I", "${javaHome}/include",
"-I", "${javaHome}/include/linux",
"-I", "$include",
"$src/ApiVersion.cpp",
"$src/X11WmUtils.cpp",
)
}
register<Exec>( "linkCrossAarch64" ) {
dependsOn( "compileCrossAarch64Cpp" )
val nativesDir = project( ":flatlaf-core" ).projectDir.resolve( "src/main/resources/com/formdev/flatlaf/natives" )
val libraryName = "libflatlaf-linux-arm64.so"
val outDir = file( layout.buildDirectory.dir( "lib/main/release/aarch64-cross" ) )
val objDir = file( layout.buildDirectory.dir( "obj/main/release/aarch64-cross" ) )
doFirst {
outDir.mkdirs()
}
commandLine = listOf(
"aarch64-linux-gnu-gcc",
"-shared",
"-Wl,-soname,$libraryName",
"-o", "$outDir/$libraryName",
"$objDir/ApiVersion.o",
"$objDir/X11WmUtils.o",
"-L${layout.projectDirectory}/lib/aarch64",
"-ljawt",
)
doLast {
// copy shared library to flatlaf-core resources
copy {
from( "$outDir/$libraryName" )
into( nativesDir )
}
// dump( file( "$outDir/$libraryName" ), false )
}
}
}
}
/*dump
interface InjectedExecOps { @get:Inject val execOps: ExecOperations }
val injected = project.objects.newInstance<InjectedExecOps>()
fun dump( dylib: File, disassemble: Boolean ) {
val dylibDir = dylib.parent
injected.execOps.exec { commandLine( "size", dylib ); standardOutput = FileOutputStream( "$dylibDir/size.txt" ) }
injected.execOps.exec {
commandLine( "objdump",
// commands
"--archive-headers",
"--section-headers",
"--private-headers",
"--reloc",
"--dynamic-reloc",
"--syms",
// files
dylib )
standardOutput = FileOutputStream( "$dylibDir/objdump.txt" )
}
if( disassemble )
injected.execOps.exec { commandLine( "objdump", "--disassemble-all", dylib ); standardOutput = FileOutputStream( "$dylibDir/disassemble.txt" ) }
injected.execOps.exec { commandLine( "objdump", "--full-contents", dylib ); standardOutput = FileOutputStream( "$dylibDir/full-contents.txt" ) }
injected.execOps.exec { commandLine( "hexdump", dylib ); standardOutput = FileOutputStream( "$dylibDir/hexdump.txt" ) }
}
dump*/

View File

@@ -0,0 +1,4 @@
Contains libraries used to compile FlatLaf native libraries.
- `aarch64/libjawt.so` is `<jdk>/lib/libjawt.so` from Eclipse Temurin 11.0.25+9 aarch64,
which is required to cross build aarch64/arm64 .so on x86_64

View File

@@ -43,6 +43,9 @@ var javaHome = System.getProperty( "java.home" )
if( javaHome.endsWith( "jre" ) )
javaHome += "/.."
interface InjectedExecOps { @get:Inject val execOps: ExecOperations }
val injected = project.objects.newInstance<InjectedExecOps>()
tasks {
register( "build-natives" ) {
group = "build"
@@ -95,21 +98,21 @@ tasks {
doLast {
// sign shared library
// exec { commandLine( "codesign", "-s", "FormDev Software GmbH", "--timestamp", "${linkedFile.asFile.get()}" ) }
// injected.execOps.exec { commandLine( "codesign", "-s", "FormDev Software GmbH", "--timestamp", "${linkedFile.asFile.get()}" ) }
// copy shared library to flatlaf-core resources
copy {
from( linkedFile )
into( nativesDir )
rename( "libflatlaf-natives-macos.dylib", libraryName )
rename( linkedFile.get().asFile.name, libraryName )
}
/*dump
val dylib = linkedFile.asFile.get()
val dylibDir = dylib.parent
exec { commandLine( "size", dylib ) }
exec { commandLine( "size", "-m", dylib ) }
exec {
injected.execOps.exec { commandLine( "size", dylib ); standardOutput = FileOutputStream( "$dylibDir/size.txt" ) }
injected.execOps.exec { commandLine( "size", "-m", dylib ); standardOutput = FileOutputStream( "$dylibDir/size-m.txt" ) }
injected.execOps.exec {
commandLine( "objdump",
// commands
"--archive-headers",
@@ -127,8 +130,8 @@ tasks {
dylib )
standardOutput = FileOutputStream( "$dylibDir/objdump.txt" )
}
exec { commandLine( "objdump", "--disassemble-all", dylib ); standardOutput = FileOutputStream( "$dylibDir/disassemble.txt" ) }
exec { commandLine( "objdump", "--full-contents", dylib ); standardOutput = FileOutputStream( "$dylibDir/full-contents.txt" ) }
injected.execOps.exec { commandLine( "objdump", "--disassemble-all", dylib ); standardOutput = FileOutputStream( "$dylibDir/disassemble.txt" ) }
injected.execOps.exec { commandLine( "objdump", "--full-contents", dylib ); standardOutput = FileOutputStream( "$dylibDir/full-contents.txt" ) }
dump*/
}
}

View File

@@ -29,15 +29,21 @@
#endif
#define JNI_COCOA_TRY() \
@try {
#define JNI_COCOA_CATCH() \
} @catch( NSException *ex ) { \
NSLog( @"Exception: %@\nReason: %@\nUser Info: %@\nStack: %@", \
[ex name], [ex reason], [ex userInfo], [ex callStackSymbols] ); \
}
#define JNI_COCOA_ENTER() \
@autoreleasepool { \
@try {
JNI_COCOA_TRY()
#define JNI_COCOA_EXIT() \
} @catch( NSException *ex ) { \
NSLog( @"Exception: %@\nReason: %@\nUser Info: %@\nStack: %@", \
[ex name], [ex reason], [ex userInfo], [ex callStackSymbols] ); \
} \
JNI_COCOA_CATCH() \
}

View File

@@ -100,10 +100,13 @@ JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_setW
return FALSE;
[FlatJNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){
JNI_COCOA_TRY()
nsWindow.hasShadow = YES;
nsWindow.contentView.wantsLayer = YES;
nsWindow.contentView.layer.cornerRadius = radius;
nsWindow.contentView.layer.masksToBounds = YES;
nsWindow.contentView.layer.opaque = NO;
nsWindow.contentView.layer.borderWidth = borderWidth;
if( borderWidth > 0 ) {
@@ -120,6 +123,8 @@ JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_setW
[nsWindow.contentView.layer removeAllAnimations];
[nsWindow invalidateShadow];
JNI_COCOA_CATCH()
}];
return TRUE;
@@ -157,6 +162,8 @@ JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_setW
WindowData* windowData = getWindowData( nsWindow, true );
[FlatJNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){
JNI_COCOA_TRY()
// NSLog( @"\n%@\n\n", [nsWindow.contentView.superview _subtreeDescription] );
// add/remove toolbar
@@ -235,6 +242,8 @@ JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_setW
windowData.didExitFullScreenObserver = nil;
}
}
JNI_COCOA_CATCH()
}];
return TRUE;

View File

@@ -8,8 +8,8 @@ The native library can be built only on Windows and requires a C++ compiler.
Tested with Microsoft Visual C++ (MSVC) 2019 and 2022 (comes with Visual Studio
2019 and 2022).
The native library is available for folloging CPU architectures: `x86_64` (or
`amd64`), `x86` and `arm64`.
The native library is available for following CPU architectures: `x86_64` (or
`amd64`), `x86` and `arm64` (or `aarch64`).
To be able to build FlatLaf on any platform, and without C++ compiler, the
pre-built DLLs are checked into Git at
@@ -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)
workflow. Then the produced Artifacts ZIP was downloaded, signed DLLs with
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.

View File

@@ -91,7 +91,7 @@ tasks {
copy {
from( linkedFile )
into( nativesDir )
rename( "flatlaf-natives-windows.dll", libraryName )
rename( linkedFile.get().asFile.name, libraryName )
}
}
}

View File

@@ -288,6 +288,23 @@ LRESULT CALLBACK FlatWndProc::WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, L
isMoving = true;
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:
// do not erase background while the user is moving the window,
// otherwise there may be rendering artifacts on HiDPI screens with Java 9+

View File

@@ -30,12 +30,26 @@ HWND getWindowHandle( JNIEnv* env, jobject window );
//---- Utility ----------------------------------------------------------------
typedef LONG (WINAPI *RtlGetVersion_Type)( OSVERSIONINFO* );
extern "C"
JNIEXPORT jlong JNICALL Java_com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_getOSBuildNumberImpl
( JNIEnv* env, jclass cls )
{
OSVERSIONINFO 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 ) )
return 0;
return info.dwBuildNumber;

View File

@@ -1,12 +1,11 @@
- Java 1.8.0_202
+ Java 1.8.0_292
+ Java 1.8.0_322
- OS Windows 10
+ OS Mac OS X
#---- ComboBox ----
+ ComboBox.roundedBorderWidth 1
+ ComboBox.showPopupOnNavigation true
@@ -47,16 +46,6 @@
+ OptionPane.isYesLast true
#---- Popup ----
+ Popup.roundedBorderWidth 1
#---- PopupMenu ----
+ PopupMenu.roundedBorderWidth 1
#---- ProgressBar ----
- ProgressBar.font [active] Segoe UI plain 10 javax.swing.plaf.FontUIResource [UI]
@@ -88,11 +77,6 @@
- TitlePane.small.font [active] Segoe UI plain 11 javax.swing.plaf.FontUIResource [UI]
+ TitlePane.small.font [active] Helvetica Neue plain 12 javax.swing.plaf.FontUIResource [UI]
#---- ToolTip ----
+ ToolTip.roundedBorderWidth 1
- defaultFont Segoe UI plain 12 javax.swing.plaf.FontUIResource [UI]
+ defaultFont Helvetica Neue plain 13 javax.swing.plaf.FontUIResource [UI]

View File

@@ -222,6 +222,7 @@ ComboBox.minimumWidth 72
ComboBox.noActionOnKeyNavigation false
ComboBox.padding 2,6,2,6 javax.swing.plaf.InsetsUIResource [UI]
ComboBox.popupInsets 0,0,0,0 javax.swing.plaf.InsetsUIResource [UI]
ComboBox.roundedBorderWidth 1
ComboBox.selectionArc 0
ComboBox.selectionBackground #4b6eaf HSL 219 40 49 javax.swing.plaf.ColorUIResource [UI]
ComboBox.selectionForeground #bbbbbb HSL 0 0 73 javax.swing.plaf.ColorUIResource [UI]
@@ -744,6 +745,7 @@ Popup.dropShadowColor #000000 HSL 0 0 0 javax.swing.plaf.Colo
Popup.dropShadowInsets -4,-4,4,4 javax.swing.plaf.InsetsUIResource [UI]
Popup.dropShadowOpacity 0.25
Popup.dropShadowPainted true
Popup.roundedBorderWidth 1
#---- PopupMenu ----
@@ -757,6 +759,7 @@ PopupMenu.consumeEventOnClose false
PopupMenu.font [active] $defaultFont [UI]
PopupMenu.foreground #bbbbbb HSL 0 0 73 javax.swing.plaf.ColorUIResource [UI]
PopupMenu.hoverScrollArrowBackground #484c4e HSL 200 4 29 javax.swing.plaf.ColorUIResource [UI]
PopupMenu.roundedBorderWidth 1
PopupMenu.scrollArrowColor #9b9b9b HSL 0 0 61 javax.swing.plaf.ColorUIResource [UI]
@@ -1375,6 +1378,7 @@ ToolTip.border [lazy] 4,6,4,6 false com.formdev.flatlaf.ui.F
ToolTip.borderCornerRadius 4
ToolTip.font [active] $defaultFont [UI]
ToolTip.foreground #bbbbbb HSL 0 0 73 javax.swing.plaf.ColorUIResource [UI]
ToolTip.roundedBorderWidth 1
#---- ToolTipManager ----
@@ -1431,6 +1435,7 @@ Tree.showDefaultIcons false
Tree.textBackground #46494b HSL 204 3 28 javax.swing.plaf.ColorUIResource [UI]
Tree.textForeground #bbbbbb HSL 0 0 73 javax.swing.plaf.ColorUIResource [UI]
Tree.timeFactor 1000
Tree.wideCellRenderer false
Tree.wideSelection true
TreeUI com.formdev.flatlaf.ui.FlatTreeUI

View File

@@ -1,12 +1,14 @@
- Java 1.8.0_202
+ Java 1.8.0_292
+ Java 1.8.0_322
- OS Windows 10
+ OS Mac OS X
#---- ComboBox ----
- ComboBox.roundedBorderWidth 1
+ ComboBox.roundedBorderWidth 0
+ ComboBox.showPopupOnNavigation true
@@ -49,11 +51,13 @@
#---- Popup ----
- Popup.roundedBorderWidth 1
+ Popup.roundedBorderWidth 0
#---- PopupMenu ----
- PopupMenu.roundedBorderWidth 1
+ PopupMenu.roundedBorderWidth 0
@@ -92,6 +96,7 @@
#---- ToolTip ----
- ToolTip.roundedBorderWidth 1
+ ToolTip.roundedBorderWidth 0
- defaultFont Segoe UI plain 12 javax.swing.plaf.FontUIResource [UI]
+ defaultFont Helvetica Neue plain 13 javax.swing.plaf.FontUIResource [UI]

View File

@@ -226,6 +226,7 @@ ComboBox.minimumWidth 72
ComboBox.noActionOnKeyNavigation false
ComboBox.padding 2,6,2,6 javax.swing.plaf.InsetsUIResource [UI]
ComboBox.popupInsets 0,0,0,0 javax.swing.plaf.InsetsUIResource [UI]
ComboBox.roundedBorderWidth 1
ComboBox.selectionArc 0
ComboBox.selectionBackground #2675bf HSL 209 67 45 javax.swing.plaf.ColorUIResource [UI]
ComboBox.selectionForeground #ffffff HSL 0 0 100 javax.swing.plaf.ColorUIResource [UI]
@@ -749,6 +750,7 @@ Popup.dropShadowColor #000000 HSL 0 0 0 javax.swing.plaf.Colo
Popup.dropShadowInsets -4,-4,4,4 javax.swing.plaf.InsetsUIResource [UI]
Popup.dropShadowOpacity 0.15
Popup.dropShadowPainted true
Popup.roundedBorderWidth 1
#---- PopupMenu ----
@@ -762,6 +764,7 @@ PopupMenu.consumeEventOnClose false
PopupMenu.font [active] $defaultFont [UI]
PopupMenu.foreground #000000 HSL 0 0 0 javax.swing.plaf.ColorUIResource [UI]
PopupMenu.hoverScrollArrowBackground #e5e5e5 HSL 0 0 90 javax.swing.plaf.ColorUIResource [UI]
PopupMenu.roundedBorderWidth 1
PopupMenu.scrollArrowColor #666666 HSL 0 0 40 javax.swing.plaf.ColorUIResource [UI]
@@ -1380,6 +1383,7 @@ ToolTip.border [lazy] 4,6,4,6 false com.formdev.flatlaf.ui.F
ToolTip.borderCornerRadius 4
ToolTip.font [active] $defaultFont [UI]
ToolTip.foreground #000000 HSL 0 0 0 javax.swing.plaf.ColorUIResource [UI]
ToolTip.roundedBorderWidth 1
#---- ToolTipManager ----
@@ -1436,6 +1440,7 @@ Tree.showDefaultIcons false
Tree.textBackground #ffffff HSL 0 0 100 javax.swing.plaf.ColorUIResource [UI]
Tree.textForeground #000000 HSL 0 0 0 javax.swing.plaf.ColorUIResource [UI]
Tree.timeFactor 1000
Tree.wideCellRenderer false
Tree.wideSelection true
TreeUI com.formdev.flatlaf.ui.FlatTreeUI

View File

@@ -228,6 +228,7 @@ ComboBox.noActionOnKeyNavigation false
ComboBox.padding 2,6,2,6 javax.swing.plaf.InsetsUIResource [UI]
ComboBox.popupBackground #323232 HSL 0 0 20 javax.swing.plaf.ColorUIResource [UI]
ComboBox.popupInsets 5,0,5,0 javax.swing.plaf.InsetsUIResource [UI]
ComboBox.roundedBorderWidth 1
ComboBox.selectionArc 8
ComboBox.selectionBackground #1458b8 HSL 215 80 40 javax.swing.plaf.ColorUIResource [UI]
ComboBox.selectionForeground #ffffff HSL 0 0 100 javax.swing.plaf.ColorUIResource [UI]
@@ -752,6 +753,7 @@ Popup.dropShadowColor #000000 HSL 0 0 0 javax.swing.plaf.Colo
Popup.dropShadowInsets -4,-4,4,4 javax.swing.plaf.InsetsUIResource [UI]
Popup.dropShadowOpacity 0.25
Popup.dropShadowPainted true
Popup.roundedBorderWidth 1
#---- PopupMenu ----
@@ -765,6 +767,7 @@ PopupMenu.consumeEventOnClose false
PopupMenu.font [active] $defaultFont [UI]
PopupMenu.foreground #dddddd HSL 0 0 87 javax.swing.plaf.ColorUIResource [UI]
PopupMenu.hoverScrollArrowBackground #2b2b2b HSL 0 0 17 javax.swing.plaf.ColorUIResource [UI]
PopupMenu.roundedBorderWidth 1
PopupMenu.scrollArrowColor #b7b7b7 HSL 0 0 72 javax.swing.plaf.ColorUIResource [UI]
@@ -1385,6 +1388,7 @@ ToolTip.border [lazy] 4,6,4,6 false com.formdev.flatlaf.ui.F
ToolTip.borderCornerRadius 4
ToolTip.font [active] $defaultFont [UI]
ToolTip.foreground #dddddd HSL 0 0 87 javax.swing.plaf.ColorUIResource [UI]
ToolTip.roundedBorderWidth 1
#---- ToolTipManager ----
@@ -1441,6 +1445,7 @@ Tree.showDefaultIcons false
Tree.textBackground #282828 HSL 0 0 16 javax.swing.plaf.ColorUIResource [UI]
Tree.textForeground #dddddd HSL 0 0 87 javax.swing.plaf.ColorUIResource [UI]
Tree.timeFactor 1000
Tree.wideCellRenderer false
Tree.wideSelection true
TreeUI com.formdev.flatlaf.ui.FlatTreeUI

View File

@@ -232,6 +232,7 @@ ComboBox.noActionOnKeyNavigation false
ComboBox.padding 2,6,2,6 javax.swing.plaf.InsetsUIResource [UI]
ComboBox.popupBackground #ececec HSL 0 0 93 javax.swing.plaf.ColorUIResource [UI]
ComboBox.popupInsets 5,0,5,0 javax.swing.plaf.InsetsUIResource [UI]
ComboBox.roundedBorderWidth 1
ComboBox.selectionArc 8
ComboBox.selectionBackground #3d9aff HSL 211 100 62 javax.swing.plaf.ColorUIResource [UI]
ComboBox.selectionForeground #ffffff HSL 0 0 100 javax.swing.plaf.ColorUIResource [UI]
@@ -756,6 +757,7 @@ Popup.dropShadowColor #000000 HSL 0 0 0 javax.swing.plaf.Colo
Popup.dropShadowInsets -4,-4,4,4 javax.swing.plaf.InsetsUIResource [UI]
Popup.dropShadowOpacity 0.15
Popup.dropShadowPainted true
Popup.roundedBorderWidth 1
#---- PopupMenu ----
@@ -769,6 +771,7 @@ PopupMenu.consumeEventOnClose false
PopupMenu.font [active] $defaultFont [UI]
PopupMenu.foreground #262626 HSL 0 0 15 javax.swing.plaf.ColorUIResource [UI]
PopupMenu.hoverScrollArrowBackground #e9e9e9 HSL 0 0 91 javax.swing.plaf.ColorUIResource [UI]
PopupMenu.roundedBorderWidth 1
PopupMenu.scrollArrowColor #7d7d7d HSL 0 0 49 javax.swing.plaf.ColorUIResource [UI]
@@ -1389,6 +1392,7 @@ ToolTip.border [lazy] 4,6,4,6 false com.formdev.flatlaf.ui.F
ToolTip.borderCornerRadius 4
ToolTip.font [active] $defaultFont [UI]
ToolTip.foreground #262626 HSL 0 0 15 javax.swing.plaf.ColorUIResource [UI]
ToolTip.roundedBorderWidth 1
#---- ToolTipManager ----
@@ -1445,6 +1449,7 @@ Tree.showDefaultIcons false
Tree.textBackground #ffffff HSL 0 0 100 javax.swing.plaf.ColorUIResource [UI]
Tree.textForeground #262626 HSL 0 0 15 javax.swing.plaf.ColorUIResource [UI]
Tree.timeFactor 1000
Tree.wideCellRenderer false
Tree.wideSelection true
TreeUI com.formdev.flatlaf.ui.FlatTreeUI

View File

@@ -254,6 +254,7 @@ ComboBox.noActionOnKeyNavigation false
ComboBox.padding 2,6,2,6 javax.swing.plaf.InsetsUIResource [UI]
ComboBox.popupBackground #ffffcc HSL 60 100 90 javax.swing.plaf.ColorUIResource [UI]
ComboBox.popupInsets 0,0,0,0 javax.swing.plaf.InsetsUIResource [UI]
ComboBox.roundedBorderWidth 1
ComboBox.selectionArc 0
ComboBox.selectionBackground #00aa00 HSL 120 100 33 javax.swing.plaf.ColorUIResource [UI]
ComboBox.selectionForeground #ffff00 HSL 60 100 50 javax.swing.plaf.ColorUIResource [UI]
@@ -782,6 +783,7 @@ Popup.dropShadowColor #00ff00 HSL 120 100 50 javax.swing.plaf.Colo
Popup.dropShadowInsets -6,6,6,6 javax.swing.plaf.InsetsUIResource [UI]
Popup.dropShadowOpacity 0.5
Popup.dropShadowPainted true
Popup.roundedBorderWidth 1
#---- PopupMenu ----
@@ -795,6 +797,7 @@ PopupMenu.consumeEventOnClose false
PopupMenu.font [active] $defaultFont [UI]
PopupMenu.foreground #ff0000 HSL 0 100 50 javax.swing.plaf.ColorUIResource [UI]
PopupMenu.hoverScrollArrowBackground #00ff00 HSL 120 100 50 javax.swing.plaf.ColorUIResource [UI]
PopupMenu.roundedBorderWidth 1
PopupMenu.scrollArrowColor #0000ff HSL 240 100 50 javax.swing.plaf.ColorUIResource [UI]
@@ -1438,6 +1441,7 @@ ToolTip.border [lazy] line: #000000 HSL 0 0 0 java.awt
ToolTip.borderCornerRadius 4
ToolTip.font [active] $defaultFont [UI]
ToolTip.foreground #ff0000 HSL 0 100 50 javax.swing.plaf.ColorUIResource [UI]
ToolTip.roundedBorderWidth 1
#---- ToolTipManager ----
@@ -1495,6 +1499,7 @@ Tree.showDefaultIcons false
Tree.textBackground #fff0ff HSL 300 100 97 javax.swing.plaf.ColorUIResource [UI]
Tree.textForeground #ff0000 HSL 0 100 50 javax.swing.plaf.ColorUIResource [UI]
Tree.timeFactor 1000
Tree.wideCellRenderer false
Tree.wideSelection true
TreeUI com.formdev.flatlaf.ui.FlatTreeUI

View File

@@ -198,17 +198,17 @@ public class FlatComponentStateTest
//---- label11 ----
label11.setText("JButton");
label11.putClientProperty("FlatLaf.styleClass", "h3");
label11.putClientProperty(FlatClientProperties.STYLE_CLASS, "h3");
add(label11, "cell 1 0 2 1");
//---- label12 ----
label12.setText("JToggleButton");
label12.putClientProperty("FlatLaf.styleClass", "h3");
label12.putClientProperty(FlatClientProperties.STYLE_CLASS, "h3");
add(label12, "cell 5 0 3 1");
//---- label32 ----
label32.setText("Help Button");
label32.putClientProperty("FlatLaf.styleClass", "h3");
label32.putClientProperty(FlatClientProperties.STYLE_CLASS, "h3");
add(label32, "cell 9 0 2 1");
//---- label5 ----
@@ -257,26 +257,26 @@ public class FlatComponentStateTest
//---- testStateButton1 ----
testStateButton1.setText("text");
testStateButton1.putClientProperty("JComponent.minimumWidth", 0);
testStateButton1.putClientProperty(FlatClientProperties.MINIMUM_WIDTH, 0);
add(testStateButton1, "cell 1 2");
//---- testStateButton7 ----
testStateButton7.setText("text");
testStateButton7.setStateDefault(true);
testStateButton7.putClientProperty("JComponent.minimumWidth", 0);
testStateButton7.putClientProperty(FlatClientProperties.MINIMUM_WIDTH, 0);
add(testStateButton7, "cell 2 2");
//---- testStateButton4 ----
testStateButton4.setText("text");
testStateButton4.setStateFocused(true);
testStateButton4.putClientProperty("JComponent.minimumWidth", 0);
testStateButton4.putClientProperty(FlatClientProperties.MINIMUM_WIDTH, 0);
add(testStateButton4, "cell 3 2");
//---- testStateButton10 ----
testStateButton10.setText("text");
testStateButton10.setStateFocused(true);
testStateButton10.setStateDefault(true);
testStateButton10.putClientProperty("JComponent.minimumWidth", 0);
testStateButton10.putClientProperty(FlatClientProperties.MINIMUM_WIDTH, 0);
add(testStateButton10, "cell 4 2");
//---- testStateToggleButton1 ----
@@ -300,14 +300,14 @@ public class FlatComponentStateTest
add(testStateToggleButton12, "cell 8 2");
//---- testStateButton15 ----
testStateButton15.putClientProperty("JComponent.minimumWidth", 0);
testStateButton15.putClientProperty("JButton.buttonType", "help");
testStateButton15.putClientProperty(FlatClientProperties.MINIMUM_WIDTH, 0);
testStateButton15.putClientProperty(FlatClientProperties.BUTTON_TYPE, FlatClientProperties.BUTTON_TYPE_HELP);
add(testStateButton15, "cell 9 2");
//---- testStateButton19 ----
testStateButton19.setStateFocused(true);
testStateButton19.putClientProperty("JComponent.minimumWidth", 0);
testStateButton19.putClientProperty("JButton.buttonType", "help");
testStateButton19.putClientProperty(FlatClientProperties.MINIMUM_WIDTH, 0);
testStateButton19.putClientProperty(FlatClientProperties.BUTTON_TYPE, FlatClientProperties.BUTTON_TYPE_HELP);
add(testStateButton19, "cell 10 2");
//---- label2 ----
@@ -317,21 +317,21 @@ public class FlatComponentStateTest
//---- testStateButton2 ----
testStateButton2.setText("text");
testStateButton2.setStateHover(true);
testStateButton2.putClientProperty("JComponent.minimumWidth", 0);
testStateButton2.putClientProperty(FlatClientProperties.MINIMUM_WIDTH, 0);
add(testStateButton2, "cell 1 3");
//---- testStateButton8 ----
testStateButton8.setText("text");
testStateButton8.setStateHover(true);
testStateButton8.setStateDefault(true);
testStateButton8.putClientProperty("JComponent.minimumWidth", 0);
testStateButton8.putClientProperty(FlatClientProperties.MINIMUM_WIDTH, 0);
add(testStateButton8, "cell 2 3");
//---- testStateButton5 ----
testStateButton5.setText("text");
testStateButton5.setStateHover(true);
testStateButton5.setStateFocused(true);
testStateButton5.putClientProperty("JComponent.minimumWidth", 0);
testStateButton5.putClientProperty(FlatClientProperties.MINIMUM_WIDTH, 0);
add(testStateButton5, "cell 3 3");
//---- testStateButton11 ----
@@ -339,7 +339,7 @@ public class FlatComponentStateTest
testStateButton11.setStateHover(true);
testStateButton11.setStateFocused(true);
testStateButton11.setStateDefault(true);
testStateButton11.putClientProperty("JComponent.minimumWidth", 0);
testStateButton11.putClientProperty(FlatClientProperties.MINIMUM_WIDTH, 0);
add(testStateButton11, "cell 4 3");
//---- testStateToggleButton2 ----
@@ -368,15 +368,15 @@ public class FlatComponentStateTest
//---- testStateButton16 ----
testStateButton16.setStateHover(true);
testStateButton16.putClientProperty("JComponent.minimumWidth", 0);
testStateButton16.putClientProperty("JButton.buttonType", "help");
testStateButton16.putClientProperty(FlatClientProperties.MINIMUM_WIDTH, 0);
testStateButton16.putClientProperty(FlatClientProperties.BUTTON_TYPE, FlatClientProperties.BUTTON_TYPE_HELP);
add(testStateButton16, "cell 9 3");
//---- testStateButton20 ----
testStateButton20.setStateHover(true);
testStateButton20.setStateFocused(true);
testStateButton20.putClientProperty("JComponent.minimumWidth", 0);
testStateButton20.putClientProperty("JButton.buttonType", "help");
testStateButton20.putClientProperty(FlatClientProperties.MINIMUM_WIDTH, 0);
testStateButton20.putClientProperty(FlatClientProperties.BUTTON_TYPE, FlatClientProperties.BUTTON_TYPE_HELP);
add(testStateButton20, "cell 10 3");
//---- label3 ----
@@ -386,21 +386,21 @@ public class FlatComponentStateTest
//---- testStateButton3 ----
testStateButton3.setText("text");
testStateButton3.setStatePressed(true);
testStateButton3.putClientProperty("JComponent.minimumWidth", 0);
testStateButton3.putClientProperty(FlatClientProperties.MINIMUM_WIDTH, 0);
add(testStateButton3, "cell 1 4");
//---- testStateButton9 ----
testStateButton9.setText("text");
testStateButton9.setStatePressed(true);
testStateButton9.setStateDefault(true);
testStateButton9.putClientProperty("JComponent.minimumWidth", 0);
testStateButton9.putClientProperty(FlatClientProperties.MINIMUM_WIDTH, 0);
add(testStateButton9, "cell 2 4");
//---- testStateButton6 ----
testStateButton6.setText("text");
testStateButton6.setStatePressed(true);
testStateButton6.setStateFocused(true);
testStateButton6.putClientProperty("JComponent.minimumWidth", 0);
testStateButton6.putClientProperty(FlatClientProperties.MINIMUM_WIDTH, 0);
add(testStateButton6, "cell 3 4");
//---- testStateButton12 ----
@@ -408,7 +408,7 @@ public class FlatComponentStateTest
testStateButton12.setStatePressed(true);
testStateButton12.setStateFocused(true);
testStateButton12.setStateDefault(true);
testStateButton12.putClientProperty("JComponent.minimumWidth", 0);
testStateButton12.putClientProperty(FlatClientProperties.MINIMUM_WIDTH, 0);
add(testStateButton12, "cell 4 4");
//---- testStateToggleButton3 ----
@@ -437,15 +437,15 @@ public class FlatComponentStateTest
//---- testStateButton17 ----
testStateButton17.setStatePressed(true);
testStateButton17.putClientProperty("JComponent.minimumWidth", 0);
testStateButton17.putClientProperty("JButton.buttonType", "help");
testStateButton17.putClientProperty(FlatClientProperties.MINIMUM_WIDTH, 0);
testStateButton17.putClientProperty(FlatClientProperties.BUTTON_TYPE, FlatClientProperties.BUTTON_TYPE_HELP);
add(testStateButton17, "cell 9 4");
//---- testStateButton21 ----
testStateButton21.setStatePressed(true);
testStateButton21.setStateFocused(true);
testStateButton21.putClientProperty("JComponent.minimumWidth", 0);
testStateButton21.putClientProperty("JButton.buttonType", "help");
testStateButton21.putClientProperty(FlatClientProperties.MINIMUM_WIDTH, 0);
testStateButton21.putClientProperty(FlatClientProperties.BUTTON_TYPE, FlatClientProperties.BUTTON_TYPE_HELP);
add(testStateButton21, "cell 10 4");
//---- label4 ----
@@ -455,14 +455,14 @@ public class FlatComponentStateTest
//---- testStateButton13 ----
testStateButton13.setText("text");
testStateButton13.setEnabled(false);
testStateButton13.putClientProperty("JComponent.minimumWidth", 0);
testStateButton13.putClientProperty(FlatClientProperties.MINIMUM_WIDTH, 0);
add(testStateButton13, "cell 1 5");
//---- testStateButton14 ----
testStateButton14.setText("text");
testStateButton14.setEnabled(false);
testStateButton14.setStateDefault(true);
testStateButton14.putClientProperty("JComponent.minimumWidth", 0);
testStateButton14.putClientProperty(FlatClientProperties.MINIMUM_WIDTH, 0);
add(testStateButton14, "cell 2 5");
//---- testStateToggleButton4 ----
@@ -478,8 +478,8 @@ public class FlatComponentStateTest
//---- testStateButton18 ----
testStateButton18.setEnabled(false);
testStateButton18.putClientProperty("JComponent.minimumWidth", 0);
testStateButton18.putClientProperty("JButton.buttonType", "help");
testStateButton18.putClientProperty(FlatClientProperties.MINIMUM_WIDTH, 0);
testStateButton18.putClientProperty(FlatClientProperties.BUTTON_TYPE, FlatClientProperties.BUTTON_TYPE_HELP);
add(testStateButton18, "cell 9 5");
//---- label10 ----
@@ -488,12 +488,12 @@ public class FlatComponentStateTest
//---- button1 ----
button1.setText("text");
button1.putClientProperty("JComponent.minimumWidth", 0);
button1.putClientProperty(FlatClientProperties.MINIMUM_WIDTH, 0);
add(button1, "cell 1 6");
//---- testDefaultButton1 ----
testDefaultButton1.setText("text");
testDefaultButton1.putClientProperty("JComponent.minimumWidth", 0);
testDefaultButton1.putClientProperty(FlatClientProperties.MINIMUM_WIDTH, 0);
add(testDefaultButton1, "cell 2 6");
//---- toggleButton1 ----
@@ -506,19 +506,19 @@ public class FlatComponentStateTest
add(toggleButton2, "cell 6 6");
//---- button2 ----
button2.putClientProperty("JComponent.minimumWidth", 0);
button2.putClientProperty("JButton.buttonType", "help");
button2.putClientProperty(FlatClientProperties.MINIMUM_WIDTH, 0);
button2.putClientProperty(FlatClientProperties.BUTTON_TYPE, FlatClientProperties.BUTTON_TYPE_HELP);
add(button2, "cell 9 6");
add(separator1, "cell 0 7 11 1");
//---- label22 ----
label22.setText("JCheckBox");
label22.putClientProperty("FlatLaf.styleClass", "h3");
label22.putClientProperty(FlatClientProperties.STYLE_CLASS, "h3");
add(label22, "cell 1 8 2 1");
//---- label27 ----
label27.setText("JRadioButton");
label27.putClientProperty("FlatLaf.styleClass", "h3");
label27.putClientProperty(FlatClientProperties.STYLE_CLASS, "h3");
add(label27, "cell 5 8 2 1");
//---- label23 ----

View File

@@ -16,6 +16,7 @@
package com.formdev.flatlaf.testing;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.ComponentOrientation;
@@ -32,6 +33,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.function.Supplier;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.TableModelEvent;
@@ -492,53 +494,33 @@ public class FlatComponents2Test
list.setVisibleRowCount( visibleRowCount );
}
private void listAlternatingRowsChanged() {
UIManager.put( "List.alternateRowColor", listAlternatingRowsCheckBox.isSelected() ? Color.YELLOW : null );
FlatLaf.updateUILater();
}
private void treeRendererChanged() {
Object sel = treeRendererComboBox.getSelectedItem();
if( !(sel instanceof String) )
return;
JTree[] trees = { tree1, tree2, xTree1 };
Supplier<TreeCellRenderer> creator;
switch( (String) sel ) {
case "default":
for( JTree tree : trees )
tree.setCellRenderer( new DefaultTreeCellRenderer() );
break;
case "defaultSubclass":
for( JTree tree : trees )
tree.setCellRenderer( new TestDefaultTreeCellRenderer() );
break;
case "defaultWithIcons":
for( JTree tree : trees )
tree.setCellRenderer( new TestDefaultWithIconsTreeCellRenderer() );
break;
case "defaultWithIcon":
for( JTree tree : trees )
tree.setCellRenderer( new TestDefaultWithIconTreeCellRenderer() );
break;
case "label":
for( JTree tree : trees )
tree.setCellRenderer( new TestLabelTreeCellRenderer() );
break;
case "swingxDefault":
for( JTree tree : trees )
tree.setCellRenderer( new DefaultTreeRenderer() );
break;
case "jideCheckBox":
for( JTree tree : trees )
tree.setCellRenderer( new CheckBoxTreeCellRenderer( new DefaultTreeCellRenderer() ) );
break;
case "jideStyled":
for( JTree tree : trees )
tree.setCellRenderer( new StyledTreeCellRenderer() );
break;
default:
case "default": creator = DefaultTreeCellRenderer::new; break;
case "defaultSubclass": creator = TestDefaultTreeCellRenderer::new; break;
case "defaultWithIcons": creator = TestDefaultWithIconsTreeCellRenderer::new; break;
case "defaultWithIcon": creator = TestDefaultWithIconTreeCellRenderer::new; break;
case "label": creator = TestLabelTreeCellRenderer::new; break;
case "wide": creator = TestWideTreeCellRenderer::new; break;
case "swingxDefault": creator = DefaultTreeRenderer::new; break;
case "jideCheckBox": creator = () -> new CheckBoxTreeCellRenderer( new DefaultTreeCellRenderer() ); break;
case "jideStyled": creator = StyledTreeCellRenderer::new; break;
}
JTree[] trees = { tree1, tree2, xTree1 };
for( JTree tree : trees )
tree.setCellRenderer( creator.get() );
}
private void treeWideSelectionChanged() {
@@ -547,6 +529,17 @@ public class FlatComponents2Test
tree.putClientProperty( FlatClientProperties.TREE_WIDE_SELECTION, wideSelection );
}
private void treeWideCellRendererChanged() {
boolean wideCellRenderer = treeWideCellRendererCheckBox.isSelected();
for( JTree tree : allTrees )
tree.putClientProperty( FlatClientProperties.TREE_WIDE_CELL_RENDERER, wideCellRenderer );
}
private void treeAlternatingRowsChanged() {
UIManager.put( "Tree.alternateRowColor", treeAlternatingRowsCheckBox.isSelected() ? Color.cyan : null );
FlatLaf.updateUILater();
}
private void treePaintSelectionChanged() {
boolean paintSelection = treePaintSelectionCheckBox.isSelected();
for( JTree tree : allTrees )
@@ -687,11 +680,14 @@ public class FlatComponents2Test
listLayoutOrientationField = new JComboBox<>();
JLabel listVisibleRowCountLabel = new JLabel();
listVisibleRowCountSpinner = new JSpinner();
listAlternatingRowsCheckBox = new JCheckBox();
treeOptionsPanel = new JPanel();
JLabel treeRendererLabel = new JLabel();
treeRendererComboBox = new JComboBox<>();
treeWideSelectionCheckBox = new JCheckBox();
treeWideCellRendererCheckBox = new JCheckBox();
treePaintSelectionCheckBox = new JCheckBox();
treeAlternatingRowsCheckBox = new JCheckBox();
treePaintLinesCheckBox = new JCheckBox();
treeRedLinesCheckBox = new JCheckBox();
treeEditableCheckBox = new JCheckBox();
@@ -753,7 +749,7 @@ public class FlatComponents2Test
// rows
"[]" +
"[grow]" +
"[]" +
"[]0" +
"[]"));
//---- listLabel ----
@@ -796,7 +792,7 @@ public class FlatComponents2Test
// rows
"[]" +
"[grow]" +
"[]" +
"[]0" +
"[]"));
//---- tableLabel ----
@@ -833,7 +829,7 @@ public class FlatComponents2Test
// rows
"[]" +
"[grow]" +
"[]" +
"[]0" +
"[]"));
//---- treeLabel ----
@@ -1022,6 +1018,7 @@ public class FlatComponents2Test
// rows
"[]" +
"[]" +
"[]" +
"[]"));
//---- listRendererLabel ----
@@ -1059,6 +1056,11 @@ public class FlatComponents2Test
listVisibleRowCountSpinner.setModel(new SpinnerNumberModel(8, 0, null, 1));
listVisibleRowCountSpinner.addChangeListener(e -> listVisibleRowCountChanged());
listOptionsPanel.add(listVisibleRowCountSpinner, "cell 1 2");
//---- listAlternatingRowsCheckBox ----
listAlternatingRowsCheckBox.setText("alternating rows");
listAlternatingRowsCheckBox.addActionListener(e -> listAlternatingRowsChanged());
listOptionsPanel.add(listAlternatingRowsCheckBox, "cell 0 3 2 1,alignx left,growx 0");
}
add(listOptionsPanel, "cell 0 4 4 1");
@@ -1088,6 +1090,7 @@ public class FlatComponents2Test
"defaultWithIcons",
"defaultWithIcon",
"label",
"wide",
"swingxDefault",
"jideCheckBox",
"jideStyled"
@@ -1100,12 +1103,22 @@ public class FlatComponents2Test
treeWideSelectionCheckBox.addActionListener(e -> treeWideSelectionChanged());
treeOptionsPanel.add(treeWideSelectionCheckBox, "cell 0 1");
//---- treeWideCellRendererCheckBox ----
treeWideCellRendererCheckBox.setText("wide cell renderer");
treeWideCellRendererCheckBox.addActionListener(e -> treeWideCellRendererChanged());
treeOptionsPanel.add(treeWideCellRendererCheckBox, "cell 0 1");
//---- treePaintSelectionCheckBox ----
treePaintSelectionCheckBox.setText("paint selection");
treePaintSelectionCheckBox.setSelected(true);
treePaintSelectionCheckBox.addActionListener(e -> treePaintSelectionChanged());
treeOptionsPanel.add(treePaintSelectionCheckBox, "cell 0 2");
//---- treeAlternatingRowsCheckBox ----
treeAlternatingRowsCheckBox.setText("alternating rows");
treeAlternatingRowsCheckBox.addActionListener(e -> treeAlternatingRowsChanged());
treeOptionsPanel.add(treeAlternatingRowsCheckBox, "cell 0 2");
//---- treePaintLinesCheckBox ----
treePaintLinesCheckBox.setText("paint lines");
treePaintLinesCheckBox.addActionListener(e -> treePaintLinesChanged());
@@ -1263,10 +1276,13 @@ public class FlatComponents2Test
private JComboBox<String> listRendererComboBox;
private JComboBox<String> listLayoutOrientationField;
private JSpinner listVisibleRowCountSpinner;
private JCheckBox listAlternatingRowsCheckBox;
private JPanel treeOptionsPanel;
private JComboBox<String> treeRendererComboBox;
private JCheckBox treeWideSelectionCheckBox;
private JCheckBox treeWideCellRendererCheckBox;
private JCheckBox treePaintSelectionCheckBox;
private JCheckBox treeAlternatingRowsCheckBox;
private JCheckBox treePaintLinesCheckBox;
private JCheckBox treeRedLinesCheckBox;
private JCheckBox treeEditableCheckBox;
@@ -1372,7 +1388,7 @@ public class FlatComponents2Test
@Override
public String getElementAt( int index ) {
return (index < 20)
? "item " + (index + 1)
? "item " + (index + 1) + ((index + 1) % 5 == 0 ? " ####" : "")
: "item " + (index + 1) + " " + randomRowString( index );
}
}
@@ -1794,6 +1810,32 @@ public class FlatComponents2Test
}
}
//---- class TestLabelTreeCellRenderer ------------------------------------
private static class TestWideTreeCellRenderer
extends JPanel
implements TreeCellRenderer
{
private final JLabel label = new JLabel();
private final JLabel icon = new JLabel( UIManager.getIcon( "FileView.floppyDriveIcon" ) );
TestWideTreeCellRenderer() {
super( new BorderLayout() );
setOpaque( false );
add( label, BorderLayout.CENTER );
add( icon, BorderLayout.LINE_END );
setBorder( new LineBorder( Color.red ) );
}
@Override
public Component getTreeCellRendererComponent( JTree tree, Object value, boolean selected, boolean expanded,
boolean leaf, int row, boolean hasFocus )
{
label.setText( String.valueOf( value ) );
return this;
}
}
//---- class TestComboBoxTableCellRenderer --------------------------------
private static class TestComboBoxTableCellRenderer

View File

@@ -1,4 +1,4 @@
JFDML JFormDesigner: "8.2.2.0.9999" Java: "21.0.1" encoding: "UTF-8"
JFDML JFormDesigner: "8.3" encoding: "UTF-8"
new FormModel {
contentType: "form/swing"
@@ -33,7 +33,7 @@ new FormModel {
} )
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$columnConstraints": "[fill]"
"$rowConstraints": "[][grow][][]"
"$rowConstraints": "[][grow][]0[]"
"$layoutConstraints": "ltr,insets 0,hidemode 3"
} ) {
name: "panel1"
@@ -95,7 +95,7 @@ new FormModel {
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "insets 0,hidemode 3"
"$columnConstraints": "[fill]"
"$rowConstraints": "[][grow][][]"
"$rowConstraints": "[][grow][]0[]"
} ) {
name: "panel3"
"$client.FlatLaf.internal.testing.ignore": true
@@ -146,7 +146,7 @@ new FormModel {
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "insets 0,hidemode 3"
"$columnConstraints": "[fill]"
"$rowConstraints": "[][grow][][]"
"$rowConstraints": "[][grow][]0[]"
} ) {
name: "panel2"
"$client.FlatLaf.internal.testing.ignore": true
@@ -385,7 +385,7 @@ new FormModel {
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "insets 8,hidemode 3"
"$columnConstraints": "[fill][fill]"
"$rowConstraints": "[][][]"
"$rowConstraints": "[][][][]"
} ) {
name: "listOptionsPanel"
"border": new javax.swing.border.TitledBorder( "JList Control" )
@@ -455,6 +455,16 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 2"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "listAlternatingRowsCheckBox"
"text": "alternating rows"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "listAlternatingRowsChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 3 2 1,alignx left,growx 0"
} )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 4 4 1"
} )
@@ -484,6 +494,7 @@ new FormModel {
addElement( "defaultWithIcons" )
addElement( "defaultWithIcon" )
addElement( "label" )
addElement( "wide" )
addElement( "swingxDefault" )
addElement( "jideCheckBox" )
addElement( "jideStyled" )
@@ -505,6 +516,16 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 1"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "treeWideCellRendererCheckBox"
"text": "wide cell renderer"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "treeWideCellRendererChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 1"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "treePaintSelectionCheckBox"
"text": "paint selection"
@@ -516,6 +537,16 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 2"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "treeAlternatingRowsCheckBox"
"text": "alternating rows"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "treeAlternatingRowsChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 2"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "treePaintLinesCheckBox"
"text": "paint lines"

View File

@@ -20,6 +20,7 @@ import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.ColorUIResource;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.extras.components.*;
import com.formdev.flatlaf.extras.components.FlatButton.ButtonType;
@@ -59,6 +60,11 @@ public class FlatComponentsTest
};
for( JSlider slider : allSliders )
slider.addChangeListener( sliderChanged );
UIManager.addPropertyChangeListener( e -> {
if( "lookAndFeel".equals( e.getPropertyName() ) && hideArrowButtonCheckBox.isSelected() )
SwingUtilities.invokeLater( () -> hideArrowButton() );
} );
}
private void changeProgress() {
@@ -127,6 +133,48 @@ 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 transparentBackground() {
EventQueue.invokeLater( () -> {
boolean transparent = transparentBackgroundCheckBox.isSelected();
Color transparentColor = new Color( 0, true );
ColorUIResource restoreColor = new ColorUIResource( Color.white );
FlatTestFrame.updateComponentsRecur( this, (c, type) -> {
if( c instanceof JComboBox ) {
((JComboBox<?>)c).putClientProperty( FlatClientProperties.STYLE,
transparent ? "background: #0000; buttonBackground: #0000; buttonEditableBackground: #0000" : null );
} else if( c instanceof JSpinner ) {
((JSpinner)c).putClientProperty( FlatClientProperties.STYLE,
transparent ? "background: #0000; buttonBackground: #0000" : null );
} else if( c instanceof JComponent )
c.setBackground( transparent ? transparentColor : restoreColor );
else
return;
// if background color is transparent it is also required to make the component non-opaque
// DO NOT USE LookAndFeel.installProperty() in real-world applications
// instead use c.setOpaque( false )
if( transparent )
LookAndFeel.installProperty( (JComponent) c, "opaque", false );
} );
if( !transparent )
SwingUtilities.updateComponentTreeUI( this );
} );
}
private void roundRectChanged() {
Boolean roundRect = roundRectCheckBox.isSelected() ? true : null;
@@ -380,6 +428,8 @@ public class FlatComponentsTest
magentaOutlineRadioButton = new JRadioButton();
magentaCyanOutlineRadioButton = new JRadioButton();
focusPaintedCheckBox = new JCheckBox();
hideArrowButtonCheckBox = new JCheckBox();
transparentBackgroundCheckBox = new JCheckBox();
JLabel scrollBarLabel = new JLabel();
JScrollBar scrollBar1 = new JScrollBar();
JScrollBar scrollBar4 = new JScrollBar();
@@ -1234,9 +1284,11 @@ public class FlatComponentsTest
"[]" +
"[]",
// rows
"[]" +
"[]" +
"[]" +
"[]0" +
"[]0" +
"[]0" +
"[]0" +
"[]0" +
"[]"));
//---- buttonTypeComboBox ----
@@ -1290,13 +1342,23 @@ public class FlatComponentsTest
magentaCyanOutlineRadioButton.addActionListener(e -> outlineChanged());
panel4.add(magentaCyanOutlineRadioButton);
}
panel5.add(panel4, "cell 0 2 1 2");
panel5.add(panel4, "cell 0 2 1 4");
//---- focusPaintedCheckBox ----
focusPaintedCheckBox.setText("focusPainted");
focusPaintedCheckBox.setSelected(true);
focusPaintedCheckBox.addActionListener(e -> focusPaintedChanged());
panel5.add(focusPaintedCheckBox, "cell 1 2");
//---- hideArrowButtonCheckBox ----
hideArrowButtonCheckBox.setText("hide arrow button");
hideArrowButtonCheckBox.addActionListener(e -> hideArrowButton());
panel5.add(hideArrowButtonCheckBox, "cell 1 3");
//---- transparentBackgroundCheckBox ----
transparentBackgroundCheckBox.setText("transparent background");
transparentBackgroundCheckBox.addActionListener(e -> transparentBackground());
panel5.add(transparentBackgroundCheckBox, "cell 1 4");
}
add(panel5, "cell 5 13 2 10,grow");
@@ -1703,6 +1765,8 @@ public class FlatComponentsTest
private JRadioButton magentaOutlineRadioButton;
private JRadioButton magentaCyanOutlineRadioButton;
private JCheckBox focusPaintedCheckBox;
private JCheckBox hideArrowButtonCheckBox;
private JCheckBox transparentBackgroundCheckBox;
private JSlider slider1;
private JSlider slider6;
private JCheckBox sliderPaintTrackCheckBox;

View File

@@ -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 {
contentType: "form/swing"
@@ -993,7 +993,7 @@ new FormModel {
} )
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$columnConstraints": "[][]"
"$rowConstraints": "[][][][]"
"$rowConstraints": "[]0[]0[]0[]0[]0[]"
"$layoutConstraints": "ltr,insets dialog,hidemode 3"
} ) {
name: "panel5"
@@ -1092,7 +1092,7 @@ new FormModel {
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "outlineChanged", false ) )
} )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 2 1 2"
"value": "cell 0 2 1 4"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "focusPaintedCheckBox"
@@ -1105,6 +1105,26 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"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"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "transparentBackgroundCheckBox"
"text": "transparent background"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "transparentBackground", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 4"
} )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 5 13 2 10,grow"
} )

View File

@@ -21,6 +21,7 @@ import javax.swing.*;
import javax.swing.border.*;
import javax.swing.plaf.basic.BasicComboBoxEditor;
import javax.swing.plaf.basic.BasicComboBoxRenderer;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.icons.FlatFileViewFloppyDriveIcon;
import com.formdev.flatlaf.util.UIScale;
import net.miginfocom.swing.*;
@@ -342,22 +343,22 @@ public class FlatCustomBordersTest
//---- button5 ----
button5.setText("text");
button5.putClientProperty("JButton.buttonType", "roundRect");
button5.putClientProperty(FlatClientProperties.BUTTON_TYPE, FlatClientProperties.BUTTON_TYPE_ROUND_RECT);
add(button5, "cell 1 2");
//---- button6 ----
button6.setText("text");
button6.putClientProperty("JButton.buttonType", "roundRect");
button6.putClientProperty(FlatClientProperties.BUTTON_TYPE, FlatClientProperties.BUTTON_TYPE_ROUND_RECT);
add(button6, "cell 2 2");
//---- button7 ----
button7.setText("text");
button7.putClientProperty("JButton.buttonType", "roundRect");
button7.putClientProperty(FlatClientProperties.BUTTON_TYPE, FlatClientProperties.BUTTON_TYPE_ROUND_RECT);
add(button7, "cell 3 2");
//---- button8 ----
button8.setText("text");
button8.putClientProperty("JButton.buttonType", "roundRect");
button8.putClientProperty(FlatClientProperties.BUTTON_TYPE, FlatClientProperties.BUTTON_TYPE_ROUND_RECT);
add(button8, "cell 4 2");
//---- label5 ----
@@ -372,31 +373,31 @@ public class FlatCustomBordersTest
add(comboBox27, "cell 7 3");
//---- comboBox5 ----
comboBox5.putClientProperty("JComponent.roundRect", true);
comboBox5.putClientProperty(FlatClientProperties.COMPONENT_ROUND_RECT, true);
add(comboBox5, "cell 1 4");
//---- comboBox6 ----
comboBox6.putClientProperty("JComponent.roundRect", true);
comboBox6.putClientProperty(FlatClientProperties.COMPONENT_ROUND_RECT, true);
add(comboBox6, "cell 2 4");
//---- comboBox7 ----
comboBox7.putClientProperty("JComponent.roundRect", true);
comboBox7.putClientProperty(FlatClientProperties.COMPONENT_ROUND_RECT, true);
add(comboBox7, "cell 3 4");
//---- comboBox8 ----
comboBox8.putClientProperty("JComponent.roundRect", true);
comboBox8.putClientProperty(FlatClientProperties.COMPONENT_ROUND_RECT, true);
add(comboBox8, "cell 4 4");
//---- comboBox24 ----
comboBox24.putClientProperty("JComponent.roundRect", true);
comboBox24.putClientProperty(FlatClientProperties.COMPONENT_ROUND_RECT, true);
add(comboBox24, "cell 5 4");
//---- comboBox26 ----
comboBox26.putClientProperty("JComponent.roundRect", true);
comboBox26.putClientProperty(FlatClientProperties.COMPONENT_ROUND_RECT, true);
add(comboBox26, "cell 6 4");
//---- comboBox28 ----
comboBox28.putClientProperty("JComponent.roundRect", true);
comboBox28.putClientProperty(FlatClientProperties.COMPONENT_ROUND_RECT, true);
add(comboBox28, "cell 7 4");
//---- comboBox9 ----
@@ -428,37 +429,37 @@ public class FlatCustomBordersTest
add(comboBox21, "cell 7 5");
//---- comboBox13 ----
comboBox13.putClientProperty("JComponent.roundRect", true);
comboBox13.putClientProperty(FlatClientProperties.COMPONENT_ROUND_RECT, true);
comboBox13.setEditable(true);
add(comboBox13, "cell 1 6");
//---- comboBox14 ----
comboBox14.putClientProperty("JComponent.roundRect", true);
comboBox14.putClientProperty(FlatClientProperties.COMPONENT_ROUND_RECT, true);
comboBox14.setEditable(true);
add(comboBox14, "cell 2 6");
//---- comboBox15 ----
comboBox15.putClientProperty("JComponent.roundRect", true);
comboBox15.putClientProperty(FlatClientProperties.COMPONENT_ROUND_RECT, true);
comboBox15.setEditable(true);
add(comboBox15, "cell 3 6");
//---- comboBox16 ----
comboBox16.putClientProperty("JComponent.roundRect", true);
comboBox16.putClientProperty(FlatClientProperties.COMPONENT_ROUND_RECT, true);
comboBox16.setEditable(true);
add(comboBox16, "cell 4 6");
//---- comboBox18 ----
comboBox18.putClientProperty("JComponent.roundRect", true);
comboBox18.putClientProperty(FlatClientProperties.COMPONENT_ROUND_RECT, true);
comboBox18.setEditable(true);
add(comboBox18, "cell 5 6");
//---- comboBox20 ----
comboBox20.putClientProperty("JComponent.roundRect", true);
comboBox20.putClientProperty(FlatClientProperties.COMPONENT_ROUND_RECT, true);
comboBox20.setEditable(true);
add(comboBox20, "cell 6 6");
//---- comboBox22 ----
comboBox22.putClientProperty("JComponent.roundRect", true);
comboBox22.putClientProperty(FlatClientProperties.COMPONENT_ROUND_RECT, true);
comboBox22.setEditable(true);
add(comboBox22, "cell 7 6");
@@ -471,19 +472,19 @@ public class FlatCustomBordersTest
add(spinner4, "cell 4 7");
//---- spinner5 ----
spinner5.putClientProperty("JComponent.roundRect", true);
spinner5.putClientProperty(FlatClientProperties.COMPONENT_ROUND_RECT, true);
add(spinner5, "cell 1 8");
//---- spinner6 ----
spinner6.putClientProperty("JComponent.roundRect", true);
spinner6.putClientProperty(FlatClientProperties.COMPONENT_ROUND_RECT, true);
add(spinner6, "cell 2 8");
//---- spinner7 ----
spinner7.putClientProperty("JComponent.roundRect", true);
spinner7.putClientProperty(FlatClientProperties.COMPONENT_ROUND_RECT, true);
add(spinner7, "cell 3 8");
//---- spinner8 ----
spinner8.putClientProperty("JComponent.roundRect", true);
spinner8.putClientProperty(FlatClientProperties.COMPONENT_ROUND_RECT, true);
add(spinner8, "cell 4 8");
//---- textFieldLabel ----
@@ -492,11 +493,11 @@ public class FlatCustomBordersTest
//---- textField1 ----
textField1.setText("text");
textField1.putClientProperty("JComponent.roundRect", false);
textField1.putClientProperty(FlatClientProperties.COMPONENT_ROUND_RECT, false);
add(textField1, "cell 1 9,growx");
//---- textField2 ----
textField2.putClientProperty("JComponent.roundRect", false);
textField2.putClientProperty(FlatClientProperties.COMPONENT_ROUND_RECT, false);
textField2.setText("text");
add(textField2, "cell 2 9");
@@ -505,27 +506,27 @@ public class FlatCustomBordersTest
add(textField3, "cell 3 9");
//---- textField4 ----
textField4.putClientProperty("JComponent.roundRect", false);
textField4.putClientProperty(FlatClientProperties.COMPONENT_ROUND_RECT, false);
textField4.setText("text");
add(textField4, "cell 4 9");
//---- textField5 ----
textField5.setText("text");
textField5.putClientProperty("JComponent.roundRect", true);
textField5.putClientProperty(FlatClientProperties.COMPONENT_ROUND_RECT, true);
add(textField5, "cell 1 10,growx");
//---- textField6 ----
textField6.putClientProperty("JComponent.roundRect", true);
textField6.putClientProperty(FlatClientProperties.COMPONENT_ROUND_RECT, true);
textField6.setText("text");
add(textField6, "cell 2 10");
//---- textField7 ----
textField7.setText("text");
textField7.putClientProperty("JComponent.roundRect", true);
textField7.putClientProperty(FlatClientProperties.COMPONENT_ROUND_RECT, true);
add(textField7, "cell 3 10");
//---- textField8 ----
textField8.putClientProperty("JComponent.roundRect", true);
textField8.putClientProperty(FlatClientProperties.COMPONENT_ROUND_RECT, true);
textField8.setText("text");
add(textField8, "cell 4 10");

View File

@@ -22,6 +22,7 @@ import java.awt.Font;
import java.util.Map;
import java.util.TreeMap;
import javax.swing.*;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.fonts.inter.FlatInterFont;
import com.formdev.flatlaf.fonts.jetbrains_mono.FlatJetBrainsMonoFont;
import com.formdev.flatlaf.fonts.roboto.FlatRobotoFont;
@@ -132,7 +133,7 @@ public class FlatFontsTest
//---- previewFamilyNameLabel ----
previewFamilyNameLabel.setText("name");
previewFamilyNameLabel.putClientProperty("FlatLaf.styleClass", "h1");
previewFamilyNameLabel.putClientProperty(FlatClientProperties.STYLE_CLASS, "h1");
add(previewFamilyNameLabel, "cell 1 1");
//======== familiesScrollPane ========

View File

@@ -21,6 +21,7 @@ import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
import javax.swing.border.*;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.demo.ScrollablePanel;
import net.miginfocom.swing.*;
@@ -63,6 +64,15 @@ public class FlatOptionPaneTest
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() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
ScrollablePanel panel9 = new ScrollablePanel();
@@ -75,6 +85,7 @@ public class FlatOptionPaneTest
JPanel panel2 = new JPanel();
JOptionPane errorOptionPane = new JOptionPane();
errorShowDialogLabel = new FlatOptionPaneTest.ShowDialogLinkLabel();
JButton showWithCustomIconButton = new JButton();
JLabel informationLabel = new JLabel();
JPanel panel3 = new JPanel();
JOptionPane informationOptionPane = new JOptionPane();
@@ -173,6 +184,11 @@ public class FlatOptionPaneTest
errorShowDialogLabel.setOptionPane(errorOptionPane);
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.setText("Information");
panel9.add(informationLabel, "cell 0 2");

View File

@@ -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 {
contentType: "form/swing"
@@ -83,6 +83,13 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"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" ) {
name: "informationLabel"
"text": "Information"

View File

@@ -21,6 +21,10 @@ import java.awt.event.MouseEvent;
import java.util.Random;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatSystemProperties;
import com.formdev.flatlaf.util.Animator;
import com.formdev.flatlaf.util.UIScale;
import net.miginfocom.swing.*;
@@ -43,6 +47,8 @@ public class FlatPopupTest
FlatPopupTest() {
initComponents();
addPopupMenuListener( popupMenu1, "popupMenu1" );
addPopupMenuListener( popupMenu2, "popupMenu2" );
}
private void showPopupMenu() {
@@ -114,6 +120,46 @@ public class FlatPopupTest
}
}
private void showDirectPopup() {
DirectPopupContent content = new DirectPopupContent();
content.putClientProperty( FlatClientProperties.POPUP_FORCE_HEAVY_WEIGHT, true );
Point pt = showDirectPopupButton.getLocationOnScreen();
System.setProperty( FlatSystemProperties.USE_ROUNDED_POPUP_BORDER, "false" );
UIManager.put( "Popup.dropShadowColor", Color.red );
UIManager.put( "Popup.dropShadowInsets", new Insets( 5, 5, 5, 5 ) );
UIManager.put( "Popup.dropShadowOpacity", 1f );
Popup popup = PopupFactory.getSharedInstance().getPopup( showDirectPopupButton,
content, pt.x, pt.y + showDirectPopupButton.getHeight() + 10 );
content.popup = popup;
popup.show();
System.clearProperty( FlatSystemProperties.USE_ROUNDED_POPUP_BORDER );
UIManager.put( "Popup.dropShadowColor", null );
UIManager.put( "Popup.dropShadowInsets", null );
UIManager.put( "Popup.dropShadowOpacity", null );
}
private void addPopupMenuListener( JPopupMenu popupMenu, String name ) {
popupMenu.addPopupMenuListener( new PopupMenuListener() {
@Override
public void popupMenuWillBecomeVisible( PopupMenuEvent e ) {
System.out.println( "popupMenuWillBecomeVisible " + name );
}
@Override
public void popupMenuWillBecomeInvisible( PopupMenuEvent e ) {
System.out.println( "popupMenuWillBecomeInvisible " + name );
}
@Override
public void popupMenuCanceled( PopupMenuEvent e ) {
System.out.println( "popupMenuCanceled " + name );
}
} );
}
@Override
public void updateUI() {
super.updateUI();
@@ -128,15 +174,12 @@ public class FlatPopupTest
}
}
private void countChanged() {
// TODO add your code here
}
private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
label1 = new JLabel();
label2 = new JLabel();
showPopupMenuButton = new JButton();
showDirectPopupButton = new JButton();
showLargePopupMenuButton = new JButton();
showPopupButton = new JButton();
hidePopupButton = new JButton();
@@ -209,6 +252,11 @@ public class FlatPopupTest
showPopupMenuButton.addActionListener(e -> showPopupMenu());
add(showPopupMenuButton, "cell 0 2");
//---- showDirectPopupButton ----
showDirectPopupButton.setText("show direct move/resize popup");
showDirectPopupButton.addActionListener(e -> showDirectPopup());
add(showDirectPopupButton, "cell 2 2 2 1");
//---- showLargePopupMenuButton ----
showLargePopupMenuButton.setText("show heavy-weight JPopupMenu");
showLargePopupMenuButton.addActionListener(e -> showLargePopupMenu());
@@ -240,7 +288,6 @@ public class FlatPopupTest
//---- countField ----
countField.setModel(new SpinnerNumberModel(1, 1, null, 1));
countField.addChangeListener(e -> countChanged());
add(countField, "cell 5 4");
//---- label4 ----
@@ -366,6 +413,7 @@ public class FlatPopupTest
private JLabel label1;
private JLabel label2;
private JButton showPopupMenuButton;
private JButton showDirectPopupButton;
private JButton showLargePopupMenuButton;
private JButton showPopupButton;
private JButton hidePopupButton;
@@ -444,4 +492,69 @@ public class FlatPopupTest
private JLabel label6;
// JFormDesigner - End of variables declaration //GEN-END:variables @formatter:on
}
//---- class MyPopupContent -----------------------------------------------
private static class DirectPopupContent
extends JPanel
{
Popup popup;
DirectPopupContent() {
initComponents();
}
private void resizePopup() {
Window popupWindow = SwingUtilities.windowForComponent( this );
popupWindow.setSize( popupWindow.getWidth() + 20, popupWindow.getHeight() + 50 );
}
private void movePopup() {
Window popupWindow = SwingUtilities.windowForComponent( this );
popupWindow.setLocation( popupWindow.getX() + 20, popupWindow.getY() + 50 );
}
private void hidePopup() {
popup.hide();
}
private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents @formatter:off
resizeButton = new JButton();
moveButton = new JButton();
hideButton = new JButton();
//======== this ========
setLayout(new MigLayout(
"hidemode 3",
// columns
"[fill]" +
"[fill]" +
"[fill]",
// rows
"[]"));
//---- resizeButton ----
resizeButton.setText("Resize");
resizeButton.addActionListener(e -> resizePopup());
add(resizeButton, "cell 0 0");
//---- moveButton ----
moveButton.setText("Move");
moveButton.addActionListener(e -> movePopup());
add(moveButton, "cell 1 0");
//---- hideButton ----
hideButton.setText("Hide");
hideButton.addActionListener(e -> hidePopup());
add(hideButton, "cell 2 0");
// JFormDesigner - End of component initialization //GEN-END:initComponents @formatter:on
}
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables @formatter:off
private JButton resizeButton;
private JButton moveButton;
private JButton hideButton;
// JFormDesigner - End of variables declaration //GEN-END:variables @formatter:on
}
}

View File

@@ -1,4 +1,4 @@
JFDML JFormDesigner: "8.2.3.0.386" Java: "21" encoding: "UTF-8"
JFDML JFormDesigner: "8.3" encoding: "UTF-8"
new FormModel {
contentType: "form/swing"
@@ -30,6 +30,13 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 2"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "showDirectPopupButton"
"text": "show direct move/resize popup"
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showDirectPopup", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 2 2 1"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "showLargePopupMenuButton"
"text": "show heavy-weight JPopupMenu"
@@ -77,7 +84,6 @@ new FormModel {
minimum: 1
value: 1
}
addEvent( new FormEvent( "javax.swing.event.ChangeListener", "stateChanged", "countChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 5 4"
} )
@@ -215,5 +221,39 @@ new FormModel {
}, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 5, 505 )
} )
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "hidemode 3"
"$columnConstraints": "[fill][fill][fill]"
"$rowConstraints": "[]"
} ) {
name: "panel1"
auxiliary() {
"JavaCodeGenerator.className": "DirectPopupContent"
}
add( new FormComponent( "javax.swing.JButton" ) {
name: "resizeButton"
"text": "Resize"
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "resizePopup", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 0"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "moveButton"
"text": "Move"
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "movePopup", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 0"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "hideButton"
"text": "Hide"
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "hidePopup", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 0"
} )
}, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 180, 395 )
"size": new java.awt.Dimension( 270, 100 )
} )
}
}

View File

@@ -37,6 +37,7 @@ import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.plaf.ColorUIResource;
import javax.swing.plaf.metal.MetalLookAndFeel;
import javax.swing.plaf.nimbus.NimbusLookAndFeel;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatDarculaLaf;
import com.formdev.flatlaf.FlatDarkLaf;
import com.formdev.flatlaf.FlatIntelliJLaf;
@@ -806,7 +807,7 @@ public class FlatTestFrame
buttonBar.add(scaleFactorComboBox, "cell 1 0");
//---- fontSizeSpinner ----
fontSizeSpinner.putClientProperty("JComponent.minimumWidth", 50);
fontSizeSpinner.putClientProperty(FlatClientProperties.MINIMUM_WIDTH, 50);
fontSizeSpinner.setModel(new SpinnerNumberModel(0, 0, null, 1));
fontSizeSpinner.addChangeListener(e -> fontSizeChanged());
buttonBar.add(fontSizeSpinner, "cell 2 0");

View File

@@ -316,13 +316,13 @@ public class FlatTextComponentsTest
//---- textField1 ----
textField1.setText("editable");
textField1.setComponentPopupMenu(popupMenu1);
textField1.putClientProperty("JTextField.placeholderText", "place");
textField1.putClientProperty(FlatClientProperties.PLACEHOLDER_TEXT, "place");
add(textField1, "cell 1 0,growx");
//---- textField3 ----
textField3.setText("longer text for testing horizontal scrolling");
textField3.setComponentPopupMenu(popupMenu1);
textField3.putClientProperty("JTextField.placeholderText", "place");
textField3.putClientProperty(FlatClientProperties.PLACEHOLDER_TEXT, "place");
add(textField3, "cell 2 0,growx");
//---- textField2 ----
@@ -330,7 +330,7 @@ public class FlatTextComponentsTest
textField2.setSelectionStart(1);
textField2.setSelectionEnd(4);
textField2.setComponentPopupMenu(popupMenu1);
textField2.putClientProperty("JTextField.placeholderText", "place");
textField2.putClientProperty(FlatClientProperties.PLACEHOLDER_TEXT, "place");
add(textField2, "cell 3 0");
//---- formattedTextFieldLabel ----
@@ -342,13 +342,13 @@ public class FlatTextComponentsTest
//---- formattedTextField1 ----
formattedTextField1.setText("editable");
formattedTextField1.setComponentPopupMenu(popupMenu1);
formattedTextField1.putClientProperty("JTextField.placeholderText", "place");
formattedTextField1.putClientProperty(FlatClientProperties.PLACEHOLDER_TEXT, "place");
add(formattedTextField1, "cell 1 1,growx");
//---- formattedTextField3 ----
formattedTextField3.setText("longer text for testing horizontal scrolling");
formattedTextField3.setComponentPopupMenu(popupMenu1);
formattedTextField3.putClientProperty("JTextField.placeholderText", "place");
formattedTextField3.putClientProperty(FlatClientProperties.PLACEHOLDER_TEXT, "place");
add(formattedTextField3, "cell 2 1,growx");
//======== panel1 ========
@@ -539,13 +539,13 @@ public class FlatTextComponentsTest
//---- passwordField1 ----
passwordField1.setText("editable");
passwordField1.setComponentPopupMenu(popupMenu1);
passwordField1.putClientProperty("JTextField.placeholderText", "place");
passwordField1.putClientProperty(FlatClientProperties.PLACEHOLDER_TEXT, "place");
add(passwordField1, "cell 1 2,growx");
//---- passwordField3 ----
passwordField3.setText("longer text for testing horizontal scrolling");
passwordField3.setComponentPopupMenu(popupMenu1);
passwordField3.putClientProperty("JTextField.placeholderText", "place");
passwordField3.putClientProperty(FlatClientProperties.PLACEHOLDER_TEXT, "place");
add(passwordField3, "cell 2 2,growx");
//---- textAreaLabel ----

View File

@@ -24,6 +24,7 @@ import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import javax.swing.*;
import com.formdev.flatlaf.FlatClientProperties;
import net.miginfocom.swing.*;
/**
@@ -205,57 +206,57 @@ public class FlatTypographyTest
//---- label54 ----
label54.setText("<html>FlatLaf<br><small>Windows</small></html>");
label54.putClientProperty("FlatLaf.styleClass", "h1");
label54.putClientProperty(FlatClientProperties.STYLE_CLASS, "h1");
add(label54, "cell 0 0");
//---- label68 ----
label68.setText("<html>JetBrains<br><small>Windows</small></html>");
label68.putClientProperty("FlatLaf.styleClass", "h1");
label68.putClientProperty(FlatClientProperties.STYLE_CLASS, "h1");
add(label68, "cell 1 0");
//---- label69 ----
label69.setText("<html>JetBrains<br><small>macOS</small></html>");
label69.putClientProperty("FlatLaf.styleClass", "h1");
label69.putClientProperty(FlatClientProperties.STYLE_CLASS, "h1");
add(label69, "cell 2 0");
//---- label10 ----
label10.setText("macOS");
label10.putClientProperty("FlatLaf.styleClass", "h1");
label10.putClientProperty(FlatClientProperties.STYLE_CLASS, "h1");
add(label10, "cell 3 0");
//---- label11 ----
label11.setText("Windows 10/11");
label11.putClientProperty("FlatLaf.styleClass", "h1");
label11.putClientProperty(FlatClientProperties.STYLE_CLASS, "h1");
add(label11, "cell 4 0");
//---- label72 ----
label72.setText("<html>GitHub<br>Primer</html>");
label72.putClientProperty("FlatLaf.styleClass", "h1");
label72.putClientProperty(FlatClientProperties.STYLE_CLASS, "h1");
add(label72, "cell 5 0");
//---- label28 ----
label28.setText("Material");
label28.putClientProperty("FlatLaf.styleClass", "h1");
label28.putClientProperty(FlatClientProperties.STYLE_CLASS, "h1");
add(label28, "cell 6 0");
//---- label29 ----
label29.setText("Material 3");
label29.putClientProperty("FlatLaf.styleClass", "h1");
label29.putClientProperty(FlatClientProperties.STYLE_CLASS, "h1");
add(label29, "cell 7 0");
//---- label1 ----
label1.setText("SAP Fiori");
label1.putClientProperty("FlatLaf.styleClass", "h1");
label1.putClientProperty(FlatClientProperties.STYLE_CLASS, "h1");
add(label1, "cell 8 0");
//---- label37 ----
label37.setText("Atlassian");
label37.putClientProperty("FlatLaf.styleClass", "h1");
label37.putClientProperty(FlatClientProperties.STYLE_CLASS, "h1");
add(label37, "cell 9 0");
//---- label46 ----
label46.setText("Iris");
label46.putClientProperty("FlatLaf.styleClass", "h1");
label46.putClientProperty(FlatClientProperties.STYLE_CLASS, "h1");
add(label46, "cell 10 0");
//---- linkLabel9 ----
@@ -1147,7 +1148,7 @@ public class FlatTypographyTest
//---- descLabel ----
descLabel.setText("description");
descLabel.putClientProperty("FlatLaf.styleClass", "small");
descLabel.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
descLabel.setEnabled(false);
add(descLabel, "cell 0 1");
// JFormDesigner - End of component initialization //GEN-END:initComponents

View File

@@ -25,6 +25,8 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import javax.swing.*;
import javax.swing.border.TitledBorder;
import com.formdev.flatlaf.FlatClientProperties;
@@ -74,6 +76,7 @@ public class FlatWindowDecorationsTest
}
private List<Image> images;
private Timer refreshStateTimer;
FlatWindowDecorationsTest() {
initComponents();
@@ -127,8 +130,54 @@ public class FlatWindowDecorationsTest
+ " @ " + bounds.x + ", " + bounds.y );
} else
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 ) {
@@ -189,9 +238,10 @@ public class FlatWindowDecorationsTest
if( rightCompCheckBox.isSelected() ) {
rightStretchCompCheckBox.setSelected( false );
tallCompCheckBox.setSelected( false );
JButton myButton = new JButton( "?" );
myButton.putClientProperty( "JButton.buttonType", "toolBarButton" );
myButton.putClientProperty( FlatClientProperties.BUTTON_TYPE, FlatClientProperties.BUTTON_TYPE_TOOLBAR_BUTTON );
myButton.setFocusable( false );
menuBar.add( Box.createGlue() );
@@ -207,6 +257,7 @@ public class FlatWindowDecorationsTest
if( rightStretchCompCheckBox.isSelected() ) {
rightCompCheckBox.setSelected( false );
tallCompCheckBox.setSelected( false );
menuBar.add( Box.createGlue() );
menuBar.add( new JProgressBar() );
@@ -216,6 +267,20 @@ public class FlatWindowDecorationsTest
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() {
Component[] components = menuBar.getComponents();
for( int i = components.length - 1; i >= 0; i-- ) {
@@ -434,7 +499,7 @@ debug*/
if( typeUtilityRadioButton.isSelected() )
window.setType( Window.Type.UTILITY );
else if( typeSmallRadioButton.isSelected() )
((RootPaneContainer)window).getRootPane().putClientProperty( "Window.style", "small" );
((RootPaneContainer)window).getRootPane().putClientProperty( FlatClientProperties.WINDOW_STYLE, FlatClientProperties.WINDOW_STYLE_SMALL );
}
private void decorationStyleChanged() {
@@ -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() {
Window window = SwingUtilities.windowForComponent( this );
return (window instanceof RootPaneContainer)
@@ -572,12 +647,14 @@ debug*/
maximizedBoundsCheckBox = new JCheckBox();
JPanel panel4 = new JPanel();
showIconCheckBox = new FlatTriStateCheckBox();
titleBarHeightCheckBox = new JCheckBox();
showTitleCheckBox = new JCheckBox();
titleBarHeightField = new JSpinner();
showIconifyCheckBox = new JCheckBox();
showMaximizeCheckBox = new JCheckBox();
showCloseCheckBox = new JCheckBox();
fullWindowContentCheckBox = new JCheckBox();
JLabel fullWindowContentButtonsBoundsLabel = new JLabel();
fullWindowContentButtonsBoundsLabel = new JLabel();
fullWindowContentButtonsBoundsField = new JLabel();
JPanel panel6 = new JPanel();
menuBarCheckBox = new JCheckBox();
@@ -585,6 +662,7 @@ debug*/
menuBarVisibleCheckBox = new JCheckBox();
rightCompCheckBox = new JCheckBox();
rightStretchCompCheckBox = new JCheckBox();
tallCompCheckBox = new JCheckBox();
JPanel panel3 = new JPanel();
addMenuButton = new JButton();
addGlueButton = new JButton();
@@ -621,6 +699,9 @@ debug*/
typeUtilityRadioButton = new JRadioButton();
typeSmallRadioButton = new JRadioButton();
showRectanglesCheckBox = new JCheckBox();
JPanel hSpacer1 = new JPanel(null);
JLabel frameStateLabel = new JLabel();
frameStateField = new JLabel();
menuBar = new JMenuBar();
JMenu fileMenu = new JMenu();
JMenuItem newMenuItem = new JMenuItem();
@@ -660,7 +741,8 @@ debug*/
"[fill]" +
"[fill]" +
"[]" +
"[]"));
"[]" +
"[40]"));
//======== panel7 ========
{
@@ -711,7 +793,8 @@ debug*/
panel4.setLayout(new MigLayout(
"ltr,hidemode 3,gap 0 0",
// columns
"[grow,left]",
"[grow,left]" +
"[fill]",
// rows
"[]" +
"[]" +
@@ -726,12 +809,23 @@ debug*/
showIconCheckBox.addActionListener(e -> showIconChanged());
panel4.add(showIconCheckBox, "cell 0 0");
//---- titleBarHeightCheckBox ----
titleBarHeightCheckBox.setText("Height:");
titleBarHeightCheckBox.addActionListener(e -> titleBarHeightChanged());
panel4.add(titleBarHeightCheckBox, "cell 1 0");
//---- showTitleCheckBox ----
showTitleCheckBox.setText("show title");
showTitleCheckBox.setSelected(true);
showTitleCheckBox.addActionListener(e -> showTitleChanged());
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.setText("show iconfiy");
showIconifyCheckBox.setSelected(true);
@@ -757,10 +851,12 @@ debug*/
//---- fullWindowContentButtonsBoundsLabel ----
fullWindowContentButtonsBoundsLabel.setText("Buttons bounds:");
fullWindowContentButtonsBoundsLabel.setEnabled(false);
panel4.add(fullWindowContentButtonsBoundsLabel, "cell 0 6");
//---- fullWindowContentButtonsBoundsField ----
fullWindowContentButtonsBoundsField.setText("null");
fullWindowContentButtonsBoundsField.setEnabled(false);
panel4.add(fullWindowContentButtonsBoundsField, "cell 0 6");
}
add(panel4, "cell 1 0");
@@ -777,6 +873,7 @@ debug*/
"[]" +
"[]" +
"[]" +
"[]" +
"[]"));
//---- menuBarCheckBox ----
@@ -806,6 +903,11 @@ debug*/
rightStretchCompCheckBox.setText("right aligned stretching component");
rightStretchCompCheckBox.addActionListener(e -> rightStretchCompChanged());
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");
@@ -1039,6 +1141,16 @@ debug*/
showRectanglesCheckBox.setSelected(true);
showRectanglesCheckBox.addActionListener(e -> showRectangles());
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 ========
{
@@ -1243,17 +1355,21 @@ debug*/
private JCheckBox fullScreenCheckBox;
private JCheckBox maximizedBoundsCheckBox;
private FlatTriStateCheckBox showIconCheckBox;
private JCheckBox titleBarHeightCheckBox;
private JCheckBox showTitleCheckBox;
private JSpinner titleBarHeightField;
private JCheckBox showIconifyCheckBox;
private JCheckBox showMaximizeCheckBox;
private JCheckBox showCloseCheckBox;
private JCheckBox fullWindowContentCheckBox;
private JLabel fullWindowContentButtonsBoundsLabel;
private JLabel fullWindowContentButtonsBoundsField;
private JCheckBox menuBarCheckBox;
private JCheckBox menuBarEmbeddedCheckBox;
private JCheckBox menuBarVisibleCheckBox;
private JCheckBox rightCompCheckBox;
private JCheckBox rightStretchCompCheckBox;
private JCheckBox tallCompCheckBox;
private JButton addMenuButton;
private JButton addGlueButton;
private JButton addCaptionButton;
@@ -1284,6 +1400,7 @@ debug*/
private JRadioButton typeUtilityRadioButton;
private JRadioButton typeSmallRadioButton;
private JCheckBox showRectanglesCheckBox;
private JLabel frameStateField;
private JMenuBar menuBar;
// JFormDesigner - End of variables declaration //GEN-END:variables
}

View File

@@ -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 {
contentType: "form/swing"
@@ -9,7 +9,7 @@ new FormModel {
add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "ltr,insets dialog,hidemode 3"
"$columnConstraints": "[left][fill][fill][fill]"
"$rowConstraints": "[fill][fill][][]"
"$rowConstraints": "[fill][fill][][][40]"
} ) {
name: "this"
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 ) {
"$layoutConstraints": "ltr,hidemode 3,gap 0 0"
"$columnConstraints": "[grow,left]"
"$columnConstraints": "[grow,left][fill]"
"$rowConstraints": "[][][][][]rel[]rel[]"
} ) {
name: "panel4"
@@ -91,6 +91,16 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"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" ) {
name: "showTitleCheckBox"
"text": "show title"
@@ -102,6 +112,20 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"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" ) {
name: "showIconifyCheckBox"
"text": "show iconfiy"
@@ -148,12 +172,17 @@ new FormModel {
add( new FormComponent( "javax.swing.JLabel" ) {
name: "fullWindowContentButtonsBoundsLabel"
"text": "Buttons bounds:"
"enabled": false
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 6"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "fullWindowContentButtonsBoundsField"
"text": "null"
"enabled": false
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
@@ -166,7 +195,7 @@ new FormModel {
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "ltr,hidemode 3,gap 0 0"
"$columnConstraints": "[left]"
"$rowConstraints": "[][][][][]"
"$rowConstraints": "[][][][][][]"
} ) {
name: "panel6"
"border": new javax.swing.border.TitledBorder( "Menu Bar" )
@@ -223,6 +252,16 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"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 ) {
"value": "cell 2 0"
} )
@@ -598,9 +637,30 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"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 ) {
"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 ) ) {
name: "menuBar"
@@ -766,23 +826,23 @@ new FormModel {
} )
} )
}, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 0, 515 )
"location": new java.awt.Point( 0, 585 )
"size": new java.awt.Dimension( 255, 30 )
} )
add( new FormNonVisual( "javax.swing.ButtonGroup" ) {
name: "styleButtonGroup"
}, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 0, 565 )
"location": new java.awt.Point( 0, 635 )
} )
add( new FormNonVisual( "javax.swing.ButtonGroup" ) {
name: "iconButtonGroup"
}, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 0, 615 )
"location": new java.awt.Point( 0, 685 )
} )
add( new FormNonVisual( "javax.swing.ButtonGroup" ) {
name: "typeButtonGroup"
}, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 0, 669 )
"location": new java.awt.Point( 0, 740 )
} )
}
}

Some files were not shown because too many files have changed in this diff Show More