Compare commits

...

99 Commits

Author SHA1 Message Date
Karl Tauber
0ba7798cbd Fonts: updated Inter to v4.1 (issue #976)
`Inter-*.otf` files are from `Inter-4.1.zip`, folder `extras/otf`
2025-03-09 13:51:34 +01:00
Karl Tauber
c486f695f2 Testing: support interprocess Laf sync (enable/disable with Alt+Shift+S) 2025-03-09 13:31:38 +01:00
Karl Tauber
0bc2513c46 for PR #982:
- updated CHANGELOG.md
- updated styling unit tests
- updated UI defaults dumps
- Demo: error/warning/success hints in a single row
- Demo: reduced height of "Data comp" tab to make Demo window smaller
- IntelliJ themes: fixed missing/overwritten success colors
2025-03-09 00:15:00 +01:00
Karl Tauber
bc3504378b Merge PR #982: Add "success" outline for borders (issue #945) 2025-03-08 23:45:20 +01:00
Karl Tauber
94fc75dc78 Merge PR #981: Add Consulo to Software Development list 2025-03-08 19:51:22 +01:00
Karl Tauber
681c0cd4fe HTML: fixed rendering of <hr noshade> in dark themes (issue #932) 2025-03-08 19:47:37 +01:00
Karl Tauber
f7495a0a5b - support key prefixes for Linux desktop environments (issue #974)
- support custom key prefixes (issue #649)
- support multi-prefixed keys
- changed handling of prefixed keys
2025-03-08 18:11:38 +01:00
Valery Semenchuk
dd44d3ed2d Merge branch 'JFormDesigner:main' into issue945 2025-03-08 14:58:22 +04:00
Valery Semenchuk
86a4d0ab12 add "success" border color
fix #945
2025-03-08 14:57:06 +04:00
Valery Semenchuk
b43c3a9e00 Add Consulo to Software Development list 2025-03-07 23:01:03 +04:00
Karl Tauber
babc8aa55d SwingX: support JXTipOfTheDay component (issue #980) 2025-03-07 11:59:21 +01:00
Karl Tauber
5dc88a6210 SwingX: moved FlatMonthDownIcon and FlatMonthUpIcon from ui to icons package 2025-03-06 18:47:48 +01:00
Karl Tauber
d612b9f4b8 Linux: use X11 window manager events to resize window, if FlatLaf window decorations are enabled (issue #866)
also made drag border slightly wider (from 5 to 6 pixels) and changed drag corner width from 16 to 32 to match native windows
2025-03-06 17:47:55 +01:00
Karl Tauber
9b1ae5c74a IntelliJ Themes: support customizing through properties files (issue #824)
re-written how .theme.json values are applied:
- old: .theme.json values were applied as last step to a UIDefaults object (after processing all FlatLaf properties files)
- new: .theme.json values are applied to the properties map while loading all FlatLaf properties files
2025-03-06 13:26:38 +01:00
Karl Tauber
143f96360b IntelliJ Themes: removed Gruvbox Dark Medium and Gruvbox Dark Soft themes 2025-02-27 11:58:09 +01:00
Karl Tauber
f5e6b90e02 UIDefaultsDump: fixed property sort order and updated dumps
GTKLookAndFeel dump updated on Ubuntu 24.10
2025-02-25 20:04:29 +01:00
Karl Tauber
f36886aeb3 IntelliJ Themes: renamed classes in package com.formdev.flatlaf.intellijthemes.materialthemeuilite from Flat<theme> to FlatMT<theme> (preparation for #824) 2025-02-25 16:18:55 +01:00
Karl Tauber
d26eb2674f Demo/Testing: use IntelliJ Theme Laf classes (from package com.formdev.flatlaf.intellijthemes) in Demo and Testing apps instead of directly loading .theme.json (preparation for #824) 2025-02-25 15:50:30 +01:00
Karl Tauber
68b8769d0d IntelliJ Themes: theme prefix in IntelliJTheme$ThemeLaf.properties changed from [theme-name] to {theme-name}
preparation to support custom/general property prefixes for #649 and #974
2025-02-25 15:04:22 +01:00
Karl Tauber
7f37e884d3 Merge PR #972: Increase contrast of text for better readability 2025-02-25 11:06:28 +01:00
Karl Tauber
a4dc1b4151 UIDefaultsLoader: support lazy option for spin(), changeHue(), changeSaturation(), changeLightness(), changeAlpha(), mix(), tint() and shade() color functions; added unit tests for lazy color functions 2025-02-25 10:42:44 +01:00
Karl Tauber
022a67929a IntelliJ Themes: use "High Contrast" from intellij repo 2025-02-25 00:24:35 +01:00
Karl Tauber
f7c867fb97 increased contrast of separator lines in dark themes (issue #762) 2025-02-24 19:54:18 +01:00
Karl Tauber
f0685d179e Linux: support loading native libraries for unknown architectures (issue #966)
expected filename is same as for `x86_64` architecture but replace `x86_64` with value of system property `os.arch`
2025-02-20 13:56:50 +01:00
Karl Tauber
c8eaf5f587 increased contrast of text for better readability (issue #762) 2025-02-18 20:06:30 +01:00
Karl Tauber
ed69049c08 UIDefaultsDump: dump contrast ratios 2025-02-18 20:06:30 +01:00
Karl Tauber
411a2f6d29 fixed errors reported by Error Prone in commit 6c8f813e53 2025-02-16 19:59:36 +01:00
Karl Tauber
f24b3a6022 UI defaults: Linux dumps updated on Ubuntu 24.10 2025-02-16 19:21:53 +01:00
Karl Tauber
ebacad2d04 UIDefaultsLoader: support derived option for mix(), tint() and shade() color functions; added unit tests for color functions 2025-02-16 16:58:21 +01:00
Karl Tauber
76f436726f IntelliJ Themes: updated themes to newest versions (used IJThemesUpdater) 2025-02-13 18:55:08 +01:00
Karl Tauber
6c8f813e53 Testing: added FlatClassLoaderTest.java (used for previous commit) 2025-02-13 00:27:44 +01:00
Karl Tauber
5f6cc719ad fixed loading FlatLaf UI delegate classes when using FlatLaf in special application where multiple class loaders are involved; e.g. in Eclipse plugin or in LibreOffice extension (issues #955 and #851) 2025-02-12 14:35:35 +01:00
Karl Tauber
00858002de Eclipse: updated org.eclipse.jdt.core.prefs using latest Eclipse and buildship versions 2025-02-05 14:00:11 +01:00
Karl Tauber
072cc3c488 Styling: MigLayout visual padding was not updated after applying style to Button, ComboBox, Spinner, TextField (and subclasses) and ToggleButton (issue #965) 2025-02-05 12:55:12 +01:00
Karl Tauber
1f594b2ba8 Linux with FlatLaf window decorations: fixed occasional maximizing of window when single-clicking the window's title bar (issue #637) 2025-01-28 15:31:13 +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
231 changed files with 19702 additions and 6198 deletions

View File

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

View File

@@ -21,16 +21,25 @@ jobs:
strategy: strategy:
matrix: matrix:
os: os:
- windows - windows-latest
- macos - macos-latest
- ubuntu - ubuntu-latest
- ubuntu-24.04-arm
runs-on: ${{ matrix.os }}-latest runs-on: ${{ matrix.os }}
steps: steps:
- uses: actions/checkout@v4 - 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 - name: Setup Java 11
uses: actions/setup-java@v4 uses: actions/setup-java@v4

1
.gitignore vendored
View File

@@ -5,6 +5,7 @@ build/
.project .project
.settings/ .settings/
.idea/ .idea/
.consulo/
out/ out/
*.iml *.iml
*.ipr *.ipr

View File

@@ -1,6 +1,140 @@
FlatLaf Change Log 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).
- Increased contrast of text for better readability: (PR #972; issue #762)
- In **FlatLaf Dark**, **FlatLaf Darcula** and many dark IntelliJ themes, made
all text colors brighter.
- In **FlatLaf Light**, **FlatLaf IntelliJ** and many light IntelliJ themes,
made disabled text colors slightly darker.
- In **FlatLaf macOS Light**, made disabled text colors darker.
- In **FlatLaf macOS Dark**, made text colors of "default" button and selected
ToggleButton lighter.
- 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)
- Linux: Use X11 window manager events to resize window, if FlatLaf window
decorations are enabled. This gives FlatLaf windows a more "native" feeling.
(issue #866)
- IntelliJ Themes:
- Updated to latest versions and fixed various issues.
- Support customizing through properties files. (issue #824)
- SwingX: Support `JXTipOfTheDay` component. (issue #980)
- Support key prefixes for Linux desktop environments (e.g. `[gnome]`, `[kde]`
or `[xfce]`) in properties files. (issue #974)
- Support custom key prefixes (e.g. `[win10]` or `[test]`) in properties files.
(issue #649)
- Support multi-prefixed keys (e.g. `[dark][gnome]TitlePane.buttonBackground`).
The value is only used if all prefixes match current platform/theme.
- Support new component border color to indicate success state (set client
property `JComponent.outline` to `success`). (PR #982, issue #945)
- Fonts: Updated **Inter** to
[v4.1](https://github.com/rsms/inter/releases/tag/v4.1).
#### 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: Fixed occasional maximizing of window when single-clicking the
window's title bar. (issue #637)
- Styling: MigLayout visual padding was not updated after applying style to
Button, ComboBox, Spinner, TextField (and subclasses) and ToggleButton. (issue
#965)
- Linux: Popups (menus and combobox lists) were not hidden when window is moved,
resized, maximized, restored, iconified or switched to another window. (issue
#962)
- Fixed loading FlatLaf UI delegate classes when using FlatLaf in special
application where multiple class loaders are involved. E.g. in Eclipse plugin
or in LibreOffice extension. (issues #955 and #851)
- HTML: Fixed rendering of `<hr noshade>` in dark themes. (issue #932)
#### Incompatibilities
- IntelliJ Themes:
- Theme prefix in `IntelliJTheme$ThemeLaf.properties` changed from
`[theme-name]` to `{theme-name}`.
- Renamed classes in package
`com.formdev.flatlaf.intellijthemes.materialthemeuilite` from `Flat<theme>`
to `FlatMT<theme>`.
- Removed `Gruvbox Dark Medium` and `Gruvbox Dark Soft` themes.
- Prefixed keys in properties files (e.g. `[dark]Button.background` or
`[win]Button.arc`) are now handled earlier than before. In previous versions,
prefixed keys always had higher priority than unprefixed keys and did always
overwrite unprefixed keys. Now prefixed keys are handled in same order as
unprefixed keys, which means that if a key is prefixed and unprefixed (e.g.
`[win]Button.arc` and `Button.arc`), the one which is last specified in
properties file is used.\
Following worked in previous versions, but now `Button.arc` is always `6`:
~~~properties
[win]Button.arc = 12
Button.arc = 6
~~~
This works in new (and old) versions:
~~~properties
Button.arc = 6
[win]Button.arc = 12
~~~
## 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 ## 3.5.2
#### Fixed bugs #### Fixed bugs

View File

@@ -35,7 +35,9 @@ Sponsors
### Current Sponsors ### Current Sponsors
[![None Sponsors](images/none-sponsors.png)](https://www.formdev.com/flatlaf/sponsor/) <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/) [Become a Sponsor](https://www.formdev.com/flatlaf/sponsor/)
@@ -224,6 +226,8 @@ Applications using FlatLaf
language created to learn programming language created to learn programming
- [lsfusion platform](https://github.com/lsfusion/platform) - information - [lsfusion platform](https://github.com/lsfusion/platform) - information
systems development platform systems development platform
- ![New](images/new.svg) [Consulo](https://github.com/consulo/consulo) - open
source cross-platform multi-language IDE (Java, .NET, JS, etc)
### Electrical ### Electrical

View File

@@ -1,4 +1,7 @@
eclipse.preferences.version=1 eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.source=1.8
org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false
org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647 org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.align_type_members_on_columns=false

View File

@@ -156,5 +156,6 @@ flatlafPublish {
NativeArtifact( "${natives}/libflatlaf-macos-arm64.dylib", "macos-arm64", "dylib" ), NativeArtifact( "${natives}/libflatlaf-macos-arm64.dylib", "macos-arm64", "dylib" ),
NativeArtifact( "${natives}/libflatlaf-macos-x86_64.dylib", "macos-x86_64", "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-x86_64.so", "linux-x86_64", "so" ),
NativeArtifact( "${natives}/libflatlaf-linux-arm64.so", "linux-arm64", "so" ),
) )
} }

View File

@@ -220,6 +220,7 @@ public interface FlatClientProperties
* <strong>Allowed Values</strong> * <strong>Allowed Values</strong>
* {@link #OUTLINE_ERROR}, * {@link #OUTLINE_ERROR},
* {@link #OUTLINE_WARNING}, * {@link #OUTLINE_WARNING},
* {@link #OUTLINE_SUCCESS},
* any color (type {@link java.awt.Color}) or * any color (type {@link java.awt.Color}) or
* an array of two colors (type {@link java.awt.Color}[2]) where the first color * an array of two colors (type {@link java.awt.Color}[2]) where the first color
* is for focused state and the second for unfocused state * is for focused state and the second for unfocused state
@@ -240,6 +241,14 @@ public interface FlatClientProperties
*/ */
String OUTLINE_WARNING = "warning"; String OUTLINE_WARNING = "warning";
/**
* Paint the component border in another color (usually greenish) to indicate a success.
*
* @see #OUTLINE
* @since 3.6
*/
String OUTLINE_SUCCESS = "success";
/** /**
* Specifies a callback that is invoked to check whether a component is permanent focus owner. * Specifies a callback that is invoked to check whether a component is permanent focus owner.
* Used to paint focus indicators. * Used to paint focus indicators.
@@ -1410,13 +1419,23 @@ public interface FlatClientProperties
//---- JTree -------------------------------------------------------------- //---- 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> * <p>
* <strong>Component</strong> {@link javax.swing.JTree}<br> * <strong>Component</strong> {@link javax.swing.JTree}<br>
* <strong>Value type</strong> {@link java.lang.Boolean} * <strong>Value type</strong> {@link java.lang.Boolean}
*/ */
String TREE_WIDE_SELECTION = "JTree.wideSelection"; 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}. * 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. * If set to {@code false}, then the tree cell renderer is responsible for painting selection.

View File

@@ -37,6 +37,7 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
@@ -44,6 +45,7 @@ import java.util.MissingResourceException;
import java.util.Properties; import java.util.Properties;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import java.util.ServiceLoader; import java.util.ServiceLoader;
import java.util.Set;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.IntUnaryOperator; import java.util.function.IntUnaryOperator;
@@ -100,6 +102,8 @@ public abstract class FlatLaf
private static Map<String, String> globalExtraDefaults; private static Map<String, String> globalExtraDefaults;
private Map<String, String> extraDefaults; private Map<String, String> extraDefaults;
private static Function<String, Color> systemColorGetter; private static Function<String, Color> systemColorGetter;
private static Set<String> uiKeyPlatformPrefixes;
private static Set<String> uiKeySpecialPrefixes;
private String desktopPropertyName; private String desktopPropertyName;
private String desktopPropertyName2; private String desktopPropertyName2;
@@ -111,6 +115,7 @@ public abstract class FlatLaf
private PopupFactory oldPopupFactory; private PopupFactory oldPopupFactory;
private MnemonicHandler mnemonicHandler; private MnemonicHandler mnemonicHandler;
private boolean subMenuUsabilityHelperInstalled; private boolean subMenuUsabilityHelperInstalled;
private LinuxPopupMenuCanceler linuxPopupMenuCanceler;
private Consumer<UIDefaults> postInitialization; private Consumer<UIDefaults> postInitialization;
private List<Function<Object, Object>> uiDefaultsGetters; private List<Function<Object, Object>> uiDefaultsGetters;
@@ -305,6 +310,10 @@ public abstract class FlatLaf
// install submenu usability helper // install submenu usability helper
subMenuUsabilityHelperInstalled = SubMenuUsabilityHelper.install(); 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 // listen to desktop property changes to update UI if system font or scaling changes
if( SystemInfo.isWindows ) { if( SystemInfo.isWindows ) {
// Windows 10 allows increasing font size independent of scaling: // Windows 10 allows increasing font size independent of scaling:
@@ -397,6 +406,12 @@ public abstract class FlatLaf
subMenuUsabilityHelperInstalled = false; subMenuUsabilityHelperInstalled = false;
} }
// uninstall Linux popup menu canceler
if( linuxPopupMenuCanceler != null ) {
linuxPopupMenuCanceler.uninstall();
linuxPopupMenuCanceler = null;
}
// restore default link color // restore default link color
new HTMLEditorKit().getStyleSheet().addRule( "a, address { color: blue; }" ); new HTMLEditorKit().getStyleSheet().addRule( "a, address { color: blue; }" );
postInitialization = null; postInitialization = null;
@@ -510,10 +525,10 @@ public abstract class FlatLaf
// load defaults from properties // load defaults from properties
List<Class<?>> lafClassesForDefaultsLoading = getLafClassesForDefaultsLoading(); List<Class<?>> lafClassesForDefaultsLoading = getLafClassesForDefaultsLoading();
if( lafClassesForDefaultsLoading != null ) if( lafClassesForDefaultsLoading == null )
UIDefaultsLoader.loadDefaultsFromProperties( lafClassesForDefaultsLoading, addons, getAdditionalDefaults(), isDark(), defaults ); lafClassesForDefaultsLoading = UIDefaultsLoader.getLafClassesForDefaultsLoading( getClass() );
else UIDefaultsLoader.loadDefaultsFromProperties( lafClassesForDefaultsLoading, addons,
UIDefaultsLoader.loadDefaultsFromProperties( getClass(), addons, getAdditionalDefaults(), isDark(), defaults ); this::applyAdditionalProperties, getAdditionalDefaults(), isDark(), defaults );
// setup default font after loading defaults from properties // setup default font after loading defaults from properties
// to allow defining "defaultFont" in properties // to allow defining "defaultFont" in properties
@@ -530,9 +545,6 @@ public abstract class FlatLaf
// initialize text antialiasing // initialize text antialiasing
putAATextInfo( defaults ); putAATextInfo( defaults );
// apply additional defaults (e.g. from IntelliJ themes)
applyAdditionalDefaults( defaults );
// allow addons modifying UI defaults // allow addons modifying UI defaults
for( FlatDefaultsAddon addon : addons ) for( FlatDefaultsAddon addon : addons )
addon.afterDefaultsLoading( this, defaults ); addon.afterDefaultsLoading( this, defaults );
@@ -542,6 +554,9 @@ public abstract class FlatLaf
return UIScale.getUserScaleFactor(); return UIScale.getUserScaleFactor();
} ); } );
// add lazy UI delegate class loading (if necessary)
addLazyUIdelegateClassLoading( defaults );
if( postInitialization != null ) { if( postInitialization != null ) {
postInitialization.accept( defaults ); postInitialization.accept( defaults );
postInitialization = null; postInitialization = null;
@@ -550,7 +565,8 @@ public abstract class FlatLaf
return defaults; return defaults;
} }
void applyAdditionalDefaults( UIDefaults defaults ) { // apply additional properties (e.g. from IntelliJ themes)
void applyAdditionalProperties( Properties properties ) {
} }
protected List<Class<?>> getLafClassesForDefaultsLoading() { protected List<Class<?>> getLafClassesForDefaultsLoading() {
@@ -739,6 +755,53 @@ public abstract class FlatLaf
} }
} }
/**
* Handle UI delegate classes if running in special application where multiple class loaders are involved.
* E.g. in Eclipse plugin or in LibreOffice extension.
* <p>
* Problem: Swing runs in Java's system classloader and FlatLaf is loaded in plugin classloader.
* When Swing tries to load UI delegate class in {@link UIDefaults#getUIClass(String, ClassLoader)},
* invoked from {@link UIDefaults#getUI(JComponent)}, it uses the component's classloader,
* which is Java's system classloader for core Swing components,
* and can not find FlatLaf UI delegates.
* <p>
* Solution: Add lazy values for UI delegate class names.
* Those lazy values use FlatLaf classloader to load UI delegate class.
* This is similar to what {@link UIDefaults#getUIClass(String, ClassLoader)} does.
* <p>
* Not using {@code defaults.put( "ClassLoader", FlatLaf.class.getClassLoader() )},
* which would work for FlatLaf UI delegates, but it would break custom
* UI delegates used in other classloaders.
*/
private static void addLazyUIdelegateClassLoading( UIDefaults defaults ) {
if( FlatLaf.class.getClassLoader() == ClassLoader.getSystemClassLoader() )
return; // not necessary
Map<String, LazyValue> map = new HashMap<>();
for( Map.Entry<Object, Object> e : defaults.entrySet() ) {
Object key = e.getKey();
Object value = e.getValue();
if( key instanceof String && ((String)key).endsWith( "UI" ) &&
value instanceof String && !defaults.containsKey( value ) )
{
String className = (String) value;
map.put( className, (LazyValue) t -> {
try {
Class<?> uiClass = FlatLaf.class.getClassLoader().loadClass( className );
if( ComponentUI.class.isAssignableFrom( uiClass ) )
return uiClass;
} catch( ClassNotFoundException ex ) {
// ignore
}
// let UIDefaults.getUIClass() try to load UI delegate class
return null;
} );
}
}
defaults.putAll( map );
}
private void putAATextInfo( UIDefaults defaults ) { private void putAATextInfo( UIDefaults defaults ) {
if ( SystemInfo.isMacOS && SystemInfo.isJetBrainsJVM ) { if ( SystemInfo.isMacOS && SystemInfo.isJetBrainsJVM ) {
// The awt.font.desktophints property suggests sub-pixel anti-aliasing // The awt.font.desktophints property suggests sub-pixel anti-aliasing
@@ -1063,6 +1126,92 @@ public abstract class FlatLaf
FlatLaf.systemColorGetter = systemColorGetter; FlatLaf.systemColorGetter = systemColorGetter;
} }
/**
* Returns UI key prefix, used in FlatLaf properties files, for light or dark themes.
* Return value is either {@code [light]} or {@code [dark]}.
*
* @since 3.6
*/
public static String getUIKeyLightOrDarkPrefix( boolean dark ) {
return dark ? "[dark]" : "[light]";
}
/**
* Returns set of UI key prefixes, used in FlatLaf properties files, for current platform.
* If UI keys in properties files start with a prefix (e.g. {@code [someprefix]Button.background}),
* then they are only used if that prefix is contained in this set
* (or is one of {@code [light]} or {@code [dark]} depending on current theme).
* <p>
* By default, the set contains one or more of following prefixes:
* <ul>
* <li>{@code [win]} on Windows
* <li>{@code [mac]} on macOS
* <li>{@code [linux]} on Linux
* <li>{@code [unknown]} on other platforms
* <li>{@code [gnome]} on Linux with GNOME desktop environment
* <li>{@code [kde]} on Linux with KDE desktop environment
* <li>on Linux, the value of the environment variable {@code XDG_CURRENT_DESKTOP},
* split at colons and converted to lower case (e.g. if value of {@code XDG_CURRENT_DESKTOP}
* is {@code ubuntu:GNOME}, then {@code [ubuntu]} and {@code [gnome]})
* </ul>
* <p>
* You can add own prefixes to the set.
* The prefixes must start with '[' and end with ']' characters, otherwise they will be ignored.
*
* @since 3.6
*/
public static Set<String> getUIKeyPlatformPrefixes() {
if( uiKeyPlatformPrefixes == null ) {
uiKeyPlatformPrefixes = new HashSet<>();
uiKeyPlatformPrefixes.add(
SystemInfo.isWindows ? "[win]" :
SystemInfo.isMacOS ? "[mac]" :
SystemInfo.isLinux ? "[linux]" : "[unknown]" );
// Linux
if( SystemInfo.isLinux ) {
if( SystemInfo.isGNOME )
uiKeyPlatformPrefixes.add( "[gnome]" );
else if( SystemInfo.isKDE )
uiKeyPlatformPrefixes.add( "[kde]" );
// add values from XDG_CURRENT_DESKTOP for other desktops
String desktop = System.getenv( "XDG_CURRENT_DESKTOP" );
if( desktop != null ) {
// XDG_CURRENT_DESKTOP is a colon-separated list of strings
// https://specifications.freedesktop.org/desktop-entry-spec/latest/recognized-keys.html#key-onlyshowin
// e.g. "ubuntu:GNOME" on Ubuntu 24.10 or "GNOME-Classic:GNOME" on CentOS 7
for( String desk : StringUtils.split( desktop.toLowerCase( Locale.ENGLISH ), ':', true, true ) )
uiKeyPlatformPrefixes.add( '[' + desk + ']' );
}
}
}
return uiKeyPlatformPrefixes;
}
/**
* Returns set of special UI key prefixes, used in FlatLaf properties files.
* Unlike other prefixes, properties with special prefixes are preserved.
* You can access them using `UIManager`. E.g. `UIManager.get( "[someSpecialPrefix]someKey" )`.
* <p>
* By default, the set contains following special prefixes:
* <ul>
* <li>{@code [style]}
* </ul>
* <p>
* You can add own prefixes to the set.
* The prefixes must start with '[' and end with ']' characters, otherwise they will be ignored.
*
* @since 3.6
*/
public static Set<String> getUIKeySpecialPrefixes() {
if( uiKeySpecialPrefixes == null ) {
uiKeySpecialPrefixes = new HashSet<>();
uiKeySpecialPrefixes.add( "[style]" );
}
return uiKeySpecialPrefixes;
}
private static void reSetLookAndFeel() { private static void reSetLookAndFeel() {
EventQueue.invokeLater( () -> { EventQueue.invokeLater( () -> {
LookAndFeel lookAndFeel = UIManager.getLookAndFeel(); LookAndFeel lookAndFeel = UIManager.getLookAndFeel();

View File

@@ -23,13 +23,15 @@ import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Locale; import java.util.Locale;
import java.util.Properties; import java.util.Properties;
import com.formdev.flatlaf.themes.FlatMacDarkLaf;
import com.formdev.flatlaf.themes.FlatMacLightLaf;
/** /**
* A Flat LaF that is able to load UI defaults from properties passed to the constructor. * A Flat LaF that is able to load UI defaults from properties passed to the constructor.
* <p> * <p>
* Specify the base theme in the properties with {@code @baseTheme=<baseTheme>}. * Specify the base theme in the properties with {@code @baseTheme=<baseTheme>}.
* Allowed values for {@code <baseTheme>} are {@code light} (the default), {@code dark}, * Allowed values for {@code <baseTheme>} are {@code light} (the default), {@code dark},
* {@code intellij} or {@code darcula}. * {@code intellij}, {@code darcula}, {@code maclight} or {@code macdark}.
* <p> * <p>
* The properties are applied after loading the base theme and may overwrite base properties. * The properties are applied after loading the base theme and may overwrite base properties.
* All features of FlatLaf properties files are available. * All features of FlatLaf properties files are available.
@@ -71,7 +73,8 @@ public class FlatPropertiesLaf
this.properties = properties; this.properties = properties;
baseTheme = properties.getProperty( "@baseTheme", "light" ); baseTheme = properties.getProperty( "@baseTheme", "light" );
dark = "dark".equalsIgnoreCase( baseTheme ) || "darcula".equalsIgnoreCase( baseTheme ); dark = "dark".equalsIgnoreCase( baseTheme ) || "darcula".equalsIgnoreCase( baseTheme ) ||
"macdark".equalsIgnoreCase( baseTheme );
} }
@Override @Override
@@ -116,6 +119,16 @@ public class FlatPropertiesLaf
lafClasses.add( FlatDarkLaf.class ); lafClasses.add( FlatDarkLaf.class );
lafClasses.add( FlatDarculaLaf.class ); lafClasses.add( FlatDarculaLaf.class );
break; break;
case "maclight":
lafClasses.add( FlatLightLaf.class );
lafClasses.add( FlatMacLightLaf.class );
break;
case "macdark":
lafClasses.add( FlatDarkLaf.class );
lafClasses.add( FlatMacDarkLaf.class );
break;
} }
return lafClasses; return lafClasses;
} }

View File

@@ -138,10 +138,10 @@ public interface FlatSystemProperties
/** /**
* Specifies whether native rounded popup borders should be used (if supported by operating system). * Specifies whether native rounded popup borders should be used (if supported by operating system).
* <p> * <p>
* (requires Window 11 or macOS) * (requires Windows 11 or macOS)
* <p> * <p>
* <strong>Allowed Values</strong> {@code false} and {@code true}<br> * <strong>Allowed Values</strong> {@code false} and {@code true}<br>
* <strong>Default</strong> {@code true}; except on macOS 14.4+ where it is {@code false} * <strong>Default</strong> {@code true}; except in FlatLaf 3.5.x on macOS 14.4+ where it was {@code false}
* *
* @since 3.5.2 * @since 3.5.2
*/ */

View File

@@ -16,7 +16,6 @@
package com.formdev.flatlaf; package com.formdev.flatlaf;
import java.awt.Color;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
@@ -25,20 +24,16 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.Map.Entry;
import javax.swing.UIDefaults;
import javax.swing.plaf.ColorUIResource;
import com.formdev.flatlaf.json.Json; import com.formdev.flatlaf.json.Json;
import com.formdev.flatlaf.json.ParseException; import com.formdev.flatlaf.json.ParseException;
import com.formdev.flatlaf.util.ColorFunctions;
import com.formdev.flatlaf.util.LoggingFacade; import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.StringUtils; import com.formdev.flatlaf.util.StringUtils;
import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.SystemInfo;
@@ -63,13 +58,11 @@ public class IntelliJTheme
public final boolean dark; public final boolean dark;
public final String author; public final String author;
private final boolean isMaterialUILite; private Map<String, String> jsonColors;
private Map<String, Object> jsonUI;
private Map<String, Object> jsonIcons;
private Map<String, String> colors; private Map<String, String> namedColors = Collections.emptyMap();
private Map<String, Object> ui;
private Map<String, Object> icons;
private Map<String, ColorUIResource> namedColors = Collections.emptyMap();
/** /**
* Loads a IntelliJ .theme.json file from the given input stream, * Loads a IntelliJ .theme.json file from the given input stream,
@@ -84,7 +77,7 @@ public class IntelliJTheme
try { try {
return FlatLaf.setup( createLaf( in ) ); return FlatLaf.setup( createLaf( in ) );
} catch( Exception ex ) { } catch( Exception ex ) {
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to load IntelliJ theme", ex ); LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to load IntelliJ theme", ex );
return false; return false;
} }
} }
@@ -138,94 +131,90 @@ public class IntelliJTheme
dark = Boolean.parseBoolean( (String) json.get( "dark" ) ); dark = Boolean.parseBoolean( (String) json.get( "dark" ) );
author = (String) json.get( "author" ); author = (String) json.get( "author" );
isMaterialUILite = author.equals( "Mallowigi" ); jsonColors = (Map<String, String>) json.get( "colors" );
jsonUI = (Map<String, Object>) json.get( "ui" );
colors = (Map<String, String>) json.get( "colors" ); jsonIcons = (Map<String, Object>) json.get( "icons" );
ui = (Map<String, Object>) json.get( "ui" );
icons = (Map<String, Object>) json.get( "icons" );
} }
private void applyProperties( UIDefaults defaults ) { private void applyProperties( Properties properties ) {
if( ui == null ) if( jsonUI == null )
return; return;
defaults.put( "Component.isIntelliJTheme", true ); put( properties, "Component.isIntelliJTheme", "true" );
// enable button shadows // enable button shadows
defaults.put( "Button.paintShadow", true ); put( properties, "Button.paintShadow", "true" );
defaults.put( "Button.shadowWidth", dark ? 2 : 1 ); put( properties, "Button.shadowWidth", dark ? "2" : "1" );
Map<Object, Object> themeSpecificDefaults = removeThemeSpecificDefaults( defaults ); Map<String, String> themeSpecificProps = removeThemeSpecificProps( properties );
Set<String> jsonUIKeys = new HashSet<>();
loadNamedColors( defaults ); // Json node "colors"
loadNamedColors( properties, jsonUIKeys );
// convert Json "ui" structure to UI defaults // convert Json "ui" structure to UI properties
ArrayList<Object> defaultsKeysCache = new ArrayList<>(); for( Map.Entry<String, Object> e : jsonUI.entrySet() )
Set<String> uiKeys = new HashSet<>(); apply( e.getKey(), e.getValue(), properties, jsonUIKeys );
for( Map.Entry<String, Object> e : ui.entrySet() )
apply( e.getKey(), e.getValue(), defaults, defaultsKeysCache, uiKeys );
applyColorPalette( defaults ); // set FlatLaf variables
applyCheckBoxColors( defaults ); copyIfSetInJson( properties, jsonUIKeys, "@background", "Panel.background", "*.background" );
copyIfSetInJson( properties, jsonUIKeys, "@foreground", "CheckBox.foreground", "*.foreground" );
copyIfSetInJson( properties, jsonUIKeys, "@accentBaseColor",
"ColorPalette.accent", // Material UI Lite, Hiberbee
"ColorPalette.accentColor", // Dracula, One Dark
"ProgressBar.foreground",
"*.selectionBackground" );
copyIfSetInJson( properties, jsonUIKeys, "@accentUnderlineColor", "*.underlineColor", "TabbedPane.underlineColor" );
copyIfSetInJson( properties, jsonUIKeys, "@selectionBackground", "*.selectionBackground" );
copyIfSetInJson( properties, jsonUIKeys, "@selectionForeground", "*.selectionForeground" );
copyIfSetInJson( properties, jsonUIKeys, "@selectionInactiveBackground", "*.selectionInactiveBackground" );
copyIfSetInJson( properties, jsonUIKeys, "@selectionInactiveForeground", "*.selectionInactiveForeground" );
// Json node "icons/ColorPalette"
applyIconsColorPalette( properties );
// apply "CheckBox.icon." colors
applyCheckBoxColors( properties );
// copy values // copy values
for( Map.Entry<String, String> e : uiKeyCopying.entrySet() ) { for( Map.Entry<String, String> e : uiKeyCopying.entrySet() ) {
Object value = defaults.get( e.getValue() ); Object value = properties.get( e.getValue() );
if( value != null ) if( value != null )
defaults.put( e.getKey(), value ); put( properties, e.getKey(), value );
} }
// IDEA does not paint button background if disabled, but FlatLaf does // IDEA does not paint button background if disabled, but FlatLaf does
Object panelBackground = defaults.get( "Panel.background" ); put( properties, "Button.disabledBackground", "@disabledBackground" );
defaults.put( "Button.disabledBackground", panelBackground ); put( properties, "ToggleButton.disabledBackground", "@disabledBackground" );
defaults.put( "ToggleButton.disabledBackground", panelBackground );
// fix Button borders // fix Button
copyIfNotSet( defaults, "Button.focusedBorderColor", "Component.focusedBorderColor", uiKeys ); fixStartEnd( properties, jsonUIKeys, "Button.startBackground", "Button.endBackground", "Button.background" );
defaults.put( "Button.hoverBorderColor", defaults.get( "Button.focusedBorderColor" ) ); fixStartEnd( properties, jsonUIKeys, "Button.startBorderColor", "Button.endBorderColor", "Button.borderColor" );
defaults.put( "HelpButton.hoverBorderColor", defaults.get( "Button.focusedBorderColor" ) ); fixStartEnd( properties, jsonUIKeys, "Button.default.startBackground", "Button.default.endBackground", "Button.default.background" );
fixStartEnd( properties, jsonUIKeys, "Button.default.startBorderColor", "Button.default.endBorderColor", "Button.default.borderColor" );
// IDEA uses an SVG icon for the help button, but paints the background with Button.startBackground and Button.endBackground
Object helpButtonBackground = defaults.get( "Button.startBackground" );
Object helpButtonBorderColor = defaults.get( "Button.startBorderColor" );
if( helpButtonBackground == null )
helpButtonBackground = defaults.get( "Button.background" );
if( helpButtonBorderColor == null )
helpButtonBorderColor = defaults.get( "Button.borderColor" );
defaults.put( "HelpButton.background", helpButtonBackground );
defaults.put( "HelpButton.borderColor", helpButtonBorderColor );
defaults.put( "HelpButton.disabledBackground", panelBackground );
defaults.put( "HelpButton.disabledBorderColor", defaults.get( "Button.disabledBorderColor" ) );
defaults.put( "HelpButton.focusedBorderColor", defaults.get( "Button.focusedBorderColor" ) );
defaults.put( "HelpButton.focusedBackground", defaults.get( "Button.focusedBackground" ) );
// IDEA uses TextField.background for editable ComboBox and Spinner // IDEA uses TextField.background for editable ComboBox and Spinner
Object textFieldBackground = get( defaults, themeSpecificDefaults, "TextField.background" ); Object textFieldBackground = get( properties, themeSpecificProps, "TextField.background" );
defaults.put( "ComboBox.editableBackground", textFieldBackground ); put( properties, "ComboBox.editableBackground", textFieldBackground );
defaults.put( "Spinner.background", textFieldBackground ); put( properties, "Spinner.background", textFieldBackground );
// Spinner arrow button always has same colors as ComboBox arrow button
defaults.put( "Spinner.buttonBackground", defaults.get( "ComboBox.buttonEditableBackground" ) );
defaults.put( "Spinner.buttonArrowColor", defaults.get( "ComboBox.buttonArrowColor" ) );
defaults.put( "Spinner.buttonDisabledArrowColor", defaults.get( "ComboBox.buttonDisabledArrowColor" ) );
// some themes specify colors for TextField.background, but forget to specify it for other components // some themes specify colors for TextField.background, but forget to specify it for other components
// (probably because those components are not used in IntelliJ IDEA) // (probably because those components are not used in IntelliJ IDEA)
putAll( defaults, textFieldBackground, putAll( properties, textFieldBackground,
"EditorPane.background", "EditorPane.background",
"FormattedTextField.background", "FormattedTextField.background",
"PasswordField.background", "PasswordField.background",
"TextArea.background", "TextArea.background",
"TextPane.background" "TextPane.background"
); );
putAll( defaults, get( defaults, themeSpecificDefaults, "TextField.selectionBackground" ), putAll( properties, get( properties, themeSpecificProps, "TextField.selectionBackground" ),
"EditorPane.selectionBackground", "EditorPane.selectionBackground",
"FormattedTextField.selectionBackground", "FormattedTextField.selectionBackground",
"PasswordField.selectionBackground", "PasswordField.selectionBackground",
"TextArea.selectionBackground", "TextArea.selectionBackground",
"TextPane.selectionBackground" "TextPane.selectionBackground"
); );
putAll( defaults, get( defaults, themeSpecificDefaults, "TextField.selectionForeground" ), putAll( properties, get( properties, themeSpecificProps, "TextField.selectionForeground" ),
"EditorPane.selectionForeground", "EditorPane.selectionForeground",
"FormattedTextField.selectionForeground", "FormattedTextField.selectionForeground",
"PasswordField.selectionForeground", "PasswordField.selectionForeground",
@@ -235,7 +224,7 @@ public class IntelliJTheme
// fix disabled and not-editable backgrounds for text components, combobox and spinner // fix disabled and not-editable backgrounds for text components, combobox and spinner
// (IntelliJ IDEA does not use those colors; instead it used background color of parent) // (IntelliJ IDEA does not use those colors; instead it used background color of parent)
putAll( defaults, panelBackground, putAll( properties, "@disabledBackground",
"ComboBox.disabledBackground", "ComboBox.disabledBackground",
"EditorPane.disabledBackground", "EditorPane.inactiveBackground", "EditorPane.disabledBackground", "EditorPane.inactiveBackground",
"FormattedTextField.disabledBackground", "FormattedTextField.inactiveBackground", "FormattedTextField.disabledBackground", "FormattedTextField.inactiveBackground",
@@ -246,132 +235,148 @@ public class IntelliJTheme
"TextPane.disabledBackground", "TextPane.inactiveBackground" "TextPane.disabledBackground", "TextPane.inactiveBackground"
); );
// fix ToggleButton
if( !uiKeys.contains( "ToggleButton.startBackground" ) && !uiKeys.contains( "*.startBackground" ) )
defaults.put( "ToggleButton.startBackground", defaults.get( "Button.startBackground" ) );
if( !uiKeys.contains( "ToggleButton.endBackground" ) && !uiKeys.contains( "*.endBackground" ) )
defaults.put( "ToggleButton.endBackground", defaults.get( "Button.endBackground" ) );
if( !uiKeys.contains( "ToggleButton.foreground" ) && uiKeys.contains( "Button.foreground" ) )
defaults.put( "ToggleButton.foreground", defaults.get( "Button.foreground" ) );
// fix DesktopPane background (use Panel.background and make it 5% darker/lighter) // fix DesktopPane background (use Panel.background and make it 5% darker/lighter)
Color desktopBackgroundBase = defaults.getColor( "Panel.background" ); put( properties, "Desktop.background", dark ? "lighten($Panel.background,5%)" : "darken($Panel.background,5%)" );
Color desktopBackground = ColorFunctions.applyFunctions( desktopBackgroundBase,
new ColorFunctions.HSLIncreaseDecrease( 2, dark, 5, false, true ) );
defaults.put( "Desktop.background", new ColorUIResource( desktopBackground ) );
// fix List and Table background colors in Material UI Lite themes
if( isMaterialUILite ) {
defaults.put( "List.background", defaults.get( "Tree.background" ) );
defaults.put( "Table.background", defaults.get( "Tree.background" ) );
}
// limit tree row height // limit tree row height
int rowHeight = defaults.getInt( "Tree.rowHeight" ); String rowHeightStr = (String) properties.get( "Tree.rowHeight" );
int rowHeight = (rowHeightStr != null) ? Integer.parseInt( rowHeightStr ) : 0;
if( rowHeight > 22 ) if( rowHeight > 22 )
defaults.put( "Tree.rowHeight", 22 ); put( properties, "Tree.rowHeight", "22" );
// get (and remove) theme specific wildcard replacements, which override all other defaults that end with same suffix // get (and remove) theme specific wildcard replacements, which override all other properties that end with same suffix
HashMap<String, Object> wildcards = new HashMap<>(); HashMap<String, String> wildcardProps = new HashMap<>();
Iterator<Entry<Object, Object>> it = themeSpecificDefaults.entrySet().iterator(); Iterator<Map.Entry<String, String>> it = themeSpecificProps.entrySet().iterator();
while( it.hasNext() ) { while( it.hasNext() ) {
Entry<Object, Object> e = it.next(); Map.Entry<String, String> e = it.next();
String key = (String) e.getKey(); String key = e.getKey();
if( key.startsWith( "*." ) ) { if( key.startsWith( "*." ) ) {
wildcards.put( key.substring( "*.".length() ), e.getValue() ); wildcardProps.put( key, e.getValue() );
it.remove(); it.remove();
} }
} }
// override UI defaults with theme specific wildcard replacements // override properties with theme specific wildcard replacements
if( !wildcards.isEmpty() ) { if( !wildcardProps.isEmpty() ) {
for( Object key : defaults.keySet().toArray() ) { for( Map.Entry<String, String> e : wildcardProps.entrySet() )
int dot; applyWildcard( properties, e.getKey(), e.getValue() );
if( !(key instanceof String) ||
(dot = ((String)key).lastIndexOf( '.' )) < 0 )
continue;
String wildcardKey = ((String)key).substring( dot + 1 );
Object wildcardValue = wildcards.get( wildcardKey );
if( wildcardValue != null )
defaults.put( key, wildcardValue );
}
} }
// apply theme specific UI defaults at the end to allow overwriting // apply theme specific properties at the end to allow overwriting
for( Map.Entry<Object, Object> e : themeSpecificDefaults.entrySet() ) { for( Map.Entry<String, String> e : themeSpecificProps.entrySet() ) {
Object key = e.getKey(); String key = e.getKey();
Object value = e.getValue(); String value = e.getValue();
// append styles to existing styles // append styles to existing styles
if( key instanceof String && ((String)key).startsWith( "[style]" ) ) { if( key.startsWith( "[style]" ) ) {
Object oldValue = defaults.get( key ); String oldValue = (String) properties.get( key );
if( oldValue != null ) if( oldValue != null )
value = oldValue + "; " + value; value = oldValue + "; " + value;
} }
defaults.put( key, value ); put( properties, key, value );
} }
// let Java release memory // let Java release memory
colors = null; jsonColors = null;
ui = null; jsonUI = null;
icons = null; jsonIcons = null;
} }
private Object get( UIDefaults defaults, Map<Object, Object> themeSpecificDefaults, String key ) { private String get( Properties properties, Map<String, String> themeSpecificProps, String key ) {
return themeSpecificDefaults.getOrDefault( key, defaults.get( key ) ); return themeSpecificProps.getOrDefault( key, (String) properties.get( key ) );
} }
private void putAll( UIDefaults defaults, Object value, String... keys ) { private void put( Properties properties, Object key, Object value ) {
if( value != null )
properties.put( key, value );
else
properties.remove( key );
}
private void putAll( Properties properties, Object value, String... keys ) {
for( String key : keys ) for( String key : keys )
defaults.put( key, value ); put( properties, key, value );
} }
private Map<Object, Object> removeThemeSpecificDefaults( UIDefaults defaults ) { private void copyIfSetInJson( Properties properties, Set<String> jsonUIKeys, String destKey, String... srcKeys ) {
// search for theme specific UI defaults keys for( String srcKey : srcKeys ) {
if( jsonUIKeys.contains( srcKey ) ) {
Object value = properties.get( srcKey );
if( value != null ) {
put( properties, destKey, value );
break;
}
}
}
}
private void fixStartEnd( Properties properties, Set<String> jsonUIKeys, String startKey, String endKey, String key ) {
if( jsonUIKeys.contains( startKey ) && jsonUIKeys.contains( endKey ) )
put( properties, key, "$" + startKey );
}
private Map<String, String> removeThemeSpecificProps( Properties properties ) {
// search for theme specific properties keys
ArrayList<String> themeSpecificKeys = new ArrayList<>(); ArrayList<String> themeSpecificKeys = new ArrayList<>();
for( Object key : defaults.keySet() ) { for( Object key : properties.keySet() ) {
if( key instanceof String && ((String)key).startsWith( "[" ) && !((String)key).startsWith( "[style]" ) ) if( ((String)key).startsWith( "{" ) )
themeSpecificKeys.add( (String) key ); themeSpecificKeys.add( (String) key );
} }
// remove theme specific UI defaults and remember only those for current theme // special prefixes (priority from highest to lowest)
Map<Object, Object> themeSpecificDefaults = new HashMap<>(); String currentThemePrefix = '{' + name.replace( ' ', '_' ) + '}';
String currentThemePrefix = '[' + name.replace( ' ', '_' ) + ']'; String currentThemeAndAuthorPrefix = '{' + name.replace( ' ', '_' ) + "---" + author.replace( ' ', '_' ) + '}';
String currentThemeAndAuthorPrefix = '[' + name.replace( ' ', '_' ) + "---" + author.replace( ' ', '_' ) + ']'; String currentAuthorPrefix = "{author-" + author.replace( ' ', '_' ) + '}';
String currentAuthorPrefix = "[author-" + author.replace( ' ', '_' ) + ']'; String lightOrDarkPrefix = dark ? "{*-dark}" : "{*-light}";
String allThemesPrefix = "[*]"; String allThemesPrefix = "{*}";
String[] prefixes = { currentThemePrefix, currentThemeAndAuthorPrefix, currentAuthorPrefix, allThemesPrefix }; String[] prefixes = { currentThemePrefix, currentThemeAndAuthorPrefix, currentAuthorPrefix, lightOrDarkPrefix, allThemesPrefix };
// collect values for special prefixes in its own maps
@SuppressWarnings( "unchecked" )
Map<String, String>[] maps = new Map[prefixes.length];
for( int i = 0; i < maps.length; i++ )
maps[i] = new HashMap<>();
// remove theme specific properties and remember only those for current theme
for( String key : themeSpecificKeys ) { for( String key : themeSpecificKeys ) {
Object value = defaults.remove( key ); String value = (String) properties.remove( key );
for( String prefix : prefixes ) { for( int i = 0; i < prefixes.length; i++ ) {
String prefix = prefixes[i];
if( key.startsWith( prefix ) ) { if( key.startsWith( prefix ) ) {
themeSpecificDefaults.put( key.substring( prefix.length() ), value ); maps[i].put( key.substring( prefix.length() ), value );
break; break;
} }
} }
} }
return themeSpecificDefaults; // copy values into single map (from lowest to highest priority)
Map<String, String> themeSpecificProps = new HashMap<>();
for( int i = maps.length - 1; i >= 0; i-- )
themeSpecificProps.putAll( maps[i] );
return themeSpecificProps;
} }
/** /**
* http://www.jetbrains.org/intellij/sdk/docs/reference_guide/ui_themes/themes_customize.html#defining-named-colors * http://www.jetbrains.org/intellij/sdk/docs/reference_guide/ui_themes/themes_customize.html#defining-named-colors
*/ */
private void loadNamedColors( UIDefaults defaults ) { private void loadNamedColors( Properties properties, Set<String> jsonUIKeys ) {
if( colors == null ) if( jsonColors == null )
return; return;
namedColors = new HashMap<>(); namedColors = new HashMap<>();
for( Map.Entry<String, String> e : colors.entrySet() ) { for( Map.Entry<String, String> e : jsonColors.entrySet() ) {
String value = e.getValue(); String value = e.getValue();
ColorUIResource color = parseColor( value ); if( canParseColor( value ) ) {
if( color != null ) {
String key = e.getKey(); String key = e.getKey();
namedColors.put( key, color ); namedColors.put( key, value );
defaults.put( "ColorPalette." + key, color );
String uiKey = "ColorPalette." + key;
put( properties, uiKey, value );
// this is only necessary for copyIfSetInJson() (used for accent color)
jsonUIKeys.add( uiKey );
} }
} }
} }
@@ -380,7 +385,7 @@ public class IntelliJTheme
* http://www.jetbrains.org/intellij/sdk/docs/reference_guide/ui_themes/themes_customize.html#custom-ui-control-colors * http://www.jetbrains.org/intellij/sdk/docs/reference_guide/ui_themes/themes_customize.html#custom-ui-control-colors
*/ */
@SuppressWarnings( "unchecked" ) @SuppressWarnings( "unchecked" )
private void apply( String key, Object value, UIDefaults defaults, ArrayList<Object> defaultsKeysCache, Set<String> uiKeys ) { private void apply( String key, Object value, Properties properties, Set<String> jsonUIKeys ) {
if( value instanceof Map ) { if( value instanceof Map ) {
Map<String, Object> map = (Map<String, Object>)value; Map<String, Object> map = (Map<String, Object>)value;
if( map.containsKey( "os.default" ) || map.containsKey( "os.windows" ) || map.containsKey( "os.mac" ) || map.containsKey( "os.linux" ) ) { if( map.containsKey( "os.default" ) || map.containsKey( "os.windows" ) || map.containsKey( "os.mac" ) || map.containsKey( "os.linux" ) ) {
@@ -388,12 +393,12 @@ public class IntelliJTheme
: SystemInfo.isMacOS ? "os.mac" : SystemInfo.isMacOS ? "os.mac"
: SystemInfo.isLinux ? "os.linux" : null; : SystemInfo.isLinux ? "os.linux" : null;
if( osKey != null && map.containsKey( osKey ) ) if( osKey != null && map.containsKey( osKey ) )
apply( key, map.get( osKey ), defaults, defaultsKeysCache, uiKeys ); apply( key, map.get( osKey ), properties, jsonUIKeys );
else if( map.containsKey( "os.default" ) ) else if( map.containsKey( "os.default" ) )
apply( key, map.get( "os.default" ), defaults, defaultsKeysCache, uiKeys ); apply( key, map.get( "os.default" ), properties, jsonUIKeys );
} else { } else {
for( Map.Entry<String, Object> e : map.entrySet() ) for( Map.Entry<String, Object> e : map.entrySet() )
apply( key + '.' + e.getKey(), e.getValue(), defaults, defaultsKeysCache, uiKeys ); apply( key + '.' + e.getKey(), e.getValue(), properties, jsonUIKeys );
} }
} else { } else {
if( "".equals( value ) ) if( "".equals( value ) )
@@ -418,15 +423,15 @@ public class IntelliJTheme
if( dot > 0 && uiKeyExcludes.contains( key.substring( 0, dot + 1 ) ) ) if( dot > 0 && uiKeyExcludes.contains( key.substring( 0, dot + 1 ) ) )
return; return;
if( uiKeyDoNotOverride.contains( key ) && uiKeys.contains( key ) ) if( uiKeyDoNotOverride.contains( key ) && jsonUIKeys.contains( key ) )
return; return;
uiKeys.add( key ); jsonUIKeys.add( key );
String valueStr = value.toString(); String valueStr = value.toString();
// map named colors // map named colors
Object uiValue = namedColors.get( valueStr ); String uiValue = namedColors.get( valueStr );
// parse value // parse value
if( uiValue == null ) { if( uiValue == null ) {
@@ -445,47 +450,64 @@ public class IntelliJTheme
// parse value // parse value
try { try {
uiValue = UIDefaultsLoader.parseValue( key, valueStr, null ); UIDefaultsLoader.parseValue( key, valueStr, null );
uiValue = valueStr;
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
UIDefaultsLoader.logParseError( key, valueStr, ex, false ); UIDefaultsLoader.logParseError( key, valueStr, ex, true );
return; // ignore invalid value return; // ignore invalid value
} }
} }
if( key.startsWith( "*." ) ) { // wildcards
// wildcard if( applyWildcard( properties, key, uiValue ) )
String tail = key.substring( 1 ); return;
// because we can not iterate over the UI defaults keys while put( properties, key, uiValue );
// modifying UI defaults in the same loop, we have to copy the keys
if( defaultsKeysCache.size() != defaults.size() ) {
defaultsKeysCache.clear();
Enumeration<Object> e = defaults.keys();
while( e.hasMoreElements() )
defaultsKeysCache.add( e.nextElement() );
}
// replace all values in UI defaults that match the wildcard key
for( Object k : defaultsKeysCache ) {
if( k.equals( "Desktop.background" ) ||
k.equals( "DesktopIcon.background" ) ||
k.equals( "TabbedPane.focusColor" ) )
continue;
if( k instanceof String ) {
// support replacing of mapped keys
// (e.g. set ComboBox.buttonEditableBackground to *.background
// because it is mapped from ComboBox.ArrowButton.background)
String km = uiKeyInverseMapping.getOrDefault( k, (String) k );
if( km.endsWith( tail ) && !((String)k).startsWith( "CheckBox.icon." ) )
defaults.put( k, uiValue );
}
}
} else
defaults.put( key, uiValue );
} }
} }
private boolean applyWildcard( Properties properties, String key, String value ) {
if( !key.startsWith( "*." ) )
return false;
String tail = key.substring( 1 );
// because we can not iterate over the properties keys while
// modifying properties in the same loop, we have to copy the keys
String[] keys = properties.keySet().toArray( new String[properties.size()] );
// replace all values in properties that match the wildcard key
for( String k : keys ) {
if( k.startsWith( "*" ) ||
k.startsWith( "@" ) ||
k.startsWith( "HelpButton." ) ||
k.startsWith( "JX" ) ||
k.startsWith( "Jide" ) ||
k.startsWith( "ProgressBar.selection" ) ||
k.startsWith( "TitlePane." ) ||
k.startsWith( "ToggleButton.tab." ) ||
k.equals( "Desktop.background" ) ||
k.equals( "DesktopIcon.background" ) ||
k.equals( "TabbedPane.focusColor" ) ||
k.endsWith( ".hoverBackground" ) ||
k.endsWith( ".pressedBackground" ) )
continue;
// support replacing of mapped keys
// (e.g. set ComboBox.buttonEditableBackground to *.background
// because it is mapped from ComboBox.ArrowButton.background)
String km = uiKeyInverseMapping.getOrDefault( k, k );
if( km.endsWith( tail ) && !k.startsWith( "CheckBox.icon." ) )
put( properties, k, value );
}
// Note: also add wildcards to properties and let UIDefaultsLoader
// process it on BasicLookAndFeel UI defaults
put( properties, key, value );
return true;
}
private String fixColorIfValid( String newColorStr, String colorStr ) { private String fixColorIfValid( String newColorStr, String colorStr ) {
try { try {
// check whether it is valid // check whether it is valid
@@ -497,11 +519,11 @@ public class IntelliJTheme
} }
} }
private void applyColorPalette( UIDefaults defaults ) { private void applyIconsColorPalette( Properties properties ) {
if( icons == null ) if( jsonIcons == null )
return; return;
Object palette = icons.get( "ColorPalette" ); Object palette = jsonIcons.get( "ColorPalette" );
if( !(palette instanceof Map) ) if( !(palette instanceof Map) )
return; return;
@@ -510,44 +532,48 @@ public class IntelliJTheme
for( Map.Entry<String, Object> e : colorPalette.entrySet() ) { for( Map.Entry<String, Object> e : colorPalette.entrySet() ) {
String key = e.getKey(); String key = e.getKey();
Object value = e.getValue(); Object value = e.getValue();
if( key.startsWith( "Checkbox." ) || !(value instanceof String) ) if( key.startsWith( "Checkbox." ) || key.startsWith( "#" ) || !(value instanceof String) )
continue; continue;
if( dark ) if( dark )
key = StringUtils.removeTrailing( key, ".Dark" ); key = StringUtils.removeTrailing( key, ".Dark" );
ColorUIResource color = toColor( (String) value ); String color = toColor( (String) value );
if( color != null ) if( color != null )
defaults.put( key, color ); put( properties, key, color );
} }
} }
private ColorUIResource toColor( String value ) { private String toColor( String value ) {
if( value.startsWith( "##" ) )
value = fixColorIfValid( value.substring( 1 ), value );
// map named colors // map named colors
ColorUIResource color = namedColors.get( value ); String color = namedColors.get( value );
// parse color // parse color
return (color != null) ? color : parseColor( value ); return (color != null) ? color : (canParseColor( value ) ? value : null);
} }
private ColorUIResource parseColor( String value ) { private boolean canParseColor( String value ) {
try { try {
return UIDefaultsLoader.parseColor( value ); return UIDefaultsLoader.parseColor( value ) != null;
} catch( IllegalArgumentException ex ) { } catch( IllegalArgumentException ex ) {
return null; LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to parse color: '" + value + '\'', ex );
return false;
} }
} }
/** /**
* Because IDEA uses SVGs for check boxes and radio buttons, the colors for * Because IDEA uses SVGs for check boxes and radio buttons, the colors for
* these two components are specified in "icons > ColorPalette". * these two components are specified in "icons > ColorPalette".
* FlatLaf uses vector icons and expects colors for the two components in UI defaults. * FlatLaf uses vector icons and expects colors for the two components in properties.
*/ */
private void applyCheckBoxColors( UIDefaults defaults ) { private void applyCheckBoxColors( Properties properties ) {
if( icons == null ) if( jsonIcons == null )
return; return;
Object palette = icons.get( "ColorPalette" ); Object palette = jsonIcons.get( "ColorPalette" );
if( !(palette instanceof Map) ) if( !(palette instanceof Map) )
return; return;
@@ -569,9 +595,9 @@ public class IntelliJTheme
if( !dark && newKey.startsWith( checkBoxIconPrefix ) ) if( !dark && newKey.startsWith( checkBoxIconPrefix ) )
newKey = "CheckBox.icon[filled].".concat( newKey.substring( checkBoxIconPrefix.length() ) ); newKey = "CheckBox.icon[filled].".concat( newKey.substring( checkBoxIconPrefix.length() ) );
ColorUIResource color = toColor( (String) value ); String color = toColor( (String) value );
if( color != null ) { if( color != null ) {
defaults.put( newKey, color ); put( properties, newKey, color );
String key2 = checkboxDuplicateColors.get( key + ".Dark"); String key2 = checkboxDuplicateColors.get( key + ".Dark");
if( key2 != null ) { if( key2 != null ) {
@@ -592,7 +618,7 @@ public class IntelliJTheme
String newKey2 = checkboxKeyMapping.get( key2 ); String newKey2 = checkboxKeyMapping.get( key2 );
if( newKey2 != null ) if( newKey2 != null )
defaults.put( newKey2, color ); put( properties, newKey2, color );
} }
} }
@@ -603,13 +629,13 @@ public class IntelliJTheme
// update hover, pressed and focused colors // update hover, pressed and focused colors
if( checkboxModified ) { if( checkboxModified ) {
// for non-filled checkbox/radiobutton used in dark themes // for non-filled checkbox/radiobutton used in dark themes
defaults.remove( "CheckBox.icon.focusWidth" ); properties.remove( "CheckBox.icon.focusWidth" );
defaults.put( "CheckBox.icon.hoverBorderColor", defaults.get( "CheckBox.icon.focusedBorderColor" ) ); put( properties, "CheckBox.icon.hoverBorderColor", properties.get( "CheckBox.icon.focusedBorderColor" ) );
// for filled checkbox/radiobutton used in light themes // for filled checkbox/radiobutton used in light themes
defaults.remove( "CheckBox.icon[filled].focusWidth" ); properties.remove( "CheckBox.icon[filled].focusWidth" );
defaults.put( "CheckBox.icon[filled].hoverBorderColor", defaults.get( "CheckBox.icon[filled].focusedBorderColor" ) ); put( properties, "CheckBox.icon[filled].hoverBorderColor", properties.get( "CheckBox.icon[filled].focusedBorderColor" ) );
defaults.put( "CheckBox.icon[filled].focusedSelectedBackground", defaults.get( "CheckBox.icon[filled].selectedBackground" ) ); put( properties, "CheckBox.icon[filled].focusedSelectedBackground", properties.get( "CheckBox.icon[filled].selectedBackground" ) );
if( dark ) { if( dark ) {
// IDEA Darcula checkBoxFocused.svg, checkBoxSelectedFocused.svg, // IDEA Darcula checkBoxFocused.svg, checkBoxSelectedFocused.svg,
@@ -623,21 +649,14 @@ public class IntelliJTheme
"CheckBox.icon[filled].focusedSelectedBorderColor", "CheckBox.icon[filled].focusedSelectedBorderColor",
}; };
for( String key : focusedBorderColorKeys ) { for( String key : focusedBorderColorKeys ) {
Color color = defaults.getColor( key ); Object color = properties.get( key );
if( color != null ) { if( color != null )
defaults.put( key, new ColorUIResource( new Color( put( properties, key, "fade(" + color + ", 65%)" );
(color.getRGB() & 0xffffff) | 0xa6000000, true ) ) );
}
} }
} }
} }
} }
private void copyIfNotSet( UIDefaults defaults, String destKey, String srcKey, Set<String> uiKeys ) {
if( !uiKeys.contains( destKey ) )
defaults.put( destKey, defaults.get( srcKey ) );
}
private static final Set<String> uiKeyExcludes; private static final Set<String> uiKeyExcludes;
private static final Set<String> uiKeyDoNotOverride; private static final Set<String> uiKeyDoNotOverride;
/** Rename UI default keys (key --> value). */ /** Rename UI default keys (key --> value). */
@@ -653,26 +672,27 @@ public class IntelliJTheme
uiKeyExcludes = new HashSet<>( Arrays.asList( uiKeyExcludes = new HashSet<>( Arrays.asList(
"ActionButton.", "ActionToolbar.", "ActionsList.", "AppInspector.", "AssignedMnemonic.", "Autocomplete.", "ActionButton.", "ActionToolbar.", "ActionsList.", "AppInspector.", "AssignedMnemonic.", "Autocomplete.",
"AvailableMnemonic.", "AvailableMnemonic.",
"BigSpinner.", "Bookmark.", "BookmarkIcon.", "BookmarkMnemonicAssigned.", "BookmarkMnemonicAvailable.", "Badge.", "Banner.", "BigSpinner.", "Bookmark.", "BookmarkIcon.", "BookmarkMnemonicAssigned.", "BookmarkMnemonicAvailable.",
"BookmarkMnemonicCurrent.", "BookmarkMnemonicIcon.", "Borders.", "Breakpoint.", "BookmarkMnemonicCurrent.", "BookmarkMnemonicIcon.", "Borders.", "Breakpoint.",
"Canvas.", "CodeWithMe.", "ComboBoxButton.", "CompletionPopup.", "ComplexPopup.", "Content.", "Canvas.", "CellEditor.", "Code.", "CodeWithMe.", "ColumnControlButton.", "CombinedDiff.", "ComboBoxButton.",
"CurrentMnemonic.", "Counter.", "CompilationCharts.", "CompletionPopup.", "ComplexPopup.", "Content.", "ContextHelp.", "CurrentMnemonic.", "Counter.",
"Debugger.", "DebuggerPopup.", "DebuggerTabs.", "DefaultTabs.", "Dialog.", "DialogWrapper.", "DragAndDrop.", "Debugger.", "DebuggerPopup.", "DebuggerTabs.", "DefaultTabs.", "Dialog.", "DialogWrapper.",
"DisclosureButton.", "DragAndDrop.",
"Editor.", "EditorGroupsTabs.", "EditorTabs.", "Editor.", "EditorGroupsTabs.", "EditorTabs.",
"FileColor.", "FlameGraph.", "Focus.", "FileColor.", "FindPopup.", "FlameGraph.", "Focus.",
"Git.", "Github.", "GotItTooltip.", "Group.", "Gutter.", "GutterTooltip.", "Git.", "Github.", "GotItTooltip.", "Group.", "Gutter.", "GutterTooltip.",
"HeaderColor.", "HelpTooltip.", "Hg.", "HeaderColor.", "HelpTooltip.", "Hg.",
"IconBadge.", "InformationHint.", "InplaceRefactoringPopup.", "IconBadge.", "InformationHint.", "InlineBanner.", "InplaceRefactoringPopup.",
"Lesson.", "Link.", "LiveIndicator.", "Lesson.", "LineProfiler.", "Link.", "LiveIndicator.",
"MainMenu.", "MainToolbar.", "MemoryIndicator.", "MlModelBinding.", "MnemonicIcon.", "MainMenu.", "MainToolbar.", "MainWindow.", "MemoryIndicator.", "MlModelBinding.", "MnemonicIcon.",
"NavBar.", "NewClass.", "NewPSD.", "Notification.", "Notifications.", "NotificationsToolwindow.", "NavBar.", "NewClass.", "NewPSD.", "Notification.", "Notifications.", "NotificationsToolwindow.",
"OnePixelDivider.", "OptionButton.", "Outline.", "OnePixelDivider.", "OptionButton.", "Outline.",
"ParameterInfo.", "Plugins.", "ProgressIcon.", "PsiViewer.", "ParameterInfo.", "PresentationAssistant.", "Plugins.", "Profiler.", "ProgressIcon.", "PsiViewer.",
"ReviewList.", "RunWidget.", "Resizable.", "Review.", "ReviewList.", "RunToolbar.", "RunWidget.",
"ScreenView.", "SearchEverywhere.", "SearchFieldWithExtension.", "SearchMatch.", "SearchOption.", "ScreenView.", "SearchEverywhere.", "SearchFieldWithExtension.", "SearchMatch.", "SearchOption.",
"SearchResults.", "SegmentedButton.", "Settings.", "SidePanel.", "Space.", "SpeedSearch.", "StateWidget.", "SearchResults.", "SegmentedButton.", "Settings.", "SidePanel.", "Space.", "SpeedSearch.", "StateWidget.",
"StatusBar.", "StatusBar.", "StripeToolbar.",
"Tag.", "TipOfTheDay.", "ToolbarComboWidget.", "ToolWindow.", "Tag.", "TipOfTheDay.", "ToolbarComboWidget.", "ToolWindow.", "TrialWidget.",
"UIDesigner.", "UnattendedHostStatus.", "UIDesigner.", "UnattendedHostStatus.",
"ValidationTooltip.", "VersionControl.", "ValidationTooltip.", "VersionControl.",
"WelcomeScreen.", "WelcomeScreen.",
@@ -688,6 +708,9 @@ public class IntelliJTheme
"TabbedPane.selectedForeground" "TabbedPane.selectedForeground"
) ); ) );
// Button
uiKeyMapping.put( "Button.minimumSize", "" ); // ignore (used in Material Theme UI Lite)
// ComboBox // ComboBox
uiKeyMapping.put( "ComboBox.background", "" ); // ignore uiKeyMapping.put( "ComboBox.background", "" ); // ignore
uiKeyMapping.put( "ComboBox.buttonBackground", "" ); // ignore uiKeyMapping.put( "ComboBox.buttonBackground", "" ); // ignore
@@ -696,14 +719,17 @@ public class IntelliJTheme
uiKeyMapping.put( "ComboBox.ArrowButton.disabledIconColor", "ComboBox.buttonDisabledArrowColor" ); uiKeyMapping.put( "ComboBox.ArrowButton.disabledIconColor", "ComboBox.buttonDisabledArrowColor" );
uiKeyMapping.put( "ComboBox.ArrowButton.iconColor", "ComboBox.buttonArrowColor" ); uiKeyMapping.put( "ComboBox.ArrowButton.iconColor", "ComboBox.buttonArrowColor" );
uiKeyMapping.put( "ComboBox.ArrowButton.nonEditableBackground", "ComboBox.buttonBackground" ); uiKeyMapping.put( "ComboBox.ArrowButton.nonEditableBackground", "ComboBox.buttonBackground" );
uiKeyCopying.put( "ComboBox.buttonSeparatorColor", "Component.borderColor" );
uiKeyCopying.put( "ComboBox.buttonDisabledSeparatorColor", "Component.disabledBorderColor" );
// Component // Component
uiKeyMapping.put( "Component.inactiveErrorFocusColor", "Component.error.borderColor" ); uiKeyMapping.put( "Component.inactiveErrorFocusColor", "Component.error.borderColor" );
uiKeyMapping.put( "Component.errorFocusColor", "Component.error.focusedBorderColor" ); uiKeyMapping.put( "Component.errorFocusColor", "Component.error.focusedBorderColor" );
uiKeyMapping.put( "Component.inactiveWarningFocusColor", "Component.warning.borderColor" ); uiKeyMapping.put( "Component.inactiveWarningFocusColor", "Component.warning.borderColor" );
uiKeyMapping.put( "Component.warningFocusColor", "Component.warning.focusedBorderColor" ); uiKeyMapping.put( "Component.warningFocusColor", "Component.warning.focusedBorderColor" );
uiKeyMapping.put( "Component.inactiveSuccessFocusColor", "Component.success.borderColor" );
uiKeyMapping.put( "Component.successFocusColor", "Component.success.focusedBorderColor" );
// Label
uiKeyMapping.put( "Label.disabledForegroundColor", "" ); // ignore (used in Material Theme UI Lite)
// Link // Link
uiKeyMapping.put( "Link.activeForeground", "Component.linkColor" ); uiKeyMapping.put( "Link.activeForeground", "Component.linkColor" );
@@ -711,10 +737,7 @@ public class IntelliJTheme
// Menu // Menu
uiKeyMapping.put( "Menu.border", "Menu.margin" ); uiKeyMapping.put( "Menu.border", "Menu.margin" );
uiKeyMapping.put( "MenuItem.border", "MenuItem.margin" ); uiKeyMapping.put( "MenuItem.border", "MenuItem.margin" );
uiKeyCopying.put( "CheckBoxMenuItem.margin", "MenuItem.margin" );
uiKeyCopying.put( "RadioButtonMenuItem.margin", "MenuItem.margin" );
uiKeyMapping.put( "PopupMenu.border", "PopupMenu.borderInsets" ); uiKeyMapping.put( "PopupMenu.border", "PopupMenu.borderInsets" );
uiKeyCopying.put( "MenuItem.underlineSelectionColor", "TabbedPane.underlineColor" );
// IDEA uses List.selectionBackground also for menu selection // IDEA uses List.selectionBackground also for menu selection
uiKeyCopying.put( "Menu.selectionBackground", "List.selectionBackground" ); uiKeyCopying.put( "Menu.selectionBackground", "List.selectionBackground" );
@@ -722,13 +745,11 @@ public class IntelliJTheme
uiKeyCopying.put( "CheckBoxMenuItem.selectionBackground", "List.selectionBackground" ); uiKeyCopying.put( "CheckBoxMenuItem.selectionBackground", "List.selectionBackground" );
uiKeyCopying.put( "RadioButtonMenuItem.selectionBackground", "List.selectionBackground" ); uiKeyCopying.put( "RadioButtonMenuItem.selectionBackground", "List.selectionBackground" );
// ProgressBar // ProgressBar: IDEA uses ProgressBar.trackColor and ProgressBar.progressColor
uiKeyMapping.put( "ProgressBar.background", "" ); // ignore uiKeyMapping.put( "ProgressBar.background", "" ); // ignore
uiKeyMapping.put( "ProgressBar.foreground", "" ); // ignore uiKeyMapping.put( "ProgressBar.foreground", "" ); // ignore
uiKeyMapping.put( "ProgressBar.trackColor", "ProgressBar.background" ); uiKeyMapping.put( "ProgressBar.trackColor", "ProgressBar.background" );
uiKeyMapping.put( "ProgressBar.progressColor", "ProgressBar.foreground" ); uiKeyMapping.put( "ProgressBar.progressColor", "ProgressBar.foreground" );
uiKeyCopying.put( "ProgressBar.selectionForeground", "ProgressBar.background" );
uiKeyCopying.put( "ProgressBar.selectionBackground", "ProgressBar.foreground" );
// ScrollBar // ScrollBar
uiKeyMapping.put( "ScrollBar.trackColor", "ScrollBar.track" ); uiKeyMapping.put( "ScrollBar.trackColor", "ScrollBar.track" );
@@ -738,34 +759,30 @@ public class IntelliJTheme
uiKeyMapping.put( "Separator.separatorColor", "Separator.foreground" ); uiKeyMapping.put( "Separator.separatorColor", "Separator.foreground" );
// Slider // Slider
uiKeyMapping.put( "Slider.buttonColor", "Slider.thumbColor" );
uiKeyMapping.put( "Slider.buttonBorderColor", "" ); // ignore
uiKeyMapping.put( "Slider.thumb", "" ); // ignore (used in Material Theme UI Lite)
uiKeyMapping.put( "Slider.track", "" ); // ignore (used in Material Theme UI Lite)
uiKeyMapping.put( "Slider.trackDisabled", "" ); // ignore (used in Material Theme UI Lite)
uiKeyMapping.put( "Slider.trackWidth", "" ); // ignore (used in Material Theme UI Lite) uiKeyMapping.put( "Slider.trackWidth", "" ); // ignore (used in Material Theme UI Lite)
uiKeyCopying.put( "Slider.trackValueColor", "ProgressBar.foreground" );
uiKeyCopying.put( "Slider.thumbColor", "ProgressBar.foreground" );
uiKeyCopying.put( "Slider.trackColor", "ProgressBar.background" );
// Spinner
uiKeyCopying.put( "Spinner.buttonSeparatorColor", "Component.borderColor" );
uiKeyCopying.put( "Spinner.buttonDisabledSeparatorColor", "Component.disabledBorderColor" );
// TabbedPane // TabbedPane
uiKeyMapping.put( "DefaultTabs.underlinedTabBackground", "TabbedPane.selectedBackground" ); uiKeyMapping.put( "DefaultTabs.underlinedTabBackground", "TabbedPane.selectedBackground" );
uiKeyMapping.put( "DefaultTabs.underlinedTabForeground", "TabbedPane.selectedForeground" ); uiKeyMapping.put( "DefaultTabs.underlinedTabForeground", "TabbedPane.selectedForeground" );
uiKeyMapping.put( "DefaultTabs.inactiveUnderlineColor", "TabbedPane.inactiveUnderlineColor" ); uiKeyMapping.put( "DefaultTabs.inactiveUnderlineColor", "TabbedPane.inactiveUnderlineColor" );
uiKeyMapping.put( "TabbedPane.tabAreaInsets", "" ); // ignore (used in Material Theme UI Lite)
// TableHeader
uiKeyMapping.put( "TableHeader.cellBorder", "" ); // ignore (used in Material Theme UI Lite)
uiKeyMapping.put( "TableHeader.height", "" ); // ignore (used in Material Theme UI Lite)
// TitlePane // TitlePane
uiKeyCopying.put( "TitlePane.inactiveBackground", "TitlePane.background" );
uiKeyMapping.put( "TitlePane.infoForeground", "TitlePane.foreground" ); uiKeyMapping.put( "TitlePane.infoForeground", "TitlePane.foreground" );
uiKeyMapping.put( "TitlePane.inactiveInfoForeground", "TitlePane.inactiveForeground" ); uiKeyMapping.put( "TitlePane.inactiveInfoForeground", "TitlePane.inactiveForeground" );
for( Map.Entry<String, String> e : uiKeyMapping.entrySet() ) for( Map.Entry<String, String> e : uiKeyMapping.entrySet() )
uiKeyInverseMapping.put( e.getValue(), e.getKey() ); uiKeyInverseMapping.put( e.getValue(), e.getKey() );
uiKeyCopying.put( "ToggleButton.tab.underlineColor", "TabbedPane.underlineColor" );
uiKeyCopying.put( "ToggleButton.tab.disabledUnderlineColor", "TabbedPane.disabledUnderlineColor" );
uiKeyCopying.put( "ToggleButton.tab.selectedBackground", "TabbedPane.selectedBackground" );
uiKeyCopying.put( "ToggleButton.tab.hoverBackground", "TabbedPane.hoverColor" );
uiKeyCopying.put( "ToggleButton.tab.focusBackground", "TabbedPane.focusColor" );
checkboxKeyMapping.put( "Checkbox.Background.Default", "CheckBox.icon.background" ); checkboxKeyMapping.put( "Checkbox.Background.Default", "CheckBox.icon.background" );
checkboxKeyMapping.put( "Checkbox.Background.Disabled", "CheckBox.icon.disabledBackground" ); checkboxKeyMapping.put( "Checkbox.Background.Disabled", "CheckBox.icon.disabledBackground" );
checkboxKeyMapping.put( "Checkbox.Border.Default", "CheckBox.icon.borderColor" ); checkboxKeyMapping.put( "Checkbox.Border.Default", "CheckBox.icon.borderColor" );
@@ -818,17 +835,15 @@ public class IntelliJTheme
} }
@Override @Override
void applyAdditionalDefaults( UIDefaults defaults ) { void applyAdditionalProperties( Properties properties ) {
theme.applyProperties( defaults ); theme.applyProperties( properties );
} }
@Override @Override
protected ArrayList<Class<?>> getLafClassesForDefaultsLoading() { protected ArrayList<Class<?>> getLafClassesForDefaultsLoading() {
ArrayList<Class<?>> lafClasses = new ArrayList<>(); ArrayList<Class<?>> lafClasses = UIDefaultsLoader.getLafClassesForDefaultsLoading( getClass() );
lafClasses.add( FlatLaf.class ); lafClasses.add( 1, theme.dark ? FlatDarkLaf.class : FlatLightLaf.class );
lafClasses.add( theme.dark ? FlatDarkLaf.class : FlatLightLaf.class ); lafClasses.add( 2, theme.dark ? FlatDarculaLaf.class : FlatIntelliJLaf.class );
lafClasses.add( theme.dark ? FlatDarculaLaf.class : FlatIntelliJLaf.class );
lafClasses.add( ThemeLaf.class );
return lafClasses; return lafClasses;
} }
} }

View File

@@ -111,7 +111,7 @@ class LinuxFontPolicy
if( logicalFamily != null ) if( logicalFamily != null )
family = logicalFamily; family = logicalFamily;
return createFontEx( family, style, size, dsize ); return createFontEx( family, style, size );
} }
/** /**
@@ -121,9 +121,9 @@ class LinuxFontPolicy
* E.g. family 'URW Bookman Light' is not found, but 'URW Bookman' is found. * E.g. family 'URW Bookman Light' is not found, but 'URW Bookman' is found.
* If still not found, then font of family 'Dialog' is returned. * If still not found, then font of family 'Dialog' is returned.
*/ */
private static Font createFontEx( String family, int style, int size, double dsize ) { private static Font createFontEx( String family, int style, int size ) {
for(;;) { for(;;) {
Font font = createFont( family, style, size, dsize ); Font font = FlatLaf.createCompositeFont( family, style, size );
if( Font.DIALOG.equals( family ) ) if( Font.DIALOG.equals( family ) )
return font; return font;
@@ -135,7 +135,7 @@ class LinuxFontPolicy
// - character width is zero (e.g. font Cantarell; Fedora; Oracle Java 8) // - character width is zero (e.g. font Cantarell; Fedora; Oracle Java 8)
FontMetrics fm = StyleContext.getDefaultStyleContext().getFontMetrics( font ); FontMetrics fm = StyleContext.getDefaultStyleContext().getFontMetrics( font );
if( fm.getHeight() > size * 2 || fm.stringWidth( "a" ) == 0 ) if( fm.getHeight() > size * 2 || fm.stringWidth( "a" ) == 0 )
return createFont( Font.DIALOG, style, size, dsize ); return FlatLaf.createCompositeFont( Font.DIALOG, style, size );
return font; return font;
} }
@@ -143,7 +143,7 @@ class LinuxFontPolicy
// find last word in family // find last word in family
int index = family.lastIndexOf( ' ' ); int index = family.lastIndexOf( ' ' );
if( index < 0 ) if( index < 0 )
return createFont( Font.DIALOG, style, size, dsize ); return FlatLaf.createCompositeFont( Font.DIALOG, style, size );
// check whether last work contains some font weight (e.g. Ultra-Bold or Heavy) // check whether last work contains some font weight (e.g. Ultra-Bold or Heavy)
String lastWord = family.substring( index + 1 ).toLowerCase( Locale.ENGLISH ); String lastWord = family.substring( index + 1 ).toLowerCase( Locale.ENGLISH );
@@ -155,15 +155,6 @@ class LinuxFontPolicy
} }
} }
private static Font createFont( String family, int style, int size, double dsize ) {
Font font = FlatLaf.createCompositeFont( family, style, size );
// set font size in floating points
font = font.deriveFont( style, (float) dsize );
return font;
}
private static double getGnomeFontScale() { private static double getGnomeFontScale() {
// do not scale font here if JRE scales // do not scale font here if JRE scales
if( isSystemScaling() ) if( isSystemScaling() )
@@ -257,7 +248,7 @@ class LinuxFontPolicy
if( size < 1 ) if( size < 1 )
size = 1; size = 1;
return createFont( family, style, size, dsize ); return FlatLaf.createCompositeFont( family, style, size );
} }
@SuppressWarnings( "MixedMutabilityReturnType" ) // Error Prone @SuppressWarnings( "MixedMutabilityReturnType" ) // Error Prone

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

@@ -41,6 +41,8 @@ import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Properties; import java.util.Properties;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import javax.swing.Icon; import javax.swing.Icon;
import javax.swing.UIDefaults; import javax.swing.UIDefaults;
@@ -61,7 +63,6 @@ import com.formdev.flatlaf.util.HSLColor;
import com.formdev.flatlaf.util.LoggingFacade; import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.SoftCache; import com.formdev.flatlaf.util.SoftCache;
import com.formdev.flatlaf.util.StringUtils; import com.formdev.flatlaf.util.StringUtils;
import com.formdev.flatlaf.util.SystemInfo;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
/** /**
@@ -85,15 +86,14 @@ class UIDefaultsLoader
private static final String WILDCARD_PREFIX = "*."; private static final String WILDCARD_PREFIX = "*.";
static final String KEY_VARIABLES = "FlatLaf.internal.variables"; static final String KEY_VARIABLES = "FlatLaf.internal.variables";
static final String KEY_PROPERTIES = "FlatLaf.internal.properties";
private static int parseColorDepth; private static int parseColorDepth;
private static Map<String, ColorUIResource> systemColorCache; private static Map<String, ColorUIResource> systemColorCache;
private static final SoftCache<String, Object> fontCache = new SoftCache<>(); private static final SoftCache<String, Object> fontCache = new SoftCache<>();
static void loadDefaultsFromProperties( Class<?> lookAndFeelClass, List<FlatDefaultsAddon> addons, static ArrayList<Class<?>> getLafClassesForDefaultsLoading( Class<?> lookAndFeelClass ) {
Properties additionalDefaults, boolean dark, UIDefaults defaults )
{
// determine classes in class hierarchy in reverse order // determine classes in class hierarchy in reverse order
ArrayList<Class<?>> lafClasses = new ArrayList<>(); ArrayList<Class<?>> lafClasses = new ArrayList<>();
for( Class<?> lafClass = lookAndFeelClass; for( Class<?> lafClass = lookAndFeelClass;
@@ -102,20 +102,54 @@ class UIDefaultsLoader
{ {
lafClasses.add( 0, lafClass ); lafClasses.add( 0, lafClass );
} }
return lafClasses;
}
loadDefaultsFromProperties( lafClasses, addons, additionalDefaults, dark, defaults ); static Properties newUIProperties( boolean dark ) {
// UI key prefixes
String lightOrDarkPrefix = FlatLaf.getUIKeyLightOrDarkPrefix( dark );
Set<String> platformPrefixes = FlatLaf.getUIKeyPlatformPrefixes();
Set<String> specialPrefixes = FlatLaf.getUIKeySpecialPrefixes();
return new Properties() {
@Override
public synchronized Object put( Object k, Object value ) {
// process key prefixes (while loading properties files)
String key = (String) k;
while( key.startsWith( "[" ) ) {
int closeIndex = key.indexOf( ']' );
if( closeIndex < 0 )
return null; // ignore property with invalid prefix
String prefix = key.substring( 0, closeIndex + 1 );
if( specialPrefixes.contains( prefix ) )
break; // keep special prefix
if( !lightOrDarkPrefix.equals( prefix ) && !platformPrefixes.contains( prefix ) )
return null; // ignore property
// prefix is known and enabled --> remove prefix
key = key.substring( closeIndex + 1 );
}
return super.put( key, value );
}
};
} }
static void loadDefaultsFromProperties( List<Class<?>> lafClasses, List<FlatDefaultsAddon> addons, static void loadDefaultsFromProperties( List<Class<?>> lafClasses, List<FlatDefaultsAddon> addons,
Properties additionalDefaults, boolean dark, UIDefaults defaults ) Consumer<Properties> intellijThemesHook, Properties additionalDefaults, boolean dark, UIDefaults defaults )
{ {
try { try {
// temporary cache system colors while loading defaults, // temporary cache system colors while loading defaults,
// which avoids that system color getter is invoked multiple times // which avoids that system color getter is invoked multiple times
systemColorCache = (FlatLaf.getSystemColorGetter() != null) ? new HashMap<>() : null; systemColorCache = (FlatLaf.getSystemColorGetter() != null) ? new HashMap<>() : null;
// all properties files will be loaded into this map
Properties properties = newUIProperties( dark );
// load core properties files // load core properties files
Properties properties = new Properties();
for( Class<?> lafClass : lafClasses ) { for( Class<?> lafClass : lafClasses ) {
String propertiesName = '/' + lafClass.getName().replace( '.', '/' ) + ".properties"; String propertiesName = '/' + lafClass.getName().replace( '.', '/' ) + ".properties";
try( InputStream in = lafClass.getResourceAsStream( propertiesName ) ) { try( InputStream in = lafClass.getResourceAsStream( propertiesName ) ) {
@@ -142,6 +176,10 @@ class UIDefaultsLoader
addonClassLoaders.add( addonClassLoader ); addonClassLoaders.add( addonClassLoader );
} }
// apply IntelliJ themes properties
if( intellijThemesHook != null )
intellijThemesHook.accept( properties );
// load custom properties files (usually provided by applications) // load custom properties files (usually provided by applications)
List<Object> customDefaultsSources = FlatLaf.getCustomDefaultsSources(); List<Object> customDefaultsSources = FlatLaf.getCustomDefaultsSources();
int size = (customDefaultsSources != null) ? customDefaultsSources.size() : 0; int size = (customDefaultsSources != null) ? customDefaultsSources.size() : 0;
@@ -198,41 +236,6 @@ class UIDefaultsLoader
if( additionalDefaults != null ) if( additionalDefaults != null )
properties.putAll( additionalDefaults ); properties.putAll( additionalDefaults );
// collect all platform specific keys (but do not modify properties)
ArrayList<String> platformSpecificKeys = new ArrayList<>();
for( Object okey : properties.keySet() ) {
String key = (String) okey;
if( key.startsWith( "[" ) &&
(key.startsWith( "[win]" ) ||
key.startsWith( "[mac]" ) ||
key.startsWith( "[linux]" ) ||
key.startsWith( "[light]" ) ||
key.startsWith( "[dark]" )) )
platformSpecificKeys.add( key );
}
// remove platform specific properties and re-add only properties
// for current platform, but with platform prefix removed
if( !platformSpecificKeys.isEmpty() ) {
// handle light/dark specific properties
String lightOrDarkPrefix = dark ? "[dark]" : "[light]";
for( String key : platformSpecificKeys ) {
if( key.startsWith( lightOrDarkPrefix ) )
properties.put( key.substring( lightOrDarkPrefix.length() ), properties.remove( key ) );
}
// handle platform specific properties
String platformPrefix =
SystemInfo.isWindows ? "[win]" :
SystemInfo.isMacOS ? "[mac]" :
SystemInfo.isLinux ? "[linux]" : "[unknown]";
for( String key : platformSpecificKeys ) {
Object value = properties.remove( key );
if( key.startsWith( platformPrefix ) )
properties.put( key.substring( platformPrefix.length() ), value );
}
}
// get (and remove) wildcard replacements, which override all other defaults that end with same suffix // get (and remove) wildcard replacements, which override all other defaults that end with same suffix
HashMap<String, String> wildcards = new HashMap<>(); HashMap<String, String> wildcards = new HashMap<>();
Iterator<Entry<Object, Object>> it = properties.entrySet().iterator(); Iterator<Entry<Object, Object>> it = properties.entrySet().iterator();
@@ -287,6 +290,15 @@ class UIDefaultsLoader
// remember variables in defaults to allow using them in styles // remember variables in defaults to allow using them in styles
defaults.put( KEY_VARIABLES, variables ); defaults.put( KEY_VARIABLES, variables );
// remember properties (for testing)
if( FlatSystemProperties.getBoolean( KEY_PROPERTIES, false ) ) {
Properties properties2 = new Properties();
properties2.putAll( properties );
for( Map.Entry<String, String> e : wildcards.entrySet() )
properties2.put( WILDCARD_PREFIX + e.getKey(), e.getValue() );
defaults.put( KEY_PROPERTIES, properties2 );
}
// clear/disable system color cache // clear/disable system color cache
systemColorCache = null; systemColorCache = null;
} catch( IOException ex ) { } catch( IOException ex ) {
@@ -830,6 +842,7 @@ class UIDefaultsLoader
try { try {
switch( function ) { switch( function ) {
case "if": return parseColorIf( value, params, resolver ); case "if": return parseColorIf( value, params, resolver );
case "lazy": return parseColorLazy( value, params, resolver );
case "systemColor": return parseColorSystemColor( value, params, resolver ); case "systemColor": return parseColorSystemColor( value, params, resolver );
case "rgb": return parseColorRgbOrRgba( false, params, resolver ); case "rgb": return parseColorRgbOrRgba( false, params, resolver );
case "rgba": return parseColorRgbOrRgba( true, params, resolver ); case "rgba": return parseColorRgbOrRgba( true, params, resolver );
@@ -877,6 +890,32 @@ class UIDefaultsLoader
return parseColorOrFunction( resolver.apply( ifValue ), resolver ); return parseColorOrFunction( resolver.apply( ifValue ), resolver );
} }
/**
* Syntax: lazy(uiKey)
* <p>
* This "lazy" function is only used if the "lazy" is passed as parameter to another
* color function. Otherwise, the general "lazy" function is used.
* <p>
* Note: The color is resolved immediately, not lazy, because it is passed as parameter to another color function.
* So e.g. {@code darken(lazy(List.background), 10%)} is the same as {@code darken($List.background, 10%)}.
* <p>
* Only useful if a property is defined as lazy and that property is used
* in another property's color function. E.g.
*
* <pre>{@code
* someProperty = lazy(List.background)
* anotherProperty = darken($someProperty, 10%)
* }</pre>
*/
private static Object parseColorLazy( String value, List<String> params, Function<String, String> resolver )
throws IllegalArgumentException
{
if( params.size() != 1 )
throw newMissingParametersException( value );
return parseColorOrFunction( resolver.apply( PROPERTY_PREFIX + params.get( 0 ) ), resolver );
}
/** /**
* Syntax: systemColor(name[,defaultValue]) * Syntax: systemColor(name[,defaultValue])
* - name: system color name * - name: system color name
@@ -974,7 +1013,7 @@ class UIDefaultsLoader
* fadein(color,amount[,options]) or fadeout(color,amount[,options]) * fadein(color,amount[,options]) or fadeout(color,amount[,options])
* - color: a color (e.g. #f00) or a color function * - color: a color (e.g. #f00) or a color function
* - amount: percentage 0-100% * - amount: percentage 0-100%
* - options: [relative] [autoInverse] [noAutoInverse] [lazy] [derived] * - options: [relative] [autoInverse] [noAutoInverse] [derived] [lazy]
*/ */
private static Object parseColorHSLIncreaseDecrease( int hslIndex, boolean increase, private static Object parseColorHSLIncreaseDecrease( int hslIndex, boolean increase,
List<String> params, Function<String, String> resolver ) List<String> params, Function<String, String> resolver )
@@ -984,15 +1023,15 @@ class UIDefaultsLoader
int amount = parsePercentage( params.get( 1 ) ); int amount = parsePercentage( params.get( 1 ) );
boolean relative = false; boolean relative = false;
boolean autoInverse = false; boolean autoInverse = false;
boolean lazy = false;
boolean derived = false; boolean derived = false;
boolean lazy = false;
if( params.size() > 2 ) { if( params.size() > 2 ) {
String options = params.get( 2 ); String options = params.get( 2 );
relative = options.contains( "relative" ); relative = options.contains( "relative" );
autoInverse = options.contains( "autoInverse" ); autoInverse = options.contains( "autoInverse" );
lazy = options.contains( "lazy" );
derived = options.contains( "derived" ); derived = options.contains( "derived" );
lazy = options.contains( "lazy" );
// use autoInverse by default for derived colors, except if noAutoInverse is set // use autoInverse by default for derived colors, except if noAutoInverse is set
if( derived && !options.contains( "noAutoInverse" ) ) if( derived && !options.contains( "noAutoInverse" ) )
@@ -1003,14 +1042,8 @@ class UIDefaultsLoader
ColorFunction function = new ColorFunctions.HSLIncreaseDecrease( ColorFunction function = new ColorFunctions.HSLIncreaseDecrease(
hslIndex, increase, amount, relative, autoInverse ); hslIndex, increase, amount, relative, autoInverse );
if( lazy ) { if( lazy )
return (LazyValue) t -> { return newLazyColorFunction( colorStr, function );
Object color = lazyUIManagerGet( colorStr );
return (color instanceof Color)
? new ColorUIResource( ColorFunctions.applyFunctions( (Color) color, function ) )
: null;
};
}
// parse base color, apply function and create derived color // parse base color, apply function and create derived color
return parseFunctionBaseColor( colorStr, function, derived, resolver ); return parseFunctionBaseColor( colorStr, function, derived, resolver );
@@ -1039,14 +1072,8 @@ class UIDefaultsLoader
// create function // create function
ColorFunction function = new ColorFunctions.Fade( amount ); ColorFunction function = new ColorFunctions.Fade( amount );
if( lazy ) { if( lazy )
return (LazyValue) t -> { return newLazyColorFunction( colorStr, function );
Object color = lazyUIManagerGet( colorStr );
return (color instanceof Color)
? new ColorUIResource( ColorFunctions.applyFunctions( (Color) color, function ) )
: null;
};
}
// parse base color, apply function and create derived color // parse base color, apply function and create derived color
return parseFunctionBaseColor( colorStr, function, derived, resolver ); return parseFunctionBaseColor( colorStr, function, derived, resolver );
@@ -1056,7 +1083,7 @@ class UIDefaultsLoader
* Syntax: spin(color,angle[,options]) * Syntax: spin(color,angle[,options])
* - color: a color (e.g. #f00) or a color function * - color: a color (e.g. #f00) or a color function
* - angle: number of degrees to rotate * - angle: number of degrees to rotate
* - options: [derived] * - options: [derived] [lazy]
*/ */
private static Object parseColorSpin( List<String> params, Function<String, String> resolver ) private static Object parseColorSpin( List<String> params, Function<String, String> resolver )
throws IllegalArgumentException throws IllegalArgumentException
@@ -1064,15 +1091,20 @@ class UIDefaultsLoader
String colorStr = params.get( 0 ); String colorStr = params.get( 0 );
int amount = parseInteger( params.get( 1 ) ); int amount = parseInteger( params.get( 1 ) );
boolean derived = false; boolean derived = false;
boolean lazy = false;
if( params.size() > 2 ) { if( params.size() > 2 ) {
String options = params.get( 2 ); String options = params.get( 2 );
derived = options.contains( "derived" ); derived = options.contains( "derived" );
lazy = options.contains( "lazy" );
} }
// create function // create function
ColorFunction function = new ColorFunctions.HSLIncreaseDecrease( 0, true, amount, false, false ); ColorFunction function = new ColorFunctions.HSLIncreaseDecrease( 0, true, amount, false, false );
if( lazy )
return newLazyColorFunction( colorStr, function );
// parse base color, apply function and create derived color // parse base color, apply function and create derived color
return parseFunctionBaseColor( colorStr, function, derived, resolver ); return parseFunctionBaseColor( colorStr, function, derived, resolver );
} }
@@ -1084,7 +1116,7 @@ class UIDefaultsLoader
* changeAlpha(color,value[,options]) * changeAlpha(color,value[,options])
* - color: a color (e.g. #f00) or a color function * - color: a color (e.g. #f00) or a color function
* - value: for hue: number of degrees; otherwise: percentage 0-100% * - value: for hue: number of degrees; otherwise: percentage 0-100%
* - options: [derived] * - options: [derived] [lazy]
*/ */
private static Object parseColorChange( int hslIndex, private static Object parseColorChange( int hslIndex,
List<String> params, Function<String, String> resolver ) List<String> params, Function<String, String> resolver )
@@ -1095,27 +1127,33 @@ class UIDefaultsLoader
? parseInteger( params.get( 1 ) ) ? parseInteger( params.get( 1 ) )
: parsePercentage( params.get( 1 ) ); : parsePercentage( params.get( 1 ) );
boolean derived = false; boolean derived = false;
boolean lazy = false;
if( params.size() > 2 ) { if( params.size() > 2 ) {
String options = params.get( 2 ); String options = params.get( 2 );
derived = options.contains( "derived" ); derived = options.contains( "derived" );
lazy = options.contains( "lazy" );
} }
// create function // create function
ColorFunction function = new ColorFunctions.HSLChange( hslIndex, value ); ColorFunction function = new ColorFunctions.HSLChange( hslIndex, value );
if( lazy )
return newLazyColorFunction( colorStr, function );
// parse base color, apply function and create derived color // parse base color, apply function and create derived color
return parseFunctionBaseColor( colorStr, function, derived, resolver ); return parseFunctionBaseColor( colorStr, function, derived, resolver );
} }
/** /**
* Syntax: mix(color1,color2[,weight]) or * Syntax: mix(color1,color2[,weight][,options]) or
* tint(color[,weight]) or * tint(color[,weight][,options]) or
* shade(color[,weight]) * shade(color[,weight][,options])
* - color1: a color (e.g. #f00) or a color function * - color1: a color (e.g. #f00) or a color function
* - color2: a color (e.g. #f00) or a color function * - color2: a color (e.g. #f00) or a color function
* - weight: the weight (in range 0-100%) to mix the two colors * - weight: the weight (in range 0-100%) to mix the two colors
* larger weight uses more of first color, smaller weight more of second color * larger weight uses more of first color, smaller weight more of second color
* - options: [derived] [lazy]
*/ */
private static Object parseColorMix( String color1Str, List<String> params, Function<String, String> resolver ) private static Object parseColorMix( String color1Str, List<String> params, Function<String, String> resolver )
throws IllegalArgumentException throws IllegalArgumentException
@@ -1124,18 +1162,36 @@ class UIDefaultsLoader
if( color1Str == null ) if( color1Str == null )
color1Str = params.get( i++ ); color1Str = params.get( i++ );
String color2Str = params.get( i++ ); String color2Str = params.get( i++ );
int weight = (params.size() > i) ? parsePercentage( params.get( i ) ) : 50; int weight = 50;
boolean derived = false;
boolean lazy = false;
if( params.size() > i ) {
String weightStr = params.get( i );
if( !weightStr.isEmpty() && Character.isDigit( weightStr.charAt( 0 ) ) ) {
weight = parsePercentage( weightStr );
i++;
}
}
if( params.size() > i ) {
String options = params.get( i );
derived = options.contains( "derived" );
lazy = options.contains( "lazy" );
}
// parse second color // parse second color
ColorUIResource color2 = (ColorUIResource) parseColorOrFunction( resolver.apply( color2Str ), resolver ); ColorUIResource color1 = (ColorUIResource) parseColorOrFunction( resolver.apply( color1Str ), resolver );
if( color2 == null ) if( color1 == null )
return null; return null;
// create function // create function
ColorFunction function = new ColorFunctions.Mix( color2, weight ); ColorFunction function = new ColorFunctions.Mix2( color1, weight );
if( lazy )
return newLazyColorFunction( color2Str, function );
// parse first color, apply function and create mixed color // parse first color, apply function and create mixed color
return parseFunctionBaseColor( color1Str, function, false, resolver ); return parseFunctionBaseColor( color2Str, function, derived, resolver );
} }
/** /**
@@ -1229,6 +1285,15 @@ class UIDefaultsLoader
return new ColorUIResource( newColor ); return new ColorUIResource( newColor );
} }
private static LazyValue newLazyColorFunction( String uiKey, ColorFunction function ) {
return (LazyValue) t -> {
Object color = lazyUIManagerGet( uiKey );
return (color instanceof Color)
? new ColorUIResource( ColorFunctions.applyFunctions( (Color) color, function ) )
: null;
};
}
/** /**
* Syntax: [normal] [bold|+bold|-bold] [italic|+italic|-italic] [<size>|+<incr>|-<decr>|<percent>%] [family[, family]] [$baseFontKey] * Syntax: [normal] [bold|+bold|-bold] [italic|+italic|-italic] [<size>|+<incr>|-<decr>|<percent>%] [family[, family]] [$baseFontKey]
*/ */

View File

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

View File

@@ -63,7 +63,7 @@ public class FlatWindowCloseIcon
int iy = y + ((height - iwh) / 2); int iy = y + ((height - iwh) / 2);
int ix2 = ix + iwh - 1; int ix2 = ix + iwh - 1;
int iy2 = iy + 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 ); Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD, 4 );
path.moveTo( ix, iy ); path.moveTo( ix, iy );

View File

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

View File

@@ -42,7 +42,7 @@ public class FlatWindowMaximizeIcon
int iwh = (int) (getSymbolHeight() * scaleFactor); int iwh = (int) (getSymbolHeight() * scaleFactor);
int ix = x + ((width - iwh) / 2); int ix = x + ((width - iwh) / 2);
int iy = y + ((height - 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 arc = Math.max( (int) (1.5 * scaleFactor), 2 );
g.fill( SystemInfo.isWindows_11_orLater g.fill( SystemInfo.isWindows_11_orLater

View File

@@ -45,7 +45,7 @@ public class FlatWindowRestoreIcon
int iwh = (int) (getSymbolHeight() * scaleFactor); int iwh = (int) (getSymbolHeight() * scaleFactor);
int ix = x + ((width - iwh) / 2); int ix = x + ((width - iwh) / 2);
int iy = y + ((height - 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 arc = Math.max( (int) (1.5 * scaleFactor), 2 );
int arcOuter = (int) (arc + (1.5 * scaleFactor)); int arcOuter = (int) (arc + (1.5 * scaleFactor));

View File

@@ -59,6 +59,8 @@ import com.formdev.flatlaf.util.DerivedColor;
* @uiDefault Component.error.focusedBorderColor Color * @uiDefault Component.error.focusedBorderColor Color
* @uiDefault Component.warning.borderColor Color * @uiDefault Component.warning.borderColor Color
* @uiDefault Component.warning.focusedBorderColor Color * @uiDefault Component.warning.focusedBorderColor Color
* @uiDefault Component.success.borderColor Color
* @uiDefault Component.success.focusedBorderColor Color
* @uiDefault Component.custom.borderColor Color * @uiDefault Component.custom.borderColor Color
* *
* @author Karl Tauber * @author Karl Tauber
@@ -81,6 +83,8 @@ public class FlatBorder
@Styleable(dot=true) protected Color errorFocusedBorderColor = UIManager.getColor( "Component.error.focusedBorderColor" ); @Styleable(dot=true) protected Color errorFocusedBorderColor = UIManager.getColor( "Component.error.focusedBorderColor" );
@Styleable(dot=true) protected Color warningBorderColor = UIManager.getColor( "Component.warning.borderColor" ); @Styleable(dot=true) protected Color warningBorderColor = UIManager.getColor( "Component.warning.borderColor" );
@Styleable(dot=true) protected Color warningFocusedBorderColor = UIManager.getColor( "Component.warning.focusedBorderColor" ); @Styleable(dot=true) protected Color warningFocusedBorderColor = UIManager.getColor( "Component.warning.focusedBorderColor" );
/** @since 3.6 */ @Styleable(dot=true) protected Color successBorderColor = UIManager.getColor( "Component.success.borderColor" );
/** @since 3.6 */ @Styleable(dot=true) protected Color successFocusedBorderColor = UIManager.getColor( "Component.success.focusedBorderColor" );
@Styleable(dot=true) protected Color customBorderColor = UIManager.getColor( "Component.custom.borderColor" ); @Styleable(dot=true) protected Color customBorderColor = UIManager.getColor( "Component.custom.borderColor" );
// only used via styling (not in UI defaults, but has likewise client properties) // only used via styling (not in UI defaults, but has likewise client properties)
@@ -168,6 +172,9 @@ public class FlatBorder
case FlatClientProperties.OUTLINE_WARNING: case FlatClientProperties.OUTLINE_WARNING:
return isFocused( c ) ? warningFocusedBorderColor : warningBorderColor; return isFocused( c ) ? warningFocusedBorderColor : warningBorderColor;
case FlatClientProperties.OUTLINE_SUCCESS:
return isFocused( c ) ? successFocusedBorderColor : successBorderColor;
} }
} else if( outline instanceof Color ) { } else if( outline instanceof Color ) {
Color color = (Color) outline; Color color = (Color) outline;

View File

@@ -280,8 +280,6 @@ public class FlatButtonUI
LookAndFeel.installProperty( b, "opaque", false ); LookAndFeel.installProperty( b, "opaque", false );
LookAndFeel.installProperty( b, "iconTextGap", scale( iconTextGap ) ); LookAndFeel.installProperty( b, "iconTextGap", scale( iconTextGap ) );
MigLayoutVisualPadding.install( b );
} }
@Override @Override
@@ -291,10 +289,23 @@ public class FlatButtonUI
oldStyleValues = null; oldStyleValues = null;
borderShared = null; borderShared = null;
MigLayoutVisualPadding.uninstall( b );
defaults_initialized = false; defaults_initialized = false;
} }
@Override
protected void installListeners( AbstractButton b ) {
super.installListeners( b );
MigLayoutVisualPadding.install( b );
}
@Override
protected void uninstallListeners( AbstractButton b ) {
super.uninstallListeners( b );
MigLayoutVisualPadding.uninstall( b );
}
@Override @Override
protected BasicButtonListener createButtonListener( AbstractButton b ) { protected BasicButtonListener createButtonListener( AbstractButton b ) {
return new FlatButtonListener( b ); return new FlatButtonListener( b );
@@ -653,7 +664,8 @@ public class FlatButtonUI
} }
protected Color getBackground( JComponent c ) { protected Color getBackground( JComponent c ) {
boolean toolBarButton = isToolBarButton( c ) || isBorderlessButton( c ); boolean def = isDefaultButton( c );
boolean toolBarButton = !def && (isToolBarButton( c ) || isBorderlessButton( c ));
// selected state // selected state
if( ((AbstractButton)c).isSelected() ) { if( ((AbstractButton)c).isSelected() ) {
@@ -681,7 +693,6 @@ public class FlatButtonUI
toolbarPressedBackground ); toolbarPressedBackground );
} }
boolean def = isDefaultButton( c );
return buttonStateColor( c, return buttonStateColor( c,
getBackgroundBase( c, def ), getBackgroundBase( c, def ),
disabledBackground, disabledBackground,
@@ -733,7 +744,8 @@ public class FlatButtonUI
protected Color getForeground( JComponent c ) { protected Color getForeground( JComponent c ) {
Color fg = c.getForeground(); Color fg = c.getForeground();
boolean toolBarButton = isToolBarButton( c ) || isBorderlessButton( c ); boolean def = isDefaultButton( c );
boolean toolBarButton = !def && (isToolBarButton( c ) || isBorderlessButton( c ));
// selected state // selected state
if( ((AbstractButton)c).isSelected() ) { if( ((AbstractButton)c).isSelected() ) {
@@ -759,7 +771,6 @@ public class FlatButtonUI
toolbarPressedForeground ); toolbarPressedForeground );
} }
boolean def = isDefaultButton( c );
return buttonStateColor( c, return buttonStateColor( c,
getForegroundBase( c, def ), getForegroundBase( c, def ),
disabledText, disabledText,

View File

@@ -225,6 +225,8 @@ public class FlatComboBoxUI
} }
}; };
comboBox.addMouseListener( hoverListener ); comboBox.addMouseListener( hoverListener );
MigLayoutVisualPadding.install( comboBox );
} }
@Override @Override
@@ -233,6 +235,8 @@ public class FlatComboBoxUI
comboBox.removeMouseListener( hoverListener ); comboBox.removeMouseListener( hoverListener );
hoverListener = null; hoverListener = null;
MigLayoutVisualPadding.uninstall( comboBox );
} }
@Override @Override
@@ -274,8 +278,6 @@ public class FlatComboBoxUI
comboBox.setMaximumRowCount( maximumRowCount ); comboBox.setMaximumRowCount( maximumRowCount );
paddingBorder = new CellPaddingBorder( padding ); paddingBorder = new CellPaddingBorder( padding );
MigLayoutVisualPadding.install( comboBox );
} }
@Override @Override
@@ -304,8 +306,6 @@ public class FlatComboBoxUI
oldStyleValues = null; oldStyleValues = null;
borderShared = null; borderShared = null;
MigLayoutVisualPadding.uninstall( comboBox );
} }
@Override @Override
@@ -585,7 +585,7 @@ public class FlatComboBoxUI
FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc ); FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc );
// paint arrow button background // paint arrow button background
if( enabled && !isCellRenderer ) { if( enabled && !isCellRenderer && arrowButton.isVisible() ) {
Color buttonColor = paintButton Color buttonColor = paintButton
? buttonEditableBackground ? buttonEditableBackground
: (buttonFocusedBackground != null || focusedBackground != null) && isPermanentFocusOwner( comboBox ) : (buttonFocusedBackground != null || focusedBackground != null) && isPermanentFocusOwner( comboBox )
@@ -612,7 +612,7 @@ public class FlatComboBoxUI
} }
// paint vertical line between value and arrow button // paint vertical line between value and arrow button
if( paintButton ) { if( paintButton && arrowButton.isVisible() ) {
Color separatorColor = enabled ? buttonSeparatorColor : buttonDisabledSeparatorColor; Color separatorColor = enabled ? buttonSeparatorColor : buttonDisabledSeparatorColor;
if( separatorColor != null && buttonSeparatorWidth > 0 ) { if( separatorColor != null && buttonSeparatorWidth > 0 ) {
g2.setColor( separatorColor ); g2.setColor( separatorColor );

View File

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

View File

@@ -376,31 +376,68 @@ public class FlatFileChooserUI
if( icon != null ) if( icon != null )
return icon; return icon;
// get system icon // new proxy icon
if( f != null ) { //
try { // Note: Since this is a super light weight icon object, we do not add it
icon = getFileChooser().getFileSystemView().getSystemIcon( f ); // to the icon cache here. This keeps cache small in case of large directories
} catch( NullPointerException ex ) { // with thousands of files when icons of all files are only needed to compute
// Java 21 may throw a NPE for exe files that use default Windows exe icon // 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 ) { //---- class FlatFileViewIcon -----------------------------------------
if( icon instanceof ImageIcon )
icon = new ScaledImageIcon( (ImageIcon) icon ); /**
cacheIcon( f, icon ); * A proxy icon that has a fixed (scaled) width/height (16x16) and
return icon; * 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 @Override
icon = super.getIcon( f ); public int getIconWidth() {
return UIScale.scale( 16 );
if( icon instanceof ImageIcon ) {
icon = new ScaledImageIcon( (ImageIcon) icon );
cacheIcon( f, icon );
} }
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; package com.formdev.flatlaf.ui;
import java.awt.Color; import java.awt.Color;
import java.awt.Font;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.Locale;
import java.util.Set; import java.util.Set;
import java.util.function.BiConsumer;
import javax.swing.AbstractButton; import javax.swing.AbstractButton;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JLabel; import javax.swing.JLabel;
@@ -74,9 +75,9 @@ public class FlatHTML
for( int i = 1; i <= 7; i++ ) for( int i = 1; i <= 7; i++ )
System.out.println( i+": "+ styleSheet.getPointSize( i ) ); System.out.println( i+": "+ styleSheet.getPointSize( i ) );
debug*/ debug*/
int fontBaseSize = c.getFont().getSize(); Font font = c.getFont();
if( styleSheet.getPointSize( 7 ) != 36f || if( styleSheet.getPointSize( 7 ) != 36f ||
styleSheet.getPointSize( 4 ) == fontBaseSize ) font == null || styleSheet.getPointSize( 4 ) == font.getSize() )
return; return;
// check whether view uses "absolute-size" keywords (e.g. "x-large") for font-size // check whether view uses "absolute-size" keywords (e.g. "x-large") for font-size
@@ -93,23 +94,22 @@ debug*/
text = ((JToolTip)c).getTipText(); text = ((JToolTip)c).getTipText();
else else
return; return;
if( text == null ) if( text == null || !BasicHTML.isHTMLString( text ) )
return; return;
// BASE_SIZE rule is parsed in javax.swing.text.html.StyleSheet.addRule() // 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 openTag = "";
String closeTag = ""; String closeTag = "";
String lowerText = text.toLowerCase( Locale.ENGLISH );
int headIndex; int headIndex;
int styleIndex; int styleIndex;
int insertIndex; int insertIndex;
if( (headIndex = lowerText.indexOf( "<head>" )) >= 0 ) { if( (headIndex = indexOfTag( text, "head", true )) >= 0 ) {
// there is a <head> tag --> insert after <head> tag // there is a <head> tag --> insert after <head> tag
insertIndex = headIndex + "<head>".length(); insertIndex = headIndex;
} else if( (styleIndex = lowerText.indexOf( "<style>" )) >= 0 ) { } else if( (styleIndex = indexOfTag( text, "style", false )) >= 0 ) {
// there is a <style> tag --> insert before <style> tag // there is a <style> tag --> insert before <style> tag
insertIndex = styleIndex; insertIndex = styleIndex;
} else { } else {
@@ -124,6 +124,41 @@ debug*/
+ text.substring( insertIndex ); + text.substring( insertIndex );
BasicHTML.updateRenderer( c, newText ); 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( 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.foreground Color
* @uiDefault List.selectionBackground Color * @uiDefault List.selectionBackground Color
* @uiDefault List.selectionForeground Color * @uiDefault List.selectionForeground Color
* @uiDefault List.alternateRowColor Color
* @uiDefault List.dropLineColor Color * @uiDefault List.dropLineColor Color
* @uiDefault List.border Border * @uiDefault List.border Border
* @uiDefault List.cellRenderer ListCellRenderer * @uiDefault List.cellRenderer ListCellRenderer
@@ -93,6 +94,7 @@ public class FlatListUI
@Styleable protected Color selectionForeground; @Styleable protected Color selectionForeground;
@Styleable protected Color selectionInactiveBackground; @Styleable protected Color selectionInactiveBackground;
@Styleable protected Color selectionInactiveForeground; @Styleable protected Color selectionInactiveForeground;
/** @since 3.6 */ @Styleable protected Color alternateRowColor;
/** @since 3 */ @Styleable protected Insets selectionInsets; /** @since 3 */ @Styleable protected Insets selectionInsets;
/** @since 3 */ @Styleable protected int selectionArc; /** @since 3 */ @Styleable protected int selectionArc;
@@ -129,6 +131,7 @@ public class FlatListUI
selectionForeground = UIManager.getColor( "List.selectionForeground" ); selectionForeground = UIManager.getColor( "List.selectionForeground" );
selectionInactiveBackground = UIManager.getColor( "List.selectionInactiveBackground" ); selectionInactiveBackground = UIManager.getColor( "List.selectionInactiveBackground" );
selectionInactiveForeground = UIManager.getColor( "List.selectionInactiveForeground" ); selectionInactiveForeground = UIManager.getColor( "List.selectionInactiveForeground" );
alternateRowColor = UIManager.getColor( "List.alternateRowColor" );
selectionInsets = UIManager.getInsets( "List.selectionInsets" ); selectionInsets = UIManager.getInsets( "List.selectionInsets" );
selectionArc = UIManager.getInt( "List.selectionArc" ); selectionArc = UIManager.getInt( "List.selectionArc" );
@@ -143,6 +146,7 @@ public class FlatListUI
selectionForeground = null; selectionForeground = null;
selectionInactiveBackground = null; selectionInactiveBackground = null;
selectionInactiveForeground = null; selectionInactiveForeground = null;
alternateRowColor = null;
oldStyleValues = null; oldStyleValues = null;
} }
@@ -299,13 +303,24 @@ public class FlatListUI
{ {
boolean isSelected = selModel.isSelectedIndex( row ); 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 // get renderer component
@SuppressWarnings( "unchecked" ) @SuppressWarnings( "unchecked" )
Component rendererComponent = cellRenderer.getListCellRendererComponent( list, Component rendererComponent = cellRenderer.getListCellRendererComponent( list,
dataModel.getElementAt( row ), row, isSelected, dataModel.getElementAt( row ), row, isSelected,
FlatUIUtils.isPermanentFocusOwner( list ) && (row == leadIndex) ); FlatUIUtils.isPermanentFocusOwner( list ) && (row == leadIndex) );
// // use smaller cell width if list is used in JFileChooser
boolean isFileList = Boolean.TRUE.equals( list.getClientProperty( "List.isFileList" ) ); boolean isFileList = Boolean.TRUE.equals( list.getClientProperty( "List.isFileList" ) );
int cx, cw; int cx, cw;
if( isFileList ) { if( isFileList ) {

View File

@@ -58,6 +58,7 @@ class FlatNativeLibrary
String classifier; String classifier;
String ext; String ext;
boolean unknownArch = false;
if( SystemInfo.isWindows_10_orLater && (SystemInfo.isX86 || SystemInfo.isX86_64 || SystemInfo.isAARCH64) ) { if( SystemInfo.isWindows_10_orLater && (SystemInfo.isX86 || SystemInfo.isX86_64 || SystemInfo.isAARCH64) ) {
// Windows: requires Windows 10/11 (x86, x86_64 or aarch64) // Windows: requires Windows 10/11 (x86, x86_64 or aarch64)
@@ -90,11 +91,14 @@ class FlatNativeLibrary
classifier = SystemInfo.isAARCH64 ? "macos-arm64" : "macos-x86_64"; classifier = SystemInfo.isAARCH64 ? "macos-arm64" : "macos-x86_64";
ext = "dylib"; ext = "dylib";
} else if( SystemInfo.isLinux && SystemInfo.isX86_64 ) { } else if( SystemInfo.isLinux ) {
// Linux: requires x86_64 // Linux: x86_64 or aarch64 (but also supports unknown architectures)
classifier = "linux-x86_64"; classifier = SystemInfo.isAARCH64 ? "linux-arm64"
: (SystemInfo.isX86_64 ? "linux-x86_64"
: "linux-" + sanitize( System.getProperty( "os.arch" ) ));
ext = "so"; ext = "so";
unknownArch = !SystemInfo.isX86_64 && !SystemInfo.isAARCH64;
// Load libjawt.so (part of JRE) explicitly because it is not found // Load libjawt.so (part of JRE) explicitly because it is not found
// in all Java versions/distributions. // in all Java versions/distributions.
@@ -106,7 +110,7 @@ class FlatNativeLibrary
return; // no native library available for current OS or CPU architecture return; // no native library available for current OS or CPU architecture
// load native library // load native library
NativeLibrary nativeLibrary = createNativeLibrary( classifier, ext ); NativeLibrary nativeLibrary = createNativeLibrary( classifier, ext, unknownArch );
if( !nativeLibrary.isLoaded() ) if( !nativeLibrary.isLoaded() )
return; return;
@@ -128,7 +132,7 @@ class FlatNativeLibrary
FlatNativeLibrary.nativeLibrary = nativeLibrary; FlatNativeLibrary.nativeLibrary = nativeLibrary;
} }
private static NativeLibrary createNativeLibrary( String classifier, String ext ) { private static NativeLibrary createNativeLibrary( String classifier, String ext, boolean unknownArch ) {
String libraryName = "flatlaf-" + classifier; String libraryName = "flatlaf-" + classifier;
// load from "java.library.path" or from path specified in system property "flatlaf.nativeLibraryPath" // load from "java.library.path" or from path specified in system property "flatlaf.nativeLibraryPath"
@@ -139,9 +143,11 @@ class FlatNativeLibrary
if( library.isLoaded() ) if( library.isLoaded() )
return library; return library;
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Native library '" + System.mapLibraryName( libraryName ) if( !unknownArch ) {
+ "' not found in java.library.path '" + System.getProperty( "java.library.path" ) LoggingFacade.INSTANCE.logSevere( "FlatLaf: Native library '" + System.mapLibraryName( libraryName )
+ "'. Using extracted native library instead.", null ); + "' not found in java.library.path '" + System.getProperty( "java.library.path" )
+ "'. Using extracted native library instead.", null );
}
} else { } else {
// try standard library naming scheme // try standard library naming scheme
// (same as in flatlaf.jar in package 'com/formdev/flatlaf/natives') // (same as in flatlaf.jar in package 'com/formdev/flatlaf/natives')
@@ -160,11 +166,13 @@ class FlatNativeLibrary
return new NativeLibrary( libraryFile2, true ); return new NativeLibrary( libraryFile2, true );
} }
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Native library '" if( !unknownArch ) {
+ libraryFile.getName() LoggingFacade.INSTANCE.logSevere( "FlatLaf: Native library '"
+ (libraryName2 != null ? ("' or '" + libraryName2) : "") + libraryFile.getName()
+ "' not found in '" + libraryFile.getParentFile().getAbsolutePath() + (libraryName2 != null ? ("' or '" + libraryName2) : "")
+ "'. Using extracted native library instead.", null ); + "' not found in '" + libraryFile.getParentFile().getAbsolutePath()
+ "'. Using extracted native library instead.", null );
}
} }
} }
@@ -175,7 +183,7 @@ class FlatNativeLibrary
return new NativeLibrary( libraryFile, true ); return new NativeLibrary( libraryFile, true );
// load from FlatLaf jar (extract native library to temp folder) // load from FlatLaf jar (extract native library to temp folder)
return new NativeLibrary( "com/formdev/flatlaf/natives/" + libraryName, null, true ); return new NativeLibrary( "com/formdev/flatlaf/natives/" + libraryName, null, !unknownArch );
} }
/** /**
@@ -273,6 +281,13 @@ class FlatNativeLibrary
+ '-' + classifier + '.' + ext; + '-' + classifier + '.' + ext;
} }
/**
* Allow only 'a'-'z', 'A'-'Z', '0'-'9', '_' and '-' in filenames.
*/
private static String sanitize( String s ) {
return s.replaceAll( "[^a-zA-Z0-9_-]", "_" );
}
private static void loadJAWT() { private static void loadJAWT() {
try { try {
System.loadLibrary( "jawt" ); System.loadLibrary( "jawt" );

View File

@@ -16,6 +16,7 @@
package com.formdev.flatlaf.ui; package com.formdev.flatlaf.ui;
import java.awt.GraphicsConfiguration;
import java.awt.Point; import java.awt.Point;
import java.awt.Toolkit; import java.awt.Toolkit;
import java.awt.Window; import java.awt.Window;
@@ -48,8 +49,17 @@ class FlatNativeLinuxLibrary
} }
// direction for _NET_WM_MOVERESIZE message // direction for _NET_WM_MOVERESIZE message
// see https://specifications.freedesktop.org/wm-spec/wm-spec-latest.html // see https://specifications.freedesktop.org/wm-spec/latest/ar01s04.html
static final int MOVE = 8; static final int
SIZE_TOPLEFT = 0,
SIZE_TOP = 1,
SIZE_TOPRIGHT = 2,
SIZE_RIGHT = 3,
SIZE_BOTTOMRIGHT = 4,
SIZE_BOTTOM = 5,
SIZE_BOTTOMLEFT = 6,
SIZE_LEFT = 7,
MOVE = 8;
private static Boolean isXWindowSystem; private static Boolean isXWindowSystem;
@@ -96,7 +106,11 @@ class FlatNativeLinuxLibrary
} }
private static Point scale( Window window, Point pt ) { private static Point scale( Window window, Point pt ) {
AffineTransform transform = window.getGraphicsConfiguration().getDefaultTransform(); GraphicsConfiguration gc = window.getGraphicsConfiguration();
if( gc == null )
return pt;
AffineTransform transform = gc.getDefaultTransform();
int x = (int) Math.round( pt.x * transform.getScaleX() ); int x = (int) Math.round( pt.x * transform.getScaleX() );
int y = (int) Math.round( pt.y * transform.getScaleY() ); int y = (int) Math.round( pt.y * transform.getScaleY() );
return new Point( x, y ); return new Point( x, y );

View File

@@ -138,7 +138,8 @@ public class FlatPopupFactory
// create drop shadow popup // create drop shadow popup
Popup popupForScreenOfOwner = getPopupForScreenOfOwner( owner, contents, x, y, forceHeavyWeight ); 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 DropShadowPopup( popupForScreenOfOwner, owner, contents )
: new NonFlashingPopup( popupForScreenOfOwner, owner, contents ); : new NonFlashingPopup( popupForScreenOfOwner, owner, contents );
} }
@@ -305,7 +306,7 @@ public class FlatPopupFactory
break; break;
} }
} }
if( gc == null ) if( gc == null && owner != null )
gc = owner.getGraphicsConfiguration(); gc = owner.getGraphicsConfiguration();
if( gc == null ) if( gc == null )
return null; return null;
@@ -364,14 +365,8 @@ public class FlatPopupFactory
} }
private static boolean isMacOSBorderSupported() { private static boolean isMacOSBorderSupported() {
// do not use rounded border on macOS 14.4+ because it may freeze the application
// and crash the macOS WindowServer process (reports vary from Finder restarts to OS restarts)
// https://github.com/apache/netbeans/issues/7560#issuecomment-2226439215
// https://github.com/apache/netbeans/issues/6647#issuecomment-2070124442
boolean isMacOS_14_4_orLater = (SystemInfo.osVersion >= SystemInfo.toVersion( 14, 4, 0, 0 ));
return SystemInfo.isMacOS && return SystemInfo.isMacOS &&
FlatSystemProperties.getBoolean( FlatSystemProperties.USE_ROUNDED_POPUP_BORDER, !isMacOS_14_4_orLater ) && FlatSystemProperties.getBoolean( FlatSystemProperties.USE_ROUNDED_POPUP_BORDER, true ) &&
FlatNativeMacLibrary.isLoaded(); FlatNativeMacLibrary.isLoaded();
} }
@@ -695,8 +690,6 @@ public class FlatPopupFactory
Container contentPane = ((JWindow)popupWindow).getContentPane(); Container contentPane = ((JWindow)popupWindow).getContentPane();
contentPane.removeAll(); contentPane.removeAll();
contentPane.add( contents, BorderLayout.CENTER ); contentPane.add( contents, BorderLayout.CENTER );
popupWindow.invalidate();
popupWindow.validate();
popupWindow.pack(); popupWindow.pack();
// update client property on contents // update client property on contents
@@ -716,6 +709,7 @@ public class FlatPopupFactory
private class DropShadowPopup private class DropShadowPopup
extends NonFlashingPopup extends NonFlashingPopup
implements ComponentListener
{ {
// light weight // light weight
private JComponent lightComp; private JComponent lightComp;
@@ -775,7 +769,7 @@ public class FlatPopupFactory
} }
// Windows 11: reset corner preference on reused heavy weight popups // Windows 11: reset corner preference on reused heavy weight popups
if( isWindows11BorderSupported() ) { if( SystemInfo.isWindows_11_orLater && FlatNativeWindowsLibrary.isLoaded() ) {
resetWindows11Border( popupWindow ); resetWindows11Border( popupWindow );
if( dropShadowWindow != null ) if( dropShadowWindow != null )
resetWindows11Border( dropShadowWindow ); resetWindows11Border( dropShadowWindow );
@@ -845,10 +839,18 @@ public class FlatPopupFactory
if( insets.left != 0 || insets.top != 0 ) if( insets.left != 0 || insets.top != 0 )
lightComp.setLocation( lightComp.getX() - insets.left, lightComp.getY() - insets.top ); lightComp.setLocation( lightComp.getX() - insets.left, lightComp.getY() - insets.top );
} }
if( popupWindow != null ) {
removeAllPopupWindowComponentListeners();
popupWindow.addComponentListener( this );
}
} }
@Override @Override
void hideImpl() { void hideImpl() {
if( popupWindow != null )
removeAllPopupWindowComponentListeners();
if( dropShadowDelegate != null ) { if( dropShadowDelegate != null ) {
dropShadowDelegate.hide(); dropShadowDelegate.hide();
dropShadowDelegate = null; dropShadowDelegate = null;
@@ -948,22 +950,55 @@ public class FlatPopupFactory
@Override @Override
void reset( Component contents, int ownerX, int ownerY ) { void reset( Component contents, int ownerX, int ownerY ) {
if( popupWindow != null )
removeAllPopupWindowComponentListeners();
super.reset( contents, ownerX, ownerY ); super.reset( contents, ownerX, ownerY );
if( dropShadowWindow != null ) { updateDropShadowWindowBounds();
// 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 ) );
// update drop shadow popup window location and size private void updateDropShadowWindowBounds() {
int x = popupWindow.getX() - insets.left; if( dropShadowWindow == null )
int y = popupWindow.getY() - insets.top; return;
dropShadowWindow.setBounds( x, y, w, h );
dropShadowWindow.pack(); // 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 ) if( gc == null && popupMenu.getInvoker() != null )
gc = popupMenu.getInvoker().getGraphicsConfiguration(); gc = popupMenu.getInvoker().getGraphicsConfiguration();
// compute screen height if( gc == null )
return new Rectangle( Toolkit.getDefaultToolkit().getScreenSize() );
// compute screen bounds
// (always subtract screen insets because there is no API to detect whether // (always subtract screen insets because there is no API to detect whether
// the popup can overlap the taskbar; see JPopupMenu.canPopupOverlapTaskBar()) // the popup can overlap the taskbar; see JPopupMenu.canPopupOverlapTaskBar())
Toolkit toolkit = Toolkit.getDefaultToolkit(); Rectangle screenBounds = gc.getBounds();
Rectangle screenBounds = (gc != null) ? gc.getBounds() : new Rectangle( toolkit.getScreenSize() );
Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets( gc ); Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets( gc );
return FlatUIUtils.subtractInsets( screenBounds, screenInsets ); return FlatUIUtils.subtractInsets( screenBounds, screenInsets );
} }

View File

@@ -684,7 +684,7 @@ public class FlatRootPaneUI
* Window border used for non-native window decorations. * Window border used for non-native window decorations.
*/ */
public static class FlatWindowBorder public static class FlatWindowBorder
extends BorderUIResource.EmptyBorderUIResource extends FlatEmptyBorder
{ {
protected final Color activeBorderColor = UIManager.getColor( "RootPane.activeBorderColor" ); protected final Color activeBorderColor = UIManager.getColor( "RootPane.activeBorderColor" );
protected final Color inactiveBorderColor = UIManager.getColor( "RootPane.inactiveBorderColor" ); protected final Color inactiveBorderColor = UIManager.getColor( "RootPane.inactiveBorderColor" );
@@ -717,7 +717,10 @@ public class FlatRootPaneUI
} }
private void paintImpl( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) { 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 ) { protected boolean isWindowMaximized( Component c ) {

View File

@@ -140,8 +140,6 @@ public class FlatSpinnerUI
buttonHoverArrowColor = UIManager.getColor( "Spinner.buttonHoverArrowColor" ); buttonHoverArrowColor = UIManager.getColor( "Spinner.buttonHoverArrowColor" );
buttonPressedArrowColor = UIManager.getColor( "Spinner.buttonPressedArrowColor" ); buttonPressedArrowColor = UIManager.getColor( "Spinner.buttonPressedArrowColor" );
padding = UIManager.getInsets( "Spinner.padding" ); padding = UIManager.getInsets( "Spinner.padding" );
MigLayoutVisualPadding.install( spinner );
} }
@Override @Override
@@ -162,8 +160,6 @@ public class FlatSpinnerUI
oldStyleValues = null; oldStyleValues = null;
borderShared = null; borderShared = null;
MigLayoutVisualPadding.uninstall( spinner );
} }
@Override @Override
@@ -173,6 +169,8 @@ public class FlatSpinnerUI
addEditorFocusListener( spinner.getEditor() ); addEditorFocusListener( spinner.getEditor() );
spinner.addFocusListener( getHandler() ); spinner.addFocusListener( getHandler() );
spinner.addPropertyChangeListener( getHandler() ); spinner.addPropertyChangeListener( getHandler() );
MigLayoutVisualPadding.install( spinner );
} }
@Override @Override
@@ -184,6 +182,8 @@ public class FlatSpinnerUI
spinner.removePropertyChangeListener( getHandler() ); spinner.removePropertyChangeListener( getHandler() );
handler = null; handler = null;
MigLayoutVisualPadding.uninstall( spinner );
} }
private Handler getHandler() { private Handler getHandler() {

View File

@@ -42,7 +42,6 @@ import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.util.HiDPIUtils; import com.formdev.flatlaf.util.HiDPIUtils;
import com.formdev.flatlaf.util.StringUtils; import com.formdev.flatlaf.util.StringUtils;
import com.formdev.flatlaf.util.SystemInfo;
/** /**
* Support for styling components in CSS syntax. * Support for styling components in CSS syntax.
@@ -325,22 +324,24 @@ public class FlatStylingSupport
return null; return null;
Map<String, Object> oldValues = new HashMap<>(); Map<String, Object> oldValues = new HashMap<>();
outer:
for( Map.Entry<String, Object> e : style.entrySet() ) { for( Map.Entry<String, Object> e : style.entrySet() ) {
String key = e.getKey(); String key = e.getKey();
Object newValue = e.getValue(); Object newValue = e.getValue();
// handle key prefix // handle key prefix
if( key.startsWith( "[" ) ) { while( key.startsWith( "[" ) ) {
if( (SystemInfo.isWindows && key.startsWith( "[win]" )) || int closeIndex = key.indexOf( ']' );
(SystemInfo.isMacOS && key.startsWith( "[mac]" )) || if( closeIndex < 0 )
(SystemInfo.isLinux && key.startsWith( "[linux]" )) || continue outer;
(key.startsWith( "[light]" ) && !FlatLaf.isLafDark()) ||
(key.startsWith( "[dark]" ) && FlatLaf.isLafDark()) ) String prefix = key.substring( 0, closeIndex + 1 );
{ String lightOrDarkPrefix = FlatLaf.getUIKeyLightOrDarkPrefix( FlatLaf.isLafDark() );
// prefix is known and enabled --> remove prefix if( !lightOrDarkPrefix.equals( prefix ) && !FlatLaf.getUIKeyPlatformPrefixes().contains( prefix ) )
key = key.substring( key.indexOf( ']' ) + 1 ); continue outer;
} else
continue; // prefix is known and enabled --> remove prefix
key = key.substring( closeIndex + 1 );
} }
Object oldValue = applyProperty.apply( key, newValue ); Object oldValue = applyProperty.apply( key, newValue );

View File

@@ -2306,8 +2306,23 @@ debug*/
/** @since 3.4 */ /** @since 3.4 */
@Override @Override
public Boolean isTitleBarCaptionAt( int x, int y ) { public Boolean isTitleBarCaptionAt( int x, int y ) {
if( tabForCoordinate( tabPane, x, y ) >= 0 ) // Note: not using tabForCoordinate() here because this may validate layout and cause dead lock
return false;
if( moreTabsButton != null ) {
// convert x,y from JTabbedPane coordinate space to ScrollableTabPanel coordinate space
Point viewPosition = tabViewport.getViewPosition();
x = x - tabViewport.getX() + viewPosition.x;
y = y - tabViewport.getY() + viewPosition.y;
// check whether point is within viewport
if( !tabViewport.getViewRect().contains( x, y ) )
return null; // check children
}
for( int i = 0; i < rects.length; i++ ) {
if( rects[i].contains( x, y ) )
return false;
}
return null; // check children return null; // check children
} }

View File

@@ -174,8 +174,6 @@ public class FlatTextFieldUI
defaultMargin = UIManager.getInsets( prefix + ".margin" ); defaultMargin = UIManager.getInsets( prefix + ".margin" );
LookAndFeel.installProperty( getComponent(), "opaque", false ); LookAndFeel.installProperty( getComponent(), "opaque", false );
MigLayoutVisualPadding.install( getComponent() );
} }
@Override @Override
@@ -193,8 +191,6 @@ public class FlatTextFieldUI
oldStyleValues = null; oldStyleValues = null;
borderShared = null; borderShared = null;
MigLayoutVisualPadding.uninstall( getComponent() );
} }
@Override @Override
@@ -204,6 +200,8 @@ public class FlatTextFieldUI
// necessary to update focus border and background // necessary to update focus border and background
focusListener = new FlatUIUtils.RepaintFocusListener( getComponent(), null ); focusListener = new FlatUIUtils.RepaintFocusListener( getComponent(), null );
getComponent().addFocusListener( focusListener ); getComponent().addFocusListener( focusListener );
MigLayoutVisualPadding.install( getComponent() );
} }
@Override @Override
@@ -217,6 +215,8 @@ public class FlatTextFieldUI
getComponent().getDocument().removeDocumentListener( documentListener ); getComponent().getDocument().removeDocumentListener( documentListener );
documentListener = null; documentListener = null;
} }
MigLayoutVisualPadding.uninstall( getComponent() );
} }
@Override @Override

View File

@@ -33,7 +33,6 @@ import java.awt.Image;
import java.awt.Insets; import java.awt.Insets;
import java.awt.Point; import java.awt.Point;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window; import java.awt.Window;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter; import java.awt.event.ComponentAdapter;
@@ -824,7 +823,8 @@ public class FlatTitlePane
Rectangle oldMaximizedBounds = frame.getMaximizedBounds(); Rectangle oldMaximizedBounds = frame.getMaximizedBounds();
if( !hasNativeCustomDecoration() && if( !hasNativeCustomDecoration() &&
(oldMaximizedBounds == null || (oldMaximizedBounds == null ||
Objects.equals( oldMaximizedBounds, rootPane.getClientProperty( "_flatlaf.maximizedBounds" ) )) ) Objects.equals( oldMaximizedBounds, rootPane.getClientProperty( "_flatlaf.maximizedBounds" ) )) &&
window.getGraphicsConfiguration() != null )
{ {
GraphicsConfiguration gc = window.getGraphicsConfiguration(); GraphicsConfiguration gc = window.getGraphicsConfiguration();
@@ -1058,10 +1058,11 @@ public class FlatTitlePane
* <p> * <p>
* Note: * Note:
* <ul> * <ul>
* <li>This method is invoked often when mouse is moved over title bar * <li>This method is invoked often when mouse is moved over window title bar area
* and should therefore return quickly. * and should therefore return quickly.
* <li>This method is invoked on 'AWT-Windows' thread (not 'AWT-EventQueue' thread) * <li>This method is invoked on 'AWT-Windows' thread (not 'AWT-EventQueue' thread)
* while processing Windows messages. * while processing Windows messages.
* It <b>must not</b> change any component property or layout because this could cause a dead lock.
* </ul> * </ul>
*/ */
private boolean captionHitTest( Point pt ) { private boolean captionHitTest( Point pt ) {
@@ -1107,8 +1108,18 @@ public class FlatTitlePane
// if component is not fully layouted, do not invoke function // if component is not fully layouted, do not invoke function
// because it is too dangerous that the function tries to layout the component, // because it is too dangerous that the function tries to layout the component,
// which could cause a dead lock // which could cause a dead lock
if( !c.isValid() ) if( !c.isValid() ) {
// revalidate if necessary so that it is valid when invoked again later
EventQueue.invokeLater( () -> {
Window w = SwingUtilities.windowForComponent( c );
if( w != null )
w.revalidate();
else
c.revalidate();
} );
return false; // assume that this is not a caption because the component has mouse listeners return false; // assume that this is not a caption because the component has mouse listeners
}
if( caption instanceof Function ) { if( caption instanceof Function ) {
// check client property function value // check client property function value
@@ -1405,22 +1416,9 @@ debug*/
private Point dragOffset; private Point dragOffset;
private boolean linuxNativeMove; private boolean linuxNativeMove;
private long lastSingleClickWhen;
@Override @Override
public void mouseClicked( MouseEvent e ) { public void mouseClicked( MouseEvent e ) {
// on Linux, when using native library, the mouse clicked event
// is usually not sent and maximize/restore is done in mouse pressed event
// this check is here for the case that a mouse clicked event comes through for some reason
if( linuxNativeMove && SystemInfo.isLinux && FlatNativeLinuxLibrary.isWMUtilsSupported( window ) ) {
// see comment in mousePressed()
if( lastSingleClickWhen != 0 && (e.getWhen() - lastSingleClickWhen) <= getMultiClickInterval() ) {
lastSingleClickWhen = 0;
maximizeOrRestore();
}
return;
}
if( e.getClickCount() == 2 && SwingUtilities.isLeftMouseButton( e ) ) { if( e.getClickCount() == 2 && SwingUtilities.isLeftMouseButton( e ) ) {
if( SwingUtilities.getDeepestComponentAt( FlatTitlePane.this, e.getX(), e.getY() ) == iconLabel ) { if( SwingUtilities.getDeepestComponentAt( FlatTitlePane.this, e.getX(), e.getY() ) == iconLabel ) {
// double-click on icon closes window // double-click on icon closes window
@@ -1451,42 +1449,6 @@ debug*/
dragOffset = SwingUtilities.convertPoint( mouseLayer, e.getPoint(), window ); dragOffset = SwingUtilities.convertPoint( mouseLayer, e.getPoint(), window );
linuxNativeMove = false; linuxNativeMove = false;
// on Linux, move or maximize/restore window
if( SystemInfo.isLinux && FlatNativeLinuxLibrary.isWMUtilsSupported( window ) ) {
// The fired Java mouse events, when doing a double-click and the first click
// sends a _NET_WM_MOVERESIZE message, are different for various Linux distributions:
// CentOS 7 (GNOME 3.28.2, X11): PRESSED(clickCount=1) PRESSED(clickCount=2) RELEASED(clickCount=2)
// Ubuntu 20.04 (GNOME 3.36.1, X11): PRESSED(clickCount=1) PRESSED(clickCount=2) RELEASED(clickCount=2)
// Ubuntu 22.04 (GNOME 42.2, Wayland): PRESSED(clickCount=1) RELEASED(clickCount=1) CLICKED(clickCount=1)
// Kubuntu 22.04 (KDE 5.24.4, X11): PRESSED(clickCount=1) PRESSED(clickCount=1) RELEASED(clickCount=1)
// double-click is not always recognized in Java when using _NET_WM_MOVERESIZE message
int clickCount = e.getClickCount();
if( clickCount == 1 && lastSingleClickWhen != 0 && (e.getWhen() - lastSingleClickWhen) <= getMultiClickInterval() )
clickCount = 2;
switch( clickCount ) {
case 1:
// move window via _NET_WM_MOVERESIZE message
e.consume();
linuxNativeMove = FlatNativeLinuxLibrary.moveOrResizeWindow( window, e, FlatNativeLinuxLibrary.MOVE );
lastSingleClickWhen = e.getWhen();
break;
case 2:
// maximize/restore on double-click
// also done here because no mouse clicked event is sent when using _NET_WM_MOVERESIZE message
lastSingleClickWhen = 0;
maximizeOrRestore();
break;
}
}
}
private int getMultiClickInterval() {
Object value = Toolkit.getDefaultToolkit().getDesktopProperty( "awt.multiClickInterval" );
return (value instanceof Integer) ? (Integer) value : 500;
} }
@Override public void mouseReleased( MouseEvent e ) {} @Override public void mouseReleased( MouseEvent e ) {}
@@ -1509,6 +1471,13 @@ debug*/
if( hasNativeCustomDecoration() ) if( hasNativeCustomDecoration() )
return; // do nothing if having native window border return; // do nothing if having native window border
// on Linux, move window using window manager
if( SystemInfo.isLinux && FlatNativeLinuxLibrary.isWMUtilsSupported( window ) ) {
linuxNativeMove = FlatNativeLinuxLibrary.moveOrResizeWindow( window, e, FlatNativeLinuxLibrary.MOVE );
if( linuxNativeMove )
return;
}
// restore window if it is maximized // restore window if it is maximized
if( window instanceof Frame ) { if( window instanceof Frame ) {
Frame frame = (Frame) window; Frame frame = (Frame) window;
@@ -1578,6 +1547,15 @@ debug*/
* Useful for components that do not use mouse input on whole component bounds. * Useful for components that do not use mouse input on whole component bounds.
* E.g. a tabbed pane with a few tabs has some empty space beside the tabs * E.g. a tabbed pane with a few tabs has some empty space beside the tabs
* that can be used to move the window. * that can be used to move the window.
* <p>
* Note:
* <ul>
* <li>This method is invoked often when mouse is moved over window title bar area
* and should therefore return quickly.
* <li>This method is invoked on 'AWT-Windows' thread (not 'AWT-EventQueue' thread)
* while processing Windows messages.
* It <b>must not</b> change any component property or layout because this could cause a dead lock.
* </ul>
* *
* @return {@code true} if the component is not interested in mouse input at the given location * @return {@code true} if the component is not interested in mouse input at the given location
* {@code false} if the component wants process mouse input at the given location * {@code false} if the component wants process mouse input at the given location

View File

@@ -102,9 +102,11 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault Tree.selectionForeground Color * @uiDefault Tree.selectionForeground Color
* @uiDefault Tree.selectionInactiveBackground Color * @uiDefault Tree.selectionInactiveBackground Color
* @uiDefault Tree.selectionInactiveForeground Color * @uiDefault Tree.selectionInactiveForeground Color
* @uiDefault Tree.alternateRowColor Color
* @uiDefault Tree.selectionInsets Insets * @uiDefault Tree.selectionInsets Insets
* @uiDefault Tree.selectionArc int * @uiDefault Tree.selectionArc int
* @uiDefault Tree.wideSelection boolean * @uiDefault Tree.wideSelection boolean
* @uiDefault Tree.wideCellRenderer boolean
* @uiDefault Tree.showCellFocusIndicator boolean * @uiDefault Tree.showCellFocusIndicator boolean
* @uiDefault Tree.showDefaultIcons boolean * @uiDefault Tree.showDefaultIcons boolean
* *
@@ -141,9 +143,11 @@ public class FlatTreeUI
@Styleable protected Color selectionInactiveBackground; @Styleable protected Color selectionInactiveBackground;
@Styleable protected Color selectionInactiveForeground; @Styleable protected Color selectionInactiveForeground;
@Styleable protected Color selectionBorderColor; @Styleable protected Color selectionBorderColor;
/** @since 3.6 */ @Styleable protected Color alternateRowColor;
/** @since 3 */ @Styleable protected Insets selectionInsets; /** @since 3 */ @Styleable protected Insets selectionInsets;
/** @since 3 */ @Styleable protected int selectionArc; /** @since 3 */ @Styleable protected int selectionArc;
@Styleable protected boolean wideSelection; @Styleable protected boolean wideSelection;
/** @since 3.6 */ @Styleable protected boolean wideCellRenderer;
@Styleable protected boolean showCellFocusIndicator; @Styleable protected boolean showCellFocusIndicator;
/** @since 3 */ protected boolean showDefaultIcons; /** @since 3 */ protected boolean showDefaultIcons;
@@ -192,9 +196,11 @@ public class FlatTreeUI
selectionInactiveBackground = UIManager.getColor( "Tree.selectionInactiveBackground" ); selectionInactiveBackground = UIManager.getColor( "Tree.selectionInactiveBackground" );
selectionInactiveForeground = UIManager.getColor( "Tree.selectionInactiveForeground" ); selectionInactiveForeground = UIManager.getColor( "Tree.selectionInactiveForeground" );
selectionBorderColor = UIManager.getColor( "Tree.selectionBorderColor" ); selectionBorderColor = UIManager.getColor( "Tree.selectionBorderColor" );
alternateRowColor = UIManager.getColor( "Tree.alternateRowColor" );
selectionInsets = UIManager.getInsets( "Tree.selectionInsets" ); selectionInsets = UIManager.getInsets( "Tree.selectionInsets" );
selectionArc = UIManager.getInt( "Tree.selectionArc" ); selectionArc = UIManager.getInt( "Tree.selectionArc" );
wideSelection = UIManager.getBoolean( "Tree.wideSelection" ); wideSelection = UIManager.getBoolean( "Tree.wideSelection" );
wideCellRenderer = UIManager.getBoolean( "Tree.wideCellRenderer" );
showCellFocusIndicator = UIManager.getBoolean( "Tree.showCellFocusIndicator" ); showCellFocusIndicator = UIManager.getBoolean( "Tree.showCellFocusIndicator" );
showDefaultIcons = UIManager.getBoolean( "Tree.showDefaultIcons" ); showDefaultIcons = UIManager.getBoolean( "Tree.showDefaultIcons" );
@@ -227,6 +233,7 @@ public class FlatTreeUI
selectionInactiveBackground = null; selectionInactiveBackground = null;
selectionInactiveForeground = null; selectionInactiveForeground = null;
selectionBorderColor = null; selectionBorderColor = null;
alternateRowColor = null;
defaultLeafIcon = null; defaultLeafIcon = null;
defaultClosedIcon = null; defaultClosedIcon = null;
@@ -310,6 +317,7 @@ public class FlatTreeUI
if( e.getSource() == tree ) { if( e.getSource() == tree ) {
switch( e.getPropertyName() ) { switch( e.getPropertyName() ) {
case TREE_WIDE_SELECTION: case TREE_WIDE_SELECTION:
case TREE_WIDE_CELL_RENDERER:
case TREE_PAINT_SELECTION: case TREE_PAINT_SELECTION:
HiDPIUtils.repaint( tree ); HiDPIUtils.repaint( tree );
break; break;
@@ -571,6 +579,27 @@ public class FlatTreeUI
boolean isDropRow = isDropRow( row ); boolean isDropRow = isDropRow( row );
boolean needsSelectionPainting = (isSelected || isDropRow) && isPaintSelection(); 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 // do not paint row if editing
if( isEditing ) { if( isEditing ) {
// paint wide selection // paint wide selection
@@ -795,6 +824,11 @@ public class FlatTreeUI
return clientPropertyBoolean( tree, TREE_WIDE_SELECTION, wideSelection ); return clientPropertyBoolean( tree, TREE_WIDE_SELECTION, wideSelection );
} }
/** @since 3.6 */
protected boolean isWideCellRenderer() {
return clientPropertyBoolean( tree, TREE_WIDE_CELL_RENDERER, wideCellRenderer );
}
protected boolean isPaintSelection() { protected boolean isPaintSelection() {
return clientPropertyBoolean( tree, TREE_PAINT_SELECTION, paintSelection ); 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; 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 ) { public static Color getUIColor( String key, int defaultColorRGB ) {
Color color = UIManager.getColor( key ); Color color = UIManager.getColor( key );
return (color != null) ? color : new Color( defaultColorRGB ); return (color != null) ? color : new Color( defaultColorRGB );

View File

@@ -41,7 +41,7 @@ import java.util.function.Supplier;
import javax.swing.DesktopManager; import javax.swing.DesktopManager;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JInternalFrame; import javax.swing.JInternalFrame;
import javax.swing.JLayeredPane; import javax.swing.JPanel;
import javax.swing.JRootPane; import javax.swing.JRootPane;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import javax.swing.UIManager; import javax.swing.UIManager;
@@ -59,8 +59,6 @@ import com.formdev.flatlaf.util.UIScale;
public abstract class FlatWindowResizer public abstract class FlatWindowResizer
implements PropertyChangeListener, ComponentListener implements PropertyChangeListener, ComponentListener
{ {
protected final static Integer WINDOW_RESIZER_LAYER = JLayeredPane.DRAG_LAYER + 1;
protected final JComponent resizeComp; protected final JComponent resizeComp;
protected final int borderDragThickness = FlatUIUtils.getUIInt( "RootPane.borderDragThickness", 5 ); 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 ); leftDragComp = createDragBorderComponent( NW_RESIZE_CURSOR, W_RESIZE_CURSOR, SW_RESIZE_CURSOR );
rightDragComp = createDragBorderComponent( NE_RESIZE_CURSOR, E_RESIZE_CURSOR, SE_RESIZE_CURSOR ); rightDragComp = createDragBorderComponent( NE_RESIZE_CURSOR, E_RESIZE_CURSOR, SE_RESIZE_CURSOR );
Container cont = (resizeComp instanceof JRootPane) ? ((JRootPane)resizeComp).getLayeredPane() : resizeComp; // for rootpanes, add after glasspane
Object cons = (cont instanceof JLayeredPane) ? WINDOW_RESIZER_LAYER : null; int insertIndex = (resizeComp instanceof JRootPane) ? 1 : 0;
cont.add( topDragComp, cons, 0 ); resizeComp.add( topDragComp, insertIndex++ );
cont.add( bottomDragComp, cons, 1 ); resizeComp.add( bottomDragComp, insertIndex++ );
cont.add( leftDragComp, cons, 2 ); resizeComp.add( leftDragComp, insertIndex++ );
cont.add( rightDragComp, cons, 3 ); resizeComp.add( rightDragComp, insertIndex++ );
resizeComp.addComponentListener( this ); resizeComp.addComponentListener( this );
resizeComp.addPropertyChangeListener( "ancestor", this ); resizeComp.addPropertyChangeListener( "ancestor", this );
@@ -105,11 +103,10 @@ public abstract class FlatWindowResizer
resizeComp.removeComponentListener( this ); resizeComp.removeComponentListener( this );
resizeComp.removePropertyChangeListener( "ancestor", this ); resizeComp.removePropertyChangeListener( "ancestor", this );
Container cont = topDragComp.getParent(); resizeComp.remove( topDragComp );
cont.remove( topDragComp ); resizeComp.remove( bottomDragComp );
cont.remove( bottomDragComp ); resizeComp.remove( leftDragComp );
cont.remove( leftDragComp ); resizeComp.remove( rightDragComp );
cont.remove( rightDragComp );
} }
public void doLayout() { public void doLayout() {
@@ -120,7 +117,7 @@ public abstract class FlatWindowResizer
int y = 0; int y = 0;
int width = resizeComp.getWidth(); int width = resizeComp.getWidth();
int height = resizeComp.getHeight(); int height = resizeComp.getHeight();
if( width == 0 || height == 0 ) if( width <= 0 || height <= 0 )
return; return;
Insets resizeInsets = getResizeInsets(); Insets resizeInsets = getResizeInsets();
@@ -191,7 +188,7 @@ public abstract class FlatWindowResizer
protected abstract Dimension getWindowMinimumSize(); protected abstract Dimension getWindowMinimumSize();
protected abstract Dimension getWindowMaximumSize(); protected abstract Dimension getWindowMaximumSize();
protected void beginResizing( int direction ) {} protected void beginResizing( int resizeDir, MouseEvent e ) {}
protected void endResizing() {} protected void endResizing() {}
//---- interface PropertyChangeListener ---- //---- interface PropertyChangeListener ----
@@ -234,17 +231,45 @@ public abstract class FlatWindowResizer
{ {
protected Window window; protected Window window;
private final JComponent centerComp;
private final boolean limitResizeToScreenBounds; private final boolean limitResizeToScreenBounds;
public WindowResizer( JRootPane rootPane ) { public WindowResizer( JRootPane rootPane ) {
super( rootPane ); super( rootPane );
// Transparent "center" component that is made visible only while resizing window.
// It uses same cursor as the area where resize dragging started.
// This ensures that the cursor shape stays stable while dragging mouse
// into the window to make window smaller. Otherwise it would toggling between
// resize and standard cursor because the component layout is not updated
// fast enough and the mouse cursor is always updated from the component
// at the mouse location.
centerComp = new JPanel();
centerComp.setOpaque( false );
centerComp.setVisible( false );
rootPane.add( centerComp, 5 );
// On Linux, limit window resizing to screen bounds because otherwise // On Linux, limit window resizing to screen bounds because otherwise
// there would be a strange effect when the mouse is moved over a sidebar // there would be a strange effect when the mouse is moved over a sidebar
// while resizing and the opposite window side is also resized. // while resizing and the opposite window side is also resized.
limitResizeToScreenBounds = SystemInfo.isLinux; limitResizeToScreenBounds = SystemInfo.isLinux;
} }
@Override
public void uninstall() {
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 @Override
protected void addNotify() { protected void addNotify() {
Container parent = resizeComp.getParent(); Container parent = resizeComp.getParent();
@@ -299,20 +324,17 @@ public abstract class FlatWindowResizer
@Override @Override
protected boolean limitToParentBounds() { protected boolean limitToParentBounds() {
return limitResizeToScreenBounds && window != null; return limitResizeToScreenBounds && window != null && window.getGraphicsConfiguration() != null;
} }
@Override @Override
protected Rectangle getParentBounds() { protected Rectangle getParentBounds() {
if( limitResizeToScreenBounds && window != null ) { GraphicsConfiguration gc = window.getGraphicsConfiguration();
GraphicsConfiguration gc = window.getGraphicsConfiguration(); Rectangle bounds = gc.getBounds();
Rectangle bounds = gc.getBounds(); Insets insets = window.getToolkit().getScreenInsets( gc );
Insets insets = window.getToolkit().getScreenInsets( gc ); return new Rectangle( bounds.x + insets.left, bounds.y + insets.top,
return new Rectangle( bounds.x + insets.left, bounds.y + insets.top, bounds.width - insets.left - insets.right,
bounds.width - insets.left - insets.right, bounds.height - insets.top - insets.bottom );
bounds.height - insets.top - insets.bottom );
}
return null;
} }
@Override @Override
@@ -346,6 +368,37 @@ public abstract class FlatWindowResizer
public void windowStateChanged( WindowEvent e ) { public void windowStateChanged( WindowEvent e ) {
updateVisibility(); updateVisibility();
} }
@Override
protected void beginResizing( int resizeDir, MouseEvent e ) {
// on Linux, resize window using window manager
if( SystemInfo.isLinux && window != null && FlatNativeLinuxLibrary.isWMUtilsSupported( window ) ) {
int direction = -1;
switch( resizeDir ) {
case N_RESIZE_CURSOR: direction = FlatNativeLinuxLibrary.SIZE_TOP; break;
case S_RESIZE_CURSOR: direction = FlatNativeLinuxLibrary.SIZE_BOTTOM; break;
case W_RESIZE_CURSOR: direction = FlatNativeLinuxLibrary.SIZE_LEFT; break;
case E_RESIZE_CURSOR: direction = FlatNativeLinuxLibrary.SIZE_RIGHT; break;
case NW_RESIZE_CURSOR: direction = FlatNativeLinuxLibrary.SIZE_TOPLEFT; break;
case NE_RESIZE_CURSOR: direction = FlatNativeLinuxLibrary.SIZE_TOPRIGHT; break;
case SW_RESIZE_CURSOR: direction = FlatNativeLinuxLibrary.SIZE_BOTTOMLEFT; break;
case SE_RESIZE_CURSOR: direction = FlatNativeLinuxLibrary.SIZE_BOTTOMRIGHT; break;
}
if( direction >= 0 && FlatNativeLinuxLibrary.moveOrResizeWindow( window, e, direction ) )
return;
}
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 ----------------------------------------- //---- class InternalFrameResizer -----------------------------------------
@@ -427,7 +480,18 @@ public abstract class FlatWindowResizer
} }
@Override @Override
protected void beginResizing( int direction ) { protected void beginResizing( int resizeDir, MouseEvent e ) {
int direction = 0;
switch( resizeDir ) {
case N_RESIZE_CURSOR: direction = NORTH; break;
case S_RESIZE_CURSOR: direction = SOUTH; break;
case W_RESIZE_CURSOR: direction = WEST; break;
case E_RESIZE_CURSOR: direction = EAST; break;
case NW_RESIZE_CURSOR: direction = NORTH_WEST; break;
case NE_RESIZE_CURSOR: direction = NORTH_EAST; break;
case SW_RESIZE_CURSOR: direction = SOUTH_WEST; break;
case SE_RESIZE_CURSOR: direction = SOUTH_EAST; break;
}
desktopManager.get().beginResizingFrame( getFrame(), direction ); desktopManager.get().beginResizingFrame( getFrame(), direction );
} }
@@ -535,18 +599,7 @@ debug*/
dragRightOffset = windowBounds.x + windowBounds.width - xOnScreen; dragRightOffset = windowBounds.x + windowBounds.width - xOnScreen;
dragBottomOffset = windowBounds.y + windowBounds.height - yOnScreen; dragBottomOffset = windowBounds.y + windowBounds.height - yOnScreen;
int direction = 0; beginResizing( resizeDir, e );
switch( resizeDir ) {
case N_RESIZE_CURSOR: direction = NORTH; break;
case S_RESIZE_CURSOR: direction = SOUTH; break;
case W_RESIZE_CURSOR: direction = WEST; break;
case E_RESIZE_CURSOR: direction = EAST; break;
case NW_RESIZE_CURSOR: direction = NORTH_WEST; break;
case NE_RESIZE_CURSOR: direction = NORTH_EAST; break;
case SW_RESIZE_CURSOR: direction = SOUTH_WEST; break;
case SE_RESIZE_CURSOR: direction = SOUTH_EAST; break;
}
beginResizing( direction );
} }
@Override @Override

View File

@@ -21,7 +21,7 @@ import java.util.function.BiPredicate;
/** /**
* @author Karl Tauber * @author Karl Tauber
*/ */
class StackUtils public class StackUtils
{ {
private static final StackUtils INSTANCE = new StackUtilsImpl(); private static final StackUtils INSTANCE = new StackUtilsImpl();

View File

@@ -224,6 +224,9 @@ public class ColorFunctions
if( functions.length == 1 && functions[0] instanceof Mix ) { if( functions.length == 1 && functions[0] instanceof Mix ) {
Mix mixFunction = (Mix) functions[0]; Mix mixFunction = (Mix) functions[0];
return mix( color, mixFunction.color2, mixFunction.weight / 100 ); return mix( color, mixFunction.color2, mixFunction.weight / 100 );
} else if( functions.length == 1 && functions[0] instanceof Mix2 ) {
Mix2 mixFunction = (Mix2) functions[0];
return mix( mixFunction.color1, color, mixFunction.weight / 100 );
} }
// convert RGB to HSL // convert RGB to HSL
@@ -386,7 +389,11 @@ public class ColorFunctions
//---- class Mix ---------------------------------------------------------- //---- class Mix ----------------------------------------------------------
/** /**
* Mix two colors. * Mix two colors using {@link ColorFunctions#mix(Color, Color, float)}.
* First color is passed to {@link #apply(float[])}.
* Second color is {@link #color2}.
* <p>
* Use {@link Mix2} to tint or shade color.
* *
* @since 1.6 * @since 1.6
*/ */
@@ -420,4 +427,44 @@ public class ColorFunctions
return String.format( "mix(#%08x,%.0f%%)", color2.getRGB(), weight ); return String.format( "mix(#%08x,%.0f%%)", color2.getRGB(), weight );
} }
} }
//---- class Mix2 ---------------------------------------------------------
/**
* Mix two colors using {@link ColorFunctions#mix(Color, Color, float)}.
* First color is {@link #color1}.
* Second color is passed to {@link #apply(float[])}.
*
* @since 3.6
*/
public static class Mix2
implements ColorFunction
{
public final Color color1;
public final float weight;
public Mix2( Color color1, float weight ) {
this.color1 = color1;
this.weight = weight;
}
@Override
public void apply( float[] hsla ) {
// convert from HSL to RGB because color mixing is done on RGB values
Color color2 = HSLColor.toRGB( hsla[0], hsla[1], hsla[2], hsla[3] / 100 );
// mix
Color color = mix( color1, color2, weight / 100 );
// convert RGB to HSL
float[] hsl = HSLColor.fromRGB( color );
System.arraycopy( hsl, 0, hsla, 0, hsl.length );
hsla[3] = (color.getAlpha() / 255f) * 100;
}
@Override
public String toString() {
return String.format( "mix2(#%08x,%.0f%%)", color1.getRGB(), weight );
}
}
} }

View File

@@ -16,6 +16,7 @@
package com.formdev.flatlaf.util; package com.formdev.flatlaf.util;
import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Font; import java.awt.Font;
import java.awt.Graphics; import java.awt.Graphics;
@@ -27,7 +28,9 @@ import java.awt.geom.Rectangle2D;
import java.text.AttributedCharacterIterator; import java.text.AttributedCharacterIterator;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.RepaintManager; import javax.swing.RepaintManager;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.FlatSystemProperties; import com.formdev.flatlaf.FlatSystemProperties;
import com.formdev.flatlaf.ui.StackUtils;
/** /**
* @author Karl Tauber * @author Karl Tauber
@@ -323,6 +326,19 @@ public class HiDPIUtils
public void drawGlyphVector( GlyphVector g, float x, float y ) { public void drawGlyphVector( GlyphVector g, float x, float y ) {
super.drawGlyphVector( g, x, y + yCorrection ); super.drawGlyphVector( g, x, y + yCorrection );
} }
@Override
public void fillRect( int x, int y, int width, int height ) {
// fix hard coded black color in HRuleView.paint() of '<hr noshade>'
if( super.getColor() == Color.black &&
StackUtils.wasInvokedFrom( "javax.swing.text.html.HRuleView", "paint", 4 ) )
{
super.setColor( FlatLaf.isLafDark() ? Color.lightGray : Color.darkGray );
super.fillRect( x, y, width, height );
super.setColor( Color.black );
} else
super.fillRect( x, y, width, height );
}
}; };
} }

View File

@@ -31,6 +31,7 @@ public class SystemInfo
public static final boolean isWindows; public static final boolean isWindows;
public static final boolean isMacOS; public static final boolean isMacOS;
public static final boolean isLinux; public static final boolean isLinux;
/** @since 3.6 */ public static final boolean isUnknownOS;
// OS versions // OS versions
public static final long osVersion; public static final long osVersion;
@@ -59,6 +60,7 @@ public class SystemInfo
public static final boolean isJetBrainsJVM_11_orLater; public static final boolean isJetBrainsJVM_11_orLater;
// UI toolkits // UI toolkits
/** @since 3.6 */ public static final boolean isGNOME;
public static final boolean isKDE; public static final boolean isKDE;
// other // other
@@ -75,6 +77,7 @@ public class SystemInfo
isWindows = osName.startsWith( "windows" ); isWindows = osName.startsWith( "windows" );
isMacOS = osName.startsWith( "mac" ); isMacOS = osName.startsWith( "mac" );
isLinux = osName.startsWith( "linux" ); isLinux = osName.startsWith( "linux" );
isUnknownOS = !isWindows && !isMacOS && !isLinux;
// OS versions // OS versions
osVersion = scanVersion( System.getProperty( "os.version" ) ); osVersion = scanVersion( System.getProperty( "os.version" ) );
@@ -104,7 +107,13 @@ public class SystemInfo
isJetBrainsJVM_11_orLater = isJetBrainsJVM && isJava_11_orLater; isJetBrainsJVM_11_orLater = isJetBrainsJVM && isJava_11_orLater;
// UI toolkits // UI toolkits
isKDE = (isLinux && System.getenv( "KDE_FULL_SESSION" ) != null); String desktop = isLinux ? System.getenv( "XDG_CURRENT_DESKTOP" ) : null;
isGNOME = (isLinux &&
(System.getenv( "GNOME_DESKTOP_SESSION_ID" ) != null ||
(desktop != null && desktop.contains( "GNOME" ))));
isKDE = (isLinux &&
(System.getenv( "KDE_FULL_SESSION" ) != null ||
(desktop != null && desktop.contains( "KDE" ))));
// other // other
isProjector = Boolean.getBoolean( "org.jetbrains.projector.server.enable" ); isProjector = Boolean.getBoolean( "org.jetbrains.projector.server.enable" );

View File

@@ -33,6 +33,7 @@ import javax.swing.plaf.DimensionUIResource;
import javax.swing.plaf.FontUIResource; import javax.swing.plaf.FontUIResource;
import javax.swing.plaf.InsetsUIResource; import javax.swing.plaf.InsetsUIResource;
import javax.swing.plaf.UIResource; import javax.swing.plaf.UIResource;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.FlatSystemProperties; import com.formdev.flatlaf.FlatSystemProperties;
/** /**
@@ -188,7 +189,9 @@ public class UIScale
// because even if we are on a HiDPI display it is not sure // because even if we are on a HiDPI display it is not sure
// that a larger font size is set by the current LaF // that a larger font size is set by the current LaF
// (e.g. can avoid large icons with small text) // (e.g. can avoid large icons with small text)
Font font = UIManager.getFont( "defaultFont" ); Font font = null;
if( UIManager.getLookAndFeel() instanceof FlatLaf )
font = UIManager.getFont( "defaultFont" );
if( font == null ) if( font == null )
font = UIManager.getFont( "Label.font" ); font = UIManager.getFont( "Label.font" );
@@ -244,6 +247,16 @@ public class UIScale
} }
private static float computeScaleFactor( Font font ) { private static float computeScaleFactor( Font font ) {
String customFontSizeDivider = System.getProperty( "flatlaf.uiScale.fontSizeDivider" );
if( customFontSizeDivider != null ) {
try {
float fontSizeDivider = Math.max( Integer.parseInt( customFontSizeDivider ), 10 );
return font.getSize() / fontSizeDivider;
} catch( NumberFormatException ex ) {
// ignore
}
}
// default font size // default font size
float fontSizeDivider = 12f; float fontSizeDivider = 12f;

View File

@@ -61,7 +61,6 @@ Component.arrowType = triangle
#---- ProgressBar ---- #---- ProgressBar ----
ProgressBar.foreground = darken(@foreground,10%) ProgressBar.foreground = darken(@foreground,10%)
ProgressBar.selectionForeground = @background
#---- RadioButton ---- #---- RadioButton ----

View File

@@ -34,7 +34,7 @@
# general background and foreground (text color) # general background and foreground (text color)
@background = #3c3f41 @background = #3c3f41
@foreground = #bbb @foreground = #ddd
@disabledBackground = @background @disabledBackground = @background
@disabledForeground = shade(@foreground,25%) @disabledForeground = shade(@foreground,25%)
@@ -45,7 +45,7 @@
# selection # selection
@selectionBackground = @accentSelectionBackground @selectionBackground = @accentSelectionBackground
@selectionForeground = contrast(@selectionBackground, @background, @foreground, 25%) @selectionForeground = contrast(@selectionBackground, shade(@background), tint(@foreground), 25%)
@selectionInactiveBackground = spin(saturate(shade(@selectionBackground,70%),20%),-15) @selectionInactiveBackground = spin(saturate(shade(@selectionBackground,70%),20%),-15)
@selectionInactiveForeground = @foreground @selectionInactiveForeground = @foreground
@@ -187,6 +187,8 @@ Component.error.borderColor = desaturate($Component.error.focusedBorderColor,25%
Component.error.focusedBorderColor = #8b3c3c Component.error.focusedBorderColor = #8b3c3c
Component.warning.borderColor = darken(desaturate($Component.warning.focusedBorderColor,20%),10%) Component.warning.borderColor = darken(desaturate($Component.warning.focusedBorderColor,20%),10%)
Component.warning.focusedBorderColor = #ac7920 Component.warning.focusedBorderColor = #ac7920
Component.success.borderColor = desaturate($Component.success.focusedBorderColor,25%)
Component.success.focusedBorderColor = #648b3c
Component.custom.borderColor = desaturate(#f00,50%,relative derived noAutoInverse) Component.custom.borderColor = desaturate(#f00,50%,relative derived noAutoInverse)
@@ -262,7 +264,7 @@ PopupMenu.hoverScrollArrowBackground = lighten(@background,5%)
ProgressBar.background = lighten(@background,8%) ProgressBar.background = lighten(@background,8%)
ProgressBar.foreground = @accentSliderColor ProgressBar.foreground = @accentSliderColor
ProgressBar.selectionBackground = @foreground ProgressBar.selectionBackground = @foreground
ProgressBar.selectionForeground = contrast($ProgressBar.foreground, @background, @foreground, 25%) ProgressBar.selectionForeground = contrast($ProgressBar.foreground, shade(@background), tint(@foreground), 25%)
#---- RootPane ---- #---- RootPane ----
@@ -284,7 +286,7 @@ ScrollBar.pressedButtonBackground = lighten(@background,10%,derived noAutoInvers
#---- Separator ---- #---- Separator ----
Separator.foreground = tint(@background,10%) Separator.foreground = tint(@background,15%)
#---- Slider ---- #---- Slider ----

View File

@@ -50,6 +50,9 @@ mini.font = -3
#defaultFont = ... #defaultFont = ...
# font weights # font weights
# fallback for unknown platform
light.font = +0
semibold.font = +0
# Windows # Windows
[win]light.font = "Segoe UI Light" [win]light.font = "Segoe UI Light"
[win]semibold.font = "Segoe UI Semibold" [win]semibold.font = "Segoe UI Semibold"
@@ -59,15 +62,12 @@ mini.font = -3
# Linux # Linux
[linux]light.font = "Lato Light", "Ubuntu Light", "Cantarell Light" [linux]light.font = "Lato Light", "Ubuntu Light", "Cantarell Light"
[linux]semibold.font = "Lato Semibold", "Ubuntu Medium", "Montserrat SemiBold" [linux]semibold.font = "Lato Semibold", "Ubuntu Medium", "Montserrat SemiBold"
# fallback for unknown platform
light.font = +0
semibold.font = +0
# monospaced # monospaced
monospaced.font = Monospaced
[win]monospaced.font = Monospaced [win]monospaced.font = Monospaced
[mac]monospaced.font = Menlo, Monospaced [mac]monospaced.font = Menlo, Monospaced
[linux]monospaced.font = "Liberation Mono", "Ubuntu Mono", Monospaced [linux]monospaced.font = "Liberation Mono", "Ubuntu Mono", Monospaced
monospaced.font = Monospaced
# styles # styles
[style].h00 = font: $h00.font [style].h00 = font: $h00.font
@@ -564,8 +564,8 @@ RadioButtonMenuItem.background = @menuBackground
#---- RootPane ---- #---- RootPane ----
RootPane.border = com.formdev.flatlaf.ui.FlatRootPaneUI$FlatWindowBorder RootPane.border = com.formdev.flatlaf.ui.FlatRootPaneUI$FlatWindowBorder
RootPane.borderDragThickness = 5 RootPane.borderDragThickness = 6
RootPane.cornerDragWidth = 16 RootPane.cornerDragWidth = 32
RootPane.honorFrameMinimumSizeOnResize = false RootPane.honorFrameMinimumSizeOnResize = false
RootPane.honorDialogMinimumSizeOnResize = true RootPane.honorDialogMinimumSizeOnResize = true
@@ -934,6 +934,7 @@ Tree.rendererMargins = 1,2,1,2
Tree.selectionInsets = 0,0,0,0 Tree.selectionInsets = 0,0,0,0
Tree.selectionArc = 0 Tree.selectionArc = 0
Tree.wideSelection = true Tree.wideSelection = true
Tree.wideCellRenderer = false
Tree.repaintWholeRow = true Tree.repaintWholeRow = true
Tree.paintLines = false Tree.paintLines = false
Tree.showCellFocusIndicator = false Tree.showCellFocusIndicator = false

View File

@@ -36,7 +36,7 @@
@background = #f2f2f2 @background = #f2f2f2
@foreground = #000 @foreground = #000
@disabledBackground = @background @disabledBackground = @background
@disabledForeground = tint(@foreground,55%) @disabledForeground = tint(@foreground,50%)
# component background # component background
@buttonBackground = lighten(@background,5%) @buttonBackground = lighten(@background,5%)
@@ -194,6 +194,8 @@ Component.error.borderColor = lighten(desaturate($Component.error.focusedBorderC
Component.error.focusedBorderColor = #e53e4d Component.error.focusedBorderColor = #e53e4d
Component.warning.borderColor = lighten(saturate($Component.warning.focusedBorderColor,25%),20%) Component.warning.borderColor = lighten(saturate($Component.warning.focusedBorderColor,25%),20%)
Component.warning.focusedBorderColor = #e2a53a Component.warning.focusedBorderColor = #e2a53a
Component.success.borderColor = lighten(desaturate($Component.success.focusedBorderColor,20%),25%)
Component.success.focusedBorderColor = #14dc92
Component.custom.borderColor = lighten(desaturate(#f00,20%,derived noAutoInverse),25%,derived noAutoInverse) Component.custom.borderColor = lighten(desaturate(#f00,20%,derived noAutoInverse),25%,derived noAutoInverse)

View File

@@ -21,27 +21,41 @@
# - https://www.formdev.com/flatlaf/properties-files/ # - https://www.formdev.com/flatlaf/properties-files/
# - https://www.formdev.com/flatlaf/how-to-customize/ # - https://www.formdev.com/flatlaf/how-to-customize/
# #
# Properties in this file are applied in following order:
# 1. properties without '{...}' and without '[...]' prefix
# 2. properties specified in .theme.json file
# 3. properties starting with '{*}'
# 4. properties starting with '{*-light}' or '{*-dark}'
# 5. properties starting with '{author-<author>}',
# where '<author>' is replaced with "author" value from .theme.json file
# 6. properties starting with '{<name>---<author>}',
# where '<name>' and '<author>' are replaced with "name" and "author" values from .theme.json file
# 7. properties starting with '{<name>}',
# where '<name>' is replaced with "name" value from .theme.json file
# 8. properties with '[...]' prefix
#
#---- system colors ---- #---- system colors ----
# fix (most) system colors because they are usually not set in .json files # fix (most) system colors because they are usually not set in .json files
desktop = lazy(TextField.background) desktop = $TextField.background
activeCaptionText = lazy(TextField.foreground) activeCaptionText = $TextField.foreground
inactiveCaptionText = lazy(TextField.foreground) inactiveCaptionText = $TextField.foreground
window = lazy(Panel.background) window = $Panel.background
windowBorder = lazy(TextField.foreground) windowBorder = $TextField.foreground
windowText = lazy(TextField.foreground) windowText = $TextField.foreground
menu = lazy(Menu.background) menu = $Menu.background
menuText = lazy(Menu.foreground) menuText = $Menu.foreground
text = lazy(TextField.background) text = $TextField.background
textText = lazy(TextField.foreground) textText = $TextField.foreground
textHighlight = lazy(TextField.selectionBackground) textHighlight = $TextField.selectionBackground
textHighlightText = lazy(TextField.selectionForeground) textHighlightText = $TextField.selectionForeground
textInactiveText = lazy(TextField.inactiveForeground) textInactiveText = $TextField.inactiveForeground
control = lazy(Panel.background) control = $Panel.background
controlText = lazy(TextField.foreground) controlText = $TextField.foreground
info = lazy(ToolTip.background) info = $ToolTip.background
infoText = lazy(ToolTip.foreground) infoText = $ToolTip.foreground
#---- variables ---- #---- variables ----
@@ -49,26 +63,13 @@ infoText = lazy(ToolTip.foreground)
# make sure that accent color (set via FlatLaf.setSystemColorGetter()) is ignored # make sure that accent color (set via FlatLaf.setSystemColorGetter()) is ignored
@accentColor = null @accentColor = null
# use same accent color for checkmark, slider, tab underline, etc.
@accentBase2Color = @accentBaseColor
# use fixed color because it is used in borders # use fixed color because it is used in borders
@cellFocusColor = #222 @cellFocusColor = #222
#---- Button ----
Button.startBackground = $Button.background
Button.endBackground = $Button.background
Button.startBorderColor = $Button.borderColor
Button.endBorderColor = $Button.borderColor
Button.default.startBackground = $Button.default.background
Button.default.endBackground = $Button.default.background
Button.default.startBorderColor = $Button.default.borderColor
Button.default.endBorderColor = $Button.default.borderColor
Button.hoverBorderColor = null
Button.default.hoverBorderColor = null
#---- CheckBoxMenuItem ---- #---- CheckBoxMenuItem ----
# colors from intellij/checkmark.svg and darcula/checkmark.svg # colors from intellij/checkmark.svg and darcula/checkmark.svg
@@ -76,34 +77,33 @@ Button.default.hoverBorderColor = null
[dark]CheckBoxMenuItem.icon.checkmarkColor=#fff9 [dark]CheckBoxMenuItem.icon.checkmarkColor=#fff9
#---- Component ----
Component.accentColor = lazy(ProgressBar.foreground)
#---- HelpButton ----
HelpButton.hoverBorderColor = null
#---- Slider ---- #---- Slider ----
Slider.focusedColor = fade($Component.focusColor,40%,derived) # this "reverses" definition in FlatLightLaf/FlatDarkLaf.properties
Slider.trackValueColor = $Slider.thumbColor
Slider.thumbColor = @accentSliderColor
#---- Spinner ----
# Spinner arrow button always has same colors as ComboBox arrow button
Spinner.buttonBackground = $ComboBox.buttonEditableBackground
Spinner.buttonArrowColor = $ComboBox.buttonArrowColor
Spinner.buttonDisabledArrowColor = $ComboBox.buttonDisabledArrowColor
#---- TabbedPane ---- #---- TabbedPane ----
# colors from JBUI.CurrentTheme.DefaultTabs.inactiveUnderlineColor() # colors from JBUI.CurrentTheme.DefaultTabs.inactiveUnderlineColor()
[light]TabbedPane.inactiveUnderlineColor = #9ca7b8 {*-light}TabbedPane.inactiveUnderlineColor = #9ca7b8
[dark]TabbedPane.inactiveUnderlineColor = #747a80 {*-dark}TabbedPane.inactiveUnderlineColor = #747a80
#---- ToggleButton ---- #---- ToggleButton ----
ToggleButton.startBackground = $ToggleButton.background {*}ToggleButton.background = $Button.background
ToggleButton.endBackground = $ToggleButton.background {*-dark}ToggleButton.selectedBackground = lighten($ToggleButton.background,15%,derived)
[dark]ToggleButton.selectedBackground = lighten($ToggleButton.background,15%,derived) {*-dark}ToggleButton.disabledSelectedBackground = lighten($ToggleButton.background,5%,derived)
[dark]ToggleButton.disabledSelectedBackground = lighten($ToggleButton.background,5%,derived)
#---- theme specific ---- #---- theme specific ----
@@ -112,357 +112,434 @@ ToggleButton.endBackground = $ToggleButton.background
@ijMenuCheckBackgroundL20 = lighten(@selectionBackground,20%,derived noAutoInverse) @ijMenuCheckBackgroundL20 = lighten(@selectionBackground,20%,derived noAutoInverse)
@ijMenuCheckBackgroundD10 = darken(@selectionBackground,10%,derived noAutoInverse) @ijMenuCheckBackgroundD10 = darken(@selectionBackground,10%,derived noAutoInverse)
@ijTextBackgroundL3 = lighten(Panel.background,3%,lazy) @ijSeparatorLight = shade(@background,15%)
@ijTextBackgroundL4 = lighten(Panel.background,4%,lazy) @ijSeparatorDark = tint(@background,25%)
[Arc_Theme]CheckBoxMenuItem.foreground = lazy(MenuItem.foreground) @ijTextBackgroundL3 = lighten($Panel.background,3%)
[Arc_Theme]PopupMenu.foreground = lazy(MenuItem.foreground) @ijTextBackgroundL4 = lighten($Panel.background,4%)
[Arc_Theme]RadioButtonMenuItem.foreground = lazy(MenuItem.foreground)
[Arc_Theme]ProgressBar.selectionBackground = #000
[Arc_Theme]ProgressBar.selectionForeground = #fff
[Arc_Theme]List.selectionInactiveForeground = #fff
[Arc_Theme]Table.selectionInactiveForeground = #fff
[Arc_Theme]Tree.selectionInactiveForeground = #fff
[Arc_Theme_-_Orange]CheckBoxMenuItem.foreground = lazy(MenuItem.foreground) {Arc_Theme}@selectionInactiveForeground = @selectionForeground
[Arc_Theme_-_Orange]PopupMenu.foreground = lazy(MenuItem.foreground) {Arc_Theme}CheckBoxMenuItem.foreground = $MenuItem.foreground
[Arc_Theme_-_Orange]RadioButtonMenuItem.foreground = lazy(MenuItem.foreground) {Arc_Theme}PopupMenu.foreground = $MenuItem.foreground
[Arc_Theme_-_Orange]ProgressBar.selectionBackground = #000 {Arc_Theme}RadioButtonMenuItem.foreground = $MenuItem.foreground
[Arc_Theme_-_Orange]ProgressBar.selectionForeground = #fff
[Arc_Theme_-_Orange]List.selectionInactiveForeground = #fff
[Arc_Theme_-_Orange]Table.selectionInactiveForeground = #fff
[Arc_Theme_-_Orange]Tree.selectionInactiveForeground = #fff
[Arc_Theme_Dark]CheckBoxMenuItem.foreground = lazy(MenuItem.foreground) {Arc_Theme_-_Orange}@selectionInactiveForeground = @selectionForeground
[Arc_Theme_Dark]PopupMenu.foreground = lazy(MenuItem.foreground) {Arc_Theme_-_Orange}CheckBoxMenuItem.foreground = $MenuItem.foreground
[Arc_Theme_Dark]RadioButtonMenuItem.foreground = lazy(MenuItem.foreground) {Arc_Theme_-_Orange}PopupMenu.foreground = $MenuItem.foreground
[Arc_Theme_Dark]ProgressBar.selectionBackground = #ddd {Arc_Theme_-_Orange}RadioButtonMenuItem.foreground = $MenuItem.foreground
[Arc_Theme_Dark]ProgressBar.selectionForeground = #ddd
[Arc_Theme_Dark]ToolBar.separatorColor = lazy(Separator.foreground)
[Arc_Theme_Dark_-_Orange]CheckBoxMenuItem.foreground = lazy(MenuItem.foreground) {Arc_Theme_Dark}CheckBoxMenuItem.foreground = $MenuItem.foreground
[Arc_Theme_Dark_-_Orange]PopupMenu.foreground = lazy(MenuItem.foreground) {Arc_Theme_Dark}PopupMenu.foreground = $MenuItem.foreground
[Arc_Theme_Dark_-_Orange]RadioButtonMenuItem.foreground = lazy(MenuItem.foreground) {Arc_Theme_Dark}RadioButtonMenuItem.foreground = $MenuItem.foreground
[Arc_Theme_Dark_-_Orange]ProgressBar.selectionBackground = #ddd {Arc_Theme_Dark}ToolBar.background = @background
[Arc_Theme_Dark_-_Orange]ProgressBar.selectionForeground = #fff
[Arc_Theme_Dark_-_Orange]ToolBar.separatorColor = lazy(Separator.foreground)
[Carbon]Table.selectionBackground = lazy(List.selectionBackground) {Arc_Theme_Dark_-_Orange}CheckBoxMenuItem.foreground = $MenuItem.foreground
[Carbon]Table.selectionInactiveForeground = lazy(List.selectionInactiveForeground) {Arc_Theme_Dark_-_Orange}PopupMenu.foreground = $MenuItem.foreground
[Carbon]TextField.background = @ijTextBackgroundL4 {Arc_Theme_Dark_-_Orange}ProgressBar.selectionForeground = #fff
{Arc_Theme_Dark_-_Orange}RadioButtonMenuItem.foreground = $MenuItem.foreground
{Arc_Theme_Dark_-_Orange}ToolBar.background = @background
[Cobalt_2]Component.accentColor = lazy(Component.focusColor) {Carbon}Separator.foreground = @ijSeparatorDark
[Cobalt_2]CheckBox.icon.background = #002946 {Carbon}ToolBar.separatorColor = $Separator.foreground
[Cobalt_2]CheckBox.icon.checkmarkColor = #002946 {Carbon}Table.selectionBackground = $List.selectionBackground
[Cobalt_2]MenuItem.checkBackground = @ijMenuCheckBackgroundL10 {Carbon}TextField.background = @ijTextBackgroundL4
[Cobalt_2]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
[Cobalt_2]ComboBox.background = @ijTextBackgroundL3
[Cobalt_2]ComboBox.buttonBackground = @ijTextBackgroundL3
[Cobalt_2]TextField.background = @ijTextBackgroundL3
[Cobalt_2]Table.background = lazy(List.background)
[Cobalt_2]Tree.background = lazy(List.background)
[Cyan_light]MenuItem.checkBackground = @ijMenuCheckBackgroundL20 {Cobalt_2}@accentBaseColor = $ColorPalette.hue3
[Cyan_light]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL20 {Cobalt_2}CheckBox.icon.background = @background
{Cobalt_2}MenuItem.checkBackground = @ijMenuCheckBackgroundL10
{Cobalt_2}MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
{Cobalt_2}ComboBox.background = @ijTextBackgroundL3
{Cobalt_2}Slider.thumbColor = $ProgressBar.foreground
{Cobalt_2}Slider.disabledTrackColor = $Separator.foreground
{Cobalt_2}TextField.background = @ijTextBackgroundL3
{Cobalt_2}Table.background = $List.background
{Cobalt_2}Tree.background = $List.background
[Dark_Flat_Theme]*.inactiveForeground = #808080 {Cyan_light}@disabledForeground = tint(@foreground,30%)
[Dark_Flat_Theme]Component.accentColor = lazy(List.selectionBackground) {Cyan_light}*.disabledText = @disabledForeground
[Dark_Flat_Theme]TableHeader.background = #3B3B3B {Cyan_light}*.disabledForeground = @disabledForeground
[Dark_Flat_Theme]TextPane.foreground = lazy(TextField.foreground) {Cyan_light}*.inactiveForeground = @disabledForeground
[Dark_Flat_Theme]CheckBoxMenuItem.selectionForeground = lazy(MenuItem.selectionForeground) {Cyan_light}Button.background = @buttonBackground
[Dark_Flat_Theme]List.selectionForeground = lazy(Tree.selectionForeground) {Cyan_light}MenuItem.checkBackground = @ijMenuCheckBackgroundL20
[Dark_Flat_Theme]RadioButtonMenuItem.selectionForeground = lazy(MenuItem.selectionForeground) {Cyan_light}MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL20
[Dark_Flat_Theme]Separator.foreground = lazy(ToolBar.separatorColor)
[Dark_purple]Slider.focusedColor = fade($Component.focusColor,70%,derived) {Dark_Flat_Theme}@accentBaseColor = $TabbedPane.underlineColor
{Dark_Flat_Theme}@disabledForeground = #808080
{Dark_Flat_Theme}*.disabledText = @disabledForeground
{Dark_Flat_Theme}*.disabledForeground = @disabledForeground
{Dark_Flat_Theme}*.inactiveForeground = @disabledForeground
{Dark_Flat_Theme}TableHeader.background = #3B3B3B
{Dark_Flat_Theme}CheckBoxMenuItem.selectionForeground = $MenuItem.selectionForeground
{Dark_Flat_Theme}ComboBox.background = $TextField.background
{Dark_Flat_Theme}ComboBox.buttonBackground = $ComboBox.background
{Dark_Flat_Theme}List.selectionForeground = $Tree.selectionForeground
{Dark_Flat_Theme}ProgressBar.selectionForeground = @foreground
{Dark_Flat_Theme}RadioButtonMenuItem.selectionForeground = $MenuItem.selectionForeground
{Dark_Flat_Theme}Separator.foreground = @ijSeparatorDark
{Dark_Flat_Theme}Slider.trackColor = $ProgressBar.background
{Dark_Flat_Theme}Slider.thumbColor = fade($ProgressBar.foreground,100%)
{Dark_Flat_Theme}TextPane.foreground = $TextField.foreground
{Dark_Flat_Theme}ToggleButton.foreground = $Button.foreground
[Dracula---Zihan_Ma]Component.accentColor = lazy(Component.focusColor) {Dracula---Zihan_Ma}CheckBox.icon.background = @background
[Dracula---Zihan_Ma]ComboBox.selectionBackground = lazy(List.selectionBackground) {Dracula---Zihan_Ma}ComboBox.selectionBackground = $List.selectionBackground
[Dracula---Zihan_Ma]ProgressBar.selectionBackground = #fff {Dracula---Zihan_Ma}ProgressBar.selectionBackground = #fff
[Dracula---Zihan_Ma]ProgressBar.selectionForeground = #fff {Dracula---Zihan_Ma}ProgressBar.selectionForeground = #fff
{Dracula---Zihan_Ma}Slider.trackColor = $?ColorPalette.selectionBackground
{Dracula---Zihan_Ma}ToggleButton.foreground = $Button.foreground
[Gradianto_Dark_Fuchsia]*.selectionBackground = #8452a7 {Gradianto_Dark_Fuchsia}MenuItem.checkBackground = @ijMenuCheckBackgroundL10
[Gradianto_Dark_Fuchsia]*.selectionInactiveBackground = #562C6A {Gradianto_Dark_Fuchsia}MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
[Gradianto_Dark_Fuchsia]MenuItem.checkBackground = @ijMenuCheckBackgroundL10 {Gradianto_Dark_Fuchsia}TextField.background = @ijTextBackgroundL4
[Gradianto_Dark_Fuchsia]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10 {Gradianto_Dark_Fuchsia}Tree.background = $List.background
[Gradianto_Dark_Fuchsia]TextField.background = @ijTextBackgroundL4 {Gradianto_Dark_Fuchsia}Tree.selectionInactiveBackground = $List.selectionInactiveBackground
[Gradianto_Dark_Fuchsia]Tree.background = lazy(List.background) {Gradianto_Dark_Fuchsia}Separator.foreground = @ijSeparatorDark
[Gradianto_Dark_Fuchsia]Separator.foreground = lazy(ScrollBar.track) {Gradianto_Dark_Fuchsia}ToolBar.separatorColor = $Separator.foreground
[Gradianto_Dark_Fuchsia]ToolBar.separatorColor = lazy(ScrollBar.track) {Gradianto_Dark_Fuchsia}ProgressBar.background = $ScrollBar.track
[Gradianto_Dark_Fuchsia]ProgressBar.background = lazy(ScrollBar.track) {Gradianto_Dark_Fuchsia}Slider.trackColor = $ScrollBar.track
[Gradianto_Dark_Fuchsia]Slider.trackColor = lazy(ScrollBar.track)
[Gradianto_Deep_Ocean]TextField.background = @ijTextBackgroundL3 {Gradianto_Deep_Ocean}Separator.foreground = @ijSeparatorDark
[Gradianto_Deep_Ocean]Tree.background = lazy(List.background) {Gradianto_Deep_Ocean}ToolBar.separatorColor = $Separator.foreground
{Gradianto_Deep_Ocean}TextField.background = @ijTextBackgroundL3
{Gradianto_Deep_Ocean}Tree.background = $List.background
[Gradianto_Midnight_Blue]ScrollBar.thumb = #533B6B {Gradianto_Midnight_Blue}ScrollBar.thumb = #533B6B
[Gradianto_Midnight_Blue]Table.selectionForeground = lazy(List.selectionForeground) {Gradianto_Midnight_Blue}Separator.foreground = @ijSeparatorDark
[Gradianto_Midnight_Blue]TextField.background = @ijTextBackgroundL4 {Gradianto_Midnight_Blue}ToolBar.separatorColor = $Separator.foreground
[Gradianto_Midnight_Blue]Tree.background = lazy(List.background) {Gradianto_Midnight_Blue}Table.selectionForeground = $List.selectionForeground
{Gradianto_Midnight_Blue}TextField.background = @ijTextBackgroundL4
{Gradianto_Midnight_Blue}Tree.background = $List.background
[Gradianto_Nature_Green]Table.selectionForeground = lazy(List.selectionForeground) {Gradianto_Nature_Green}Separator.foreground = @ijSeparatorDark
[Gradianto_Nature_Green]TextField.background = @ijTextBackgroundL4 {Gradianto_Nature_Green}ToolBar.separatorColor = $Separator.foreground
{Gradianto_Nature_Green}Table.selectionForeground = $List.selectionForeground
{Gradianto_Nature_Green}TextField.background = @ijTextBackgroundL4
[Gray]Separator.foreground = lazy(Slider.trackColor) {Gray}@disabledForeground = tint(@foreground,40%)
[Gray]ToolBar.separatorColor = lazy(Slider.trackColor) {Gray}*.disabledText = @disabledForeground
{Gray}*.disabledForeground = @disabledForeground
{Gray}*.inactiveForeground = @disabledForeground
{Gray}Button.background = @buttonBackground
{Gray}Separator.foreground = @ijSeparatorLight
{Gray}ToolBar.separatorColor = $Separator.foreground
[Gruvbox_Dark_Hard]Component.accentColor = lazy(TabbedPane.underlineColor) {Gruvbox_Dark_Hard}@accentBaseColor = #4B6EAF
[Gruvbox_Dark_Hard]ToggleButton.selectedBackground = $ToggleButton.selectedBackground {Gruvbox_Dark_Hard}ComboBox.background = @ijTextBackgroundL3
[Gruvbox_Dark_Hard]ToggleButton.toolbar.selectedBackground = $ToggleButton.toolbar.selectedBackground {Gruvbox_Dark_Hard}ComboBox.buttonBackground = $ComboBox.background
[Gruvbox_Dark_Hard]ComboBox.background = @ijTextBackgroundL3 {Gruvbox_Dark_Hard}TextField.background = @ijTextBackgroundL3
[Gruvbox_Dark_Hard]ComboBox.buttonBackground = @ijTextBackgroundL3
[Gruvbox_Dark_Hard]TextField.background = @ijTextBackgroundL3
[Gruvbox_Dark_Medium]Component.accentColor = lazy(TabbedPane.underlineColor) {Hiberbee_Dark}@disabledForeground = $ColorPalette.light3
[Gruvbox_Dark_Medium]ToggleButton.selectedBackground = $ToggleButton.selectedBackground {Hiberbee_Dark}*.disabledText = @disabledForeground
[Gruvbox_Dark_Medium]ToggleButton.toolbar.selectedBackground = $ToggleButton.toolbar.selectedBackground {Hiberbee_Dark}*.disabledForeground = @disabledForeground
[Gruvbox_Dark_Medium]ComboBox.background = @ijTextBackgroundL3 {Hiberbee_Dark}*.inactiveForeground = @disabledForeground
[Gruvbox_Dark_Medium]ComboBox.buttonBackground = @ijTextBackgroundL3 {Hiberbee_Dark}List.selectionInactiveBackground = $Table.selectionInactiveBackground
[Gruvbox_Dark_Medium]TextField.background = @ijTextBackgroundL3 {Hiberbee_Dark}ProgressBar.background = $Separator.foreground
{Hiberbee_Dark}RadioButtonMenuItem.selectionForeground = $MenuItem.selectionForeground
{Hiberbee_Dark}Slider.trackColor = $ColorPalette.light1
{Hiberbee_Dark}Slider.trackColor = $ColorPalette.dark10
{Hiberbee_Dark}Slider.thumbColor = @accentBaseColor
{Hiberbee_Dark}ToggleButton.foreground = $Button.foreground
{Hiberbee_Dark}ToolBar.background = @background
[Gruvbox_Dark_Soft]Component.accentColor = lazy(TabbedPane.underlineColor) {High_Contrast}@accentBaseColor = $TabbedPane.underlineColor
[Gruvbox_Dark_Soft]MenuItem.checkBackground = @ijMenuCheckBackgroundL10 {High_Contrast}Slider.thumbBorderColor = $Slider.thumbColor
[Gruvbox_Dark_Soft]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10 {High_Contrast}Slider.focusedThumbBorderColor = @background
[Gruvbox_Dark_Soft]ToggleButton.selectedBackground = $ToggleButton.selectedBackground {High_Contrast}Slider.focusedColor = $Component.focusColor
[Gruvbox_Dark_Soft]ToggleButton.toolbar.selectedBackground = $ToggleButton.toolbar.selectedBackground {High_Contrast}Slider.focusWidth = 2
[Gruvbox_Dark_Soft]ComboBox.background = @ijTextBackgroundL3 {High_Contrast}ToggleButton.selectedBackground = @selectionBackground
[Gruvbox_Dark_Soft]ComboBox.buttonBackground = @ijTextBackgroundL3 {High_Contrast}ToggleButton.selectedForeground = @selectionForeground
[Gruvbox_Dark_Soft]TextField.background = @ijTextBackgroundL3 {High_Contrast}ToggleButton.disabledSelectedBackground = shade(@selectionBackground,50%)
{High_Contrast}ToggleButton.toolbar.selectedBackground = @selectionBackground
[Hiberbee_Dark]*.disabledForeground = #7F7E7D {High_Contrast}[style]Button.inTextField = \
[Hiberbee_Dark]*.disabledText = #7F7E7D
[Hiberbee_Dark]*.inactiveForeground = #7F7E7D
[Hiberbee_Dark]ProgressBar.background = lazy(Separator.foreground)
[Hiberbee_Dark]Slider.trackColor = lazy(Separator.foreground)
[Hiberbee_Dark]TabbedPane.focusColor = #5A5A5A
[Hiberbee_Dark]TabbedPane.selectedBackground = #434241
[Hiberbee_Dark]TabbedPane.selectedForeground = #70D7FF
[Hiberbee_Dark]ToggleButton.selectedBackground = $ToggleButton.selectedBackground
[Hiberbee_Dark]ToggleButton.toolbar.selectedBackground = $ToggleButton.toolbar.selectedBackground
[Hiberbee_Dark]Table.selectionInactiveBackground = lazy(List.selectionInactiveBackground)
[Hiberbee_Dark]Tree.selectionBackground = lazy(List.selectionBackground)
[Hiberbee_Dark]Tree.selectionInactiveBackground = lazy(List.selectionInactiveBackground)
[High_contrast]Component.accentColor = lazy(Component.focusColor)
[High_contrast]ToggleButton.selectedBackground = #fff
[High_contrast]ToggleButton.selectedForeground = #000
[High_contrast]ToggleButton.disabledSelectedBackground = #444
[High_contrast]ToggleButton.toolbar.selectedBackground = #fff
[High_contrast][style]Button.inTextField = \
toolbar.hoverBackground: #444; \ toolbar.hoverBackground: #444; \
toolbar.pressedBackground: #666; \ toolbar.pressedBackground: #666; \
toolbar.selectedBackground: #fff toolbar.selectedBackground: @selectionBackground
[High_contrast][style]ToggleButton.inTextField = $[High_contrast][style]Button.inTextField
[Light_Flat]*.disabledForeground = #8C8C8C {Light_Flat}@accentBaseColor = $TabbedPane.underlineColor
[Light_Flat]*.inactiveForeground = #8C8C8C {Light_Flat}@accentFocusColor = lighten(@accentBaseColor,15%)
[Light_Flat]CheckBox.icon[filled].background = #fff {Light_Flat}@disabledForeground = #808080
[Light_Flat]CheckBox.icon[filled].checkmarkColor = #fff {Light_Flat}*.disabledText = @disabledForeground
[Light_Flat]Component.accentColor = lazy(TabbedPane.underlineColor) {Light_Flat}*.disabledForeground = @disabledForeground
[Light_Flat]ComboBox.background = lazy(ComboBox.editableBackground) {Light_Flat}*.inactiveForeground = @disabledForeground
[Light_Flat]ComboBox.buttonBackground = lazy(ComboBox.editableBackground) {Light_Flat}CheckBox.icon[filled].background = #fff
[Light_Flat]Separator.foreground = lazy(ToolBar.separatorColor) {Light_Flat}CheckBox.icon[filled].checkmarkColor = #fff
[Light_Flat]TableHeader.background = #E5E5E9 {Light_Flat}ComboBox.background = $ComboBox.editableBackground
[Light_Flat]TextPane.foreground = lazy(TextField.foreground) {Light_Flat}ComboBox.buttonBackground = $ComboBox.background
[Light_Flat]CheckBoxMenuItem.selectionForeground = lazy(MenuItem.selectionForeground) {Light_Flat}ProgressBar.selectionForeground = @foreground
[Light_Flat]RadioButtonMenuItem.selectionForeground = lazy(MenuItem.selectionForeground) {Light_Flat}Separator.foreground = @ijSeparatorLight
{Light_Flat}TableHeader.background = #E5E5E9
{Light_Flat}TextPane.foreground = $TextField.foreground
{Light_Flat}ToggleButton.foreground = $Button.foreground
{Light_Flat}CheckBoxMenuItem.selectionForeground = $MenuItem.selectionForeground
{Light_Flat}RadioButtonMenuItem.selectionForeground = $MenuItem.selectionForeground
[Monocai]Button.default.foreground = #2D2A2F {Monocai}@accentUnderlineColor = @accentBaseColor
[Monocai]MenuItem.checkBackground = @ijMenuCheckBackgroundL10 {Monocai}*.acceleratorForeground = @menuAcceleratorForeground
[Monocai]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10 {Monocai}*.acceleratorSelectionForeground = @menuAcceleratorSelectionForeground
@Monocai.acceleratorForeground = lazy(MenuItem.disabledForeground) {Monocai}Button.default.foreground = @background
@Monocai.acceleratorSelectionForeground = lighten(MenuItem.disabledForeground,10%,lazy) {Monocai}MenuItem.checkBackground = @ijMenuCheckBackgroundL10
[Monocai]CheckBoxMenuItem.acceleratorForeground = @Monocai.acceleratorForeground {Monocai}TabbedPane.underlineColor = @accentUnderlineColor
[Monocai]CheckBoxMenuItem.acceleratorSelectionForeground = @Monocai.acceleratorSelectionForeground {Monocai}TextField.background = @ijTextBackgroundL4
[Monocai]Menu.acceleratorForeground = @Monocai.acceleratorForeground @Monocai.selectionBackground = $TextField.selectionBackground
[Monocai]Menu.acceleratorSelectionForeground = @Monocai.acceleratorSelectionForeground {Monocai}ComboBox.selectionBackground = @Monocai.selectionBackground
[Monocai]MenuItem.acceleratorForeground = @Monocai.acceleratorForeground {Monocai}List.selectionBackground = @Monocai.selectionBackground
[Monocai]MenuItem.acceleratorSelectionForeground = @Monocai.acceleratorSelectionForeground {Monocai}Table.selectionBackground = @Monocai.selectionBackground
[Monocai]RadioButtonMenuItem.acceleratorForeground = @Monocai.acceleratorForeground {Monocai}Tree.selectionBackground = @Monocai.selectionBackground
[Monocai]RadioButtonMenuItem.acceleratorSelectionForeground = @Monocai.acceleratorSelectionForeground @Monocai.selectionInactiveBackground = $MenuItem.selectionBackground
[Monocai]TextField.background = @ijTextBackgroundL4 {Monocai}List.selectionInactiveBackground = @Monocai.selectionInactiveBackground
@Monocai.selectionBackground = lazy(TextField.selectionBackground) {Monocai}Table.selectionInactiveBackground = @Monocai.selectionInactiveBackground
[Monocai]ComboBox.selectionBackground = @Monocai.selectionBackground {Monocai}Tree.selectionInactiveBackground = @Monocai.selectionInactiveBackground
[Monocai]List.selectionBackground = @Monocai.selectionBackground
[Monocai]Table.selectionBackground = @Monocai.selectionBackground
[Monocai]Tree.selectionBackground = @Monocai.selectionBackground
@Monocai.selectionInactiveBackground = lazy(MenuItem.selectionBackground)
[Monocai]List.selectionInactiveBackground = @Monocai.selectionInactiveBackground
[Monocai]Table.selectionInactiveBackground = @Monocai.selectionInactiveBackground
[Monocai]Tree.selectionInactiveBackground = @Monocai.selectionInactiveBackground
[Monokai_Pro---Subtheme]Table.selectionInactiveForeground = lazy(List.selectionInactiveForeground) {Monokai_Pro---Subtheme}@disabledForeground = shade(@foreground,40%)
[Monokai_Pro---Subtheme]Tree.selectionBackground = lazy(List.selectionBackground) {Monokai_Pro---Subtheme}*.disabledText = @disabledForeground
[Monokai_Pro---Subtheme]Separator.foreground = lazy(Slider.trackColor) {Monokai_Pro---Subtheme}*.disabledForeground = @disabledForeground
[Monokai_Pro---Subtheme]ToolBar.separatorColor = lazy(Slider.trackColor) {Monokai_Pro---Subtheme}*.inactiveForeground = @disabledForeground
{Monokai_Pro---Subtheme}ProgressBar.selectionBackground = #fff
{Monokai_Pro---Subtheme}Table.selectionInactiveForeground = $List.selectionInactiveForeground
{Monokai_Pro---Subtheme}Tree.selectionBackground = $List.selectionBackground
{Monokai_Pro---Subtheme}ToggleButton.foreground = $Button.foreground
{Monokai_Pro---Subtheme}Separator.foreground = @ijSeparatorDark
{Monokai_Pro---Subtheme}ToolBar.separatorColor = $Separator.foreground
{Monokai_Pro---Subtheme}ToolBar.background = @background
[Nord]*.inactiveForeground = #616E88 {Nord}@disabledForeground = #616E88
[Nord]MenuItem.checkBackground = @ijMenuCheckBackgroundL10 {Nord}*.disabledText = @disabledForeground
[Nord]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10 {Nord}*.disabledForeground = @disabledForeground
[Nord]List.selectionBackground = lazy(Tree.selectionBackground) {Nord}*.inactiveForeground = @disabledForeground
[Nord]List.selectionForeground = lazy(Tree.selectionForeground) {Nord}MenuItem.checkBackground = @ijMenuCheckBackgroundL10
[Nord]Table.selectionBackground = lazy(Tree.selectionBackground) {Nord}MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
[Nord]Table.selectionForeground = lazy(Tree.selectionForeground) {Nord}RadioButtonMenuItem.selectionBackground = $MenuItem.selectionBackground
[Nord]TextField.selectionBackground = lazy(Tree.selectionBackground) {Nord}ProgressBar.selectionBackground = @foreground
[Nord]TextField.selectionForeground = lazy(Tree.selectionForeground) {Nord}ProgressBar.selectionForeground = @background
[Nord]Tree.selectionInactiveForeground = lazy(List.selectionInactiveForeground) {Nord}List.selectionBackground = $Tree.selectionBackground
{Nord}List.selectionForeground = $Tree.selectionForeground
{Nord}Table.selectionBackground = $Tree.selectionBackground
{Nord}Table.selectionForeground = $Tree.selectionForeground
{Nord}TextField.selectionBackground = $Tree.selectionBackground
{Nord}TextField.selectionForeground = $Tree.selectionForeground
{Nord}Tree.selectionInactiveForeground = $List.selectionInactiveForeground
[NotReallyMDTheme]*.selectionInactiveBackground = #21384E {NotReallyMDTheme}*.selectionInactiveBackground = #21384E
[NotReallyMDTheme]ToolBar.separatorColor = lazy(Separator.foreground) {NotReallyMDTheme}ToolBar.separatorColor = $Separator.foreground
[One_Dark]List.selectionInactiveForeground = lazy(Tree.selectionInactiveForeground) {One_Dark}MenuItem.checkBackground = @ijMenuCheckBackgroundL10
[One_Dark]MenuItem.checkBackground = @ijMenuCheckBackgroundL10 {One_Dark}MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
[One_Dark]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10 {One_Dark}ProgressBar.background = $Separator.foreground
[One_Dark]ProgressBar.background = lazy(Separator.foreground) {One_Dark}ProgressBar.selectionForeground = #fff
[One_Dark]Slider.trackColor = lazy(Separator.foreground) {One_Dark}Table.background = $Tree.background
[One_Dark]Slider.focusedColor = fade(#568af2,40%) {One_Dark}Table.selectionBackground = $Tree.selectionBackground
[One_Dark]Table.background = lazy(Tree.background) {One_Dark}TextField.selectionBackground = $List.selectionBackground
[One_Dark]Table.selectionBackground = lazy(Tree.selectionBackground) {One_Dark}Tree.selectionForeground = $List.selectionForeground
[One_Dark]TextField.selectionBackground = lazy(List.selectionBackground)
[One_Dark]Tree.selectionForeground = lazy(List.selectionForeground)
[Solarized_Dark---4lex4]*.inactiveForeground = #657B83 {Solarized_Dark---4lex4}@accentBaseColor = $TabbedPane.underlineColor
[Solarized_Dark---4lex4]Component.accentColor = lazy(TabbedPane.underlineColor) {Solarized_Dark---4lex4}*.acceleratorForeground = @menuAcceleratorForeground
[Solarized_Dark---4lex4]ComboBox.background = lazy(ComboBox.editableBackground) {Solarized_Dark---4lex4}ComboBox.background = $ComboBox.editableBackground
[Solarized_Dark---4lex4]ComboBox.buttonBackground = lazy(ComboBox.editableBackground) {Solarized_Dark---4lex4}ComboBox.buttonBackground = $ComboBox.editableBackground
[Solarized_Dark---4lex4]Slider.focusedColor = fade($Component.focusColor,80%,derived) {Solarized_Dark---4lex4}Slider.disabledTrackColor = $ColorPalette.colorSeparator
[Solarized_Dark---4lex4]ToolBar.separatorColor = lazy(Separator.foreground)
[Solarized_Light---4lex4]*.inactiveForeground = #839496 {Solarized_Light---4lex4}@accentBaseColor = $TabbedPane.underlineColor
[Solarized_Light---4lex4]Button.default.hoverBackground = darken($Button.default.background,3%,derived) {Solarized_Light---4lex4}Slider.thumbColor = $ProgressBar.foreground
[Solarized_Light---4lex4]Component.accentColor = lazy(TabbedPane.underlineColor) {Solarized_Light---4lex4}Slider.disabledTrackColor = $ColorPalette.colorSeparator
[Spacegray]ComboBox.background = @ijTextBackgroundL4 {Spacegray}ComboBox.background = @ijTextBackgroundL4
[Spacegray]ComboBox.buttonBackground = @ijTextBackgroundL4 {Spacegray}ComboBox.buttonBackground = $ComboBox.background
[Spacegray]TextField.background = @ijTextBackgroundL4 {Spacegray}TextField.background = @ijTextBackgroundL4
[Spacegray]TextField.selectionBackground = lazy(Tree.selectionBackground)
[Spacegray]TextField.selectionForeground = lazy(Tree.selectionForeground)
[vuesion-theme]*.disabledForeground = #8C8C8C {vuesion-theme}@accentBaseColor = $TabbedPane.underlineColor
[vuesion-theme]*.disabledText = #8C8C8C {vuesion-theme}@disabledForeground = #8C8C8C
[vuesion-theme]*.inactiveForeground = #8C8C8C {vuesion-theme}*.disabledText = @disabledForeground
[vuesion-theme]Component.accentColor = lazy(Button.default.endBackground) {vuesion-theme}*.disabledForeground = @disabledForeground
[vuesion-theme]MenuItem.checkBackground = @ijMenuCheckBackgroundL10 {vuesion-theme}*.inactiveForeground = @disabledForeground
[vuesion-theme]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10 {vuesion-theme}MenuItem.checkBackground = @ijMenuCheckBackgroundL10
[vuesion-theme]Slider.trackValueColor = #ececee {vuesion-theme}MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
[vuesion-theme]Slider.trackColor = #303a45 {vuesion-theme}ProgressBar.background = #303a45
[vuesion-theme]Slider.thumbColor = #ececee {vuesion-theme}ProgressBar.foreground = #ececee
[vuesion-theme]Slider.focusedColor = fade(#ececee,20%) {vuesion-theme}Slider.thumbColor = #ececee
[vuesion-theme]ComboBox.background = @ijTextBackgroundL4 {vuesion-theme}Slider.focusedColor = fade($Slider.thumbColor,20%)
[vuesion-theme]ComboBox.buttonBackground = @ijTextBackgroundL4 {vuesion-theme}ComboBox.background = @ijTextBackgroundL4
[vuesion-theme]TextField.background = @ijTextBackgroundL4 {vuesion-theme}ComboBox.buttonBackground = $ComboBox.background
[vuesion-theme]TextField.selectionBackground = lighten(#303A45,15%) {vuesion-theme}TextField.background = @ijTextBackgroundL4
{vuesion-theme}TextField.selectionBackground = lighten(#303A45,15%)
[Xcode-Dark]TextField.background = @ijTextBackgroundL4 {Xcode-Dark}@accentBaseColor = $List.selectionBackground
{Xcode-Dark}TextField.background = @ijTextBackgroundL4
# Material Theme UI Lite # Material Theme UI Lite
[light][author-Mallowigi]MenuItem.checkBackground = @ijMenuCheckBackgroundD10 {author-Mallowigi}[light]controlHighlight = lighten($controlShadow,8%)
[light][author-Mallowigi]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundD10 {author-Mallowigi}[light]controlLtHighlight = lighten($controlShadow,15%)
[dark][author-Mallowigi]MenuItem.checkBackground = @ijMenuCheckBackgroundL20 {author-Mallowigi}[light]controlDkShadow = darken($controlShadow,15%)
[dark][author-Mallowigi]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL20 {author-Mallowigi}[dark]controlHighlight = darken($controlShadow,10%)
{author-Mallowigi}[dark]controlLtHighlight = darken($controlShadow,15%)
{author-Mallowigi}[dark]controlDkShadow = lighten($controlShadow,10%)
[author-Mallowigi]Tree.selectionInactiveBackground = lazy(List.selectionInactiveBackground) {author-Mallowigi}Button.hoverBorderColor = $Button.focusedBorderColor
{author-Mallowigi}HelpButton.hoverBorderColor = $Button.focusedBorderColor
[Arc_Dark]ComboBox.selectionBackground = lazy(List.selectionBackground) {author-Mallowigi}[light]ToggleButton.selectedForeground = #000
[Arc_Dark]Table.selectionBackground = lazy(List.selectionBackground) {author-Mallowigi}[dark]ToggleButton.selectedForeground = #fff
[Atom_One_Dark]Separator.foreground = lazy(Slider.trackColor) {author-Mallowigi}[light]MenuItem.checkBackground = @ijMenuCheckBackgroundD10
[Atom_One_Dark]ToolBar.separatorColor = lazy(Slider.trackColor) {author-Mallowigi}[light]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundD10
{author-Mallowigi}[dark]MenuItem.checkBackground = @ijMenuCheckBackgroundL20
{author-Mallowigi}[dark]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL20
[Atom_One_Light]List.selectionBackground = lazy(Table.selectionBackground) {author-Mallowigi}[light]Separator.foreground = @ijSeparatorLight
[Atom_One_Light]Tree.selectionBackground = lazy(Table.selectionBackground) {author-Mallowigi}[dark]Separator.foreground = @ijSeparatorDark
[Atom_One_Light]TabbedPane.contentAreaColor = lazy(Separator.foreground) {author-Mallowigi}ProgressBar.selectionBackground = @foreground
{author-Mallowigi}TabbedPane.selectedBackground = mix(@background,$ColorPalette.table,60%)
{author-Mallowigi}ToolBar.separatorColor = $Separator.foreground
{author-Mallowigi}Button.foreground = @foreground
{author-Mallowigi}Tree.foreground = @foreground
[Dracula---Mallowigi]*.selectionBackground = #44475A
[Dracula---Mallowigi]List.selectionInactiveForeground = lazy(Tree.selectionInactiveForeground)
[Dracula---Mallowigi]ProgressBar.selectionBackground = #fff
[Dracula---Mallowigi]ProgressBar.selectionForeground = #fff
[Dracula---Mallowigi]RadioButtonMenuItem.selectionForeground = lazy(CheckBoxMenuItem.selectionForeground)
[Dracula---Mallowigi]Table.selectionForeground = lazy(List.selectionForeground)
[Dracula---Mallowigi]Separator.foreground = lazy(Slider.trackColor)
[Dracula---Mallowigi]ToolBar.separatorColor = lazy(Slider.trackColor)
[GitHub]ProgressBar.selectionBackground = #222 {Arc_Dark}ComboBox.selectionBackground = $List.selectionBackground
[GitHub]ProgressBar.selectionForeground = #222 {Arc_Dark}ProgressBar.selectionBackground = #fff
[GitHub]TextField.background = @ijTextBackgroundL3 {Arc_Dark}ProgressBar.selectionForeground = #fff
[GitHub]List.selectionBackground = lazy(Table.selectionBackground) {Arc_Dark}Table.selectionBackground = $List.selectionBackground
[GitHub]Tree.selectionBackground = lazy(Table.selectionBackground) {Arc_Dark}Tree.selectionInactiveBackground = $List.selectionInactiveBackground
[GitHub_Dark]ComboBox.selectionBackground = lazy(Tree.selectionBackground) {Atom_One_Dark}ProgressBar.selectionBackground = #fff
[GitHub_Dark]Table.selectionBackground = lazy(Tree.selectionBackground) {Atom_One_Dark}ProgressBar.selectionForeground = #fff
[GitHub_Dark]Separator.foreground = lazy(Slider.trackColor) {Atom_One_Dark}List.selectionBackground = $Table.selectionBackground
[GitHub_Dark]ToolBar.separatorColor = lazy(Slider.trackColor) {Atom_One_Dark}Tree.selectionBackground = $Table.selectionBackground
{Atom_One_Dark}List.selectionInactiveBackground = $Tree.selectionInactiveBackground
{Atom_One_Dark}Table.selectionInactiveBackground = $Tree.selectionInactiveBackground
[Light_Owl]CheckBoxMenuItem.selectionForeground = lazy(CheckBoxMenuItem.foreground) {Atom_One_Light}@disabledForeground = shade($ColorPalette.dis,20%)
[Light_Owl]ComboBox.selectionForeground = lazy(ComboBox.foreground) {Atom_One_Light}*.disabledText = @disabledForeground
[Light_Owl]List.selectionInactiveForeground = lazy(List.foreground) {Atom_One_Light}*.disabledForeground = @disabledForeground
[Light_Owl]Menu.selectionForeground = lazy(Menu.foreground) {Atom_One_Light}*.inactiveForeground = @disabledForeground
[Light_Owl]MenuBar.selectionForeground = lazy(MenuBar.foreground) {Atom_One_Light}TabbedPane.contentAreaColor = $Separator.foreground
[Light_Owl]MenuItem.selectionForeground = lazy(MenuItem.foreground)
[Light_Owl]ProgressBar.selectionBackground = #111
[Light_Owl]ProgressBar.selectionForeground = #fff
[Light_Owl]Spinner.selectionForeground = lazy(Spinner.foreground)
[Light_Owl]Table.selectionForeground = lazy(Table.foreground)
[Light_Owl]TextField.selectionForeground = lazy(TextField.foreground)
[Light_Owl]TextField.background = @ijTextBackgroundL3
[Light_Owl]List.selectionBackground = lazy(Table.selectionBackground)
[Light_Owl]Tree.selectionBackground = lazy(Table.selectionBackground)
[Material_Darker]*.selectionBackground = lighten(#2D2D2D,15%) {Dracula---Mallowigi}ProgressBar.selectionBackground = #fff
[Material_Darker]Separator.foreground = lazy(Slider.trackColor) {Dracula---Mallowigi}ProgressBar.selectionForeground = #fff
[Material_Darker]ToolBar.separatorColor = lazy(Slider.trackColor) {Dracula---Mallowigi}List.selectionBackground = $Table.selectionBackground
{Dracula---Mallowigi}Tree.selectionBackground = $Table.selectionBackground
{Dracula---Mallowigi}List.selectionInactiveBackground = $Tree.selectionInactiveBackground
{Dracula---Mallowigi}Table.selectionInactiveBackground = $Tree.selectionInactiveBackground
[Material_Deep_Ocean]*.selectionBackground = lighten(#222533,15%) {GitHub}ProgressBar.selectionBackground = #222
[Material_Deep_Ocean]Separator.foreground = lazy(Slider.trackColor) {GitHub}ProgressBar.selectionForeground = #222
[Material_Deep_Ocean]ToolBar.separatorColor = lazy(Slider.trackColor) {GitHub}TextField.background = @ijTextBackgroundL3
{GitHub}List.selectionBackground = $Table.selectionBackground
{GitHub}Tree.selectionBackground = $Table.selectionBackground
{GitHub}List.selectionInactiveBackground = $Tree.selectionInactiveBackground
{GitHub}Table.selectionInactiveBackground = $Tree.selectionInactiveBackground
[Material_Lighter]List.selectionInactiveForeground = lazy(Tree.selectionInactiveForeground) {GitHub_Dark}ComboBox.selectionBackground = $Tree.selectionBackground
[Material_Lighter]ProgressBar.selectionBackground = #222 {GitHub_Dark}ProgressBar.selectionForeground = #fff
[Material_Lighter]ProgressBar.selectionForeground = #fff {GitHub_Dark}Slider.trackColor = lighten(#2b3036,5%)
[Material_Lighter]ComboBox.selectionBackground = lazy(List.selectionBackground) {GitHub_Dark}Table.selectionBackground = $Tree.selectionBackground
[Material_Lighter]Table.selectionBackground = lazy(List.selectionBackground) {GitHub_Dark}Tree.selectionInactiveBackground = $Table.selectionInactiveBackground
[Material_Lighter]List.selectionForeground = lazy(Table.selectionForeground)
[Material_Lighter]RadioButtonMenuItem.selectionForeground = lazy(Table.selectionForeground)
[Material_Lighter]Tree.selectionForeground = lazy(Table.selectionForeground)
[Material_Oceanic]ProgressBar.selectionBackground = #ddd {Light_Owl}@disabledForeground = shade($ColorPalette.dis,10%)
[Material_Oceanic]ProgressBar.selectionForeground = #ddd {Light_Owl}*.disabledText = @disabledForeground
[Material_Oceanic]Separator.foreground = lazy(Slider.trackColor) {Light_Owl}*.disabledForeground = @disabledForeground
[Material_Oceanic]ToolBar.separatorColor = lazy(Slider.trackColor) {Light_Owl}*.inactiveForeground = @disabledForeground
{Light_Owl}CheckBoxMenuItem.selectionForeground = $CheckBoxMenuItem.foreground
{Light_Owl}ComboBox.selectionForeground = $ComboBox.foreground
{Light_Owl}List.selectionInactiveForeground = $Table.selectionInactiveForeground
{Light_Owl}Menu.selectionForeground = $Menu.foreground
{Light_Owl}MenuBar.selectionForeground = $MenuBar.foreground
{Light_Owl}MenuItem.selectionForeground = $MenuItem.foreground
{Light_Owl}Table.selectionForeground = $List.selectionForeground
{Light_Owl}TextField.selectionForeground = $TextField.foreground
{Light_Owl}TextField.background = @ijTextBackgroundL3
{Light_Owl}List.selectionBackground = $Table.selectionBackground
{Light_Owl}Tree.selectionBackground = $Table.selectionBackground
{Light_Owl}List.selectionInactiveBackground = $Tree.selectionInactiveBackground
{Light_Owl}Table.selectionInactiveBackground = $Tree.selectionInactiveBackground
[Material_Palenight]ProgressBar.selectionBackground = #ddd {Material_Darker}@disabledForeground = tint($ColorPalette.dis,30%)
[Material_Palenight]ProgressBar.selectionForeground = #ddd {Material_Darker}*.disabledText = @disabledForeground
[Material_Palenight]List.selectionBackground = lazy(Table.selectionBackground) {Material_Darker}*.disabledForeground = @disabledForeground
[Material_Palenight]Tree.selectionBackground = lazy(Table.selectionBackground) {Material_Darker}*.inactiveForeground = @disabledForeground
[Material_Palenight]Separator.foreground = lazy(Slider.trackColor) {Material_Darker}*.selectionBackground = lighten($ColorPalette.tree,15%)
[Material_Palenight]ToolBar.separatorColor = lazy(Slider.trackColor) {Material_Darker}ProgressBar.selectionForeground = #fff
{Material_Darker}Tree.selectionInactiveBackground = $List.selectionInactiveBackground
[Monokai_Pro---Mallowigi]List.selectionForeground = lazy(Table.selectionForeground) {Material_Deep_Ocean}@disabledForeground = tint($ColorPalette.dis,10%)
[Monokai_Pro---Mallowigi]RadioButtonMenuItem.selectionForeground = lazy(Table.selectionForeground) {Material_Deep_Ocean}*.disabledText = @disabledForeground
[Monokai_Pro---Mallowigi]Table.selectionInactiveForeground = lazy(List.selectionInactiveForeground) {Material_Deep_Ocean}*.disabledForeground = @disabledForeground
[Monokai_Pro---Mallowigi]Tree.selectionForeground = lazy(Table.selectionForeground) {Material_Deep_Ocean}*.inactiveForeground = @disabledForeground
[Monokai_Pro---Mallowigi]Tree.selectionInactiveForeground = lazy(List.selectionInactiveForeground) {Material_Deep_Ocean}*.selectionBackground = lighten($ColorPalette.tree,15%)
[Monokai_Pro---Mallowigi]Separator.foreground = lazy(Slider.trackColor) {Material_Deep_Ocean}ProgressBar.selectionBackground = #fff
[Monokai_Pro---Mallowigi]ToolBar.separatorColor = lazy(Slider.trackColor) {Material_Deep_Ocean}Slider.trackColor = lighten(#1A1C25,5%)
{Material_Deep_Ocean}Tree.selectionInactiveBackground = $List.selectionInactiveBackground
[Moonlight]ComboBox.selectionBackground = lazy(List.selectionBackground) {Material_Lighter}@disabledForeground = shade($ColorPalette.dis,30%)
[Moonlight]Table.selectionBackground = lazy(List.selectionBackground) {Material_Lighter}*.disabledText = @disabledForeground
[Moonlight]Separator.foreground = lazy(Slider.trackColor) {Material_Lighter}*.disabledForeground = @disabledForeground
[Moonlight]ToolBar.separatorColor = lazy(Slider.trackColor) {Material_Lighter}*.inactiveForeground = @disabledForeground
{Material_Lighter}ComboBox.selectionBackground = $List.selectionBackground
{Material_Lighter}List.selectionForeground = $Table.selectionForeground
{Material_Lighter}List.selectionInactiveForeground = $Table.selectionInactiveForeground
{Material_Lighter}ProgressBar.selectionBackground = #222
{Material_Lighter}RadioButtonMenuItem.selectionForeground = $Table.selectionForeground
{Material_Lighter}Table.selectionBackground = $List.selectionBackground
{Material_Lighter}Tree.selectionForeground = $Table.selectionForeground
{Material_Lighter}Tree.selectionInactiveBackground = $List.selectionInactiveBackground
[Night_Owl]ProgressBar.selectionBackground = #ddd {Material_Oceanic}@disabledForeground = tint($ColorPalette.dis,30%)
[Night_Owl]ProgressBar.selectionForeground = #ddd {Material_Oceanic}*.disabledText = @disabledForeground
{Material_Oceanic}*.disabledForeground = @disabledForeground
{Material_Oceanic}*.inactiveForeground = @disabledForeground
{Material_Oceanic}ProgressBar.selectionBackground = #ddd
{Material_Oceanic}ProgressBar.selectionForeground = #ddd
{Material_Oceanic}List.selectionBackground = $Table.selectionBackground
{Material_Oceanic}Tree.selectionBackground = $Table.selectionBackground
{Material_Oceanic}List.selectionInactiveBackground = $Tree.selectionInactiveBackground
{Material_Oceanic}Table.selectionInactiveBackground = $Tree.selectionInactiveBackground
[Solarized_Dark---Mallowigi]ProgressBar.selectionBackground = #ccc {Material_Palenight}@disabledForeground = tint($ColorPalette.dis,20%)
[Solarized_Dark---Mallowigi]ProgressBar.selectionForeground = #ccc {Material_Palenight}*.disabledText = @disabledForeground
[Solarized_Dark---Mallowigi]Separator.foreground = lazy(Slider.trackColor) {Material_Palenight}*.disabledForeground = @disabledForeground
[Solarized_Dark---Mallowigi]ToolBar.separatorColor = lazy(Slider.trackColor) {Material_Palenight}*.inactiveForeground = @disabledForeground
{Material_Palenight}ProgressBar.selectionBackground = #ddd
{Material_Palenight}ProgressBar.selectionForeground = #ddd
{Material_Palenight}List.selectionBackground = $Table.selectionBackground
{Material_Palenight}Tree.selectionBackground = $Table.selectionBackground
{Material_Palenight}List.selectionInactiveBackground = $Tree.selectionInactiveBackground
{Material_Palenight}Table.selectionInactiveBackground = $Tree.selectionInactiveBackground
[Solarized_Light---Mallowigi]ProgressBar.selectionBackground = #222 {Monokai_Pro---Mallowigi}@disabledForeground = tint($ColorPalette.dis,20%)
[Solarized_Light---Mallowigi]ProgressBar.selectionForeground = #fff {Monokai_Pro---Mallowigi}*.disabledText = @disabledForeground
[Solarized_Light---Mallowigi]ComboBox.selectionBackground = lazy(List.selectionBackground) {Monokai_Pro---Mallowigi}*.disabledForeground = @disabledForeground
[Solarized_Light---Mallowigi]Table.selectionBackground = lazy(List.selectionBackground) {Monokai_Pro---Mallowigi}*.inactiveForeground = @disabledForeground
[Solarized_Light---Mallowigi]Separator.foreground = lazy(Slider.trackColor) {Monokai_Pro---Mallowigi}RadioButtonMenuItem.selectionForeground = $MenuItem.selectionForeground
[Solarized_Light---Mallowigi]ToolBar.separatorColor = lazy(Slider.trackColor) {Monokai_Pro---Mallowigi}List.selectionForeground = $Table.selectionForeground
{Monokai_Pro---Mallowigi}Tree.selectionForeground = $Table.selectionForeground
{Monokai_Pro---Mallowigi}List.selectionInactiveForeground = $Table.selectionInactiveForeground
{Monokai_Pro---Mallowigi}List.selectionBackground = $Table.selectionBackground
{Monokai_Pro---Mallowigi}Tree.selectionBackground = $Table.selectionBackground
{Monokai_Pro---Mallowigi}List.selectionInactiveBackground = $Tree.selectionInactiveBackground
{Monokai_Pro---Mallowigi}Table.selectionInactiveBackground = $Tree.selectionInactiveBackground
{Moonlight}ComboBox.selectionBackground = $List.selectionBackground
{Moonlight}ProgressBar.selectionForeground = #000
{Moonlight}Table.selectionBackground = $List.selectionBackground
{Moonlight}Tree.selectionInactiveBackground = $List.selectionInactiveBackground
{Solarized_Dark---Mallowigi}@disabledForeground = tint($ColorPalette.dis,20%)
{Solarized_Dark---Mallowigi}*.disabledForeground = @disabledForeground
{Solarized_Dark---Mallowigi}*.inactiveForeground = @disabledForeground
{Solarized_Dark---Mallowigi}*.disabledText = @disabledForeground
{Solarized_Dark---Mallowigi}ProgressBar.selectionBackground = #ccc
{Solarized_Dark---Mallowigi}ProgressBar.selectionForeground = #ccc
{Solarized_Dark---Mallowigi}Slider.trackColor = lighten(@background,10%)
{Solarized_Dark---Mallowigi}Table.selectionBackground = $List.selectionBackground
{Solarized_Dark---Mallowigi}Tree.selectionInactiveBackground = $List.selectionInactiveBackground
{Solarized_Light---Mallowigi}@disabledForeground = tint(@foreground,30%)
{Solarized_Light---Mallowigi}*.disabledForeground = @disabledForeground
{Solarized_Light---Mallowigi}*.inactiveForeground = @disabledForeground
{Solarized_Light---Mallowigi}*.disabledText = @disabledForeground
{Solarized_Light---Mallowigi}ProgressBar.selectionBackground = #222
{Solarized_Light---Mallowigi}ComboBox.selectionBackground = $List.selectionBackground
{Solarized_Light---Mallowigi}Slider.disabledTrackColor = lighten($Slider.trackColor,5%)
{Solarized_Light---Mallowigi}Table.selectionBackground = $List.selectionBackground
{Solarized_Light---Mallowigi}Tree.selectionInactiveBackground = $List.selectionInactiveBackground
{Solarized_Light---Mallowigi}Button.toolbar.selectedBackground = darken($@background,15%)
{Solarized_Light---Mallowigi}ToggleButton.toolbar.selectedBackground = $Button.toolbar.selectedBackground

View File

@@ -112,6 +112,7 @@ Button.borderWidth = 0
Button.disabledBackground = darken($Button.background,10%) Button.disabledBackground = darken($Button.background,10%)
Button.default.borderWidth = 0 Button.default.borderWidth = 0
Button.default.foreground = contrast($Button.default.background, @background, @selectionForeground, 25%)
Button.toolbar.hoverBackground = #fff1 Button.toolbar.hoverBackground = #fff1
Button.toolbar.pressedBackground = #fff2 Button.toolbar.pressedBackground = #fff2
@@ -293,6 +294,7 @@ TextPane.selectionForeground = @textSelectionForeground
ToggleButton.disabledBackground = $Button.disabledBackground ToggleButton.disabledBackground = $Button.disabledBackground
ToggleButton.selectedBackground = lighten($ToggleButton.background,20%,derived) ToggleButton.selectedBackground = lighten($ToggleButton.background,20%,derived)
ToggleButton.selectedForeground = lighten($ToggleButton.foreground,20%)
ToggleButton.toolbar.selectedBackground = #fff3 ToggleButton.toolbar.selectedBackground = #fff3

View File

@@ -79,7 +79,7 @@
# general background and foreground (text color) # general background and foreground (text color)
@background = #f6f6f6 @background = #f6f6f6
@foreground = over(@nsControlTextColor,@background) @foreground = over(@nsControlTextColor,@background)
@disabledForeground = over(@nsTertiaryLabelColor,@background) @disabledForeground = over(@nsSecondaryLabelColor,@background)
# component background # component background
@buttonBackground = @nsControlColor @buttonBackground = @nsControlColor

View File

@@ -17,6 +17,8 @@
package com.formdev.flatlaf; package com.formdev.flatlaf;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.awt.Color; import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Font; import java.awt.Font;
@@ -29,6 +31,13 @@ import javax.swing.UIDefaults.LazyValue;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import com.formdev.flatlaf.ui.FlatEmptyBorder; import com.formdev.flatlaf.ui.FlatEmptyBorder;
import com.formdev.flatlaf.ui.FlatLineBorder; import com.formdev.flatlaf.ui.FlatLineBorder;
import com.formdev.flatlaf.util.DerivedColor;
import com.formdev.flatlaf.util.ColorFunctions.ColorFunction;
import com.formdev.flatlaf.util.ColorFunctions.Fade;
import com.formdev.flatlaf.util.ColorFunctions.HSLChange;
import com.formdev.flatlaf.util.ColorFunctions.HSLIncreaseDecrease;
import com.formdev.flatlaf.util.ColorFunctions.Mix;
import com.formdev.flatlaf.util.ColorFunctions.Mix2;
/** /**
* @author Karl Tauber * @author Karl Tauber
@@ -180,6 +189,269 @@ public class TestUIDefaultsLoader
assertEquals( expected, ((LazyValue)UIDefaultsLoader.parseValue( "dummyIcon", value, null )).createValue( null ) ); assertEquals( expected, ((LazyValue)UIDefaultsLoader.parseValue( "dummyIcon", value, null )).createValue( null ) );
} }
@Test
void parseColorFunctions() {
// lighten
assertEquals( new Color( 0xff6666 ), parseColor( "lighten(#f00, 20%)" ) );
assertEquals( new Color( 0xff3333 ), parseColor( "lighten(#f00, 20%, relative)" ) );
assertEquals( new Color( 0xaaaaaa ), parseColor( "lighten(#ddd, 20%, autoInverse)" ) );
assertEquals( new Color( 0xb1b1b1 ), parseColor( "lighten(#ddd, 20%, relative autoInverse)" ) );
// darken
assertEquals( new Color( 0x990000 ), parseColor( "darken(#f00, 20%)" ) );
assertEquals( new Color( 0xcc0000 ), parseColor( "darken(#f00, 20%, relative)" ) );
assertEquals( new Color( 0x555555 ), parseColor( "darken(#222, 20%, autoInverse)" ) );
assertEquals( new Color( 0x292929 ), parseColor( "darken(#222, 20%, relative autoInverse)" ) );
// saturate
assertEquals( new Color( 0xf32e2e ), parseColor( "saturate(#d44, 20%)" ) );
assertEquals( new Color( 0xec3535 ), parseColor( "saturate(#d44, 20%, relative)" ) );
assertEquals( new Color( 0xc75a5a ), parseColor( "saturate(#d44, 20%, autoInverse)" ) );
assertEquals( new Color( 0xce5353 ), parseColor( "saturate(#d44, 20%, relative autoInverse)" ) );
// desaturate
assertEquals( new Color( 0x745858 ), parseColor( "desaturate(#844, 20%)" ) );
assertEquals( new Color( 0x814b4b ), parseColor( "desaturate(#844, 20%, relative)" ) );
assertEquals( new Color( 0x9c3030 ), parseColor( "desaturate(#844, 20%, autoInverse)" ) );
assertEquals( new Color( 0x8f3d3d ), parseColor( "desaturate(#844, 20%, relative autoInverse)" ) );
// fadein
assertEquals( new Color( 0xddff0000, true ), parseColor( "fadein(#f00a, 20%)" ) );
assertEquals( new Color( 0xccff0000, true ), parseColor( "fadein(#f00a, 20%, relative)" ) );
assertEquals( new Color( 0x77ff0000, true ), parseColor( "fadein(#f00a, 20%, autoInverse)" ) );
assertEquals( new Color( 0x88ff0000, true ), parseColor( "fadein(#f00a, 20%, relative autoInverse)" ) );
// fadeout
assertEquals( new Color( 0x11ff0000, true ), parseColor( "fadeout(#f004, 20%)" ) );
assertEquals( new Color( 0x36ff0000, true ), parseColor( "fadeout(#f004, 20%, relative)" ) );
assertEquals( new Color( 0x77ff0000, true ), parseColor( "fadeout(#f004, 20%, autoInverse)" ) );
assertEquals( new Color( 0x52ff0000, true ), parseColor( "fadeout(#f004, 20%, relative autoInverse)" ) );
// fade
assertEquals( new Color( 0x33ff0000, true ), parseColor( "fade(#f00, 20%)" ) );
assertEquals( new Color( 0xccff0000, true ), parseColor( "fade(#ff000010, 80%)" ) );
// spin
assertEquals( new Color( 0xffaa00 ), parseColor( "spin(#f00, 40)" ) );
assertEquals( new Color( 0xff00aa ), parseColor( "spin(#f00, -40)" ) );
// changeHue / changeSaturation / changeLightness / changeAlpha
assertEquals( new Color( 0xffaa00 ), parseColor( "changeHue(#f00, 40)" ) );
assertEquals( new Color( 0xb34d4d ), parseColor( "changeSaturation(#f00, 40%)" ) );
assertEquals( new Color( 0xcc0000 ), parseColor( "changeLightness(#f00, 40%)" ) );
assertEquals( new Color( 0x66ff0000, true ), parseColor( "changeAlpha(#f00, 40%)" ) );
// mix
assertEquals( new Color( 0x808000 ), parseColor( "mix(#f00, #0f0)" ) );
assertEquals( new Color( 0xbf4000 ), parseColor( "mix(#f00, #0f0, 75%)" ) );
// tint
assertEquals( new Color( 0xff80ff ), parseColor( "tint(#f0f)" ) );
assertEquals( new Color( 0xffbfff ), parseColor( "tint(#f0f, 75%)" ) );
// shade
assertEquals( new Color( 0x800080 ), parseColor( "shade(#f0f)" ) );
assertEquals( new Color( 0x400040 ), parseColor( "shade(#f0f, 75%)" ) );
// contrast
assertEquals( new Color( 0x0000ff ), parseColor( "contrast(#bbb, #00f, #0f0)" ) );
assertEquals( new Color( 0x00ff00 ), parseColor( "contrast(#444, #00f, #0f0)" ) );
assertEquals( new Color( 0x00ff00 ), parseColor( "contrast(#bbb, #00f, #0f0, 60%)" ) );
// rgb / rgba
assertEquals( new Color( 0x5a8120 ), parseColor( "rgb(90, 129, 32)" ) );
assertEquals( new Color( 0x5a8120 ), parseColor( "rgb(90, 129, 32)" ) );
assertEquals( new Color( 0x197fb2 ), parseColor( "rgb(10%,50%,70%)" ) );
assertEquals( new Color( 0x197f46 ), parseColor( "rgb(10%,50%,70)" ) );
assertEquals( new Color( 0x405a8120, true ), parseColor( "rgba(90, 129, 32, 64)" ) );
assertEquals( new Color( 0x335a8120, true ), parseColor( "rgba(90, 129, 32, 20%)" ) );
// hsl / hsla
assertEquals( new Color( 0x7fff00 ), parseColor( "hsl(90, 100%, 50%)" ) );
assertEquals( new Color( 0x337fff00, true ), parseColor( "hsla(90, 100%, 50%, 20%)" ) );
}
@Test
void parseLazyColorFunctions() {
// lighten
assertEquals( new Color( 0xff6666 ), parseColorLazy( "lighten(dummyColor, 20%, lazy)", new Color( 0xff0000 ) ) );
// darken
assertEquals( new Color( 0x990000 ), parseColorLazy( "darken(dummyColor, 20%, lazy)", new Color( 0xff0000 ) ) );
// saturate
assertEquals( new Color( 0xf32e2e ), parseColorLazy( "saturate(dummyColor, 20%, lazy)", new Color( 0xdd4444 ) ) );
// desaturate
assertEquals( new Color( 0x745858 ), parseColorLazy( "desaturate(dummyColor, 20%, lazy)", new Color( 0x884444 ) ) );
// fadein
assertEquals( new Color( 0xddff0000, true ), parseColorLazy( "fadein(dummyColor, 20%, lazy)", new Color( 0xaaff0000, true ) ) );
// fadeout
assertEquals( new Color( 0x11ff0000, true ), parseColorLazy( "fadeout(dummyColor, 20%, lazy)", new Color( 0x44ff0000, true ) ) );
// fade
assertEquals( new Color( 0x33ff0000, true ), parseColorLazy( "fade(dummyColor, 20%, lazy)", new Color( 0xff0000 ) ) );
assertEquals( new Color( 0xccff0000, true ), parseColorLazy( "fade(dummyColor, 80%, lazy)", new Color( 0x10ff0000, true ) ) );
// spin
assertEquals( new Color( 0xffaa00 ), parseColorLazy( "spin(dummyColor, 40, lazy)", new Color( 0xff0000 ) ) );
assertEquals( new Color( 0xff00aa ), parseColorLazy( "spin(dummyColor, -40, lazy)", new Color( 0xff0000 ) ) );
// changeHue / changeSaturation / changeLightness / changeAlpha
assertEquals( new Color( 0xffaa00 ), parseColorLazy( "changeHue(dummyColor, 40, lazy)", new Color( 0xff0000 ) ) );
assertEquals( new Color( 0xb34d4d ), parseColorLazy( "changeSaturation(dummyColor, 40%, lazy)", new Color( 0xff0000 ) ) );
assertEquals( new Color( 0xcc0000 ), parseColorLazy( "changeLightness(dummyColor, 40%, lazy)", new Color( 0xff0000 ) ) );
assertEquals( new Color( 0x66ff0000, true ), parseColorLazy( "changeAlpha(dummyColor, 40%, lazy)", new Color( 0xff0000 ) ) );
// mix
assertEquals( new Color( 0x808000 ), parseColorLazy( "mix(#f00, dummyColor, lazy)", new Color( 0x00ff00 ) ) );
assertEquals( new Color( 0xbf4000 ), parseColorLazy( "mix(#f00, dummyColor, 75%, lazy)", new Color( 0x00ff00 ) ) );
// tint
assertEquals( new Color( 0xff80ff ), parseColorLazy( "tint(dummyColor, lazy)", new Color( 0xff00ff ) ) );
assertEquals( new Color( 0xffbfff ), parseColorLazy( "tint(dummyColor, 75%, lazy)", new Color( 0xff00ff ) ) );
// shade
assertEquals( new Color( 0x800080 ), parseColorLazy( "shade(dummyColor, lazy)", new Color( 0xff00ff ) ) );
assertEquals( new Color( 0x400040 ), parseColorLazy( "shade(dummyColor, 75%, lazy)", new Color( 0xff00ff ) ) );
}
@Test
void parseDerivedColorFunctions() {
// mix
assertDerivedColorEquals( new Color( 0x808000 ), "mix(#f00, #0f0, derived)", new Mix2( Color.red, 50 ) );
assertDerivedColorEquals( new Color( 0xbf4000 ), "mix(#f00, #0f0, 75%, derived)", new Mix2( Color.red, 75 ) );
// tint
assertDerivedColorEquals( new Color( 0xff80ff ), "tint(#f0f, derived)", new Mix2( Color.white, 50 ) );
assertDerivedColorEquals( new Color( 0xffbfff ), "tint(#f0f, 75%, derived)", new Mix2( Color.white, 75 ) );
// shade
assertDerivedColorEquals( new Color( 0x800080 ), "shade(#f0f, derived)", new Mix2( Color.black, 50 ) );
assertDerivedColorEquals( new Color( 0x400040 ), "shade(#f0f, 75%, derived)", new Mix2( Color.black, 75 ) );
// lighten
assertDerivedColorEquals( new Color( 0xff6666 ), "lighten(#f00, 20%, derived)", new HSLIncreaseDecrease( 2, true, 20, false, true ) );
assertDerivedColorEquals( new Color( 0xff3333 ), "lighten(#f00, 20%, derived relative)", new HSLIncreaseDecrease( 2, true, 20, true, true ) );
assertDerivedColorEquals( new Color( 0xffffff ), "lighten(#ddd, 20%, derived noAutoInverse)", new HSLIncreaseDecrease( 2, true, 20, false, false ) );
assertDerivedColorEquals( new Color( 0xffffff ), "lighten(#ddd, 20%, derived relative noAutoInverse)", new HSLIncreaseDecrease( 2, true, 20, true, false ) );
// darken
assertDerivedColorEquals( new Color( 0x990000 ), "darken(#f00, 20%, derived)", new HSLIncreaseDecrease( 2, false, 20, false, true ) );
assertDerivedColorEquals( new Color( 0xcc0000 ), "darken(#f00, 20%, derived relative)", new HSLIncreaseDecrease( 2, false, 20, true, true ) );
assertDerivedColorEquals( new Color( 0x000000 ), "darken(#222, 20%, derived noAutoInverse)", new HSLIncreaseDecrease( 2, false, 20, false, false ) );
assertDerivedColorEquals( new Color( 0x1b1b1b ), "darken(#222, 20%, derived relative noAutoInverse)", new HSLIncreaseDecrease( 2, false, 20, true, false ) );
// saturate
assertDerivedColorEquals( new Color( 0xc75a5a ), "saturate(#d44, 20%, derived)", new HSLIncreaseDecrease( 1, true, 20, false, true ) );
assertDerivedColorEquals( new Color( 0xce5353 ), "saturate(#d44, 20%, derived relative)", new HSLIncreaseDecrease( 1, true, 20, true, true ) );
assertDerivedColorEquals( new Color( 0xf32e2e ), "saturate(#d44, 20%, derived noAutoInverse)", new HSLIncreaseDecrease( 1, true, 20, false, false ) );
assertDerivedColorEquals( new Color( 0xec3535 ), "saturate(#d44, 20%, derived relative noAutoInverse)", new HSLIncreaseDecrease( 1, true, 20, true, false ) );
// desaturate
assertDerivedColorEquals( new Color( 0x9c3030 ), "desaturate(#844, 20%, derived)", new HSLIncreaseDecrease( 1, false, 20, false, true ) );
assertDerivedColorEquals( new Color( 0x8f3d3d ), "desaturate(#844, 20%, derived relative)", new HSLIncreaseDecrease( 1, false, 20, true, true ) );
assertDerivedColorEquals( new Color( 0x745858 ), "desaturate(#844, 20%, derived noAutoInverse)", new HSLIncreaseDecrease( 1, false, 20, false, false ) );
assertDerivedColorEquals( new Color( 0x814b4b ), "desaturate(#844, 20%, derived relative noAutoInverse)", new HSLIncreaseDecrease( 1, false, 20, true, false ) );
// fadein
assertDerivedColorEquals( new Color( 0x77ff0000, true ), "fadein(#f00a, 20%, derived)", new HSLIncreaseDecrease( 3, true, 20, false, true ) );
assertDerivedColorEquals( new Color( 0x88ff0000, true ), "fadein(#f00a, 20%, derived relative)", new HSLIncreaseDecrease( 3, true, 20, true, true ) );
assertDerivedColorEquals( new Color( 0xddff0000, true ), "fadein(#f00a, 20%, derived noAutoInverse)", new HSLIncreaseDecrease( 3, true, 20, false, false ) );
assertDerivedColorEquals( new Color( 0xccff0000, true ), "fadein(#f00a, 20%, derived relative noAutoInverse)", new HSLIncreaseDecrease( 3, true, 20, true, false ) );
// fadeout
assertDerivedColorEquals( new Color( 0x77ff0000, true ), "fadeout(#f004, 20%, derived)", new HSLIncreaseDecrease( 3, false, 20, false, true ) );
assertDerivedColorEquals( new Color( 0x52ff0000, true ), "fadeout(#f004, 20%, derived relative)", new HSLIncreaseDecrease( 3, false, 20, true, true ) );
assertDerivedColorEquals( new Color( 0x11ff0000, true ), "fadeout(#f004, 20%, derived noAutoInverse)", new HSLIncreaseDecrease( 3, false, 20, false, false ) );
assertDerivedColorEquals( new Color( 0x36ff0000, true ), "fadeout(#f004, 20%, derived relative noAutoInverse)", new HSLIncreaseDecrease( 3, false, 20, true, false ) );
// fade
assertDerivedColorEquals( new Color( 0x33ff0000, true ), "fade(#f00, 20%, derived)", new Fade( 20 ) );
assertDerivedColorEquals( new Color( 0xccff0000, true ), "fade(#ff000010, 80%, derived)", new Fade( 80 ) );
// spin
assertDerivedColorEquals( new Color( 0xffaa00 ), "spin(#f00, 40, derived)", new HSLIncreaseDecrease( 0, true, 40, false, false ) );
assertDerivedColorEquals( new Color( 0xff00aa ), "spin(#f00, -40, derived)", new HSLIncreaseDecrease( 0, true, -40, false, false ) );
// changeHue / changeSaturation / changeLightness / changeAlpha
assertDerivedColorEquals( new Color( 0xffaa00 ), "changeHue(#f00, 40, derived)", new HSLChange( 0, 40 ) );
assertDerivedColorEquals( new Color( 0xb34d4d ), "changeSaturation(#f00, 40%, derived)", new HSLChange( 1, 40 ) );
assertDerivedColorEquals( new Color( 0xcc0000 ), "changeLightness(#f00, 40%, derived)", new HSLChange( 2, 40 ) );
assertDerivedColorEquals( new Color( 0x66ff0000, true ), "changeAlpha(#f00, 40%, derived)", new HSLChange( 3, 40 ) );
// mix
assertDerivedColorEquals( new Color( 0x808000 ), "mix(#f00, #0f0, derived)", new Mix2( new Color( 0xff0000 ), 50 ) );
assertDerivedColorEquals( new Color( 0xbf4000 ), "mix(#f00, #0f0, 75%, derived)", new Mix2( new Color( 0xff0000 ), 75 ) );
// tint
assertDerivedColorEquals( new Color( 0xff80ff ), "tint(#f0f, derived)", new Mix2( new Color( 0xffffff ), 50 ) );
assertDerivedColorEquals( new Color( 0xffbfff ), "tint(#f0f, 75%, derived)", new Mix2( new Color( 0xffffff ), 75 ) );
// shade
assertDerivedColorEquals( new Color( 0x800080 ), "shade(#f0f, derived)", new Mix2( new Color( 0x000000 ), 50 ) );
assertDerivedColorEquals( new Color( 0x400040 ), "shade(#f0f, 75%, derived)", new Mix2( new Color( 0x000000 ), 75 ) );
}
private void assertDerivedColorEquals( Color expectedColor, String actualStyle, ColorFunction... expectedFunctions ) {
Object actual = parseColor( actualStyle );
assertInstanceOf( DerivedColor.class, actual );
assertEquals( expectedColor, actual );
ColorFunction[] actualFunctions = ((DerivedColor)actual).getFunctions();
assertEquals( expectedFunctions.length, actualFunctions.length );
for( int i = 0; i < expectedFunctions.length; i++ )
assertColorFunctionEquals( expectedFunctions[i], actualFunctions[i] );
}
private void assertColorFunctionEquals( ColorFunction expected, ColorFunction actual ) {
assertEquals( expected.getClass(), actual.getClass() );
if( expected instanceof HSLIncreaseDecrease ) {
HSLIncreaseDecrease e = (HSLIncreaseDecrease) expected;
HSLIncreaseDecrease a = (HSLIncreaseDecrease) actual;
assertEquals( e.hslIndex, a.hslIndex );
assertEquals( e.increase, a.increase );
assertEquals( e.amount, a.amount );
assertEquals( e.relative, a.relative );
assertEquals( e.autoInverse, a.autoInverse );
} else if( expected instanceof HSLChange ) {
HSLChange e = (HSLChange) expected;
HSLChange a = (HSLChange) actual;
assertEquals( e.hslIndex, a.hslIndex );
assertEquals( e.value, a.value );
} else if( expected instanceof Fade ) {
Fade e = (Fade) expected;
Fade a = (Fade) actual;
assertEquals( e.amount, a.amount );
} else if( expected instanceof Mix ) {
Mix e = (Mix) expected;
Mix a = (Mix) actual;
assertEquals( e.color2, a.color2 );
assertEquals( e.weight, a.weight );
} else if( expected instanceof Mix2 ) {
Mix2 e = (Mix2) expected;
Mix2 a = (Mix2) actual;
assertEquals( e.color1, a.color1 );
assertEquals( e.weight, a.weight );
} else
assertTrue( false );
}
private Object parseColor( String value ) {
return UIDefaultsLoader.parseValue( "dummyColor", value, null );
}
private Object parseColorLazy( String value, Color actual ) {
UIManager.put( "dummyColor", actual );
Object v = UIDefaultsLoader.parseValue( "dummyColor", value, null );
assertInstanceOf( LazyValue.class, v );
return ((LazyValue)v).createValue( null );
}
//---- class TestInstance ------------------------------------------------- //---- class TestInstance -------------------------------------------------
@SuppressWarnings( "EqualsHashCode" ) // Error Prone @SuppressWarnings( "EqualsHashCode" ) // Error Prone

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, "selectionForeground", Color.class,
"selectionInactiveBackground", Color.class, "selectionInactiveBackground", Color.class,
"selectionInactiveForeground", Color.class, "selectionInactiveForeground", Color.class,
"alternateRowColor", Color.class,
"selectionInsets", Insets.class, "selectionInsets", Insets.class,
"selectionArc", int.class, "selectionArc", int.class,
@@ -517,6 +518,8 @@ public class TestFlatStyleableInfo
"icon.borderWidth", float.class, "icon.borderWidth", float.class,
"icon.selectedBorderWidth", float.class, "icon.selectedBorderWidth", float.class,
"icon.disabledSelectedBorderWidth", float.class, "icon.disabledSelectedBorderWidth", float.class,
"icon.indeterminateBorderWidth", float.class,
"icon.disabledIndeterminateBorderWidth", float.class,
"icon.arc", int.class, "icon.arc", int.class,
// enabled // enabled
@@ -525,6 +528,9 @@ public class TestFlatStyleableInfo
"icon.selectedBorderColor", Color.class, "icon.selectedBorderColor", Color.class,
"icon.selectedBackground", Color.class, "icon.selectedBackground", Color.class,
"icon.checkmarkColor", Color.class, "icon.checkmarkColor", Color.class,
"icon.indeterminateBorderColor", Color.class,
"icon.indeterminateBackground", Color.class,
"icon.indeterminateCheckmarkColor", Color.class,
// disabled // disabled
"icon.disabledBorderColor", Color.class, "icon.disabledBorderColor", Color.class,
@@ -532,6 +538,9 @@ public class TestFlatStyleableInfo
"icon.disabledSelectedBorderColor", Color.class, "icon.disabledSelectedBorderColor", Color.class,
"icon.disabledSelectedBackground", Color.class, "icon.disabledSelectedBackground", Color.class,
"icon.disabledCheckmarkColor", Color.class, "icon.disabledCheckmarkColor", Color.class,
"icon.disabledIndeterminateBorderColor", Color.class,
"icon.disabledIndeterminateBackground", Color.class,
"icon.disabledIndeterminateCheckmarkColor", Color.class,
// focused // focused
"icon.focusedBorderColor", Color.class, "icon.focusedBorderColor", Color.class,
@@ -539,6 +548,9 @@ public class TestFlatStyleableInfo
"icon.focusedSelectedBorderColor", Color.class, "icon.focusedSelectedBorderColor", Color.class,
"icon.focusedSelectedBackground", Color.class, "icon.focusedSelectedBackground", Color.class,
"icon.focusedCheckmarkColor", Color.class, "icon.focusedCheckmarkColor", Color.class,
"icon.focusedIndeterminateBorderColor", Color.class,
"icon.focusedIndeterminateBackground", Color.class,
"icon.focusedIndeterminateCheckmarkColor", Color.class,
// hover // hover
"icon.hoverBorderColor", Color.class, "icon.hoverBorderColor", Color.class,
@@ -546,13 +558,19 @@ public class TestFlatStyleableInfo
"icon.hoverSelectedBorderColor", Color.class, "icon.hoverSelectedBorderColor", Color.class,
"icon.hoverSelectedBackground", Color.class, "icon.hoverSelectedBackground", Color.class,
"icon.hoverCheckmarkColor", Color.class, "icon.hoverCheckmarkColor", Color.class,
"icon.hoverIndeterminateBorderColor", Color.class,
"icon.hoverIndeterminateBackground", Color.class,
"icon.hoverIndeterminateCheckmarkColor", Color.class,
// pressed // pressed
"icon.pressedBorderColor", Color.class, "icon.pressedBorderColor", Color.class,
"icon.pressedBackground", Color.class, "icon.pressedBackground", Color.class,
"icon.pressedSelectedBorderColor", Color.class, "icon.pressedSelectedBorderColor", Color.class,
"icon.pressedSelectedBackground", 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, "selectionInactiveBackground", Color.class,
"selectionInactiveForeground", Color.class, "selectionInactiveForeground", Color.class,
"selectionBorderColor", Color.class, "selectionBorderColor", Color.class,
"alternateRowColor", Color.class,
"selectionInsets", Insets.class, "selectionInsets", Insets.class,
"selectionArc", int.class, "selectionArc", int.class,
"wideSelection", boolean.class, "wideSelection", boolean.class,
"wideCellRenderer", boolean.class,
"showCellFocusIndicator", boolean.class, "showCellFocusIndicator", boolean.class,
"paintSelection", boolean.class, "paintSelection", boolean.class,
@@ -1060,6 +1080,8 @@ public class TestFlatStyleableInfo
"error.focusedBorderColor", Color.class, "error.focusedBorderColor", Color.class,
"warning.borderColor", Color.class, "warning.borderColor", Color.class,
"warning.focusedBorderColor", Color.class, "warning.focusedBorderColor", Color.class,
"success.borderColor", Color.class,
"success.focusedBorderColor", Color.class,
"custom.borderColor", Color.class, "custom.borderColor", Color.class,
"outline", String.class, "outline", String.class,
@@ -1144,6 +1166,8 @@ public class TestFlatStyleableInfo
"borderWidth", float.class, "borderWidth", float.class,
"selectedBorderWidth", float.class, "selectedBorderWidth", float.class,
"disabledSelectedBorderWidth", float.class, "disabledSelectedBorderWidth", float.class,
"indeterminateBorderWidth", float.class,
"disabledIndeterminateBorderWidth", float.class,
"arc", int.class, "arc", int.class,
// enabled // enabled
@@ -1152,6 +1176,9 @@ public class TestFlatStyleableInfo
"selectedBorderColor", Color.class, "selectedBorderColor", Color.class,
"selectedBackground", Color.class, "selectedBackground", Color.class,
"checkmarkColor", Color.class, "checkmarkColor", Color.class,
"indeterminateBorderColor", Color.class,
"indeterminateBackground", Color.class,
"indeterminateCheckmarkColor", Color.class,
// disabled // disabled
"disabledBorderColor", Color.class, "disabledBorderColor", Color.class,
@@ -1159,6 +1186,9 @@ public class TestFlatStyleableInfo
"disabledSelectedBorderColor", Color.class, "disabledSelectedBorderColor", Color.class,
"disabledSelectedBackground", Color.class, "disabledSelectedBackground", Color.class,
"disabledCheckmarkColor", Color.class, "disabledCheckmarkColor", Color.class,
"disabledIndeterminateBorderColor", Color.class,
"disabledIndeterminateBackground", Color.class,
"disabledIndeterminateCheckmarkColor", Color.class,
// focused // focused
"focusedBorderColor", Color.class, "focusedBorderColor", Color.class,
@@ -1166,6 +1196,9 @@ public class TestFlatStyleableInfo
"focusedSelectedBorderColor", Color.class, "focusedSelectedBorderColor", Color.class,
"focusedSelectedBackground", Color.class, "focusedSelectedBackground", Color.class,
"focusedCheckmarkColor", Color.class, "focusedCheckmarkColor", Color.class,
"focusedIndeterminateBorderColor", Color.class,
"focusedIndeterminateBackground", Color.class,
"focusedIndeterminateCheckmarkColor", Color.class,
// hover // hover
"hoverBorderColor", Color.class, "hoverBorderColor", Color.class,
@@ -1173,13 +1206,19 @@ public class TestFlatStyleableInfo
"hoverSelectedBorderColor", Color.class, "hoverSelectedBorderColor", Color.class,
"hoverSelectedBackground", Color.class, "hoverSelectedBackground", Color.class,
"hoverCheckmarkColor", Color.class, "hoverCheckmarkColor", Color.class,
"hoverIndeterminateBorderColor", Color.class,
"hoverIndeterminateBackground", Color.class,
"hoverIndeterminateCheckmarkColor", Color.class,
// pressed // pressed
"pressedBorderColor", Color.class, "pressedBorderColor", Color.class,
"pressedBackground", Color.class, "pressedBackground", Color.class,
"pressedSelectedBorderColor", Color.class, "pressedSelectedBorderColor", Color.class,
"pressedSelectedBackground", 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, "selectionForeground", 0x123456 );
testColor( c, ui, "selectionInactiveBackground", 0x123456 ); testColor( c, ui, "selectionInactiveBackground", 0x123456 );
testColor( c, ui, "selectionInactiveForeground", 0x123456 ); testColor( c, ui, "selectionInactiveForeground", 0x123456 );
testColor( c, ui, "alternateRowColor", 0x123456 );
testInsets( c, ui, "selectionInsets", 1,2,3,4 ); testInsets( c, ui, "selectionInsets", 1,2,3,4 );
testInteger( c, ui, "selectionArc", 123 ); testInteger( c, ui, "selectionArc", 123 );
@@ -938,9 +939,11 @@ public class TestFlatStyleableValue
testColor( c, ui, "selectionInactiveBackground", 0x123456 ); testColor( c, ui, "selectionInactiveBackground", 0x123456 );
testColor( c, ui, "selectionInactiveForeground", 0x123456 ); testColor( c, ui, "selectionInactiveForeground", 0x123456 );
testColor( c, ui, "selectionBorderColor", 0x123456 ); testColor( c, ui, "selectionBorderColor", 0x123456 );
testColor( c, ui, "alternateRowColor", 0x123456 );
testInsets( c, ui, "selectionInsets", 1,2,3,4 ); testInsets( c, ui, "selectionInsets", 1,2,3,4 );
testInteger( c, ui, "selectionArc", 123 ); testInteger( c, ui, "selectionArc", 123 );
testBoolean( c, ui, "wideSelection", true ); testBoolean( c, ui, "wideSelection", true );
testBoolean( c, ui, "wideCellRenderer", true );
testBoolean( c, ui, "showCellFocusIndicator", true ); testBoolean( c, ui, "showCellFocusIndicator", true );
testBoolean( c, ui, "paintSelection", false ); testBoolean( c, ui, "paintSelection", false );
@@ -1021,6 +1024,8 @@ public class TestFlatStyleableValue
testColor( c, ui, "error.focusedBorderColor", 0x123456 ); testColor( c, ui, "error.focusedBorderColor", 0x123456 );
testColor( c, ui, "warning.borderColor", 0x123456 ); testColor( c, ui, "warning.borderColor", 0x123456 );
testColor( c, ui, "warning.focusedBorderColor", 0x123456 ); testColor( c, ui, "warning.focusedBorderColor", 0x123456 );
testColor( c, ui, "success.borderColor", 0x123456 );
testColor( c, ui, "success.focusedBorderColor", 0x123456 );
testColor( c, ui, "custom.borderColor", 0x123456 ); testColor( c, ui, "custom.borderColor", 0x123456 );
testString( c, ui, "outline", "error" ); testString( c, ui, "outline", "error" );
@@ -1118,6 +1123,8 @@ public class TestFlatStyleableValue
testValue( border, "error.focusedBorderColor", Color.WHITE ); testValue( border, "error.focusedBorderColor", Color.WHITE );
testValue( border, "warning.borderColor", Color.WHITE ); testValue( border, "warning.borderColor", Color.WHITE );
testValue( border, "warning.focusedBorderColor", Color.WHITE ); testValue( border, "warning.focusedBorderColor", Color.WHITE );
testValue( border, "success.borderColor", Color.WHITE );
testValue( border, "success.focusedBorderColor", Color.WHITE );
testValue( border, "custom.borderColor", Color.WHITE ); testValue( border, "custom.borderColor", Color.WHITE );
} }
@@ -1146,6 +1153,8 @@ public class TestFlatStyleableValue
testValue( icon, "borderWidth", 1.5f ); testValue( icon, "borderWidth", 1.5f );
testValue( icon, "selectedBorderWidth", 1.5f ); testValue( icon, "selectedBorderWidth", 1.5f );
testValue( icon, "disabledSelectedBorderWidth", 1.5f ); testValue( icon, "disabledSelectedBorderWidth", 1.5f );
testValue( icon, "indeterminateBorderWidth", 1.5f );
testValue( icon, "disabledIndeterminateBorderWidth", 1.5f );
testValue( icon, "arc", 5 ); testValue( icon, "arc", 5 );
// enabled // enabled
@@ -1154,6 +1163,9 @@ public class TestFlatStyleableValue
testValue( icon, "selectedBorderColor", Color.WHITE ); testValue( icon, "selectedBorderColor", Color.WHITE );
testValue( icon, "selectedBackground", Color.WHITE ); testValue( icon, "selectedBackground", Color.WHITE );
testValue( icon, "checkmarkColor", Color.WHITE ); testValue( icon, "checkmarkColor", Color.WHITE );
testValue( icon, "indeterminateBorderColor", Color.WHITE );
testValue( icon, "indeterminateBackground", Color.WHITE );
testValue( icon, "indeterminateCheckmarkColor", Color.WHITE );
// disabled // disabled
testValue( icon, "disabledBorderColor", Color.WHITE ); testValue( icon, "disabledBorderColor", Color.WHITE );
@@ -1161,6 +1173,9 @@ public class TestFlatStyleableValue
testValue( icon, "disabledSelectedBorderColor", Color.WHITE ); testValue( icon, "disabledSelectedBorderColor", Color.WHITE );
testValue( icon, "disabledSelectedBackground", Color.WHITE ); testValue( icon, "disabledSelectedBackground", Color.WHITE );
testValue( icon, "disabledCheckmarkColor", Color.WHITE ); testValue( icon, "disabledCheckmarkColor", Color.WHITE );
testValue( icon, "disabledIndeterminateBorderColor", Color.WHITE );
testValue( icon, "disabledIndeterminateBackground", Color.WHITE );
testValue( icon, "disabledIndeterminateCheckmarkColor", Color.WHITE );
// focused // focused
testValue( icon, "focusedBorderColor", Color.WHITE ); testValue( icon, "focusedBorderColor", Color.WHITE );
@@ -1168,6 +1183,9 @@ public class TestFlatStyleableValue
testValue( icon, "focusedSelectedBorderColor", Color.WHITE ); testValue( icon, "focusedSelectedBorderColor", Color.WHITE );
testValue( icon, "focusedSelectedBackground", Color.WHITE ); testValue( icon, "focusedSelectedBackground", Color.WHITE );
testValue( icon, "focusedCheckmarkColor", Color.WHITE ); testValue( icon, "focusedCheckmarkColor", Color.WHITE );
testValue( icon, "focusedIndeterminateBorderColor", Color.WHITE );
testValue( icon, "focusedIndeterminateBackground", Color.WHITE );
testValue( icon, "focusedIndeterminateCheckmarkColor", Color.WHITE );
// hover // hover
testValue( icon, "hoverBorderColor", Color.WHITE ); testValue( icon, "hoverBorderColor", Color.WHITE );
@@ -1175,6 +1193,9 @@ public class TestFlatStyleableValue
testValue( icon, "hoverSelectedBorderColor", Color.WHITE ); testValue( icon, "hoverSelectedBorderColor", Color.WHITE );
testValue( icon, "hoverSelectedBackground", Color.WHITE ); testValue( icon, "hoverSelectedBackground", Color.WHITE );
testValue( icon, "hoverCheckmarkColor", Color.WHITE ); testValue( icon, "hoverCheckmarkColor", Color.WHITE );
testValue( icon, "hoverIndeterminateBorderColor", Color.WHITE );
testValue( icon, "hoverIndeterminateBackground", Color.WHITE );
testValue( icon, "hoverIndeterminateCheckmarkColor", Color.WHITE );
// pressed // pressed
testValue( icon, "pressedBorderColor", Color.WHITE ); testValue( icon, "pressedBorderColor", Color.WHITE );
@@ -1182,6 +1203,9 @@ public class TestFlatStyleableValue
testValue( icon, "pressedSelectedBorderColor", Color.WHITE ); testValue( icon, "pressedSelectedBorderColor", Color.WHITE );
testValue( icon, "pressedSelectedBackground", Color.WHITE ); testValue( icon, "pressedSelectedBackground", Color.WHITE );
testValue( icon, "pressedCheckmarkColor", Color.WHITE ); testValue( icon, "pressedCheckmarkColor", Color.WHITE );
testValue( icon, "pressedIndeterminateBorderColor", Color.WHITE );
testValue( icon, "pressedIndeterminateBackground", Color.WHITE );
testValue( icon, "pressedIndeterminateCheckmarkColor", Color.WHITE );
} }
@Test @Test

View File

@@ -433,6 +433,7 @@ public class TestFlatStyling
ui.applyStyle( "selectionForeground: #fff" ); ui.applyStyle( "selectionForeground: #fff" );
ui.applyStyle( "selectionInactiveBackground: #fff" ); ui.applyStyle( "selectionInactiveBackground: #fff" );
ui.applyStyle( "selectionInactiveForeground: #fff" ); ui.applyStyle( "selectionInactiveForeground: #fff" );
ui.applyStyle( "alternateRowColor: #fff" );
ui.applyStyle( "selectionInsets: 1,2,3,4" ); ui.applyStyle( "selectionInsets: 1,2,3,4" );
ui.applyStyle( "selectionArc: 8" ); ui.applyStyle( "selectionArc: 8" );
@@ -1187,9 +1188,11 @@ public class TestFlatStyling
ui.applyStyle( "selectionInactiveBackground: #fff" ); ui.applyStyle( "selectionInactiveBackground: #fff" );
ui.applyStyle( "selectionInactiveForeground: #fff" ); ui.applyStyle( "selectionInactiveForeground: #fff" );
ui.applyStyle( "selectionBorderColor: #fff" ); ui.applyStyle( "selectionBorderColor: #fff" );
ui.applyStyle( "alternateRowColor: #fff" );
ui.applyStyle( "selectionInsets: 1,2,3,4" ); ui.applyStyle( "selectionInsets: 1,2,3,4" );
ui.applyStyle( "selectionArc: 8" ); ui.applyStyle( "selectionArc: 8" );
ui.applyStyle( "wideSelection: true" ); ui.applyStyle( "wideSelection: true" );
ui.applyStyle( "wideCellRenderer: true" );
ui.applyStyle( "showCellFocusIndicator: true" ); ui.applyStyle( "showCellFocusIndicator: true" );
ui.applyStyle( "paintSelection: false" ); ui.applyStyle( "paintSelection: false" );
@@ -1275,6 +1278,8 @@ public class TestFlatStyling
applyStyle.accept( "error.focusedBorderColor: #fff" ); applyStyle.accept( "error.focusedBorderColor: #fff" );
applyStyle.accept( "warning.borderColor: #fff" ); applyStyle.accept( "warning.borderColor: #fff" );
applyStyle.accept( "warning.focusedBorderColor: #fff" ); applyStyle.accept( "warning.focusedBorderColor: #fff" );
applyStyle.accept( "success.borderColor: #fff" );
applyStyle.accept( "success.focusedBorderColor: #fff" );
applyStyle.accept( "custom.borderColor: desaturate(#f00,50%,relative derived noAutoInverse)" ); applyStyle.accept( "custom.borderColor: desaturate(#f00,50%,relative derived noAutoInverse)" );
applyStyle.accept( "outline: error" ); applyStyle.accept( "outline: error" );
@@ -1360,6 +1365,8 @@ public class TestFlatStyling
border.applyStyleProperty( "error.focusedBorderColor", Color.WHITE ); border.applyStyleProperty( "error.focusedBorderColor", Color.WHITE );
border.applyStyleProperty( "warning.borderColor", Color.WHITE ); border.applyStyleProperty( "warning.borderColor", Color.WHITE );
border.applyStyleProperty( "warning.focusedBorderColor", Color.WHITE ); border.applyStyleProperty( "warning.focusedBorderColor", Color.WHITE );
border.applyStyleProperty( "success.borderColor", Color.WHITE );
border.applyStyleProperty( "success.focusedBorderColor", Color.WHITE );
border.applyStyleProperty( "custom.borderColor", Color.WHITE ); border.applyStyleProperty( "custom.borderColor", Color.WHITE );
} }
@@ -1388,6 +1395,8 @@ public class TestFlatStyling
icon.applyStyleProperty( "borderWidth", 1.5f ); icon.applyStyleProperty( "borderWidth", 1.5f );
icon.applyStyleProperty( "selectedBorderWidth", 1.5f ); icon.applyStyleProperty( "selectedBorderWidth", 1.5f );
icon.applyStyleProperty( "disabledSelectedBorderWidth", 1.5f ); icon.applyStyleProperty( "disabledSelectedBorderWidth", 1.5f );
icon.applyStyleProperty( "indeterminateBorderWidth", 1.5f );
icon.applyStyleProperty( "disabledIndeterminateBorderWidth", 1.5f );
icon.applyStyleProperty( "arc", 5 ); icon.applyStyleProperty( "arc", 5 );
// enabled // enabled
@@ -1396,6 +1405,9 @@ public class TestFlatStyling
icon.applyStyleProperty( "selectedBorderColor", Color.WHITE ); icon.applyStyleProperty( "selectedBorderColor", Color.WHITE );
icon.applyStyleProperty( "selectedBackground", Color.WHITE ); icon.applyStyleProperty( "selectedBackground", Color.WHITE );
icon.applyStyleProperty( "checkmarkColor", Color.WHITE ); icon.applyStyleProperty( "checkmarkColor", Color.WHITE );
icon.applyStyleProperty( "indeterminateBorderColor", Color.WHITE );
icon.applyStyleProperty( "indeterminateBackground", Color.WHITE );
icon.applyStyleProperty( "indeterminateCheckmarkColor", Color.WHITE );
// disabled // disabled
icon.applyStyleProperty( "disabledBorderColor", Color.WHITE ); icon.applyStyleProperty( "disabledBorderColor", Color.WHITE );
@@ -1403,6 +1415,9 @@ public class TestFlatStyling
icon.applyStyleProperty( "disabledSelectedBorderColor", Color.WHITE ); icon.applyStyleProperty( "disabledSelectedBorderColor", Color.WHITE );
icon.applyStyleProperty( "disabledSelectedBackground", Color.WHITE ); icon.applyStyleProperty( "disabledSelectedBackground", Color.WHITE );
icon.applyStyleProperty( "disabledCheckmarkColor", Color.WHITE ); icon.applyStyleProperty( "disabledCheckmarkColor", Color.WHITE );
icon.applyStyleProperty( "disabledIndeterminateBorderColor", Color.WHITE );
icon.applyStyleProperty( "disabledIndeterminateBackground", Color.WHITE );
icon.applyStyleProperty( "disabledIndeterminateCheckmarkColor", Color.WHITE );
// focused // focused
icon.applyStyleProperty( "focusedBorderColor", Color.WHITE ); icon.applyStyleProperty( "focusedBorderColor", Color.WHITE );
@@ -1410,6 +1425,9 @@ public class TestFlatStyling
icon.applyStyleProperty( "focusedSelectedBorderColor", Color.WHITE ); icon.applyStyleProperty( "focusedSelectedBorderColor", Color.WHITE );
icon.applyStyleProperty( "focusedSelectedBackground", Color.WHITE ); icon.applyStyleProperty( "focusedSelectedBackground", Color.WHITE );
icon.applyStyleProperty( "focusedCheckmarkColor", Color.WHITE ); icon.applyStyleProperty( "focusedCheckmarkColor", Color.WHITE );
icon.applyStyleProperty( "focusedIndeterminateBorderColor", Color.WHITE );
icon.applyStyleProperty( "focusedIndeterminateBackground", Color.WHITE );
icon.applyStyleProperty( "focusedIndeterminateCheckmarkColor", Color.WHITE );
// hover // hover
icon.applyStyleProperty( "hoverBorderColor", Color.WHITE ); icon.applyStyleProperty( "hoverBorderColor", Color.WHITE );
@@ -1417,6 +1435,9 @@ public class TestFlatStyling
icon.applyStyleProperty( "hoverSelectedBorderColor", Color.WHITE ); icon.applyStyleProperty( "hoverSelectedBorderColor", Color.WHITE );
icon.applyStyleProperty( "hoverSelectedBackground", Color.WHITE ); icon.applyStyleProperty( "hoverSelectedBackground", Color.WHITE );
icon.applyStyleProperty( "hoverCheckmarkColor", Color.WHITE ); icon.applyStyleProperty( "hoverCheckmarkColor", Color.WHITE );
icon.applyStyleProperty( "hoverIndeterminateBorderColor", Color.WHITE );
icon.applyStyleProperty( "hoverIndeterminateBackground", Color.WHITE );
icon.applyStyleProperty( "hoverIndeterminateCheckmarkColor", Color.WHITE );
// pressed // pressed
icon.applyStyleProperty( "pressedBorderColor", Color.WHITE ); icon.applyStyleProperty( "pressedBorderColor", Color.WHITE );
@@ -1424,6 +1445,9 @@ public class TestFlatStyling
icon.applyStyleProperty( "pressedSelectedBorderColor", Color.WHITE ); icon.applyStyleProperty( "pressedSelectedBorderColor", Color.WHITE );
icon.applyStyleProperty( "pressedSelectedBackground", Color.WHITE ); icon.applyStyleProperty( "pressedSelectedBackground", Color.WHITE );
icon.applyStyleProperty( "pressedCheckmarkColor", Color.WHITE ); icon.applyStyleProperty( "pressedCheckmarkColor", Color.WHITE );
icon.applyStyleProperty( "pressedIndeterminateBorderColor", Color.WHITE );
icon.applyStyleProperty( "pressedIndeterminateBackground", Color.WHITE );
icon.applyStyleProperty( "pressedIndeterminateCheckmarkColor", Color.WHITE );
} }
@Test @Test

View File

@@ -1,4 +1,7 @@
eclipse.preferences.version=1 eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.source=1.8
org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false
org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647 org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.align_type_members_on_columns=false

View File

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

View File

@@ -179,14 +179,10 @@ class BasicComponentsPanel
JScrollPane scrollPane12 = new JScrollPane(); JScrollPane scrollPane12 = new JScrollPane();
JTextPane textPane4 = new JTextPane(); JTextPane textPane4 = new JTextPane();
JTextPane textPane5 = new JTextPane(); JTextPane textPane5 = new JTextPane();
JLabel errorHintsLabel = new JLabel(); JLabel hintsLabel = new JLabel();
JTextField errorHintsTextField = new JTextField(); JTextField errorHintsTextField = new JTextField();
JComboBox<String> errorHintsComboBox = new JComboBox<>();
JSpinner errorHintsSpinner = new JSpinner();
JLabel warningHintsLabel = new JLabel();
JTextField warningHintsTextField = new JTextField(); JTextField warningHintsTextField = new JTextField();
JComboBox<String> warningHintsComboBox = new JComboBox<>(); JTextField successHintsTextField = new JTextField();
JSpinner warningHintsSpinner = new JSpinner();
JLabel iconsLabel = new JLabel(); JLabel iconsLabel = new JLabel();
leadingIconTextField = new JTextField(); leadingIconTextField = new JTextField();
trailingIconTextField = new JTextField(); trailingIconTextField = new JTextField();
@@ -241,7 +237,6 @@ class BasicComponentsPanel
"[]" + "[]" +
"[]" + "[]" +
"[]" + "[]" +
"[]" +
"[]0" + "[]0" +
"[]")); "[]"));
@@ -277,22 +272,22 @@ class BasicComponentsPanel
//---- button5 ---- //---- button5 ----
button5.setText("Square"); button5.setText("Square");
button5.putClientProperty("JButton.buttonType", "square"); button5.putClientProperty(FlatClientProperties.BUTTON_TYPE, FlatClientProperties.BUTTON_TYPE_SQUARE);
add(button5, "cell 3 1"); add(button5, "cell 3 1");
//---- button6 ---- //---- button6 ----
button6.setText("Round"); button6.setText("Round");
button6.putClientProperty("JButton.buttonType", "roundRect"); button6.putClientProperty(FlatClientProperties.BUTTON_TYPE, FlatClientProperties.BUTTON_TYPE_ROUND_RECT);
add(button6, "cell 4 1"); add(button6, "cell 4 1");
//---- button3 ---- //---- button3 ----
button3.setText("Help"); button3.setText("Help");
button3.putClientProperty("JButton.buttonType", "help"); button3.putClientProperty(FlatClientProperties.BUTTON_TYPE, FlatClientProperties.BUTTON_TYPE_HELP);
add(button3, "cell 4 1"); add(button3, "cell 4 1");
//---- button4 ---- //---- button4 ----
button4.setText("Help"); button4.setText("Help");
button4.putClientProperty("JButton.buttonType", "help"); button4.putClientProperty(FlatClientProperties.BUTTON_TYPE, FlatClientProperties.BUTTON_TYPE_HELP);
button4.setEnabled(false); button4.setEnabled(false);
add(button4, "cell 4 1"); add(button4, "cell 4 1");
@@ -432,7 +427,7 @@ class BasicComponentsPanel
//---- comboBox6 ---- //---- comboBox6 ----
comboBox6.setEditable(true); comboBox6.setEditable(true);
comboBox6.putClientProperty("JTextField.placeholderText", "Placeholder"); comboBox6.putClientProperty(FlatClientProperties.PLACEHOLDER_TEXT, "Placeholder");
add(comboBox6, "cell 5 5,growx"); add(comboBox6, "cell 5 5,growx");
//---- textFieldLabel ---- //---- textFieldLabel ----
@@ -463,7 +458,7 @@ class BasicComponentsPanel
add(textField4, "cell 4 6,growx"); add(textField4, "cell 4 6,growx");
//---- textField6 ---- //---- textField6 ----
textField6.putClientProperty("JTextField.placeholderText", "Placeholder"); textField6.putClientProperty(FlatClientProperties.PLACEHOLDER_TEXT, "Placeholder");
add(textField6, "cell 5 6,growx"); add(textField6, "cell 5 6,growx");
//---- formattedTextFieldLabel ---- //---- formattedTextFieldLabel ----
@@ -494,7 +489,7 @@ class BasicComponentsPanel
add(formattedTextField4, "cell 4 7,growx"); add(formattedTextField4, "cell 4 7,growx");
//---- formattedTextField5 ---- //---- formattedTextField5 ----
formattedTextField5.putClientProperty("JTextField.placeholderText", "Placeholder"); formattedTextField5.putClientProperty(FlatClientProperties.PLACEHOLDER_TEXT, "Placeholder");
add(formattedTextField5, "cell 5 7,growx"); add(formattedTextField5, "cell 5 7,growx");
//---- passwordFieldLabel ---- //---- passwordFieldLabel ----
@@ -522,7 +517,7 @@ class BasicComponentsPanel
add(passwordField4, "cell 4 8,growx"); add(passwordField4, "cell 4 8,growx");
//---- passwordField5 ---- //---- passwordField5 ----
passwordField5.putClientProperty("JTextField.placeholderText", "Placeholder"); passwordField5.putClientProperty(FlatClientProperties.PLACEHOLDER_TEXT, "Placeholder");
add(passwordField5, "cell 5 8,growx"); add(passwordField5, "cell 5 8,growx");
//---- textAreaLabel ---- //---- textAreaLabel ----
@@ -698,145 +693,122 @@ class BasicComponentsPanel
textPane5.setText("No scroll pane"); textPane5.setText("No scroll pane");
add(textPane5, "cell 5 11,growx"); add(textPane5, "cell 5 11,growx");
//---- errorHintsLabel ---- //---- hintsLabel ----
errorHintsLabel.setText("Error hints:"); hintsLabel.setText("Error/warning/success:");
add(errorHintsLabel, "cell 0 12"); add(hintsLabel, "cell 0 12");
//---- errorHintsTextField ---- //---- errorHintsTextField ----
errorHintsTextField.putClientProperty("JComponent.outline", "error"); errorHintsTextField.putClientProperty(FlatClientProperties.OUTLINE, FlatClientProperties.OUTLINE_ERROR);
add(errorHintsTextField, "cell 1 12,growx"); add(errorHintsTextField, "cell 1 12,growx");
//---- errorHintsComboBox ----
errorHintsComboBox.putClientProperty("JComponent.outline", "error");
errorHintsComboBox.setModel(new DefaultComboBoxModel<>(new String[] {
"Editable"
}));
errorHintsComboBox.setEditable(true);
add(errorHintsComboBox, "cell 2 12,growx");
//---- errorHintsSpinner ----
errorHintsSpinner.putClientProperty("JComponent.outline", "error");
add(errorHintsSpinner, "cell 3 12,growx");
//---- warningHintsLabel ----
warningHintsLabel.setText("Warning hints:");
add(warningHintsLabel, "cell 0 13");
//---- warningHintsTextField ---- //---- warningHintsTextField ----
warningHintsTextField.putClientProperty("JComponent.outline", "warning"); warningHintsTextField.putClientProperty(FlatClientProperties.OUTLINE, FlatClientProperties.OUTLINE_WARNING);
add(warningHintsTextField, "cell 1 13,growx"); add(warningHintsTextField, "cell 2 12,growx");
//---- warningHintsComboBox ---- //---- successHintsTextField ----
warningHintsComboBox.putClientProperty("JComponent.outline", "warning"); successHintsTextField.putClientProperty(FlatClientProperties.OUTLINE, "success");
warningHintsComboBox.setModel(new DefaultComboBoxModel<>(new String[] { add(successHintsTextField, "cell 3 12,growx");
"Not editable"
}));
add(warningHintsComboBox, "cell 2 13,growx");
//---- warningHintsSpinner ----
warningHintsSpinner.putClientProperty("JComponent.outline", "warning");
add(warningHintsSpinner, "cell 3 13,growx");
//---- iconsLabel ---- //---- iconsLabel ----
iconsLabel.setText("Leading/trailing icons:"); iconsLabel.setText("Leading/trailing icons:");
add(iconsLabel, "cell 0 14"); add(iconsLabel, "cell 0 13");
add(leadingIconTextField, "cell 1 14,growx"); add(leadingIconTextField, "cell 1 13,growx");
//---- trailingIconTextField ---- //---- trailingIconTextField ----
trailingIconTextField.setText("text"); trailingIconTextField.setText("text");
add(trailingIconTextField, "cell 2 14,growx"); add(trailingIconTextField, "cell 2 13,growx");
//---- iconsTextField ---- //---- iconsTextField ----
iconsTextField.setText("text"); iconsTextField.setText("text");
add(iconsTextField, "cell 3 14,growx"); add(iconsTextField, "cell 3 13,growx");
//---- compsLabel ---- //---- compsLabel ----
compsLabel.setText("Leading/trailing comp.:"); compsLabel.setText("Leading/trailing comp.:");
add(compsLabel, "cell 0 15"); add(compsLabel, "cell 0 14");
add(compsTextField, "cell 1 15 2 1,growx"); add(compsTextField, "cell 1 14 2 1,growx");
//---- clearTextField ---- //---- clearTextField ----
clearTextField.setText("clear me"); clearTextField.setText("clear me");
add(clearTextField, "cell 3 15,growx"); add(clearTextField, "cell 3 14,growx");
//---- fontsLabel ---- //---- fontsLabel ----
fontsLabel.setText("Typography / Fonts:"); fontsLabel.setText("Typography / Fonts:");
add(fontsLabel, "cell 0 16"); add(fontsLabel, "cell 0 15");
//---- h00Label ---- //---- h00Label ----
h00Label.setText("H00"); h00Label.setText("H00");
h00Label.putClientProperty("FlatLaf.styleClass", "h00"); h00Label.putClientProperty(FlatClientProperties.STYLE_CLASS, "h00");
add(h00Label, "cell 1 16 5 1"); add(h00Label, "cell 1 15 5 1");
//---- h0Label ---- //---- h0Label ----
h0Label.setText("H0"); h0Label.setText("H0");
h0Label.putClientProperty("FlatLaf.styleClass", "h0"); h0Label.putClientProperty(FlatClientProperties.STYLE_CLASS, "h0");
add(h0Label, "cell 1 16 5 1"); add(h0Label, "cell 1 15 5 1");
//---- h1Label ---- //---- h1Label ----
h1Label.setText("H1"); h1Label.setText("H1");
h1Label.putClientProperty("FlatLaf.styleClass", "h1"); h1Label.putClientProperty(FlatClientProperties.STYLE_CLASS, "h1");
add(h1Label, "cell 1 16 5 1"); add(h1Label, "cell 1 15 5 1");
//---- h2Label ---- //---- h2Label ----
h2Label.setText("H2"); h2Label.setText("H2");
h2Label.putClientProperty("FlatLaf.styleClass", "h2"); h2Label.putClientProperty(FlatClientProperties.STYLE_CLASS, "h2");
add(h2Label, "cell 1 16 5 1"); add(h2Label, "cell 1 15 5 1");
//---- h3Label ---- //---- h3Label ----
h3Label.setText("H3"); h3Label.setText("H3");
h3Label.putClientProperty("FlatLaf.styleClass", "h3"); h3Label.putClientProperty(FlatClientProperties.STYLE_CLASS, "h3");
add(h3Label, "cell 1 16 5 1"); add(h3Label, "cell 1 15 5 1");
//---- h4Label ---- //---- h4Label ----
h4Label.setText("H4"); h4Label.setText("H4");
h4Label.putClientProperty("FlatLaf.styleClass", "h4"); h4Label.putClientProperty(FlatClientProperties.STYLE_CLASS, "h4");
add(h4Label, "cell 1 16 5 1"); add(h4Label, "cell 1 15 5 1");
//---- lightLabel ---- //---- lightLabel ----
lightLabel.setText("light"); 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"); add(lightLabel, "cell 1 15 5 1,gapx 30");
//---- semiboldLabel ---- //---- semiboldLabel ----
semiboldLabel.setText("semibold"); 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"); add(semiboldLabel, "cell 1 15 5 1");
//---- fontZoomLabel ---- //---- fontZoomLabel ----
fontZoomLabel.setText("(200%)"); fontZoomLabel.setText("(200%)");
fontZoomLabel.putClientProperty("FlatLaf.styleClass", "small"); fontZoomLabel.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
fontZoomLabel.setEnabled(false); fontZoomLabel.setEnabled(false);
add(fontZoomLabel, "cell 1 16 5 1"); add(fontZoomLabel, "cell 1 15 5 1");
//---- largeLabel ---- //---- largeLabel ----
largeLabel.setText("large"); largeLabel.setText("large");
largeLabel.putClientProperty("FlatLaf.styleClass", "large"); largeLabel.putClientProperty(FlatClientProperties.STYLE_CLASS, "large");
add(largeLabel, "cell 1 17 5 1"); add(largeLabel, "cell 1 16 5 1");
//---- defaultLabel ---- //---- defaultLabel ----
defaultLabel.setText("default"); defaultLabel.setText("default");
add(defaultLabel, "cell 1 17 5 1"); add(defaultLabel, "cell 1 16 5 1");
//---- mediumLabel ---- //---- mediumLabel ----
mediumLabel.setText("medium"); mediumLabel.setText("medium");
mediumLabel.putClientProperty("FlatLaf.styleClass", "medium"); mediumLabel.putClientProperty(FlatClientProperties.STYLE_CLASS, "medium");
add(mediumLabel, "cell 1 17 5 1"); add(mediumLabel, "cell 1 16 5 1");
//---- smallLabel ---- //---- smallLabel ----
smallLabel.setText("small"); smallLabel.setText("small");
smallLabel.putClientProperty("FlatLaf.styleClass", "small"); smallLabel.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
add(smallLabel, "cell 1 17 5 1"); add(smallLabel, "cell 1 16 5 1");
//---- miniLabel ---- //---- miniLabel ----
miniLabel.setText("mini"); miniLabel.setText("mini");
miniLabel.putClientProperty("FlatLaf.styleClass", "mini"); miniLabel.putClientProperty(FlatClientProperties.STYLE_CLASS, "mini");
add(miniLabel, "cell 1 17 5 1"); add(miniLabel, "cell 1 16 5 1");
//---- monospacedLabel ---- //---- monospacedLabel ----
monospacedLabel.setText("monospaced"); monospacedLabel.setText("monospaced");
monospacedLabel.putClientProperty("FlatLaf.styleClass", "monospaced"); monospacedLabel.putClientProperty(FlatClientProperties.STYLE_CLASS, "monospaced");
add(monospacedLabel, "cell 1 17 5 1,gapx 30"); add(monospacedLabel, "cell 1 16 5 1,gapx 30");
//======== popupMenu1 ======== //======== popupMenu1 ========
{ {
@@ -875,8 +847,7 @@ class BasicComponentsPanel
editorPaneLabel, scrollPane5, scrollPane6, scrollPane7, scrollPane8, editorPane5, editorPaneLabel, scrollPane5, scrollPane6, scrollPane7, scrollPane8, editorPane5,
textPaneLabel, scrollPane9, scrollPane10, scrollPane11, scrollPane12, textPane5, textPaneLabel, scrollPane9, scrollPane10, scrollPane11, scrollPane12, textPane5,
errorHintsLabel, errorHintsTextField, errorHintsComboBox, errorHintsSpinner, hintsLabel, errorHintsTextField, warningHintsTextField, successHintsTextField,
warningHintsLabel, warningHintsTextField, warningHintsComboBox, warningHintsSpinner,
fontZoomLabel, fontZoomLabel,
}; };
@@ -899,8 +870,7 @@ class BasicComponentsPanel
rows[11].setGapBefore( zeroGap ); rows[11].setGapBefore( zeroGap );
rows[11].setGapAfter( zeroGap ); rows[11].setGapAfter( zeroGap );
rows[12].setGapBefore( zeroGap ); rows[12].setGapBefore( zeroGap );
rows[13].setGapBefore( zeroGap ); rows[15].setGapBefore( zeroGap );
rows[16].setGapBefore( zeroGap );
layout.setRowConstraints( ac ); layout.setRowConstraints( ac );
// move two text field into same row as spinners // move two text field into same row as spinners

View File

@@ -1,4 +1,4 @@
JFDML JFormDesigner: "7.0.5.0.404" Java: "17" encoding: "UTF-8" JFDML JFormDesigner: "8.3" encoding: "UTF-8"
new FormModel { new FormModel {
contentType: "form/swing" contentType: "form/swing"
@@ -9,7 +9,7 @@ new FormModel {
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "insets dialog,hidemode 3" "$layoutConstraints": "insets dialog,hidemode 3"
"$columnConstraints": "[][sizegroup 1][sizegroup 1][sizegroup 1][][]" "$columnConstraints": "[][sizegroup 1][sizegroup 1][sizegroup 1][][]"
"$rowConstraints": "[][][][][][][][][][][][]para[][][][][]0[]" "$rowConstraints": "[][][][][][][][][][][][]para[][][][]0[]"
} ) { } ) {
name: "this" name: "this"
add( new FormComponent( "javax.swing.JLabel" ) { add( new FormComponent( "javax.swing.JLabel" ) {
@@ -595,8 +595,8 @@ new FormModel {
"value": "cell 5 11,growx" "value": "cell 5 11,growx"
} ) } )
add( new FormComponent( "javax.swing.JLabel" ) { add( new FormComponent( "javax.swing.JLabel" ) {
name: "errorHintsLabel" name: "hintsLabel"
"text": "Error hints:" "text": "Error/warning/success:"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 12" "value": "cell 0 12"
} ) } )
@@ -606,56 +606,23 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 12,growx" "value": "cell 1 12,growx"
} ) } )
add( new FormComponent( "javax.swing.JComboBox" ) {
name: "errorHintsComboBox"
"$client.JComponent.outline": "error"
"model": new javax.swing.DefaultComboBoxModel {
selectedItem: "Editable"
addElement( "Editable" )
}
"editable": true
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 12,growx"
} )
add( new FormComponent( "javax.swing.JSpinner" ) {
name: "errorHintsSpinner"
"$client.JComponent.outline": "error"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 3 12,growx"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "warningHintsLabel"
"text": "Warning hints:"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 13"
} )
add( new FormComponent( "javax.swing.JTextField" ) { add( new FormComponent( "javax.swing.JTextField" ) {
name: "warningHintsTextField" name: "warningHintsTextField"
"$client.JComponent.outline": "warning" "$client.JComponent.outline": "warning"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 13,growx" "value": "cell 2 12,growx"
} ) } )
add( new FormComponent( "javax.swing.JComboBox" ) { add( new FormComponent( "javax.swing.JTextField" ) {
name: "warningHintsComboBox" name: "successHintsTextField"
"$client.JComponent.outline": "warning" "$client.JComponent.outline": "success"
"model": new javax.swing.DefaultComboBoxModel {
selectedItem: "Not editable"
addElement( "Not editable" )
}
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 13,growx" "value": "cell 3 12,growx"
} )
add( new FormComponent( "javax.swing.JSpinner" ) {
name: "warningHintsSpinner"
"$client.JComponent.outline": "warning"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 3 13,growx"
} ) } )
add( new FormComponent( "javax.swing.JLabel" ) { add( new FormComponent( "javax.swing.JLabel" ) {
name: "iconsLabel" name: "iconsLabel"
"text": "Leading/trailing icons:" "text": "Leading/trailing icons:"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 14" "value": "cell 0 13"
} ) } )
add( new FormComponent( "javax.swing.JTextField" ) { add( new FormComponent( "javax.swing.JTextField" ) {
name: "leadingIconTextField" name: "leadingIconTextField"
@@ -663,7 +630,7 @@ new FormModel {
"JavaCodeGenerator.variableLocal": false "JavaCodeGenerator.variableLocal": false
} }
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 14,growx" "value": "cell 1 13,growx"
} ) } )
add( new FormComponent( "javax.swing.JTextField" ) { add( new FormComponent( "javax.swing.JTextField" ) {
name: "trailingIconTextField" name: "trailingIconTextField"
@@ -672,7 +639,7 @@ new FormModel {
"JavaCodeGenerator.variableLocal": false "JavaCodeGenerator.variableLocal": false
} }
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 14,growx" "value": "cell 2 13,growx"
} ) } )
add( new FormComponent( "javax.swing.JTextField" ) { add( new FormComponent( "javax.swing.JTextField" ) {
name: "iconsTextField" name: "iconsTextField"
@@ -681,13 +648,13 @@ new FormModel {
"JavaCodeGenerator.variableLocal": false "JavaCodeGenerator.variableLocal": false
} }
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 3 14,growx" "value": "cell 3 13,growx"
} ) } )
add( new FormComponent( "javax.swing.JLabel" ) { add( new FormComponent( "javax.swing.JLabel" ) {
name: "compsLabel" name: "compsLabel"
"text": "Leading/trailing comp.:" "text": "Leading/trailing comp.:"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 15" "value": "cell 0 14"
} ) } )
add( new FormComponent( "javax.swing.JTextField" ) { add( new FormComponent( "javax.swing.JTextField" ) {
name: "compsTextField" name: "compsTextField"
@@ -695,7 +662,7 @@ new FormModel {
"JavaCodeGenerator.variableLocal": false "JavaCodeGenerator.variableLocal": false
} }
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 15 2 1,growx" "value": "cell 1 14 2 1,growx"
} ) } )
add( new FormComponent( "javax.swing.JTextField" ) { add( new FormComponent( "javax.swing.JTextField" ) {
name: "clearTextField" name: "clearTextField"
@@ -704,69 +671,69 @@ new FormModel {
"JavaCodeGenerator.variableLocal": false "JavaCodeGenerator.variableLocal": false
} }
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 3 15,growx" "value": "cell 3 14,growx"
} ) } )
add( new FormComponent( "javax.swing.JLabel" ) { add( new FormComponent( "javax.swing.JLabel" ) {
name: "fontsLabel" name: "fontsLabel"
"text": "Typography / Fonts:" "text": "Typography / Fonts:"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 16" "value": "cell 0 15"
} ) } )
add( new FormComponent( "javax.swing.JLabel" ) { add( new FormComponent( "javax.swing.JLabel" ) {
name: "h00Label" name: "h00Label"
"text": "H00" "text": "H00"
"$client.FlatLaf.styleClass": "h00" "$client.FlatLaf.styleClass": "h00"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 16 5 1" "value": "cell 1 15 5 1"
} ) } )
add( new FormComponent( "javax.swing.JLabel" ) { add( new FormComponent( "javax.swing.JLabel" ) {
name: "h0Label" name: "h0Label"
"text": "H0" "text": "H0"
"$client.FlatLaf.styleClass": "h0" "$client.FlatLaf.styleClass": "h0"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 16 5 1" "value": "cell 1 15 5 1"
} ) } )
add( new FormComponent( "javax.swing.JLabel" ) { add( new FormComponent( "javax.swing.JLabel" ) {
name: "h1Label" name: "h1Label"
"text": "H1" "text": "H1"
"$client.FlatLaf.styleClass": "h1" "$client.FlatLaf.styleClass": "h1"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 16 5 1" "value": "cell 1 15 5 1"
} ) } )
add( new FormComponent( "javax.swing.JLabel" ) { add( new FormComponent( "javax.swing.JLabel" ) {
name: "h2Label" name: "h2Label"
"text": "H2" "text": "H2"
"$client.FlatLaf.styleClass": "h2" "$client.FlatLaf.styleClass": "h2"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 16 5 1" "value": "cell 1 15 5 1"
} ) } )
add( new FormComponent( "javax.swing.JLabel" ) { add( new FormComponent( "javax.swing.JLabel" ) {
name: "h3Label" name: "h3Label"
"text": "H3" "text": "H3"
"$client.FlatLaf.styleClass": "h3" "$client.FlatLaf.styleClass": "h3"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 16 5 1" "value": "cell 1 15 5 1"
} ) } )
add( new FormComponent( "javax.swing.JLabel" ) { add( new FormComponent( "javax.swing.JLabel" ) {
name: "h4Label" name: "h4Label"
"text": "H4" "text": "H4"
"$client.FlatLaf.styleClass": "h4" "$client.FlatLaf.styleClass": "h4"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 16 5 1" "value": "cell 1 15 5 1"
} ) } )
add( new FormComponent( "javax.swing.JLabel" ) { add( new FormComponent( "javax.swing.JLabel" ) {
name: "lightLabel" name: "lightLabel"
"text": "light" "text": "light"
"$client.FlatLaf.style": "font: 200% $light.font" "$client.FlatLaf.style": "font: 200% $light.font"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 16 5 1,gapx 30" "value": "cell 1 15 5 1,gapx 30"
} ) } )
add( new FormComponent( "javax.swing.JLabel" ) { add( new FormComponent( "javax.swing.JLabel" ) {
name: "semiboldLabel" name: "semiboldLabel"
"text": "semibold" "text": "semibold"
"$client.FlatLaf.style": "font: 200% $semibold.font" "$client.FlatLaf.style": "font: 200% $semibold.font"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 16 5 1" "value": "cell 1 15 5 1"
} ) } )
add( new FormComponent( "javax.swing.JLabel" ) { add( new FormComponent( "javax.swing.JLabel" ) {
name: "fontZoomLabel" name: "fontZoomLabel"
@@ -774,52 +741,52 @@ new FormModel {
"$client.FlatLaf.styleClass": "small" "$client.FlatLaf.styleClass": "small"
"enabled": false "enabled": false
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 16 5 1" "value": "cell 1 15 5 1"
} ) } )
add( new FormComponent( "javax.swing.JLabel" ) { add( new FormComponent( "javax.swing.JLabel" ) {
name: "largeLabel" name: "largeLabel"
"text": "large" "text": "large"
"$client.FlatLaf.styleClass": "large" "$client.FlatLaf.styleClass": "large"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 17 5 1" "value": "cell 1 16 5 1"
} ) } )
add( new FormComponent( "javax.swing.JLabel" ) { add( new FormComponent( "javax.swing.JLabel" ) {
name: "defaultLabel" name: "defaultLabel"
"text": "default" "text": "default"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 17 5 1" "value": "cell 1 16 5 1"
} ) } )
add( new FormComponent( "javax.swing.JLabel" ) { add( new FormComponent( "javax.swing.JLabel" ) {
name: "mediumLabel" name: "mediumLabel"
"text": "medium" "text": "medium"
"$client.FlatLaf.styleClass": "medium" "$client.FlatLaf.styleClass": "medium"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 17 5 1" "value": "cell 1 16 5 1"
} ) } )
add( new FormComponent( "javax.swing.JLabel" ) { add( new FormComponent( "javax.swing.JLabel" ) {
name: "smallLabel" name: "smallLabel"
"text": "small" "text": "small"
"$client.FlatLaf.styleClass": "small" "$client.FlatLaf.styleClass": "small"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 17 5 1" "value": "cell 1 16 5 1"
} ) } )
add( new FormComponent( "javax.swing.JLabel" ) { add( new FormComponent( "javax.swing.JLabel" ) {
name: "miniLabel" name: "miniLabel"
"text": "mini" "text": "mini"
"$client.FlatLaf.styleClass": "mini" "$client.FlatLaf.styleClass": "mini"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 17 5 1" "value": "cell 1 16 5 1"
} ) } )
add( new FormComponent( "javax.swing.JLabel" ) { add( new FormComponent( "javax.swing.JLabel" ) {
name: "monospacedLabel" name: "monospacedLabel"
"text": "monospaced" "text": "monospaced"
"$client.FlatLaf.styleClass": "monospaced" "$client.FlatLaf.styleClass": "monospaced"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 17 5 1,gapx 30" "value": "cell 1 16 5 1,gapx 30"
} ) } )
}, new FormLayoutConstraints( null ) { }, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 0, 0 ) "location": new java.awt.Point( 0, 0 )
"size": new java.awt.Dimension( 920, 550 ) "size": new java.awt.Dimension( 840, 565 )
} ) } )
add( new FormContainer( "javax.swing.JPopupMenu", new FormLayoutManager( class javax.swing.JPopupMenu ) ) { add( new FormContainer( "javax.swing.JPopupMenu", new FormLayoutManager( class javax.swing.JPopupMenu ) ) {
name: "popupMenu1" name: "popupMenu1"
@@ -839,7 +806,7 @@ new FormModel {
"mnemonic": 80 "mnemonic": 80
} ) } )
}, new FormLayoutConstraints( null ) { }, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 0, 570 ) "location": new java.awt.Point( 0, 605 )
"size": new java.awt.Dimension( 91, 87 ) "size": new java.awt.Dimension( 91, 87 )
} ) } )
} }

View File

@@ -156,6 +156,9 @@ class ControlBar
// register Alt+Shift+F1, F2, ... keys to change system scale factor // register Alt+Shift+F1, F2, ... keys to change system scale factor
DemoPrefs.registerSystemScaleFactors( frame ); DemoPrefs.registerSystemScaleFactors( frame );
// register Alt+Shift+S to enable/disable interprocess Laf sync
DemoPrefs.initLafSync( frame );
// register ESC key to close frame // register ESC key to close frame
((JComponent)frame.getContentPane()).registerKeyboardAction( ((JComponent)frame.getContentPane()).registerKeyboardAction(
e -> { e -> {

View File

@@ -22,6 +22,7 @@ import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable; import java.awt.datatransfer.Transferable;
import javax.swing.*; import javax.swing.*;
import javax.swing.UIDefaults.ActiveValue;
import javax.swing.table.*; import javax.swing.table.*;
import javax.swing.tree.*; import javax.swing.tree.*;
import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.FlatClientProperties;
@@ -65,6 +66,45 @@ class DataComponentsPanel
tree3.putClientProperty( FlatClientProperties.STYLE, "selectionInsets: 0,1,0,1; selectionArc: 6" ); 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() { private void dndChanged() {
boolean dnd = dndCheckBox.isSelected(); boolean dnd = dndCheckBox.isSelected();
DropMode dropMode = dnd ? DropMode.ON_OR_INSERT : DropMode.USE_SELECTION; DropMode dropMode = dnd ? DropMode.ON_OR_INSERT : DropMode.USE_SELECTION;
@@ -142,18 +182,20 @@ class DataComponentsPanel
} }
private void alternatingRowsChanged() { private void alternatingRowsChanged() {
Color alternateRowColor = null; ActiveValue alternateRowColor = null;
if( alternatingRowsCheckBox.isSelected() ) { if( alternatingRowsCheckBox.isSelected() ) {
Color background = table1.getBackground(); alternateRowColor = table -> {
alternateRowColor = FlatLaf.isLafDark() Color background = table1.getBackground();
? ColorFunctions.lighten( background, 0.05f ) return FlatLaf.isLafDark()
: ColorFunctions.darken( background, 0.05f ); ? ColorFunctions.lighten( background, 0.05f )
: ColorFunctions.darken( background, 0.05f );
};
} }
UIManager.put( "Table.alternateRowColor", alternateRowColor ); UIManager.put( "Table.alternateRowColor", alternateRowColor );
table1.repaint(); table1.repaint();
} }
@SuppressWarnings( { "unchecked", "rawtypes" } ) @SuppressWarnings( { "rawtypes" } )
private void initComponents() { private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents // JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
JLabel label1 = new JLabel(); JLabel label1 = new JLabel();
@@ -166,6 +208,8 @@ class DataComponentsPanel
list3 = new JList<>(); list3 = new JList<>();
JScrollPane scrollPane2 = new JScrollPane(); JScrollPane scrollPane2 = new JScrollPane();
list2 = new JList<>(); list2 = new JList<>();
JPanel listOptionsPanel = new JPanel();
listAlternatingRowsCheckBox = new JCheckBox();
JLabel treeLabel = new JLabel(); JLabel treeLabel = new JLabel();
JScrollPane scrollPane3 = new JScrollPane(); JScrollPane scrollPane3 = new JScrollPane();
tree1 = new JTree(); tree1 = new JTree();
@@ -173,6 +217,9 @@ class DataComponentsPanel
tree3 = new JTree(); tree3 = new JTree();
JScrollPane scrollPane4 = new JScrollPane(); JScrollPane scrollPane4 = new JScrollPane();
tree2 = new JTree(); tree2 = new JTree();
JPanel treeOptionsPanel = new JPanel();
treeWideSelectionCheckBox = new JCheckBox();
treeAlternatingRowsCheckBox = new JCheckBox();
JLabel tableLabel = new JLabel(); JLabel tableLabel = new JLabel();
JScrollPane scrollPane5 = new JScrollPane(); JScrollPane scrollPane5 = new JScrollPane();
table1 = new JTable(); table1 = new JTable();
@@ -205,7 +252,7 @@ class DataComponentsPanel
"[]" + "[]" +
"[150,grow,sizegroup 1,fill]" + "[150,grow,sizegroup 1,fill]" +
"[150,grow,sizegroup 1,fill]" + "[150,grow,sizegroup 1,fill]" +
"[150,grow,sizegroup 1,fill]")); "[150,grow,fill]"));
//---- label1 ---- //---- label1 ----
label1.setText("Square Selection"); label1.setText("Square Selection");
@@ -273,6 +320,22 @@ class DataComponentsPanel
} }
add(scrollPane2, "cell 3 1"); 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 ----
treeLabel.setText("JTree:"); treeLabel.setText("JTree:");
add(treeLabel, "cell 0 2,aligny top,growy 0"); add(treeLabel, "cell 0 2,aligny top,growy 0");
@@ -334,6 +397,29 @@ class DataComponentsPanel
} }
add(scrollPane4, "cell 3 2"); 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 ----
tableLabel.setText("JTable:"); tableLabel.setText("JTable:");
add(tableLabel, "cell 0 3,aligny top,growy 0"); add(tableLabel, "cell 0 3,aligny top,growy 0");
@@ -379,7 +465,7 @@ class DataComponentsPanel
{ {
TableColumnModel cm = table1.getColumnModel(); TableColumnModel cm = table1.getColumnModel();
cm.getColumn(2).setCellEditor(new DefaultCellEditor( cm.getColumn(2).setCellEditor(new DefaultCellEditor(
new JComboBox(new DefaultComboBoxModel(new String[] { new JComboBox<>(new DefaultComboBoxModel<>(new String[] {
"January", "January",
"February", "February",
"March", "March",
@@ -394,7 +480,7 @@ class DataComponentsPanel
"December" "December"
})))); }))));
cm.getColumn(3).setCellEditor(new DefaultCellEditor( cm.getColumn(3).setCellEditor(new DefaultCellEditor(
new JComboBox(new DefaultComboBoxModel(new String[] { new JComboBox<>(new DefaultComboBoxModel<>(new String[] {
"January", "January",
"February", "February",
"March", "March",
@@ -513,9 +599,12 @@ class DataComponentsPanel
private JList<String> list1; private JList<String> list1;
private JList<String> list3; private JList<String> list3;
private JList<String> list2; private JList<String> list2;
private JCheckBox listAlternatingRowsCheckBox;
private JTree tree1; private JTree tree1;
private JTree tree3; private JTree tree3;
private JTree tree2; private JTree tree2;
private JCheckBox treeWideSelectionCheckBox;
private JCheckBox treeAlternatingRowsCheckBox;
private JTable table1; private JTable table1;
private JCheckBox roundedSelectionCheckBox; private JCheckBox roundedSelectionCheckBox;
private JCheckBox showHorizontalLinesCheckBox; 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 { new FormModel {
contentType: "form/swing" contentType: "form/swing"
@@ -9,7 +9,7 @@ new FormModel {
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "insets dialog,hidemode 3" "$layoutConstraints": "insets dialog,hidemode 3"
"$columnConstraints": "[][150,fill][150,fill][150,fill][fill]" "$columnConstraints": "[][150,fill][150,fill][150,fill][fill]"
"$rowConstraints": "[][150,grow,sizegroup 1,fill][150,grow,sizegroup 1,fill][150,grow,sizegroup 1,fill]" "$rowConstraints": "[][150,grow,sizegroup 1,fill][150,grow,sizegroup 1,fill][150,grow,fill]"
} ) { } ) {
name: "this" name: "this"
add( new FormComponent( "javax.swing.JLabel" ) { add( new FormComponent( "javax.swing.JLabel" ) {
@@ -92,6 +92,25 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 3 1" "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" ) { add( new FormComponent( "javax.swing.JLabel" ) {
name: "treeLabel" name: "treeLabel"
"text": "JTree:" "text": "JTree:"
@@ -192,6 +211,36 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 3 2" "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" ) { add( new FormComponent( "javax.swing.JLabel" ) {
name: "tableLabel" name: "tableLabel"
"text": "JTable:" "text": "JTable:"

View File

@@ -16,8 +16,15 @@
package com.formdev.flatlaf.demo; package com.formdev.flatlaf.demo;
import java.awt.EventQueue;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.util.prefs.Preferences; import java.util.prefs.Preferences;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JFrame; import javax.swing.JFrame;
@@ -28,7 +35,6 @@ import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.FlatLightLaf; import com.formdev.flatlaf.FlatLightLaf;
import com.formdev.flatlaf.FlatPropertiesLaf; import com.formdev.flatlaf.FlatPropertiesLaf;
import com.formdev.flatlaf.IntelliJTheme; import com.formdev.flatlaf.IntelliJTheme;
import com.formdev.flatlaf.demo.intellijthemes.IJThemesPanel;
import com.formdev.flatlaf.util.LoggingFacade; import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.StringUtils; import com.formdev.flatlaf.util.StringUtils;
import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.SystemInfo;
@@ -38,14 +44,10 @@ import com.formdev.flatlaf.util.SystemInfo;
*/ */
public class DemoPrefs public class DemoPrefs
{ {
public static final String KEY_LAF = "laf"; public static final String KEY_LAF_CLASS_NAME = "lafClassName";
public static final String KEY_LAF_THEME = "lafTheme"; public static final String KEY_LAF_THEME_FILE = "lafThemeFile";
public static final String KEY_SYSTEM_SCALE_FACTOR = "systemScaleFactor"; public static final String KEY_SYSTEM_SCALE_FACTOR = "systemScaleFactor";
public static final String KEY_LAF_SYNC = "lafSync";
public static final String RESOURCE_PREFIX = "res:";
public static final String FILE_PREFIX = "file:";
public static final String THEME_UI_KEY = "__FlatLaf.demo.theme";
private static Preferences state; private static Preferences state;
@@ -58,37 +60,14 @@ public class DemoPrefs
} }
public static void setupLaf( String[] args ) { public static void setupLaf( String[] args ) {
// com.formdev.flatlaf.demo.intellijthemes.IJThemesDump.install();
// set look and feel // set look and feel
try { try {
if( args.length > 0 ) if( args.length > 0 )
UIManager.setLookAndFeel( args[0] ); UIManager.setLookAndFeel( args[0] );
else { else
String lafClassName = state.get( KEY_LAF, FlatLightLaf.class.getName() ); restoreLaf();
if( IntelliJTheme.ThemeLaf.class.getName().equals( lafClassName ) ) {
String theme = state.get( KEY_LAF_THEME, "" );
if( theme.startsWith( RESOURCE_PREFIX ) )
IntelliJTheme.setup( IJThemesPanel.class.getResourceAsStream( IJThemesPanel.THEMES_PACKAGE + theme.substring( RESOURCE_PREFIX.length() ) ) );
else if( theme.startsWith( FILE_PREFIX ) )
FlatLaf.setup( IntelliJTheme.createLaf( new FileInputStream( theme.substring( FILE_PREFIX.length() ) ) ) );
else
FlatLightLaf.setup();
if( !theme.isEmpty() )
UIManager.getLookAndFeelDefaults().put( THEME_UI_KEY, theme );
} else if( FlatPropertiesLaf.class.getName().equals( lafClassName ) ) {
String theme = state.get( KEY_LAF_THEME, "" );
if( theme.startsWith( FILE_PREFIX ) ) {
File themeFile = new File( theme.substring( FILE_PREFIX.length() ) );
String themeName = StringUtils.removeTrailing( themeFile.getName(), ".properties" );
FlatLaf.setup( new FlatPropertiesLaf( themeName, themeFile ) );
} else
FlatLightLaf.setup();
if( !theme.isEmpty() )
UIManager.getLookAndFeelDefaults().put( THEME_UI_KEY, theme );
} else
UIManager.setLookAndFeel( lafClassName );
}
} catch( Throwable ex ) { } catch( Throwable ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex ); LoggingFacade.INSTANCE.logSevere( null, ex );
@@ -98,16 +77,44 @@ public class DemoPrefs
// remember active look and feel // remember active look and feel
UIManager.addPropertyChangeListener( e -> { UIManager.addPropertyChangeListener( e -> {
if( "lookAndFeel".equals( e.getPropertyName() ) ) if( "lookAndFeel".equals( e.getPropertyName() ) ) {
state.put( KEY_LAF, UIManager.getLookAndFeel().getClass().getName() ); state.put( KEY_LAF_CLASS_NAME, UIManager.getLookAndFeel().getClass().getName() );
notifyLafChange();
}
} ); } );
} }
private static void restoreLaf()
throws Exception
{
String lafClassName = state.get( KEY_LAF_CLASS_NAME, FlatLightLaf.class.getName() );
if( FlatPropertiesLaf.class.getName().equals( lafClassName ) ||
IntelliJTheme.ThemeLaf.class.getName().equals( lafClassName ) )
{
String themeFileName = state.get( KEY_LAF_THEME_FILE, "" );
if( !themeFileName.isEmpty() ) {
File themeFile = new File( themeFileName );
if( themeFileName.endsWith( ".properties" ) ) {
String themeName = StringUtils.removeTrailing( themeFile.getName(), ".properties" );
FlatLaf.setup( new FlatPropertiesLaf( themeName, themeFile ) );
} else
FlatLaf.setup( IntelliJTheme.createLaf( new FileInputStream( themeFile ) ) );
} else
FlatLightLaf.setup();
} else
UIManager.setLookAndFeel( lafClassName );
}
public static void initSystemScale() { public static void initSystemScale() {
if( System.getProperty( "sun.java2d.uiScale" ) == null ) { if( System.getProperty( "sun.java2d.uiScale" ) == null ) {
String scaleFactor = getState().get( KEY_SYSTEM_SCALE_FACTOR, null ); String scaleFactor = state.get( KEY_SYSTEM_SCALE_FACTOR, null );
if( scaleFactor != null ) if( scaleFactor != null ) {
System.setProperty( "sun.java2d.uiScale", scaleFactor ); System.setProperty( "sun.java2d.uiScale", scaleFactor );
System.out.println( "FlatLaf: setting 'sun.java2d.uiScale' to " + scaleFactor );
System.out.println( " use 'Alt+Shift+F1...12' to change it to 1x...4x" );
}
} }
} }
@@ -158,10 +165,113 @@ public class DemoPrefs
return; return;
if( scaleFactor != null ) if( scaleFactor != null )
DemoPrefs.getState().put( KEY_SYSTEM_SCALE_FACTOR, scaleFactor ); state.put( KEY_SYSTEM_SCALE_FACTOR, scaleFactor );
else else
DemoPrefs.getState().remove( KEY_SYSTEM_SCALE_FACTOR ); state.remove( KEY_SYSTEM_SCALE_FACTOR );
System.exit( 0 ); System.exit( 0 );
} }
//---- inter-process Laf change notification/synchronisation --------------
// used for FlatLaf development when running multiple testing apps
private static final String MULTICAST_ADDRESS = "224.63.31.41";
private static final int MULTICAST_PORT = 36584;
private static final long PROCESS_ID = System.nanoTime();
private static Thread thread;
private static boolean notifyEnabled = true;
public static void initLafSync( JFrame frame ) {
((JComponent)frame.getContentPane()).registerKeyboardAction(
e -> enableDisableLafSync(),
KeyStroke.getKeyStroke( "alt shift S" ),
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT );
if( state.getBoolean( KEY_LAF_SYNC, false ) ) {
System.out.println( "FlatLaf: theme sync enabled; use Alt+Shift+S to disable it" );
listenToLafChange();
}
}
private static void enableDisableLafSync() {
boolean enabled = !state.getBoolean( KEY_LAF_SYNC, false );
state.putBoolean( KEY_LAF_SYNC, enabled );
if( enabled )
listenToLafChange();
else if( thread != null) {
thread.interrupt();
thread = null;
}
}
private static void listenToLafChange() {
if( thread != null )
return;
thread = new Thread( "FlatLaf Laf change listener" ) {
MulticastSocket socket;
@Override
public void run() {
try( MulticastSocket socket = new MulticastSocket( MULTICAST_PORT ) ) {
this.socket = socket;
socket.joinGroup( InetAddress.getByName( MULTICAST_ADDRESS ) );
byte[] buffer = new byte[Long.BYTES];
for(;;) {
DatagramPacket packet = new DatagramPacket( buffer, buffer.length );
socket.receive( packet );
long id = ByteBuffer.wrap( buffer ).getLong();
if( id == PROCESS_ID )
continue; // was sent from this process
EventQueue.invokeLater( () -> {
notifyEnabled = false;
try {
restoreLaf();
FlatLaf.updateUI();
} catch( Throwable ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex );
} finally {
notifyEnabled = true;
}
} );
}
} catch( IOException ex ) {
if( ex instanceof SocketException && "Socket closed".equals( ex.getMessage() ) )
return; // interrupted
LoggingFacade.INSTANCE.logSevere( null, ex );
}
}
@Override
public void interrupt() {
super.interrupt();
socket.close();
}
};
thread.setDaemon( true );
thread.start();
}
private static void notifyLafChange() {
if( thread == null || !notifyEnabled )
return;
EventQueue.invokeLater( () -> {
try( MulticastSocket socket = new MulticastSocket() ) {
InetAddress address = InetAddress.getByName( MULTICAST_ADDRESS );
byte[] buffer = ByteBuffer.wrap( new byte[Long.BYTES] ).putLong( PROCESS_ID ).array();
DatagramPacket packet = new DatagramPacket( buffer, buffer.length, address, MULTICAST_PORT );
socket.send( packet );
} catch( IOException ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex );
}
} );
}
} }

View File

@@ -19,6 +19,7 @@ package com.formdev.flatlaf.demo;
import java.awt.*; import java.awt.*;
import javax.swing.*; import javax.swing.*;
import javax.swing.border.*; import javax.swing.border.*;
import com.formdev.flatlaf.FlatClientProperties;
import net.miginfocom.swing.*; import net.miginfocom.swing.*;
/** /**
@@ -176,12 +177,12 @@ class MoreComponentsPanel
add(scrollBar3, "cell 2 0 1 6,growy"); add(scrollBar3, "cell 2 0 1 6,growy");
//---- scrollBar7 ---- //---- scrollBar7 ----
scrollBar7.putClientProperty("JScrollBar.showButtons", true); scrollBar7.putClientProperty(FlatClientProperties.SCROLL_BAR_SHOW_BUTTONS, true);
add(scrollBar7, "cell 2 0 1 6,growy"); add(scrollBar7, "cell 2 0 1 6,growy");
//---- scrollBar8 ---- //---- scrollBar8 ----
scrollBar8.setEnabled(false); scrollBar8.setEnabled(false);
scrollBar8.putClientProperty("JScrollBar.showButtons", true); scrollBar8.putClientProperty(FlatClientProperties.SCROLL_BAR_SHOW_BUTTONS, true);
add(scrollBar8, "cell 2 0 1 6,growy"); add(scrollBar8, "cell 2 0 1 6,growy");
//---- separator2 ---- //---- separator2 ----
@@ -301,13 +302,13 @@ class MoreComponentsPanel
//---- scrollBar5 ---- //---- scrollBar5 ----
scrollBar5.setOrientation(Adjustable.HORIZONTAL); scrollBar5.setOrientation(Adjustable.HORIZONTAL);
scrollBar5.putClientProperty("JScrollBar.showButtons", true); scrollBar5.putClientProperty(FlatClientProperties.SCROLL_BAR_SHOW_BUTTONS, true);
add(scrollBar5, "cell 1 3,growx"); add(scrollBar5, "cell 1 3,growx");
//---- scrollBar6 ---- //---- scrollBar6 ----
scrollBar6.setOrientation(Adjustable.HORIZONTAL); scrollBar6.setOrientation(Adjustable.HORIZONTAL);
scrollBar6.setEnabled(false); scrollBar6.setEnabled(false);
scrollBar6.putClientProperty("JScrollBar.showButtons", true); scrollBar6.putClientProperty(FlatClientProperties.SCROLL_BAR_SHOW_BUTTONS, true);
add(scrollBar6, "cell 1 4,growx"); add(scrollBar6, "cell 1 4,growx");
//---- separatorLabel ---- //---- separatorLabel ----
@@ -518,7 +519,7 @@ class MoreComponentsPanel
//======== panel5 ======== //======== 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()); panel5.setLayout(new BorderLayout());
//---- label9 ---- //---- label9 ----
@@ -530,7 +531,7 @@ class MoreComponentsPanel
//======== panel4 ======== //======== 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()); panel4.setLayout(new BorderLayout());
//---- label8 ---- //---- label8 ----
@@ -546,14 +547,14 @@ class MoreComponentsPanel
//---- label13 ---- //---- label13 ----
label13.setText("rounded background"); 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.setBackground(new Color(0xb8e4f3));
label13.setForeground(new Color(0x135b76)); label13.setForeground(new Color(0x135b76));
add(label13, "cell 1 13 4 1"); add(label13, "cell 1 13 4 1");
//---- label10 ---- //---- label10 ----
label10.setText("rounded border"); 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.setBackground(new Color(0xb8e4f3));
label10.setForeground(new Color(0x135b76)); label10.setForeground(new Color(0x135b76));
add(label10, "cell 1 13 4 1"); add(label10, "cell 1 13 4 1");

View File

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

View File

@@ -25,24 +25,32 @@ class IJThemeInfo
{ {
final String name; final String name;
final String resourceName; final String resourceName;
final boolean discontinued;
final boolean dark; final boolean dark;
final String license; final String license;
final String licenseFile; final String licenseFile;
final String pluginUrl;
final String sourceCodeUrl; final String sourceCodeUrl;
final String sourceCodePath; final String sourceCodePath;
final File themeFile; final File themeFile;
final String lafClassName; final String lafClassName;
IJThemeInfo( String name, String resourceName, boolean dark, IJThemeInfo( String name, boolean dark, String lafClassName ) {
this( name, null, false, dark, null, null, null, null, null, null, lafClassName );
}
IJThemeInfo( String name, String resourceName, boolean discontinued, boolean dark,
String license, String licenseFile, String license, String licenseFile,
String sourceCodeUrl, String sourceCodePath, String pluginUrl, String sourceCodeUrl, String sourceCodePath,
File themeFile, String lafClassName ) File themeFile, String lafClassName )
{ {
this.name = name; this.name = name;
this.resourceName = resourceName; this.resourceName = resourceName;
this.discontinued = discontinued;
this.dark = dark; this.dark = dark;
this.license = license; this.license = license;
this.licenseFile = licenseFile; this.licenseFile = licenseFile;
this.pluginUrl = pluginUrl;
this.sourceCodeUrl = sourceCodeUrl; this.sourceCodeUrl = sourceCodeUrl;
this.sourceCodePath = sourceCodePath; this.sourceCodePath = sourceCodePath;
this.themeFile = themeFile; this.themeFile = themeFile;

View File

@@ -73,10 +73,12 @@ public class IJThemesClassGenerator
name = name.substring( nameSep + 1 ).trim(); name = name.substring( nameSep + 1 ).trim();
String themeName = name; String themeName = name;
if( "material-theme-ui-lite".equals( resourcePath ) )
themeName += " (Material)";
StringBuilder buf = new StringBuilder(); StringBuilder buf = new StringBuilder();
if( "material-theme-ui-lite".equals( resourcePath ) ) {
themeName += " (Material)";
buf.append( "MT" );
}
for( String n : name.split( "[ \\-]" ) ) { for( String n : name.split( "[ \\-]" ) ) {
if( n.length() == 0 || n.equals( "-" ) ) if( n.length() == 0 || n.equals( "-" ) )
continue; continue;

View File

@@ -0,0 +1,118 @@
/*
* 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.demo.intellijthemes;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicReference;
import javax.swing.LookAndFeel;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.IntelliJTheme;
import com.formdev.flatlaf.util.LoggingFacade;
/**
* @author Karl Tauber
*/
public class IJThemesDump
{
// same as UIDefaultsLoader.KEY_PROPERTIES
private static final String KEY_PROPERTIES = "FlatLaf.internal.properties";
public static void enablePropertiesRecording() {
System.setProperty( KEY_PROPERTIES, "true" );
}
public static void install() {
enablePropertiesRecording();
UIManager.addPropertyChangeListener( e -> {
if( "lookAndFeel".equals( e.getPropertyName() ) ) {
LookAndFeel lookAndFeel = UIManager.getLookAndFeel();
if( lookAndFeel instanceof IntelliJTheme.ThemeLaf ) {
IntelliJTheme theme = (lookAndFeel.getClass() == IntelliJTheme.ThemeLaf.class)
? ((IntelliJTheme.ThemeLaf)lookAndFeel).getTheme()
: null;
String name = (theme != null) ? theme.name : lookAndFeel.getClass().getSimpleName();
File dir = new File( "dumps/properties" );
dumpProperties( dir, name, UIManager.getLookAndFeelDefaults() );
}
}
} );
}
public static void dumpProperties( File dir, String name, UIDefaults defaults ) {
String content = dumpPropertiesToString( defaults );
if( content == null )
return;
// write to file
File file = new File( dir, name + ".properties" );
file.getParentFile().mkdirs();
try( Writer fileWriter = new OutputStreamWriter(
new FileOutputStream( file ), StandardCharsets.UTF_8 ) )
{
fileWriter.write( content );
} catch( IOException ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex );
}
}
public static String dumpPropertiesToString( UIDefaults defaults ) {
Properties properties = (Properties) defaults.get( KEY_PROPERTIES );
if( properties == null )
return null;
// dump to string
StringWriter stringWriter = new StringWriter( 100000 );
PrintWriter out = new PrintWriter( stringWriter );
out.printf( "@baseTheme = %s%n", FlatLaf.isLafDark() ? "dark" : "light" );
AtomicReference<String> lastPrefix = new AtomicReference<>();
properties.entrySet().stream()
.sorted( (e1, e2) -> ((String)e1.getKey()).compareTo( (String) e2.getKey() ) )
.forEach( e -> {
String key = (String) e.getKey();
String value = (String) e.getValue();
String prefix = keyPrefix( key );
if( !prefix.equals( lastPrefix.get() ) ) {
lastPrefix.set( prefix );
out.printf( "%n%n#---- %s ----%n%n", prefix );
}
out.printf( "%-50s = %s%n", key, value.replace( ";", "; \\\n\t" ) );
} );
return stringWriter.toString().replace( "\r", "" );
}
private static String keyPrefix( String key ) {
int dotIndex = key.indexOf( '.' );
return (dotIndex > 0)
? key.substring( 0, dotIndex )
: key.endsWith( "UI" )
? key.substring( 0, key.length() - 2 )
: "";
}
}

View File

@@ -56,13 +56,17 @@ class IJThemesManager
String resourceName = e.getKey(); String resourceName = e.getKey();
Map<String, String> value = (Map<String, String>) e.getValue(); Map<String, String> value = (Map<String, String>) e.getValue();
String name = value.get( "name" ); String name = value.get( "name" );
boolean discontinued = Boolean.parseBoolean( value.get( "discontinued" ) );
boolean dark = Boolean.parseBoolean( value.get( "dark" ) ); boolean dark = Boolean.parseBoolean( value.get( "dark" ) );
String lafClassName = value.get( "lafClassName" );
String license = value.get( "license" ); String license = value.get( "license" );
String licenseFile = value.get( "licenseFile" ); String licenseFile = value.get( "licenseFile" );
String pluginUrl = value.get( "pluginUrl" );
String sourceCodeUrl = value.get( "sourceCodeUrl" ); String sourceCodeUrl = value.get( "sourceCodeUrl" );
String sourceCodePath = value.get( "sourceCodePath" ); String sourceCodePath = value.get( "sourceCodePath" );
bundledThemes.add( new IJThemeInfo( name, resourceName, dark, license, licenseFile, sourceCodeUrl, sourceCodePath, null, null ) ); bundledThemes.add( new IJThemeInfo( name, resourceName, discontinued, dark,
license, licenseFile, pluginUrl, sourceCodeUrl, sourceCodePath, null, lafClassName ) );
} }
} }
@@ -85,7 +89,7 @@ class IJThemesManager
String name = fname.endsWith( ".properties" ) String name = fname.endsWith( ".properties" )
? StringUtils.removeTrailing( fname, ".properties" ) ? StringUtils.removeTrailing( fname, ".properties" )
: StringUtils.removeTrailing( fname, ".theme.json" ); : StringUtils.removeTrailing( fname, ".theme.json" );
moreThemes.add( new IJThemeInfo( name, null, false, null, null, null, null, f, null ) ); moreThemes.add( new IJThemeInfo( name, null, false, false, null, null, null, null, null, f, null ) );
lastModifiedMap.put( f, f.lastModified() ); lastModifiedMap.put( f, f.lastModified() );
} }
} }

View File

@@ -33,8 +33,6 @@ import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
@@ -45,6 +43,7 @@ import javax.swing.*;
import javax.swing.border.Border; import javax.swing.border.Border;
import javax.swing.border.CompoundBorder; import javax.swing.border.CompoundBorder;
import javax.swing.event.*; import javax.swing.event.*;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatDarculaLaf; import com.formdev.flatlaf.FlatDarculaLaf;
import com.formdev.flatlaf.FlatDarkLaf; import com.formdev.flatlaf.FlatDarkLaf;
import com.formdev.flatlaf.FlatIntelliJLaf; import com.formdev.flatlaf.FlatIntelliJLaf;
@@ -58,7 +57,6 @@ import com.formdev.flatlaf.extras.FlatSVGIcon;
import com.formdev.flatlaf.themes.*; import com.formdev.flatlaf.themes.*;
import com.formdev.flatlaf.ui.FlatListUI; import com.formdev.flatlaf.ui.FlatListUI;
import com.formdev.flatlaf.util.LoggingFacade; import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.StringUtils;
import net.miginfocom.swing.*; import net.miginfocom.swing.*;
/** /**
@@ -81,14 +79,13 @@ public class IJThemesPanel
}; };
private Window window; private Window window;
private File lastDirectory;
private boolean isAdjustingThemesList; private boolean isAdjustingThemesList;
private long lastLafChangeTime = System.currentTimeMillis(); private long lastLafChangeTime = System.currentTimeMillis();
public IJThemesPanel() { public IJThemesPanel() {
initComponents(); initComponents();
saveButton.setEnabled( false ); pluginButton.setEnabled( false );
sourceCodeButton.setEnabled( false ); sourceCodeButton.setEnabled( false );
// create renderer // create renderer
@@ -143,7 +140,7 @@ public class IJThemesPanel
private String buildToolTip( IJThemeInfo ti ) { private String buildToolTip( IJThemeInfo ti ) {
if( ti.themeFile != null ) if( ti.themeFile != null )
return ti.themeFile.getPath(); return ti.themeFile.getPath();
if( ti.resourceName == null ) if( ti.license == null )
return ti.name; return ti.name;
return "Name: " + ti.name return "Name: " + ti.name
@@ -178,18 +175,18 @@ public class IJThemesPanel
// add core themes at beginning // add core themes at beginning
categories.put( themes.size(), "Core Themes" ); categories.put( themes.size(), "Core Themes" );
if( showLight ) if( showLight )
themes.add( new IJThemeInfo( "FlatLaf Light", null, false, null, null, null, null, null, FlatLightLaf.class.getName() ) ); themes.add( new IJThemeInfo( "FlatLaf Light", false, FlatLightLaf.class.getName() ) );
if( showDark ) if( showDark )
themes.add( new IJThemeInfo( "FlatLaf Dark", null, true, null, null, null, null, null, FlatDarkLaf.class.getName() ) ); themes.add( new IJThemeInfo( "FlatLaf Dark", true, FlatDarkLaf.class.getName() ) );
if( showLight ) if( showLight )
themes.add( new IJThemeInfo( "FlatLaf IntelliJ", null, false, null, null, null, null, null, FlatIntelliJLaf.class.getName() ) ); themes.add( new IJThemeInfo( "FlatLaf IntelliJ", false, FlatIntelliJLaf.class.getName() ) );
if( showDark ) if( showDark )
themes.add( new IJThemeInfo( "FlatLaf Darcula", null, true, null, null, null, null, null, FlatDarculaLaf.class.getName() ) ); themes.add( new IJThemeInfo( "FlatLaf Darcula", true, FlatDarculaLaf.class.getName() ) );
if( showLight ) if( showLight )
themes.add( new IJThemeInfo( "FlatLaf macOS Light", null, false, null, null, null, null, null, FlatMacLightLaf.class.getName() ) ); themes.add( new IJThemeInfo( "FlatLaf macOS Light", false, FlatMacLightLaf.class.getName() ) );
if( showDark ) if( showDark )
themes.add( new IJThemeInfo( "FlatLaf macOS Dark", null, true, null, null, null, null, null, FlatMacDarkLaf.class.getName() ) ); themes.add( new IJThemeInfo( "FlatLaf macOS Dark", true, FlatMacDarkLaf.class.getName() ) );
// add themes from directory // add themes from directory
categories.put( themes.size(), "Current Directory" ); categories.put( themes.size(), "Current Directory" );
@@ -237,7 +234,6 @@ public class IJThemesPanel
for( int i = 0; i < themes.size(); i++ ) { for( int i = 0; i < themes.size(); i++ ) {
IJThemeInfo theme = themes.get( i ); IJThemeInfo theme = themes.get( i );
if( oldSel.name.equals( theme.name ) && if( oldSel.name.equals( theme.name ) &&
Objects.equals( oldSel.resourceName, theme.resourceName ) &&
Objects.equals( oldSel.themeFile, theme.themeFile ) && Objects.equals( oldSel.themeFile, theme.themeFile ) &&
Objects.equals( oldSel.lafClassName, theme.lafClassName ) ) Objects.equals( oldSel.lafClassName, theme.lafClassName ) )
{ {
@@ -273,28 +269,28 @@ public class IJThemesPanel
private void themesListValueChanged( ListSelectionEvent e ) { private void themesListValueChanged( ListSelectionEvent e ) {
IJThemeInfo themeInfo = themesList.getSelectedValue(); IJThemeInfo themeInfo = themesList.getSelectedValue();
boolean bundledTheme = (themeInfo != null && themeInfo.resourceName != null); pluginButton.setEnabled( themeInfo != null && themeInfo.pluginUrl != null );
saveButton.setEnabled( bundledTheme ); sourceCodeButton.setEnabled( themeInfo != null && themeInfo.sourceCodePath != null );
sourceCodeButton.setEnabled( bundledTheme );
if( e.getValueIsAdjusting() || isAdjustingThemesList ) if( e.getValueIsAdjusting() || isAdjustingThemesList )
return; return;
EventQueue.invokeLater( () -> { EventQueue.invokeLater( () -> {
setTheme( themeInfo ); setTheme( themeInfo, false );
} ); } );
} }
private void setTheme( IJThemeInfo themeInfo ) { private void setTheme( IJThemeInfo themeInfo, boolean reload ) {
if( themeInfo == null ) if( themeInfo == null )
return; return;
// change look and feel // change look and feel
if( themeInfo.lafClassName != null ) { if( themeInfo.lafClassName != null ) {
if( themeInfo.lafClassName.equals( UIManager.getLookAndFeel().getClass().getName() ) ) if( !reload && themeInfo.lafClassName.equals( UIManager.getLookAndFeel().getClass().getName() ) )
return; return;
FlatAnimatedLafChange.showSnapshot(); if( !reload )
FlatAnimatedLafChange.showSnapshot();
try { try {
UIManager.setLookAndFeel( themeInfo.lafClassName ); UIManager.setLookAndFeel( themeInfo.lafClassName );
@@ -303,81 +299,59 @@ public class IJThemesPanel
showInformationDialog( "Failed to create '" + themeInfo.lafClassName + "'.", ex ); showInformationDialog( "Failed to create '" + themeInfo.lafClassName + "'.", ex );
} }
} else if( themeInfo.themeFile != null ) { } else if( themeInfo.themeFile != null ) {
FlatAnimatedLafChange.showSnapshot(); if( !reload )
FlatAnimatedLafChange.showSnapshot();
try { try {
if( themeInfo.themeFile.getName().endsWith( ".properties" ) ) { if( themeInfo.themeFile.getName().endsWith( ".properties" ) )
FlatLaf.setup( new FlatPropertiesLaf( themeInfo.name, themeInfo.themeFile ) ); FlatLaf.setup( new FlatPropertiesLaf( themeInfo.name, themeInfo.themeFile ) );
} else else
FlatLaf.setup( IntelliJTheme.createLaf( new FileInputStream( themeInfo.themeFile ) ) ); FlatLaf.setup( IntelliJTheme.createLaf( new FileInputStream( themeInfo.themeFile ) ) );
DemoPrefs.getState().put( DemoPrefs.KEY_LAF_THEME, DemoPrefs.FILE_PREFIX + themeInfo.themeFile ); DemoPrefs.getState().put( DemoPrefs.KEY_LAF_THEME_FILE, themeInfo.themeFile.getAbsolutePath() );
} catch( Exception ex ) { } catch( Exception ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex ); LoggingFacade.INSTANCE.logSevere( null, ex );
showInformationDialog( "Failed to load '" + themeInfo.themeFile + "'.", ex ); showInformationDialog( "Failed to load '" + themeInfo.themeFile + "'.", ex );
} }
} else { } else {
FlatAnimatedLafChange.showSnapshot(); JOptionPane.showMessageDialog( SwingUtilities.windowForComponent( this ),
"Missing lafClassName for '" + themeInfo.name + "'",
IntelliJTheme.setup( getClass().getResourceAsStream( THEMES_PACKAGE + themeInfo.resourceName ) ); "FlatLaf", JOptionPane.INFORMATION_MESSAGE );
DemoPrefs.getState().put( DemoPrefs.KEY_LAF_THEME, DemoPrefs.RESOURCE_PREFIX + themeInfo.resourceName ); return;
} }
// update all components // update all components
FlatLaf.updateUI(); FlatLaf.updateUI();
FlatAnimatedLafChange.hideSnapshotWithAnimation();
if( !reload )
FlatAnimatedLafChange.hideSnapshotWithAnimation();
} }
private void saveTheme() { private void browsePlugin() {
IJThemeInfo themeInfo = themesList.getSelectedValue(); IJThemeInfo themeInfo = themesList.getSelectedValue();
if( themeInfo == null || themeInfo.resourceName == null ) if( themeInfo == null || themeInfo.pluginUrl == null )
return; return;
JFileChooser fileChooser = new JFileChooser(); browse( themeInfo.pluginUrl );
fileChooser.setSelectedFile( new File( lastDirectory, themeInfo.resourceName ) );
if( fileChooser.showSaveDialog( SwingUtilities.windowForComponent( this ) ) != JFileChooser.APPROVE_OPTION )
return;
File file = fileChooser.getSelectedFile();
lastDirectory = file.getParentFile();
// save theme
try {
Files.copy( getClass().getResourceAsStream( THEMES_PACKAGE + themeInfo.resourceName ),
file.toPath(), StandardCopyOption.REPLACE_EXISTING );
} catch( IOException ex ) {
showInformationDialog( "Failed to save theme to '" + file + "'.", ex );
return;
}
// save license
if( themeInfo.licenseFile != null ) {
try {
File licenseFile = new File( file.getParentFile(),
StringUtils.removeTrailing( file.getName(), ".theme.json" ) +
themeInfo.licenseFile.substring( themeInfo.licenseFile.indexOf( '.' ) ) );
Files.copy( getClass().getResourceAsStream( THEMES_PACKAGE + themeInfo.licenseFile ),
licenseFile.toPath(), StandardCopyOption.REPLACE_EXISTING );
} catch( IOException ex ) {
showInformationDialog( "Failed to save theme license to '" + file + "'.", ex );
return;
}
}
} }
private void browseSourceCode() { private void browseSourceCode() {
IJThemeInfo themeInfo = themesList.getSelectedValue(); IJThemeInfo themeInfo = themesList.getSelectedValue();
if( themeInfo == null || themeInfo.resourceName == null ) if( themeInfo == null || themeInfo.sourceCodeUrl == null )
return; return;
String themeUrl = themeInfo.sourceCodeUrl; String themeUrl = themeInfo.sourceCodeUrl;
if( themeInfo.sourceCodePath != null ) if( themeInfo.sourceCodePath != null )
themeUrl += '/' + themeInfo.sourceCodePath; themeUrl += '/' + themeInfo.sourceCodePath;
themeUrl = themeUrl.replace( " ", "%20" ); browse( themeUrl );
}
private void browse( String url ) {
url = url.replace( " ", "%20" );
try { try {
Desktop.getDesktop().browse( new URI( themeUrl ) ); Desktop.getDesktop().browse( new URI( url ) );
} catch( IOException | URISyntaxException ex ) { } catch( IOException | URISyntaxException ex ) {
showInformationDialog( "Failed to browse '" + themeUrl + "'.", ex ); showInformationDialog( "Failed to browse '" + url + "'.", ex );
} }
} }
@@ -413,8 +387,11 @@ public class IJThemesPanel
private void lafChanged( PropertyChangeEvent e ) { private void lafChanged( PropertyChangeEvent e ) {
if( "lookAndFeel".equals( e.getPropertyName() ) ) { if( "lookAndFeel".equals( e.getPropertyName() ) ) {
selectedCurrentLookAndFeel(); // use invokeLater() because KEY_LAF_THEME_FILE is updated after this event
lastLafChangeTime = System.currentTimeMillis(); EventQueue.invokeLater( () -> {
selectedCurrentLookAndFeel();
lastLafChangeTime = System.currentTimeMillis();
} );
} }
} }
@@ -429,19 +406,19 @@ public class IJThemesPanel
if( laf instanceof FlatLaf ) { if( laf instanceof FlatLaf ) {
List<Class<?>> lafClasses = new ArrayList<>(); List<Class<?>> lafClasses = new ArrayList<>();
// same as in UIDefaultsLoader.getLafClassesForDefaultsLoading()
for( Class<?> lafClass = laf.getClass();
FlatLaf.class.isAssignableFrom( lafClass );
lafClass = lafClass.getSuperclass() )
{
lafClasses.add( 0, lafClass );
}
// same as in IntelliJTheme.ThemeLaf.getLafClassesForDefaultsLoading()
if( laf instanceof IntelliJTheme.ThemeLaf ) { if( laf instanceof IntelliJTheme.ThemeLaf ) {
boolean dark = ((FlatLaf)laf).isDark(); boolean dark = ((FlatLaf)laf).isDark();
lafClasses.add( FlatLaf.class ); lafClasses.add( 1, dark ? FlatDarkLaf.class : FlatLightLaf.class );
lafClasses.add( dark ? FlatDarkLaf.class : FlatLightLaf.class ); lafClasses.add( 2, dark ? FlatDarculaLaf.class : FlatIntelliJLaf.class );
lafClasses.add( dark ? FlatDarculaLaf.class : FlatIntelliJLaf.class );
lafClasses.add( IntelliJTheme.ThemeLaf.class );
} else {
for( Class<?> lafClass = laf.getClass();
FlatLaf.class.isAssignableFrom( lafClass );
lafClass = lafClass.getSuperclass() )
{
lafClasses.add( 0, lafClass );
}
} }
boolean reload = false; boolean reload = false;
@@ -462,29 +439,25 @@ public class IJThemesPanel
} }
if( reload ) if( reload )
setTheme( themesList.getSelectedValue() ); setTheme( themesList.getSelectedValue(), true );
} }
} }
} }
private void selectedCurrentLookAndFeel() { private void selectedCurrentLookAndFeel() {
LookAndFeel lookAndFeel = UIManager.getLookAndFeel();
String theme = UIManager.getLookAndFeelDefaults().getString( DemoPrefs.THEME_UI_KEY );
if( theme == null && (lookAndFeel instanceof IntelliJTheme.ThemeLaf || lookAndFeel instanceof FlatPropertiesLaf) )
return;
Predicate<IJThemeInfo> test; Predicate<IJThemeInfo> test;
if( theme != null && theme.startsWith( DemoPrefs.RESOURCE_PREFIX ) ) { String lafClassName = UIManager.getLookAndFeel().getClass().getName();
String resourceName = theme.substring( DemoPrefs.RESOURCE_PREFIX.length() ); if( FlatPropertiesLaf.class.getName().equals( lafClassName ) ||
test = ti -> Objects.equals( ti.resourceName, resourceName ); IntelliJTheme.ThemeLaf.class.getName().equals( lafClassName ) )
} else if( theme != null && theme.startsWith( DemoPrefs.FILE_PREFIX ) ) { {
File themeFile = new File( theme.substring( DemoPrefs.FILE_PREFIX.length() ) ); String themeFileName = DemoPrefs.getState().get( DemoPrefs.KEY_LAF_THEME_FILE, "" );
if( themeFileName == null )
return;
File themeFile = new File( themeFileName );
test = ti -> Objects.equals( ti.themeFile, themeFile ); test = ti -> Objects.equals( ti.themeFile, themeFile );
} else { } else
String lafClassName = lookAndFeel.getClass().getName();
test = ti -> Objects.equals( ti.lafClassName, lafClassName ); test = ti -> Objects.equals( ti.lafClassName, lafClassName );
}
int newSel = -1; int newSel = -1;
for( int i = 0; i < themes.size(); i++ ) { for( int i = 0; i < themes.size(); i++ ) {
@@ -511,7 +484,7 @@ public class IJThemesPanel
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents // JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
JLabel themesLabel = new JLabel(); JLabel themesLabel = new JLabel();
toolBar = new JToolBar(); toolBar = new JToolBar();
saveButton = new JButton(); pluginButton = new JButton();
sourceCodeButton = new JButton(); sourceCodeButton = new JButton();
filterComboBox = new JComboBox<>(); filterComboBox = new JComboBox<>();
themesScrollPane = new JScrollPane(); themesScrollPane = new JScrollPane();
@@ -534,11 +507,11 @@ public class IJThemesPanel
{ {
toolBar.setFloatable(false); toolBar.setFloatable(false);
//---- saveButton ---- //---- pluginButton ----
saveButton.setToolTipText("Save .theme.json of selected IntelliJ theme to file."); pluginButton.setToolTipText("Opens the IntelliJ plugin page of selected IntelliJ theme in the browser.");
saveButton.setIcon(new FlatSVGIcon("com/formdev/flatlaf/demo/icons/download.svg")); pluginButton.setIcon(new FlatSVGIcon("com/formdev/flatlaf/demo/icons/plugin.svg"));
saveButton.addActionListener(e -> saveTheme()); pluginButton.addActionListener(e -> browsePlugin());
toolBar.add(saveButton); toolBar.add(pluginButton);
//---- sourceCodeButton ---- //---- sourceCodeButton ----
sourceCodeButton.setToolTipText("Opens the source code repository of selected IntelliJ theme in the browser."); sourceCodeButton.setToolTipText("Opens the source code repository of selected IntelliJ theme in the browser.");
@@ -554,7 +527,7 @@ public class IJThemesPanel
"light", "light",
"dark" "dark"
})); }));
filterComboBox.putClientProperty("JComponent.minimumWidth", 0); filterComboBox.putClientProperty(FlatClientProperties.MINIMUM_WIDTH, 0);
filterComboBox.setFocusable(false); filterComboBox.setFocusable(false);
filterComboBox.addActionListener(e -> filterChanged()); filterComboBox.addActionListener(e -> filterChanged());
add(filterComboBox, "cell 0 0,alignx right,growx 0"); add(filterComboBox, "cell 0 0,alignx right,growx 0");
@@ -573,7 +546,7 @@ public class IJThemesPanel
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables // JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
private JToolBar toolBar; private JToolBar toolBar;
private JButton saveButton; private JButton pluginButton;
private JButton sourceCodeButton; private JButton sourceCodeButton;
private JComboBox<String> filterComboBox; private JComboBox<String> filterComboBox;
private JScrollPane themesScrollPane; private JScrollPane themesScrollPane;

View File

@@ -1,4 +1,4 @@
JFDML JFormDesigner: "8.1.0.0.283" Java: "19.0.2" encoding: "UTF-8" JFDML JFormDesigner: "8.3" encoding: "UTF-8"
new FormModel { new FormModel {
contentType: "form/swing" contentType: "form/swing"
@@ -22,10 +22,10 @@ new FormModel {
name: "toolBar" name: "toolBar"
"floatable": false "floatable": false
add( new FormComponent( "javax.swing.JButton" ) { add( new FormComponent( "javax.swing.JButton" ) {
name: "saveButton" name: "pluginButton"
"toolTipText": "Save .theme.json of selected IntelliJ theme to file." "toolTipText": "Opens the IntelliJ plugin page of selected IntelliJ theme in the browser."
"icon": new com.jformdesigner.model.SwingIcon( 0, "/com/formdev/flatlaf/demo/icons/download.svg" ) "icon": new com.jformdesigner.model.SwingIcon( 0, "/com/formdev/flatlaf/demo/icons/plugin.svg" )
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "saveTheme", false ) ) addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "browsePlugin", false ) )
} ) } )
add( new FormComponent( "javax.swing.JButton" ) { add( new FormComponent( "javax.swing.JButton" ) {
name: "sourceCodeButton" name: "sourceCodeButton"

View File

@@ -38,6 +38,9 @@ public class IJThemesUpdater
themesManager.loadBundledThemes(); themesManager.loadBundledThemes();
for( IJThemeInfo ti : themesManager.bundledThemes ) { for( IJThemeInfo ti : themesManager.bundledThemes ) {
if( ti.discontinued )
continue;
if( ti.sourceCodeUrl == null || ti.sourceCodePath == null ) { if( ti.sourceCodeUrl == null || ti.sourceCodePath == null ) {
System.out.println( " " + ti.name + " NOT downloaded. Needs manual update from release on JetBrains Plugin portal." ); System.out.println( " " + ti.name + " NOT downloaded. Needs manual update from release on JetBrains Plugin portal." );
continue; continue;

View File

@@ -1,7 +0,0 @@
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd">
<polygon fill="#6E6E6E" points="9 7 12 7 8 11 4 7 7 7 7 2 9 2" transform="matrix(-1 0 0 1 16 0)"/>
<rect width="12" height="2" x="2" y="12" fill="#6E6E6E"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 448 B

View File

@@ -0,0 +1,4 @@
<!-- Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -->
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M11 4H7C5.34315 4 4 5.34315 4 7V9C4 10.6569 5.34315 12 7 12H11V11V10V6V5V4ZM12 5V4C12 3.44772 11.5523 3 11 3H7C5.13616 3 3.57006 4.27477 3.12602 6H1C0.447715 6 0 6.44772 0 7V9C0 9.55228 0.447715 10 1 10H3.12602C3.57006 11.7252 5.13616 13 7 13H11C11.5523 13 12 12.5523 12 12V11H15.5C15.7761 11 16 10.7761 16 10.5C16 10.2239 15.7761 10 15.5 10H12V6H15.5C15.7761 6 16 5.77614 16 5.5C16 5.22386 15.7761 5 15.5 5H12ZM3 7V9H1V7L3 7Z" fill="#6C707E"/>
</svg>

After

Width:  |  Height:  |  Size: 724 B

View File

@@ -0,0 +1,4 @@
<!-- Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -->
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M11 4H7C5.34315 4 4 5.34315 4 7V9C4 10.6569 5.34315 12 7 12H11V11V10V6V5V4ZM12 5V4C12 3.44772 11.5523 3 11 3H7C5.13616 3 3.57006 4.27477 3.12602 6H1C0.447715 6 0 6.44772 0 7V9C0 9.55228 0.447715 10 1 10H3.12602C3.57006 11.7252 5.13616 13 7 13H11C11.5523 13 12 12.5523 12 12V11H15.5C15.7761 11 16 10.7761 16 10.5C16 10.2239 15.7761 10 15.5 10H12V6H15.5C15.7761 6 16 5.77614 16 5.5C16 5.22386 15.7761 5 15.5 5H12ZM3 7V9H1V7L3 7Z" fill="#CED0D6"/>
</svg>

After

Width:  |  Height:  |  Size: 724 B

View File

@@ -1,186 +1,213 @@
{ {
"arc-theme.theme.json": { "arc-theme.theme.json": {
"name": "Arc", "name": "Arc",
"lafClassName": "com.formdev.flatlaf.intellijthemes.FlatArcIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "arc-themes.LICENSE.txt", "licenseFile": "arc-themes.LICENSE.txt",
"pluginUrl": "https://plugins.jetbrains.com/plugin/12451-arc-theme",
"sourceCodeUrl": "https://gitlab.com/zlamalp/arc-theme-idea", "sourceCodeUrl": "https://gitlab.com/zlamalp/arc-theme-idea",
"sourceCodePath": "blob/master/arc-theme-idea-light/resources/arc-theme.theme.json" "sourceCodePath": "blob/master/arc-theme-idea-light/resources/arc-theme.theme.json"
}, },
"arc-theme-orange.theme.json": { "arc-theme-orange.theme.json": {
"name": "Arc - Orange", "name": "Arc - Orange",
"lafClassName": "com.formdev.flatlaf.intellijthemes.FlatArcOrangeIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "arc-themes.LICENSE.txt", "licenseFile": "arc-themes.LICENSE.txt",
"pluginUrl": "https://plugins.jetbrains.com/plugin/12451-arc-theme",
"sourceCodeUrl": "https://gitlab.com/zlamalp/arc-theme-idea", "sourceCodeUrl": "https://gitlab.com/zlamalp/arc-theme-idea",
"sourceCodePath": "blob/master/arc-theme-idea-light/resources/arc-theme-orange.theme.json" "sourceCodePath": "blob/master/arc-theme-idea-light/resources/arc-theme-orange.theme.json"
}, },
"arc_theme_dark.theme.json": { "arc_theme_dark.theme.json": {
"name": "Arc Dark", "name": "Arc Dark",
"dark": true, "dark": true,
"lafClassName": "com.formdev.flatlaf.intellijthemes.FlatArcDarkIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "arc-themes.LICENSE.txt", "licenseFile": "arc-themes.LICENSE.txt",
"pluginUrl": "https://plugins.jetbrains.com/plugin/15175-arc-theme-dark",
"sourceCodeUrl": "https://gitlab.com/zlamalp/arc-theme-idea", "sourceCodeUrl": "https://gitlab.com/zlamalp/arc-theme-idea",
"sourceCodePath": "blob/master/arc-theme-idea-dark/resources/arc_theme_dark.theme.json" "sourceCodePath": "blob/master/arc-theme-idea-dark/resources/arc_theme_dark.theme.json"
}, },
"arc_theme_dark_orange.theme.json": { "arc_theme_dark_orange.theme.json": {
"name": "Arc Dark - Orange", "name": "Arc Dark - Orange",
"dark": true, "dark": true,
"lafClassName": "com.formdev.flatlaf.intellijthemes.FlatArcDarkOrangeIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "arc-themes.LICENSE.txt", "licenseFile": "arc-themes.LICENSE.txt",
"pluginUrl": "https://plugins.jetbrains.com/plugin/15175-arc-theme-dark",
"sourceCodeUrl": "https://gitlab.com/zlamalp/arc-theme-idea", "sourceCodeUrl": "https://gitlab.com/zlamalp/arc-theme-idea",
"sourceCodePath": "blob/master/arc-theme-idea-dark/resources/arc_theme_dark_orange.theme.json" "sourceCodePath": "blob/master/arc-theme-idea-dark/resources/arc_theme_dark_orange.theme.json"
}, },
"Carbon.theme.json": { "Carbon.theme.json": {
"name": "Carbon", "name": "Carbon",
"dark": true, "dark": true,
"lafClassName": "com.formdev.flatlaf.intellijthemes.FlatCarbonIJTheme",
"license": "Apache License 2.0", "license": "Apache License 2.0",
"licenseFile": "arc-themes.LICENSE.txt", "licenseFile": "arc-themes.LICENSE.txt",
"pluginUrl": "https://plugins.jetbrains.com/plugin/12280-carbon",
"sourceCodeUrl": "https://github.com/luisfer0793/theme-carbon", "sourceCodeUrl": "https://github.com/luisfer0793/theme-carbon",
"sourceCodePath": "blob/master/resources/matte_carbon_basics.theme.json" "sourceCodePath": "blob/master/resources/matte_carbon_basics.theme.json"
}, },
"Cobalt_2.theme.json": { "Cobalt_2.theme.json": {
"name": "Cobalt 2", "name": "Cobalt 2",
"dark": true, "dark": true,
"lafClassName": "com.formdev.flatlaf.intellijthemes.FlatCobalt2IJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "Cobalt_2.LICENSE.txt", "licenseFile": "Cobalt_2.LICENSE.txt",
"pluginUrl": "https://plugins.jetbrains.com/plugin/10745-cobalt-2",
"sourceCodeUrl": "https://github.com/ngehlert/cobalt2", "sourceCodeUrl": "https://github.com/ngehlert/cobalt2",
"sourceCodePath": "blob/master/Cobalt2-UI-Theme/resources/Cobalt_2.theme.json" "sourceCodePath": "blob/master/Cobalt2-UI-Theme/resources/Cobalt_2.theme.json"
}, },
"Cyan.theme.json": { "Cyan.theme.json": {
"name": "Cyan light", "name": "Cyan light",
"license": "MIT", "license": "MIT",
"lafClassName": "com.formdev.flatlaf.intellijthemes.FlatCyanLightIJTheme",
"licenseFile": "Cyan.LICENSE.txt", "licenseFile": "Cyan.LICENSE.txt",
"pluginUrl": "https://plugins.jetbrains.com/plugin/12102-cyan-light-theme",
"sourceCodeUrl": "https://github.com/OlyaB/CyanTheme", "sourceCodeUrl": "https://github.com/OlyaB/CyanTheme",
"sourceCodePath": "blob/master/src/Cyan.theme.json" "sourceCodePath": "blob/master/src/Cyan.theme.json"
}, },
"DarkFlatTheme.theme.json": { "DarkFlatTheme.theme.json": {
"name": "Dark Flat", "name": "Dark Flat",
"dark": true, "dark": true,
"lafClassName": "com.formdev.flatlaf.intellijthemes.FlatDarkFlatIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "DarkFlatTheme.LICENSE.txt", "licenseFile": "DarkFlatTheme.LICENSE.txt",
"pluginUrl": "https://plugins.jetbrains.com/plugin/12165-dark-flat-theme",
"sourceCodeUrl": "https://github.com/nerzhulart/DarkFlatTheme", "sourceCodeUrl": "https://github.com/nerzhulart/DarkFlatTheme",
"sourceCodePath": "blob/master/src/DarkFlatTheme.theme.json" "sourceCodePath": "blob/master/src/DarkFlatTheme.theme.json"
}, },
"DarkPurple.theme.json": { "DarkPurple.theme.json": {
"name": "Dark purple", "name": "Dark purple",
"dark": true, "dark": true,
"lafClassName": "com.formdev.flatlaf.intellijthemes.FlatDarkPurpleIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "DarkPurple.LICENSE.txt", "licenseFile": "DarkPurple.LICENSE.txt",
"pluginUrl": "https://plugins.jetbrains.com/plugin/12100-dark-purple-theme",
"sourceCodeUrl": "https://github.com/OlyaB/DarkPurpleTheme", "sourceCodeUrl": "https://github.com/OlyaB/DarkPurpleTheme",
"sourceCodePath": "blob/master/src/DarkPurple.theme.json" "sourceCodePath": "blob/master/src/DarkPurple.theme.json"
}, },
"Dracula.theme.json": { "Dracula.theme.json": {
"name": "Dracula", "name": "Dracula",
"dark": true, "dark": true,
"lafClassName": "com.formdev.flatlaf.intellijthemes.FlatDraculaIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "Dracula.LICENSE.txt", "licenseFile": "Dracula.LICENSE.txt",
"pluginUrl": "https://plugins.jetbrains.com/plugin/12275-dracula-theme",
"sourceCodeUrl": "https://github.com/dracula/jetbrains", "sourceCodeUrl": "https://github.com/dracula/jetbrains",
"sourceCodePath": "blob/master/src/main/resources/themes/Dracula.theme.json" "sourceCodePath": "blob/master/src/main/resources/themes/Dracula.theme.json"
}, },
"Gradianto_dark_fuchsia.theme.json": { "Gradianto_dark_fuchsia.theme.json": {
"name": "Gradianto Dark Fuchsia", "name": "Gradianto Dark Fuchsia",
"dark": true, "dark": true,
"lafClassName": "com.formdev.flatlaf.intellijthemes.FlatGradiantoDarkFuchsiaIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "Gradianto.LICENSE.txt", "licenseFile": "Gradianto.LICENSE.txt",
"pluginUrl": "https://plugins.jetbrains.com/plugin/12334-gradianto",
"sourceCodeUrl": "https://github.com/thvardhan/Gradianto", "sourceCodeUrl": "https://github.com/thvardhan/Gradianto",
"sourceCodePath": "blob/master/src/main/resources/Gradianto_dark_fuchsia.theme.json" "sourceCodePath": "blob/master/src/main/resources/Gradianto_dark_fuchsia.theme.json"
}, },
"Gradianto_deep_ocean.theme.json": { "Gradianto_deep_ocean.theme.json": {
"name": "Gradianto Deep Ocean", "name": "Gradianto Deep Ocean",
"dark": true, "dark": true,
"lafClassName": "com.formdev.flatlaf.intellijthemes.FlatGradiantoDeepOceanIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "Gradianto.LICENSE.txt", "licenseFile": "Gradianto.LICENSE.txt",
"pluginUrl": "https://plugins.jetbrains.com/plugin/12334-gradianto",
"sourceCodeUrl": "https://github.com/thvardhan/Gradianto", "sourceCodeUrl": "https://github.com/thvardhan/Gradianto",
"sourceCodePath": "blob/master/src/main/resources/Gradianto_deep_ocean.theme.json" "sourceCodePath": "blob/master/src/main/resources/Gradianto_deep_ocean.theme.json"
}, },
"Gradianto_midnight_blue.theme.json": { "Gradianto_midnight_blue.theme.json": {
"name": "Gradianto Midnight Blue", "name": "Gradianto Midnight Blue",
"dark": true, "dark": true,
"lafClassName": "com.formdev.flatlaf.intellijthemes.FlatGradiantoMidnightBlueIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "Gradianto.LICENSE.txt", "licenseFile": "Gradianto.LICENSE.txt",
"pluginUrl": "https://plugins.jetbrains.com/plugin/12334-gradianto",
"sourceCodeUrl": "https://github.com/thvardhan/Gradianto", "sourceCodeUrl": "https://github.com/thvardhan/Gradianto",
"sourceCodePath": "blob/master/src/main/resources/Gradianto_midnight_blue.theme.json" "sourceCodePath": "blob/master/src/main/resources/Gradianto_midnight_blue.theme.json"
}, },
"Gradianto_Nature_Green.theme.json": { "Gradianto_Nature_Green.theme.json": {
"name": "Gradianto Nature Green", "name": "Gradianto Nature Green",
"dark": true, "dark": true,
"lafClassName": "com.formdev.flatlaf.intellijthemes.FlatGradiantoNatureGreenIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "Gradianto.LICENSE.txt", "licenseFile": "Gradianto.LICENSE.txt",
"pluginUrl": "https://plugins.jetbrains.com/plugin/12334-gradianto",
"sourceCodeUrl": "https://github.com/thvardhan/Gradianto", "sourceCodeUrl": "https://github.com/thvardhan/Gradianto",
"sourceCodePath": "blob/master/src/main/resources/Gradianto_Nature_Green.theme.json" "sourceCodePath": "blob/master/src/main/resources/Gradianto_Nature_Green.theme.json"
}, },
"Gray.theme.json": { "Gray.theme.json": {
"name": "Gray", "name": "Gray",
"license": "MIT", "license": "MIT",
"lafClassName": "com.formdev.flatlaf.intellijthemes.FlatGrayIJTheme",
"licenseFile": "Gray.LICENSE.txt", "licenseFile": "Gray.LICENSE.txt",
"pluginUrl": "https://plugins.jetbrains.com/plugin/12103-gray-theme",
"sourceCodeUrl": "https://github.com/OlyaB/GreyTheme", "sourceCodeUrl": "https://github.com/OlyaB/GreyTheme",
"sourceCodePath": "blob/master/src/Gray.theme.json" "sourceCodePath": "blob/master/src/Gray.theme.json"
}, },
"gruvbox_dark_hard.theme.json": { "gruvbox_dark_hard.theme.json": {
"name": "Gruvbox Dark Hard", "name": "Gruvbox Dark Hard",
"dark": true, "dark": true,
"lafClassName": "com.formdev.flatlaf.intellijthemes.FlatGruvboxDarkHardIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "gruvbox_theme.LICENSE.txt", "licenseFile": "gruvbox_theme.LICENSE.txt",
"pluginUrl": "https://plugins.jetbrains.com/plugin/12310-gruvbox-theme",
"sourceCodeUrl": "https://github.com/Vincent-P/gruvbox-intellij-theme", "sourceCodeUrl": "https://github.com/Vincent-P/gruvbox-intellij-theme",
"sourceCodePath": "blob/master/src/main/resources/gruvbox_dark_hard.theme.json" "sourceCodePath": "blob/master/src/main/resources/gruvbox_dark_hard.theme.json"
}, },
"gruvbox_dark_medium.theme.json": {
"name": "Gruvbox Dark Medium",
"dark": true,
"license": "MIT",
"licenseFile": "gruvbox_theme.LICENSE.txt",
"sourceCodeUrl": "https://github.com/Vincent-P/gruvbox-intellij-theme",
"sourceCodePath": "blob/master/src/main/resources/gruvbox_dark_medium.theme.json"
},
"gruvbox_dark_soft.theme.json": {
"name": "Gruvbox Dark Soft",
"dark": true,
"license": "MIT",
"licenseFile": "gruvbox_theme.LICENSE.txt",
"sourceCodeUrl": "https://github.com/Vincent-P/gruvbox-intellij-theme",
"sourceCodePath": "blob/master/src/main/resources/gruvbox_dark_soft.theme.json"
},
"HiberbeeDark.theme.json": { "HiberbeeDark.theme.json": {
"name": "Hiberbee Dark", "name": "Hiberbee Dark",
"dark": true, "dark": true,
"lafClassName": "com.formdev.flatlaf.intellijthemes.FlatHiberbeeDarkIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "Hiberbee.LICENSE.txt", "licenseFile": "Hiberbee.LICENSE.txt",
"pluginUrl": "https://plugins.jetbrains.com/plugin/12118-hiberbee-theme",
"sourceCodeUrl": "https://github.com/Hiberbee/themes", "sourceCodeUrl": "https://github.com/Hiberbee/themes",
"sourceCodePath": "blob/latest/src/intellij/src/main/resources/themes/HiberbeeDark.theme.json" "sourceCodePath": "blob/latest/src/intellij/src/main/resources/themes/HiberbeeDark.theme.json"
}, },
"HighContrast.theme.json": { "HighContrast.theme.json": {
"name": "High contrast", "name": "High Contrast",
"dark": true, "dark": true,
"license": "MIT", "lafClassName": "com.formdev.flatlaf.intellijthemes.FlatHighContrastIJTheme",
"license": "Apache License 2.0",
"licenseFile": "HighContrast.LICENSE.txt", "licenseFile": "HighContrast.LICENSE.txt",
"sourceCodeUrl": "https://github.com/OlyaB/HighContrastTheme", "sourceCodeUrl": "https://github.com/JetBrains/intellij-community",
"sourceCodePath": "blob/master/src/HighContrast.theme.json" "sourceCodePath": "blob/master/platform/platform-resources/src/themes/HighContrast.theme.json"
}, },
"LightFlatTheme.theme.json": { "LightFlatTheme.theme.json": {
"name": "Light Flat", "name": "Light Flat",
"license": "MIT", "license": "MIT",
"lafClassName": "com.formdev.flatlaf.intellijthemes.FlatLightFlatIJTheme",
"licenseFile": "LightFlatTheme.LICENSE.txt", "licenseFile": "LightFlatTheme.LICENSE.txt",
"pluginUrl": "https://plugins.jetbrains.com/plugin/12169-light-flat-theme",
"sourceCodeUrl": "https://github.com/nerzhulart/LightFlatTheme", "sourceCodeUrl": "https://github.com/nerzhulart/LightFlatTheme",
"sourceCodePath": "blob/master/src/LightFlatTheme.theme.json" "sourceCodePath": "blob/master/src/LightFlatTheme.theme.json"
}, },
"MaterialTheme.theme.json": { "MaterialTheme.theme.json": {
"name": "Material Design Dark", "name": "Material Design Dark",
"dark": true, "dark": true,
"lafClassName": "com.formdev.flatlaf.intellijthemes.FlatMaterialDesignDarkIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "MaterialTheme.LICENSE.txt", "licenseFile": "MaterialTheme.LICENSE.txt",
"pluginUrl": "https://plugins.jetbrains.com/plugin/12134-material-design-dark-theme",
"sourceCodeUrl": "https://github.com/xinkunZ/NotReallyMDTheme", "sourceCodeUrl": "https://github.com/xinkunZ/NotReallyMDTheme",
"sourceCodePath": "blob/master/src/main/resources/MaterialTheme.theme.json" "sourceCodePath": "blob/master/src/main/resources/MaterialTheme.theme.json"
}, },
"Monocai.theme.json": { "Monocai.theme.json": {
"name": "Monocai", "name": "Monocai",
"dark": true, "dark": true,
"lafClassName": "com.formdev.flatlaf.intellijthemes.FlatMonocaiIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "Monocai.LICENSE.txt", "licenseFile": "Monocai.LICENSE.txt",
"sourceCodeUrl": "https://github.com/bmikaili/intellij-monocai-theme", "pluginUrl": "https://plugins.jetbrains.com/plugin/12163-monocai-color-theme",
"sourceCodeUrl": "https://github.com/TheEggi/intellij-monocai-theme",
"sourceCodePath": "blob/master/resources/Monocai.theme.json" "sourceCodePath": "blob/master/resources/Monocai.theme.json"
}, },
"Monokai_Pro.default.theme.json": { "Monokai_Pro.default.theme.json": {
"name": "Monokai Pro", "name": "Monokai Pro",
"discontinued": true,
"dark": true, "dark": true,
"lafClassName": "com.formdev.flatlaf.intellijthemes.FlatMonokaiProIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "Monokai_Pro.LICENSE.txt", "licenseFile": "Monokai_Pro.LICENSE.txt",
"sourceCodeUrl": "https://github.com/subtheme-dev/monokai-pro" "sourceCodeUrl": "https://github.com/subtheme-dev/monokai-pro"
@@ -188,22 +215,28 @@
"nord.theme.json": { "nord.theme.json": {
"name": "Nord", "name": "Nord",
"dark": true, "dark": true,
"lafClassName": "com.formdev.flatlaf.intellijthemes.FlatNordIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "nord.LICENSE.txt", "licenseFile": "nord.LICENSE.txt",
"sourceCodeUrl": "https://github.com/arcticicestudio/nord-jetbrains", "pluginUrl": "https://plugins.jetbrains.com/plugin/10321-nord",
"sourceCodeUrl": "https://github.com/nordtheme/jetbrains",
"sourceCodePath": "blob/main/src/nord.theme.json" "sourceCodePath": "blob/main/src/nord.theme.json"
}, },
"one_dark.theme.json": { "one_dark.theme.json": {
"name": "One Dark", "name": "One Dark",
"dark": true, "dark": true,
"lafClassName": "com.formdev.flatlaf.intellijthemes.FlatOneDarkIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "one_dark.LICENSE.txt", "licenseFile": "one_dark.LICENSE.txt",
"pluginUrl": "https://plugins.jetbrains.com/plugin/11938-one-dark-theme",
"sourceCodeUrl": "https://github.com/one-dark/jetbrains-one-dark-theme", "sourceCodeUrl": "https://github.com/one-dark/jetbrains-one-dark-theme",
"sourceCodePath": "blob/master/buildSrc/templates/oneDark.template.theme.json" "sourceCodePath": "blob/master/buildSrc/templates/oneDark.template.theme.json"
}, },
"SolarizedDark.theme.json": { "SolarizedDark.theme.json": {
"name": "Solarized Dark", "name": "Solarized Dark",
"discontinued": true,
"dark": true, "dark": true,
"lafClassName": "com.formdev.flatlaf.intellijthemes.FlatSolarizedDarkIJTheme",
"license": "The Unlicense", "license": "The Unlicense",
"licenseFile": "Solarized.LICENSE.txt", "licenseFile": "Solarized.LICENSE.txt",
"sourceCodeUrl": "https://github.com/4lex4/intellij-platform-solarized", "sourceCodeUrl": "https://github.com/4lex4/intellij-platform-solarized",
@@ -211,6 +244,8 @@
}, },
"SolarizedLight.theme.json": { "SolarizedLight.theme.json": {
"name": "Solarized Light", "name": "Solarized Light",
"discontinued": true,
"lafClassName": "com.formdev.flatlaf.intellijthemes.FlatSolarizedLightIJTheme",
"license": "The Unlicense", "license": "The Unlicense",
"licenseFile": "Solarized.LICENSE.txt", "licenseFile": "Solarized.LICENSE.txt",
"sourceCodeUrl": "https://github.com/4lex4/intellij-platform-solarized", "sourceCodeUrl": "https://github.com/4lex4/intellij-platform-solarized",
@@ -219,24 +254,30 @@
"Spacegray.theme.json": { "Spacegray.theme.json": {
"name": "Spacegray", "name": "Spacegray",
"dark": true, "dark": true,
"lafClassName": "com.formdev.flatlaf.intellijthemes.FlatSpacegrayIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "Spacegray.LICENSE.txt", "licenseFile": "Spacegray.LICENSE.txt",
"pluginUrl": "https://plugins.jetbrains.com/plugin/12122-spacegray-theme",
"sourceCodeUrl": "https://github.com/mturlo/intellij-spacegray", "sourceCodeUrl": "https://github.com/mturlo/intellij-spacegray",
"sourceCodePath": "blob/master/src/Spacegray.theme.json" "sourceCodePath": "blob/master/src/Spacegray.theme.json"
}, },
"vuesion_theme.theme.json": { "vuesion_theme.theme.json": {
"name": "Vuesion", "name": "Vuesion",
"dark": true, "dark": true,
"lafClassName": "com.formdev.flatlaf.intellijthemes.FlatVuesionIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "vuesion_theme.LICENSE.txt", "licenseFile": "vuesion_theme.LICENSE.txt",
"pluginUrl": "https://plugins.jetbrains.com/plugin/12226-vuesion-theme",
"sourceCodeUrl": "https://github.com/vuesion/intellij-theme", "sourceCodeUrl": "https://github.com/vuesion/intellij-theme",
"sourceCodePath": "blob/master/resources/META-INF/vuesion_theme.theme.json" "sourceCodePath": "blob/master/resources/META-INF/vuesion_theme.theme.json"
}, },
"Xcode-Dark.theme.json": { "Xcode-Dark.theme.json": {
"name": "Xcode-Dark", "name": "Xcode-Dark",
"dark": true, "dark": true,
"lafClassName": "com.formdev.flatlaf.intellijthemes.FlatXcodeDarkIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "Xcode-Dark.LICENSE.txt", "licenseFile": "Xcode-Dark.LICENSE.txt",
"pluginUrl": "https://plugins.jetbrains.com/plugin/13106-xcode-dark-theme",
"sourceCodeUrl": "https://github.com/antelle/intellij-xcode-dark-theme", "sourceCodeUrl": "https://github.com/antelle/intellij-xcode-dark-theme",
"sourceCodePath": "blob/master/resources/Xcode-Dark.theme.json" "sourceCodePath": "blob/master/resources/Xcode-Dark.theme.json"
}, },
@@ -244,132 +285,166 @@
"material-theme-ui-lite/Arc Dark.theme.json": { "material-theme-ui-lite/Arc Dark.theme.json": {
"name": "Material Theme UI Lite / Arc Dark", "name": "Material Theme UI Lite / Arc Dark",
"dark": true, "dark": true,
"lafClassName": "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatMTArcDarkIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt", "licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite", "pluginUrl": "https://plugins.jetbrains.com/plugin/8006-material-theme-ui",
"sourceCodeUrl": "https://github.com/AtomMaterialUI/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/regular/Arc Dark.theme.json" "sourceCodePath": "blob/master/src/main/resources/themes/regular/Arc Dark.theme.json"
}, },
"material-theme-ui-lite/Atom One Dark.theme.json": { "material-theme-ui-lite/Atom One Dark.theme.json": {
"name": "Material Theme UI Lite / Atom One Dark", "name": "Material Theme UI Lite / Atom One Dark",
"dark": true, "dark": true,
"lafClassName": "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatMTAtomOneDarkIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt", "licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite", "pluginUrl": "https://plugins.jetbrains.com/plugin/8006-material-theme-ui",
"sourceCodeUrl": "https://github.com/AtomMaterialUI/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/regular/Atom One Dark.theme.json" "sourceCodePath": "blob/master/src/main/resources/themes/regular/Atom One Dark.theme.json"
}, },
"material-theme-ui-lite/Atom One Light.theme.json": { "material-theme-ui-lite/Atom One Light.theme.json": {
"name": "Material Theme UI Lite / Atom One Light", "name": "Material Theme UI Lite / Atom One Light",
"lafClassName": "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatMTAtomOneLightIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt", "licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite", "pluginUrl": "https://plugins.jetbrains.com/plugin/8006-material-theme-ui",
"sourceCodeUrl": "https://github.com/AtomMaterialUI/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/regular/Atom One Light.theme.json" "sourceCodePath": "blob/master/src/main/resources/themes/regular/Atom One Light.theme.json"
}, },
"material-theme-ui-lite/Dracula.theme.json": { "material-theme-ui-lite/Dracula.theme.json": {
"name": "Material Theme UI Lite / Dracula", "name": "Material Theme UI Lite / Dracula",
"dark": true, "dark": true,
"lafClassName": "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatMTDraculaIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt", "licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite", "pluginUrl": "https://plugins.jetbrains.com/plugin/8006-material-theme-ui",
"sourceCodeUrl": "https://github.com/AtomMaterialUI/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/regular/Dracula.theme.json" "sourceCodePath": "blob/master/src/main/resources/themes/regular/Dracula.theme.json"
}, },
"material-theme-ui-lite/GitHub.theme.json": { "material-theme-ui-lite/GitHub.theme.json": {
"name": "Material Theme UI Lite / GitHub", "name": "Material Theme UI Lite / GitHub",
"lafClassName": "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatMTGitHubIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt", "licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite", "pluginUrl": "https://plugins.jetbrains.com/plugin/8006-material-theme-ui",
"sourceCodeUrl": "https://github.com/AtomMaterialUI/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/regular/GitHub.theme.json" "sourceCodePath": "blob/master/src/main/resources/themes/regular/GitHub.theme.json"
}, },
"material-theme-ui-lite/GitHub Dark.theme.json": { "material-theme-ui-lite/GitHub Dark.theme.json": {
"name": "Material Theme UI Lite / GitHub Dark", "name": "Material Theme UI Lite / GitHub Dark",
"dark": true, "dark": true,
"lafClassName": "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatMTGitHubDarkIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt", "licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite", "pluginUrl": "https://plugins.jetbrains.com/plugin/8006-material-theme-ui",
"sourceCodeUrl": "https://github.com/AtomMaterialUI/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/regular/GitHub Dark.theme.json" "sourceCodePath": "blob/master/src/main/resources/themes/regular/GitHub Dark.theme.json"
}, },
"material-theme-ui-lite/Light Owl.theme.json": { "material-theme-ui-lite/Light Owl.theme.json": {
"name": "Material Theme UI Lite / Light Owl", "name": "Material Theme UI Lite / Light Owl",
"lafClassName": "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatMTLightOwlIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt", "licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite", "pluginUrl": "https://plugins.jetbrains.com/plugin/8006-material-theme-ui",
"sourceCodeUrl": "https://github.com/AtomMaterialUI/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/regular/Light Owl.theme.json" "sourceCodePath": "blob/master/src/main/resources/themes/regular/Light Owl.theme.json"
}, },
"material-theme-ui-lite/Material Darker.theme.json": { "material-theme-ui-lite/Material Darker.theme.json": {
"name": "Material Theme UI Lite / Material Darker", "name": "Material Theme UI Lite / Material Darker",
"dark": true, "dark": true,
"lafClassName": "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatMTMaterialDarkerIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt", "licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite", "pluginUrl": "https://plugins.jetbrains.com/plugin/8006-material-theme-ui",
"sourceCodeUrl": "https://github.com/AtomMaterialUI/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/regular/Material Darker.theme.json" "sourceCodePath": "blob/master/src/main/resources/themes/regular/Material Darker.theme.json"
}, },
"material-theme-ui-lite/Material Deep Ocean.theme.json": { "material-theme-ui-lite/Material Deep Ocean.theme.json": {
"name": "Material Theme UI Lite / Material Deep Ocean", "name": "Material Theme UI Lite / Material Deep Ocean",
"dark": true, "dark": true,
"lafClassName": "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatMTMaterialDeepOceanIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt", "licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite", "pluginUrl": "https://plugins.jetbrains.com/plugin/8006-material-theme-ui",
"sourceCodeUrl": "https://github.com/AtomMaterialUI/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/regular/Material Deep Ocean.theme.json" "sourceCodePath": "blob/master/src/main/resources/themes/regular/Material Deep Ocean.theme.json"
}, },
"material-theme-ui-lite/Material Lighter.theme.json": { "material-theme-ui-lite/Material Lighter.theme.json": {
"name": "Material Theme UI Lite / Material Lighter", "name": "Material Theme UI Lite / Material Lighter",
"lafClassName": "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatMTMaterialLighterIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt", "licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite", "pluginUrl": "https://plugins.jetbrains.com/plugin/8006-material-theme-ui",
"sourceCodeUrl": "https://github.com/AtomMaterialUI/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/regular/Material Lighter.theme.json" "sourceCodePath": "blob/master/src/main/resources/themes/regular/Material Lighter.theme.json"
}, },
"material-theme-ui-lite/Material Oceanic.theme.json": { "material-theme-ui-lite/Material Oceanic.theme.json": {
"name": "Material Theme UI Lite / Material Oceanic", "name": "Material Theme UI Lite / Material Oceanic",
"dark": true, "dark": true,
"lafClassName": "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatMTMaterialOceanicIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt", "licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite", "pluginUrl": "https://plugins.jetbrains.com/plugin/8006-material-theme-ui",
"sourceCodeUrl": "https://github.com/AtomMaterialUI/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/regular/Material Oceanic.theme.json" "sourceCodePath": "blob/master/src/main/resources/themes/regular/Material Oceanic.theme.json"
}, },
"material-theme-ui-lite/Material Palenight.theme.json": { "material-theme-ui-lite/Material Palenight.theme.json": {
"name": "Material Theme UI Lite / Material Palenight", "name": "Material Theme UI Lite / Material Palenight",
"dark": true, "dark": true,
"lafClassName": "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatMTMaterialPalenightIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt", "licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite", "pluginUrl": "https://plugins.jetbrains.com/plugin/8006-material-theme-ui",
"sourceCodeUrl": "https://github.com/AtomMaterialUI/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/regular/Material Palenight.theme.json" "sourceCodePath": "blob/master/src/main/resources/themes/regular/Material Palenight.theme.json"
}, },
"material-theme-ui-lite/Monokai Pro.theme.json": { "material-theme-ui-lite/Monokai Pro.theme.json": {
"name": "Material Theme UI Lite / Monokai Pro", "name": "Material Theme UI Lite / Monokai Pro",
"dark": true, "dark": true,
"lafClassName": "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatMTMonokaiProIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt", "licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite", "pluginUrl": "https://plugins.jetbrains.com/plugin/8006-material-theme-ui",
"sourceCodeUrl": "https://github.com/AtomMaterialUI/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/regular/Monokai Pro.theme.json" "sourceCodePath": "blob/master/src/main/resources/themes/regular/Monokai Pro.theme.json"
}, },
"material-theme-ui-lite/Moonlight.theme.json": { "material-theme-ui-lite/Moonlight.theme.json": {
"name": "Material Theme UI Lite / Moonlight", "name": "Material Theme UI Lite / Moonlight",
"dark": true, "dark": true,
"lafClassName": "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatMTMoonlightIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt", "licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite", "pluginUrl": "https://plugins.jetbrains.com/plugin/8006-material-theme-ui",
"sourceCodeUrl": "https://github.com/AtomMaterialUI/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/regular/Moonlight.theme.json" "sourceCodePath": "blob/master/src/main/resources/themes/regular/Moonlight.theme.json"
}, },
"material-theme-ui-lite/Night Owl.theme.json": { "material-theme-ui-lite/Night Owl.theme.json": {
"name": "Material Theme UI Lite / Night Owl", "name": "Material Theme UI Lite / Night Owl",
"dark": true, "dark": true,
"lafClassName": "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatMTNightOwlIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt", "licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite", "pluginUrl": "https://plugins.jetbrains.com/plugin/8006-material-theme-ui",
"sourceCodeUrl": "https://github.com/AtomMaterialUI/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/regular/Night Owl.theme.json" "sourceCodePath": "blob/master/src/main/resources/themes/regular/Night Owl.theme.json"
}, },
"material-theme-ui-lite/Solarized Dark.theme.json": { "material-theme-ui-lite/Solarized Dark.theme.json": {
"name": "Material Theme UI Lite / Solarized Dark", "name": "Material Theme UI Lite / Solarized Dark",
"dark": true, "dark": true,
"lafClassName": "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatMTSolarizedDarkIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt", "licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite", "pluginUrl": "https://plugins.jetbrains.com/plugin/8006-material-theme-ui",
"sourceCodeUrl": "https://github.com/AtomMaterialUI/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/regular/Solarized Dark.theme.json" "sourceCodePath": "blob/master/src/main/resources/themes/regular/Solarized Dark.theme.json"
}, },
"material-theme-ui-lite/Solarized Light.theme.json": { "material-theme-ui-lite/Solarized Light.theme.json": {
"name": "Material Theme UI Lite / Solarized Light", "name": "Material Theme UI Lite / Solarized Light",
"lafClassName": "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatMTSolarizedLightIJTheme",
"license": "MIT", "license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt", "licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite", "pluginUrl": "https://plugins.jetbrains.com/plugin/8006-material-theme-ui",
"sourceCodeUrl": "https://github.com/AtomMaterialUI/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/regular/Solarized Light.theme.json" "sourceCodePath": "blob/master/src/main/resources/themes/regular/Solarized Light.theme.json"
} }
} }

View File

@@ -1,4 +1,7 @@
eclipse.preferences.version=1 eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.source=1.8
org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false
org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647 org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.align_type_members_on_columns=false

View File

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

View File

@@ -37,6 +37,7 @@ import java.net.URL;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.Function; import java.util.function.Function;
import javax.swing.Icon; import javax.swing.Icon;
import javax.swing.ImageIcon; import javax.swing.ImageIcon;
@@ -588,7 +589,12 @@ public class FlatSVGIcon
: GrayFilter.createDisabledIconFilter( dark ); : 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 { try {
setRenderingHints( g2 ); setRenderingHints( g2 );
@@ -596,6 +602,10 @@ public class FlatSVGIcon
paintSvg( g2, x, y ); paintSvg( g2, x, y );
} finally { } finally {
g2.dispose(); 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> colorMap;
private Map<Color, Color> darkColorMap; private Map<Color, Color> darkColorMap;
private Function<Color, Color> mapper; private Function<Color, Color> mapper;
private BiFunction<Component, Color, Color> mapperEx;
private Component c;
/** /**
* Returns the global ColorFilter that is applied to all icons. * Returns the global ColorFilter that is applied to all icons.
@@ -800,6 +812,22 @@ public class FlatSVGIcon
setMapper( mapper ); 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} * Returns a color modifying function or {@code null}
* *
@@ -821,12 +849,39 @@ public class FlatSVGIcon
* <pre>filter.setMapper( color -&gt; Color.RED );</pre> * <pre>filter.setMapper( color -&gt; Color.RED );</pre>
* *
* @param mapper The color mapper function * @param mapper The color mapper function
* @see #setMapperEx(BiFunction)
* @since 1.2 * @since 1.2
*/ */
public void setMapper( Function<Color, Color> mapper ) { public void setMapper( Function<Color, Color> mapper ) {
this.mapper = 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. * Returns the color mappings used for light themes.
* *
@@ -936,6 +991,11 @@ public class FlatSVGIcon
} }
public Color filter( Color color ) { public Color filter( Color color ) {
return filter( c, color );
}
/** @since 3.6 */
public Color filter( Component c, Color color ) {
// apply mappings // apply mappings
color = applyMappings( color ); color = applyMappings( color );
@@ -943,6 +1003,10 @@ public class FlatSVGIcon
if( mapper != null ) if( mapper != null )
color = mapper.apply( color ); color = mapper.apply( color );
// apply mapperEx function
if( mapperEx != null )
color = mapperEx.apply( c, color );
return color; return color;
} }
@@ -974,6 +1038,16 @@ public class FlatSVGIcon
return color; 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)}. * 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)}. * 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 * 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"). * 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 ) { public static void install( String activationKeys ) {
if( activationKeys == null )
activationKeys = "ctrl shift alt Y";
KeyStroke keyStroke = KeyStroke.getKeyStroke( activationKeys ); KeyStroke keyStroke = KeyStroke.getKeyStroke( activationKeys );
Toolkit.getDefaultToolkit().addAWTEventListener( e -> { Toolkit.getDefaultToolkit().addAWTEventListener( e -> {
if( e.getID() == KeyEvent.KEY_RELEASED && if( e.getID() == KeyEvent.KEY_RELEASED &&

View File

@@ -29,19 +29,37 @@ public class FlatTree
implements FlatComponentExtension, FlatStyleableComponent implements FlatComponentExtension, FlatStyleableComponent
{ {
/** /**
* Returns if the tree shows a wide selection * Returns whether tree shows a wide selection
*/ */
public boolean isWideSelection() { public boolean isWideSelection() {
return getClientPropertyBoolean( TREE_WIDE_SELECTION, "Tree.wideSelection" ); 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 ) { public void setWideSelection( boolean wideSelection ) {
putClientProperty( TREE_WIDE_SELECTION, 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}. * 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. * 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.focusedSelectedBackground = CheckBox.icon.selectedBackground
CheckBox.icon.hoverSelectedBackground = CheckBox.icon.selectedBackground CheckBox.icon.hoverSelectedBackground = CheckBox.icon.selectedBackground
CheckBox.icon.pressedSelectedBackground = 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].disabledBackground = CheckBox.icon[filled].background
CheckBox.icon[filled].focusedBackground = 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].focusedSelectedBackground = CheckBox.icon[filled].selectedBackground
CheckBox.icon[filled].hoverSelectedBackground = CheckBox.icon[filled].selectedBackground CheckBox.icon[filled].hoverSelectedBackground = CheckBox.icon[filled].selectedBackground
CheckBox.icon[filled].pressedSelectedBackground = 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 ---- #---- CheckBoxMenuItem ----

View File

@@ -18,7 +18,7 @@
// For maven compatibility, <font-version> should be in format <major>.<minor>[.<micro>]. // For maven compatibility, <font-version> should be in format <major>.<minor>[.<micro>].
// <build-number> is optional and should be incremented only if a new release is // <build-number> is optional and should be incremented only if a new release is
// necessary, but the <font-version> has not changed. // necessary, but the <font-version> has not changed.
version = "4.0" version = "4.1"
if( !rootProject.hasProperty( "release" ) ) if( !rootProject.hasProperty( "release" ) )
version = version.toString() + "-SNAPSHOT" version = version.toString() + "-SNAPSHOT"

View File

@@ -1,4 +1,7 @@
eclipse.preferences.version=1 eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.source=1.8
org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false
org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647 org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.align_type_members_on_columns=false

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