mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2026-02-11 22:47:13 -06:00
Compare commits
221 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
93408b50df | ||
|
|
465254c0da | ||
|
|
aaca7cace1 | ||
|
|
c995b4cbdf | ||
|
|
b251ff76e8 | ||
|
|
ea2a985481 | ||
|
|
3ca7ebbfee | ||
|
|
7e6dc269c5 | ||
|
|
7680c3a817 | ||
|
|
0e3cb95791 | ||
|
|
3f0b5d5a0e | ||
|
|
6e3633cca3 | ||
|
|
4f1e5cdb05 | ||
|
|
070cf9c40d | ||
|
|
5b0f13110a | ||
|
|
d7a5c353fe | ||
|
|
9e8b8697d1 | ||
|
|
58e073a05b | ||
|
|
1c6e8774cf | ||
|
|
1e724029ae | ||
|
|
9fdaa827b5 | ||
|
|
b9441050b2 | ||
|
|
8239cdd540 | ||
|
|
08419d6135 | ||
|
|
3a72232ae3 | ||
|
|
e61499e7c6 | ||
|
|
d3e6c7af14 | ||
|
|
ff11a11d28 | ||
|
|
855c41bf4a | ||
|
|
2b587d4dba | ||
|
|
5fabfc7051 | ||
|
|
db4173dd06 | ||
|
|
03b7a1c29e | ||
|
|
60968f77eb | ||
|
|
8bafa37b4a | ||
|
|
04602ac227 | ||
|
|
02636b260a | ||
|
|
c8e2e78955 | ||
|
|
19c86cf1f7 | ||
|
|
7ebc1b27c1 | ||
|
|
d4827b6ddf | ||
|
|
02f7cb8972 | ||
|
|
10677d469f | ||
|
|
df8212b49e | ||
|
|
c583a21bf7 | ||
|
|
5263125a04 | ||
|
|
056da35758 | ||
|
|
3ccaacfb00 | ||
|
|
bdb7438672 | ||
|
|
299250a710 | ||
|
|
1e2a75a19c | ||
|
|
0fb4c811f6 | ||
|
|
0d4946230e | ||
|
|
960f9d86c1 | ||
|
|
015645e173 | ||
|
|
36d5685f4c | ||
|
|
ddc8d6e29c | ||
|
|
119b4a922d | ||
|
|
5e4f00f0c8 | ||
|
|
15cbf28a0d | ||
|
|
f8e53c9064 | ||
|
|
b3c9638e47 | ||
|
|
d079741f94 | ||
|
|
c051ad5f72 | ||
|
|
1ed7aeaa45 | ||
|
|
2ac7234c32 | ||
|
|
6f63982054 | ||
|
|
d388158de7 | ||
|
|
8cfe1ca597 | ||
|
|
e7a766bf8f | ||
|
|
97988e90b4 | ||
|
|
f71dbb2647 | ||
|
|
04ad21b5b6 | ||
|
|
ff722c0b34 | ||
|
|
34b19f00e4 | ||
|
|
286ce15146 | ||
|
|
abfaf86cd5 | ||
|
|
1eee35035d | ||
|
|
bc4c7b25d3 | ||
|
|
0863e289a1 | ||
|
|
5c2d8ba555 | ||
|
|
0f27125107 | ||
|
|
f2882370de | ||
|
|
6715886b24 | ||
|
|
4945378dd3 | ||
|
|
b178450e81 | ||
|
|
e3ffdd3b7c | ||
|
|
5326971287 | ||
|
|
cd34c08dc9 | ||
|
|
edee73e0ea | ||
|
|
54a53fb527 | ||
|
|
62b96fbccd | ||
|
|
42cbb0666d | ||
|
|
1465fbaabc | ||
|
|
5575854e68 | ||
|
|
640f2ba9a2 | ||
|
|
b221fd1894 | ||
|
|
b64ab09b88 | ||
|
|
2870ee5c51 | ||
|
|
23f8ce867b | ||
|
|
835a1f155b | ||
|
|
3925f198d9 | ||
|
|
35e86ba772 | ||
|
|
dade1cba5a | ||
|
|
dcb4c09387 | ||
|
|
3e8b213367 | ||
|
|
202a0d159b | ||
|
|
5d247f6269 | ||
|
|
d8e59f2cf3 | ||
|
|
d81bcd5254 | ||
|
|
666b99971d | ||
|
|
0ba7798cbd | ||
|
|
c486f695f2 | ||
|
|
0bc2513c46 | ||
|
|
bc3504378b | ||
|
|
94fc75dc78 | ||
|
|
681c0cd4fe | ||
|
|
f7495a0a5b | ||
|
|
dd44d3ed2d | ||
|
|
86a4d0ab12 | ||
|
|
b43c3a9e00 | ||
|
|
babc8aa55d | ||
|
|
5dc88a6210 | ||
|
|
d612b9f4b8 | ||
|
|
9b1ae5c74a | ||
|
|
143f96360b | ||
|
|
f5e6b90e02 | ||
|
|
f36886aeb3 | ||
|
|
d26eb2674f | ||
|
|
68b8769d0d | ||
|
|
7f37e884d3 | ||
|
|
a4dc1b4151 | ||
|
|
022a67929a | ||
|
|
f7c867fb97 | ||
|
|
f0685d179e | ||
|
|
c8eaf5f587 | ||
|
|
ed69049c08 | ||
|
|
ae4037ee82 | ||
|
|
411a2f6d29 | ||
|
|
f24b3a6022 | ||
|
|
ebacad2d04 | ||
|
|
76f436726f | ||
|
|
6c8f813e53 | ||
|
|
5f6cc719ad | ||
|
|
00858002de | ||
|
|
072cc3c488 | ||
|
|
1f594b2ba8 | ||
|
|
03e5f8623e | ||
|
|
c32c00a5eb | ||
|
|
3a8a55a545 | ||
|
|
6c49b8bc4d | ||
|
|
cca9707f6b | ||
|
|
54d6959533 | ||
|
|
112116556d | ||
|
|
f30dd876e4 | ||
|
|
c6872d48b3 | ||
|
|
3283cfe22f | ||
|
|
aecb496142 | ||
|
|
5e78b21df7 | ||
|
|
1e3e4d7c61 | ||
|
|
2ef87dc789 | ||
|
|
b808f6e803 | ||
|
|
f3ca3a001a | ||
|
|
d524536575 | ||
|
|
0a4c01cd40 | ||
|
|
28904c34cc | ||
|
|
91f19bf94c | ||
|
|
0ea188f8db | ||
|
|
6c77b81277 | ||
|
|
d513ec497b | ||
|
|
07fc190b5f | ||
|
|
078e59a443 | ||
|
|
d49282dfe8 | ||
|
|
ddee4ef526 | ||
|
|
f11f68282b | ||
|
|
ac0cceb09b | ||
|
|
a238fd4505 | ||
|
|
8dc6242889 | ||
|
|
d17fffb82a | ||
|
|
0ad3180b10 | ||
|
|
c73fd51704 | ||
|
|
251198c66d | ||
|
|
d7462bd424 | ||
|
|
9af7f95197 | ||
|
|
2e16ded5d4 | ||
|
|
91e8d04a9f | ||
|
|
9453d55abd | ||
|
|
641fada6c4 | ||
|
|
a303cd2dec | ||
|
|
2b810addd8 | ||
|
|
63272a03cf | ||
|
|
49a0a83eca | ||
|
|
516bd80702 | ||
|
|
80ba75fdeb | ||
|
|
7027821c00 | ||
|
|
a3a49cef73 | ||
|
|
abf77d5399 | ||
|
|
6404b8de2a | ||
|
|
19055d5a18 | ||
|
|
c12adf12e7 | ||
|
|
b9c68fbe77 | ||
|
|
7bdfd49921 | ||
|
|
58fa2a5085 | ||
|
|
a400799db5 | ||
|
|
2a8e487c1f | ||
|
|
145631fd43 | ||
|
|
6a774d8c70 | ||
|
|
bfd746f981 | ||
|
|
3af54b7215 | ||
|
|
3ba9fc6c1c | ||
|
|
0a9ecd66a9 | ||
|
|
6991d6729e | ||
|
|
304cb0d57b | ||
|
|
41332de275 | ||
|
|
ef61ae504b | ||
|
|
f96baf1bc2 | ||
|
|
a20cfa6db3 | ||
|
|
6ac6698ecf | ||
|
|
8004d2761a | ||
|
|
25c2bbc851 | ||
|
|
33e37a7167 |
@@ -7,6 +7,11 @@ charset = latin1
|
|||||||
indent_style = tab
|
indent_style = tab
|
||||||
indent_size = 4
|
indent_size = 4
|
||||||
|
|
||||||
|
[{*.yaml,*.yml}]
|
||||||
|
end_of_line = lf
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
[*.java]
|
[*.java]
|
||||||
indent_style = tab
|
indent_style = tab
|
||||||
ij_continuation_indent_size = 4
|
ij_continuation_indent_size = 4
|
||||||
|
|||||||
32
.github/actions/cache-gradle/action.yml
vendored
Normal file
32
.github/actions/cache-gradle/action.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# https://docs.github.com/en/actions/tutorials/create-actions/create-a-composite-action#creating-a-composite-action-within-the-same-repository
|
||||||
|
|
||||||
|
# cache uses two files:
|
||||||
|
#
|
||||||
|
# - gradle-wrapper-<os>-<arch>-<hash>:
|
||||||
|
# contains the Gradle wrapper/distribution (~/.gradle/wrapper)
|
||||||
|
# and is updated when the Gradle version changed
|
||||||
|
# - gradle-caches-<os>-<arch>-<hash>:
|
||||||
|
# contains the Gradle caches (~/.gradle/caches), buildSrc/build and buildSrc/.gradle
|
||||||
|
# and is updated when Gradle related files were changed
|
||||||
|
# buildSrc/.gradle is needed so that buildSrc tasks are UP-TO-DATE
|
||||||
|
|
||||||
|
name: 'Cache Gradle'
|
||||||
|
runs:
|
||||||
|
using: "composite"
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: Cache '.gradle/wrapper'
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
key: gradle-wrapper-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles( 'gradle/wrapper/gradle-wrapper.properties' ) }}
|
||||||
|
path: |
|
||||||
|
~/.gradle/wrapper
|
||||||
|
|
||||||
|
- name: Cache '.gradle/caches' and 'buildSrc/build'
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
key: gradle-caches-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles( '**/*.gradle*', 'gradle/**', 'gradle.properties', 'buildSrc/src/**' ) }}
|
||||||
|
path: |
|
||||||
|
~/.gradle/caches
|
||||||
|
buildSrc/build
|
||||||
|
buildSrc/.gradle
|
||||||
144
.github/workflows/ci.yml
vendored
144
.github/workflows/ci.yml
vendored
@@ -14,6 +14,7 @@ on:
|
|||||||
- '.*'
|
- '.*'
|
||||||
- '**/.settings/**'
|
- '**/.settings/**'
|
||||||
- 'flatlaf-core/svg/**'
|
- 'flatlaf-core/svg/**'
|
||||||
|
- 'flatlaf-natives/**'
|
||||||
- 'flatlaf-testing/dumps/**'
|
- 'flatlaf-testing/dumps/**'
|
||||||
- 'flatlaf-testing/misc/**'
|
- 'flatlaf-testing/misc/**'
|
||||||
- 'images/**'
|
- 'images/**'
|
||||||
@@ -22,46 +23,50 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
strategy:
|
steps:
|
||||||
matrix:
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- uses: gradle/actions/wrapper-validation@v4
|
||||||
|
|
||||||
|
- name: Setup Java 21
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
java-version: 21
|
||||||
|
distribution: temurin # pre-installed on ubuntu-latest
|
||||||
|
|
||||||
|
- name: Cache Gradle
|
||||||
|
uses: ./.github/actions/cache-gradle
|
||||||
|
|
||||||
|
|
||||||
# test against
|
# test against
|
||||||
# - Java 8 (minimum requirement)
|
# - Java 8 (minimum requirement)
|
||||||
# - Java LTS versions (11, 17, ...)
|
# - Java LTS versions (11, 17, ...)
|
||||||
# - latest Java version(s)
|
# - latest Java version(s)
|
||||||
java:
|
|
||||||
- 8
|
|
||||||
- 11 # LTS
|
|
||||||
- 17 # LTS
|
|
||||||
- 21 # LTS
|
|
||||||
- 23 # latest
|
|
||||||
toolchain: [""]
|
|
||||||
# include:
|
|
||||||
# - java: 21
|
|
||||||
# toolchain: 22 # latest
|
|
||||||
|
|
||||||
steps:
|
- name: Build with Java 11 LTS
|
||||||
- uses: actions/checkout@v4
|
if: github.repository == 'JFormDesigner/FlatLaf'
|
||||||
|
run: ./gradlew build clean -Dtoolchain=11
|
||||||
|
|
||||||
- uses: gradle/wrapper-validation-action@v2
|
- name: Build with Java 17 LTS
|
||||||
if: matrix.java == '8'
|
if: github.repository == 'JFormDesigner/FlatLaf'
|
||||||
|
run: ./gradlew build clean -Dtoolchain=17
|
||||||
|
|
||||||
- name: Setup Java ${{ matrix.java }}
|
- name: Build with Java 21 LTS
|
||||||
uses: actions/setup-java@v4
|
if: github.repository == 'JFormDesigner/FlatLaf'
|
||||||
with:
|
run: ./gradlew build clean -Dtoolchain=21
|
||||||
java-version: ${{ matrix.java }}
|
|
||||||
distribution: temurin # Java 8, 11, 17 and 21 are pre-installed on ubuntu-latest
|
|
||||||
cache: gradle
|
|
||||||
|
|
||||||
- name: Check with Error Prone
|
- name: Build with Java 25 LTS
|
||||||
if: matrix.java == '11'
|
if: github.repository == 'JFormDesigner/FlatLaf'
|
||||||
run: ./gradlew errorprone clean -Dtoolchain=${{ matrix.toolchain }}
|
run: ./gradlew build clean -Dtoolchain=25
|
||||||
|
|
||||||
- name: Build with Gradle
|
|
||||||
run: ./gradlew build -Dtoolchain=${{ matrix.toolchain }}
|
|
||||||
|
|
||||||
- name: Upload artifacts
|
# build with Java 8 for snapshot
|
||||||
|
|
||||||
|
- name: Build with Java 8
|
||||||
|
run: ./gradlew build
|
||||||
|
|
||||||
|
- name: Upload artifacts to GitHub Actions
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
if: matrix.java == '11'
|
|
||||||
with:
|
with:
|
||||||
name: FlatLaf-build-artifacts
|
name: FlatLaf-build-artifacts
|
||||||
path: |
|
path: |
|
||||||
@@ -71,40 +76,15 @@ jobs:
|
|||||||
!**/*-sources.jar
|
!**/*-sources.jar
|
||||||
|
|
||||||
|
|
||||||
snapshot:
|
- name: Publish snapshot to Sonatype Central
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: build
|
|
||||||
if: |
|
if: |
|
||||||
|
github.repository == 'JFormDesigner/FlatLaf' &&
|
||||||
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-' ))
|
||||||
github.repository == 'JFormDesigner/FlatLaf'
|
run: ./gradlew publish -PskipFonts -Dorg.gradle.internal.publish.checksums.insecure=true -Dorg.gradle.parallel=false
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Setup Java 11
|
|
||||||
uses: actions/setup-java@v4
|
|
||||||
with:
|
|
||||||
java-version: 11
|
|
||||||
distribution: temurin # pre-installed on ubuntu-latest
|
|
||||||
cache: gradle
|
|
||||||
|
|
||||||
- name: Publish snapshot to oss.sonatype.org
|
|
||||||
run: ./gradlew publish :flatlaf-theme-editor:build -PskipFonts -Dorg.gradle.internal.publish.checksums.insecure=true -Dorg.gradle.parallel=false
|
|
||||||
env:
|
env:
|
||||||
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
|
SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }}
|
||||||
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
|
SONATYPE_PASSWORD: ${{ secrets.SONATYPE_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:
|
||||||
@@ -118,39 +98,29 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Java 11
|
- name: Setup Java 21
|
||||||
uses: actions/setup-java@v4
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
java-version: 11
|
java-version: 21
|
||||||
distribution: temurin # pre-installed on ubuntu-latest
|
distribution: temurin # pre-installed on ubuntu-latest
|
||||||
cache: gradle
|
|
||||||
|
|
||||||
- name: Release a new stable version to Maven Central
|
- name: Cache Gradle
|
||||||
run: ./gradlew publish :flatlaf-demo:build :flatlaf-theme-editor:build -PskipFonts -Prelease -Dorg.gradle.parallel=false
|
uses: ./.github/actions/cache-gradle
|
||||||
|
|
||||||
|
- name: Release a new stable version to Maven Central and build demo and theme editor
|
||||||
|
run: ./gradlew publishToSonatype closeSonatypeStagingRepository :flatlaf-demo:build :flatlaf-theme-editor:build -PskipFonts -Prelease -Dorg.gradle.parallel=false
|
||||||
env:
|
env:
|
||||||
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
|
SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }}
|
||||||
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
|
SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
|
||||||
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"
|
|
||||||
|
|||||||
40
.github/workflows/error-prone.yml
vendored
Normal file
40
.github/workflows/error-prone.yml
vendored
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions
|
||||||
|
# https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle
|
||||||
|
|
||||||
|
name: Error Prone
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- '*'
|
||||||
|
tags:
|
||||||
|
- '[0-9]*'
|
||||||
|
paths-ignore:
|
||||||
|
- '**.md'
|
||||||
|
- '.*'
|
||||||
|
- '**/.settings/**'
|
||||||
|
- 'flatlaf-core/svg/**'
|
||||||
|
- 'flatlaf-natives/**'
|
||||||
|
- 'flatlaf-testing/dumps/**'
|
||||||
|
- 'flatlaf-testing/misc/**'
|
||||||
|
- 'images/**'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
error-prone:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.repository == 'JFormDesigner/FlatLaf'
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Java 21
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
java-version: 21
|
||||||
|
distribution: temurin # pre-installed on ubuntu-latest
|
||||||
|
|
||||||
|
- name: Cache Gradle
|
||||||
|
uses: ./.github/actions/cache-gradle
|
||||||
|
|
||||||
|
- name: Check with Error Prone
|
||||||
|
run: ./gradlew errorprone
|
||||||
18
.github/workflows/fonts.yml
vendored
18
.github/workflows/fonts.yml
vendored
@@ -34,29 +34,31 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Java 11
|
- name: Setup Java 21
|
||||||
uses: actions/setup-java@v4
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
java-version: 11
|
java-version: 21
|
||||||
distribution: temurin # pre-installed on ubuntu-latest
|
distribution: temurin # pre-installed on ubuntu-latest
|
||||||
cache: gradle
|
|
||||||
|
- name: Cache Gradle
|
||||||
|
uses: ./.github/actions/cache-gradle
|
||||||
|
|
||||||
- name: Build with Gradle
|
- name: Build with Gradle
|
||||||
run: ./gradlew :flatlaf-fonts-${{ matrix.font }}:build
|
run: ./gradlew :flatlaf-fonts-${{ matrix.font }}:build
|
||||||
if: startsWith( github.ref, format( 'refs/tags/fonts/{0}-', matrix.font ) ) != true
|
if: startsWith( github.ref, format( 'refs/tags/fonts/{0}-', matrix.font ) ) != true
|
||||||
|
|
||||||
- name: Publish snapshot to oss.sonatype.org
|
- name: Publish snapshot to Sonatype Central
|
||||||
run: ./gradlew :flatlaf-fonts-${{ matrix.font }}:publish -Dorg.gradle.internal.publish.checksums.insecure=true
|
run: ./gradlew :flatlaf-fonts-${{ matrix.font }}:publish -Dorg.gradle.internal.publish.checksums.insecure=true
|
||||||
env:
|
env:
|
||||||
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
|
SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }}
|
||||||
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
|
SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
|
||||||
if: github.ref == 'refs/heads/main' || startsWith( github.ref, 'refs/heads/develop-' )
|
if: github.ref == 'refs/heads/main' || startsWith( github.ref, 'refs/heads/develop-' )
|
||||||
|
|
||||||
- name: Release a new stable version to Maven Central
|
- name: Release a new stable version to Maven Central
|
||||||
run: ./gradlew :flatlaf-fonts-${{ matrix.font }}:build :flatlaf-fonts-${{ matrix.font }}:publish -Prelease
|
run: ./gradlew :flatlaf-fonts-${{ matrix.font }}:build :flatlaf-fonts-${{ matrix.font }}:publish -Prelease
|
||||||
env:
|
env:
|
||||||
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
|
SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }}
|
||||||
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
|
SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
|
||||||
SIGNING_KEY: ${{ secrets.SIGNING_KEY }}
|
SIGNING_KEY: ${{ secrets.SIGNING_KEY }}
|
||||||
SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }}
|
SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }}
|
||||||
if: startsWith( github.ref, format( 'refs/tags/fonts/{0}-', matrix.font ) )
|
if: startsWith( github.ref, format( 'refs/tags/fonts/{0}-', matrix.font ) )
|
||||||
|
|||||||
118
.github/workflows/natives.yml
vendored
118
.github/workflows/natives.yml
vendored
@@ -21,33 +21,133 @@ 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: Setup Java 11
|
- name: apt update (Linux)
|
||||||
|
if: matrix.os == 'ubuntu-latest' || matrix.os == 'ubuntu-24.04-arm'
|
||||||
|
run: sudo apt-get update
|
||||||
|
|
||||||
|
- name: install libxt-dev and libgtk-3-dev (Linux)
|
||||||
|
if: matrix.os == 'ubuntu-latest' || matrix.os == 'ubuntu-24.04-arm'
|
||||||
|
run: sudo apt-get install libxt-dev libgtk-3-dev
|
||||||
|
|
||||||
|
# - name: Download libgtk-3.so for arm64 (Linux)
|
||||||
|
# if: matrix.os == 'ubuntu-latest'
|
||||||
|
# working-directory: flatlaf-natives/flatlaf-natives-linux/lib/aarch64
|
||||||
|
# run: |
|
||||||
|
# pwd
|
||||||
|
# ls -l /usr/lib/x86_64-linux-gnu/libgtk*
|
||||||
|
# wget --no-verbose https://ports.ubuntu.com/pool/main/g/gtk%2b3.0/libgtk-3-0_3.24.18-1ubuntu1_arm64.deb
|
||||||
|
# ls -l
|
||||||
|
# ar -x libgtk-3-0_3.24.18-1ubuntu1_arm64.deb data.tar.xz
|
||||||
|
# tar -xvf data.tar.xz --wildcards --to-stdout "./usr/lib/aarch64-linux-gnu/libgtk-3.so.0.*" > libgtk-3.so
|
||||||
|
# rm libgtk-3-0_3.24.18-1ubuntu1_arm64.deb data.tar.xz
|
||||||
|
# ls -l
|
||||||
|
|
||||||
|
# - name: install g++-aarch64-linux-gnu (Linux)
|
||||||
|
# if: matrix.os == 'ubuntu-latest'
|
||||||
|
# run: sudo apt-get install g++-aarch64-linux-gnu
|
||||||
|
|
||||||
|
- name: Setup Java 21
|
||||||
uses: actions/setup-java@v4
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
java-version: 11
|
java-version: 21
|
||||||
distribution: temurin
|
distribution: temurin
|
||||||
cache: gradle
|
|
||||||
|
- name: Cache Gradle
|
||||||
|
uses: ./.github/actions/cache-gradle
|
||||||
|
|
||||||
- name: Build with Gradle
|
- name: Build with Gradle
|
||||||
# --no-daemon is necessary on Windows otherwise caching Gradle would fail with:
|
# --no-daemon is necessary on Windows otherwise caching Gradle would fail with:
|
||||||
# tar.exe: Couldn't open ~/.gradle/caches/modules-2/modules-2.lock: Permission denied
|
# tar.exe: Couldn't open ~/.gradle/caches/modules-2/modules-2.lock: Permission denied
|
||||||
run: ./gradlew build-natives --no-daemon
|
run: ./gradlew build-natives --no-daemon
|
||||||
|
|
||||||
|
- name: Upload unsigned Windows DLLs for signing by SignPath.org
|
||||||
|
if: matrix.os == 'windows-latest' && github.repository == 'JFormDesigner/FlatLaf'
|
||||||
|
id: windows-unsigned
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: FlatLaf-natives-windows-unsigned
|
||||||
|
path: flatlaf-natives/flatlaf-natives-windows/build/lib/main/release/**/*.dll
|
||||||
|
|
||||||
|
- name: Sign Windows DLLs using SignPath.org
|
||||||
|
if: matrix.os == 'windows-latest' && github.repository == 'JFormDesigner/FlatLaf'
|
||||||
|
uses: signpath/github-action-submit-signing-request@v2
|
||||||
|
with:
|
||||||
|
api-token: ${{ secrets.SIGNPATH_API_TOKEN }}
|
||||||
|
organization-id: ${{ secrets.SIGNPATH_ORGANIZATION_ID }}
|
||||||
|
project-slug: FlatLaf
|
||||||
|
signing-policy-slug: release-signing
|
||||||
|
artifact-configuration-slug: windows-dlls
|
||||||
|
github-artifact-id: ${{ steps.windows-unsigned.outputs.artifact-id }}
|
||||||
|
wait-for-completion: true
|
||||||
|
output-artifact-directory: flatlaf-natives/flatlaf-natives-windows/build/lib/signed
|
||||||
|
|
||||||
|
- name: Copy signed Windows DLLs to flatlaf-core
|
||||||
|
if: matrix.os == 'windows-latest' && github.repository == 'JFormDesigner/FlatLaf'
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
SRC=flatlaf-natives/flatlaf-natives-windows/build/lib/signed
|
||||||
|
DEST=flatlaf-core/src/main/resources/com/formdev/flatlaf/natives
|
||||||
|
cp $SRC/aarch64/flatlaf-natives-windows.dll $DEST/flatlaf-windows-arm64.dll
|
||||||
|
cp $SRC/x86/flatlaf-natives-windows.dll $DEST/flatlaf-windows-x86.dll
|
||||||
|
cp $SRC/x86-64/flatlaf-natives-windows.dll $DEST/flatlaf-windows-x86_64.dll
|
||||||
|
|
||||||
|
- name: Sign macOS natives
|
||||||
|
if: matrix.os == 'DISABLED--macos-latest'
|
||||||
|
env:
|
||||||
|
CERT_BASE64: ${{ secrets.CODE_SIGN_CERT_BASE64 }}
|
||||||
|
CERT_PASSWORD: ${{ secrets.CODE_SIGN_CERT_PASSWORD }}
|
||||||
|
CERT_IDENTITY: ${{ secrets.CODE_SIGN_CERT_IDENTITY }}
|
||||||
|
run: |
|
||||||
|
# https://docs.github.com/en/actions/use-cases-and-examples/deploying/installing-an-apple-certificate-on-macos-runners-for-xcode-development
|
||||||
|
# create variables
|
||||||
|
CERTIFICATE_PATH=$RUNNER_TEMP/cert.p12
|
||||||
|
KEYCHAIN_PATH=$RUNNER_TEMP/signing.keychain-db
|
||||||
|
KEYCHAIN_PASSWORD=$CERT_PASSWORD
|
||||||
|
# decode certificate
|
||||||
|
printenv CERT_BASE64 | base64 --decode > $CERTIFICATE_PATH
|
||||||
|
# create temporary keychain
|
||||||
|
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
||||||
|
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
|
||||||
|
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
||||||
|
# import certificate to keychain
|
||||||
|
security import $CERTIFICATE_PATH -P "$CERT_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
|
||||||
|
# set partition list (required for codesign)
|
||||||
|
security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
||||||
|
# add keychain to keychain search list
|
||||||
|
security list-keychains -d user -s $KEYCHAIN_PATH
|
||||||
|
# sign code
|
||||||
|
codesign --sign "$CERT_IDENTITY" --force --verbose=4 --timestamp \
|
||||||
|
flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/libflatlaf-macos-*.dylib
|
||||||
|
codesign --display --verbose=4 flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/libflatlaf-macos-*.dylib
|
||||||
|
# cleanup
|
||||||
|
security delete-keychain $KEYCHAIN_PATH
|
||||||
|
|
||||||
|
- name: Set artifacts pattern for upload step
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
case ${{ matrix.os }} in
|
||||||
|
windows-latest) echo "artifactPattern=flatlaf-windows-*.dll" >> $GITHUB_ENV ;;
|
||||||
|
macos-latest) echo "artifactPattern=libflatlaf-macos-*.dylib" >> $GITHUB_ENV ;;
|
||||||
|
ubuntu-latest) echo "artifactPattern=libflatlaf-linux-x86_64.so" >> $GITHUB_ENV ;;
|
||||||
|
ubuntu-24.04-arm) echo "artifactPattern=libflatlaf-linux-arm64.so" >> $GITHUB_ENV ;;
|
||||||
|
esac
|
||||||
|
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: FlatLaf-natives-build-artifacts-${{ matrix.os }}
|
name: FlatLaf-natives-build-artifacts-${{ matrix.os }}
|
||||||
path: |
|
path: |
|
||||||
flatlaf-core/src/main/resources/com/formdev/flatlaf/natives
|
flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/${{ env.artifactPattern }}
|
||||||
flatlaf-natives/flatlaf-natives-*/build
|
flatlaf-natives/flatlaf-natives-*/build
|
||||||
|
|||||||
14
.github/workflows/pr-snapshots.yml
vendored
14
.github/workflows/pr-snapshots.yml
vendored
@@ -21,17 +21,19 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Java 11
|
- name: Setup Java 21
|
||||||
uses: actions/setup-java@v4
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
java-version: 11
|
java-version: 21
|
||||||
distribution: temurin # pre-installed on ubuntu-latest
|
distribution: temurin # pre-installed on ubuntu-latest
|
||||||
cache: gradle
|
|
||||||
|
|
||||||
- name: Publish PR snapshot to oss.sonatype.org
|
- name: Cache Gradle
|
||||||
|
uses: ./.github/actions/cache-gradle
|
||||||
|
|
||||||
|
- name: Publish PR snapshot to Sonatype Central
|
||||||
run: >
|
run: >
|
||||||
./gradlew publish -PskipFonts -Dorg.gradle.internal.publish.checksums.insecure=true -Dorg.gradle.parallel=false
|
./gradlew publish -PskipFonts -Dorg.gradle.internal.publish.checksums.insecure=true -Dorg.gradle.parallel=false
|
||||||
-Pgithub.event.pull_request.number=${{ github.event.pull_request.number }}
|
-Pgithub.event.pull_request.number=${{ github.event.pull_request.number }}
|
||||||
env:
|
env:
|
||||||
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
|
SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }}
|
||||||
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
|
SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -5,6 +5,7 @@ build/
|
|||||||
.project
|
.project
|
||||||
.settings/
|
.settings/
|
||||||
.idea/
|
.idea/
|
||||||
|
.consulo/
|
||||||
out/
|
out/
|
||||||
*.iml
|
*.iml
|
||||||
*.ipr
|
*.ipr
|
||||||
|
|||||||
225
CHANGELOG.md
225
CHANGELOG.md
@@ -1,6 +1,231 @@
|
|||||||
FlatLaf Change Log
|
FlatLaf Change Log
|
||||||
==================
|
==================
|
||||||
|
|
||||||
|
## 3.7.1-SNAPSHOT
|
||||||
|
|
||||||
|
- ComboBox: Added UI property `ComboBox.buttonFocusedEditableBackground`. (issue
|
||||||
|
#1068)
|
||||||
|
- Popup: Fixed scrolling popup painting issue on Windows 10 when a glass pane is
|
||||||
|
visible and frame is maximized. (issue #1071)
|
||||||
|
- Slider: Styling `thumbSize` or `focusWidth` did not update slider size/layout.
|
||||||
|
(PR #1074)
|
||||||
|
- ToolBar: Grip disappeared when switching between Look and Feels. (issue #1075)
|
||||||
|
- Extras:
|
||||||
|
- UI defaults inspector: Fixed NPE if color of `FlatLineBorder` is null. Also
|
||||||
|
use `FlatLineBorder` line color as cell background color in "Value" column.
|
||||||
|
(PR #1080)
|
||||||
|
- `FlatDesktop`: Avoid unnecessary logging if desktop is not supported (e.g.
|
||||||
|
on NixOS with Plasma/KDE desktop).
|
||||||
|
|
||||||
|
|
||||||
|
## 3.7
|
||||||
|
|
||||||
|
#### New features and improvements
|
||||||
|
|
||||||
|
- System File Chooser allows using **operating system file dialogs** in Java
|
||||||
|
Swing applications. (PR #988)
|
||||||
|
- Zooming API. (PR #1051)
|
||||||
|
- Icons:
|
||||||
|
- Support scaling Laf icons (checkbox, radiobutton, etc). (issue #1061)
|
||||||
|
- Scale checkbox and radiobutton icons when using
|
||||||
|
[text styles](https://www.formdev.com/flatlaf/typography/#text_styles)
|
||||||
|
`large`, `medium`, `small` and `mini`.
|
||||||
|
- TabbedPane: Added icon-only tab mode, which shows tab icons but hides tab
|
||||||
|
titles. Tab titles are used in "Show Hidden Tabs" popup menu. (set client
|
||||||
|
property `JTabbedPane.tabWidthMode` to `"iconOnly"`)
|
||||||
|
- TabbedPane: In scroll tab layout, propagate mouse wheel events to ancestors.
|
||||||
|
This allows mouse wheel scrolling if JTabbedPane is inside a JScrollPane. (PR
|
||||||
|
#1030)
|
||||||
|
|
||||||
|
#### Fixed bugs
|
||||||
|
|
||||||
|
- CheckBox and RadioButton: Fixed styling of custom icon. Also fixed focus width
|
||||||
|
(and preferred size) if using custom icon. (PR #1060)
|
||||||
|
- TabbedPane: In "Show Hidden Tabs" popup menu, do not show text "x. Tab" if tab
|
||||||
|
has icon but no title. (issue #1062)
|
||||||
|
- TextField: Fixed wrong leading/trailing icon placement if border is set to
|
||||||
|
`null`. (issue #1047)
|
||||||
|
- Extras: UI defaults inspector: Exclude inspector window from being blocked by
|
||||||
|
modal dialogs. (issue #1048)
|
||||||
|
- JideButton, JideToggleButton, JideSplitButton and JideToggleSplitButton: Paint
|
||||||
|
border in button style `TOOLBAR_STYLE` if in selected state. (issue #1045)
|
||||||
|
- IntelliJ Themes: Fixed problem when using theme instance more than once when
|
||||||
|
switching to that theme. (issue #990)
|
||||||
|
|
||||||
|
|
||||||
|
## 3.6.2
|
||||||
|
|
||||||
|
#### New features and improvements
|
||||||
|
|
||||||
|
- If using `FlatLaf.registerCustomDefaultsSource( "com.myapp.themes" )` and
|
||||||
|
named Java modules, it is no longer necessary to add `opens com.myapp.themes;`
|
||||||
|
to `module-info.java`. (issue #1026)
|
||||||
|
- Extras: Made animated theme change (class `FlatAnimatedLafChange`) smoother.
|
||||||
|
|
||||||
|
#### Fixed bugs
|
||||||
|
|
||||||
|
- Tree and List: Fixed painting of rounded drop backgrounds. (issue #1023)
|
||||||
|
- Popup: Showing tooltip in inactive window brought that window to front (made
|
||||||
|
it active) and potentially hid the previously active window. (issue #1037)
|
||||||
|
- Popup: No longer reuse popup windows for menus to avoid immediately closing
|
||||||
|
dialogs on ChromeOS. (issue #1029)
|
||||||
|
- macOS: Fixed window "flashing" when switching from a light to a dark theme (or
|
||||||
|
vice versa). Especially when using animated theme changer (see
|
||||||
|
[FlatLaf Extras](flatlaf-extras)).
|
||||||
|
|
||||||
|
#### Incompatibilities
|
||||||
|
|
||||||
|
- FlatLaf properties files are now loaded using the UTF-8 character encoding
|
||||||
|
instead of ISO 8859-1. In usual properties files you will not notice any
|
||||||
|
difference because they use only ASCII characters, but if you've put localized
|
||||||
|
(non-English) texts (e.g. German umlauts) into your properties files, you need
|
||||||
|
to convert them to UTF-8. Properties files created with the FlatLaf Theme
|
||||||
|
Editor already use UTF-8, including in older versions. (issue #1031)
|
||||||
|
|
||||||
|
|
||||||
|
## 3.6.1
|
||||||
|
|
||||||
|
- Extras: Support JSVG 2.0.0. Minimum JSVG version is now 1.6.0. (issue #997)
|
||||||
|
- FlatLaf window decorations (Windows 10/11 only): Improved diagonal window
|
||||||
|
resizing on top-left and top-right window corners. Top window resize area now
|
||||||
|
also covers iconify/maximize/close buttons. (issue #1015)
|
||||||
|
- ToggleButton: Styling `selectedForeground` did not work if `foreground` is
|
||||||
|
also styled. (issue #1017)
|
||||||
|
- JideSplitButton: Fixed updating popup when switching theme. (issue #1000)
|
||||||
|
- IntelliJ Themes: Fixed logging false errors when loading 3rd party
|
||||||
|
`.theme.json` files. (issue #990)
|
||||||
|
- Linux: Popups appeared in wrong position on multi-screen setup if primary
|
||||||
|
display is located below or right to secondary display. (see
|
||||||
|
[NetBeans issue #8532](https://github.com/apache/netbeans/issues/8532))
|
||||||
|
- macOS: Fixed popup flickering after theme change. (issue #1009)
|
||||||
|
- macOS with JetBrains Runtime: Fixed sometimes empty popups. (issue #1019)
|
||||||
|
|
||||||
|
|
||||||
|
## 3.6
|
||||||
|
|
||||||
|
#### 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)
|
||||||
|
- ScrollBar: Use rounded thumb also on Windows (as on macOS and Linux) and made
|
||||||
|
thumb slightly darker/lighter. (issue #918)
|
||||||
|
- Extras: `FlatSVGIcon` color filters now can access painting component to
|
||||||
|
implement component state based color mappings. (issue #906)
|
||||||
|
- Linux:
|
||||||
|
- Rounded iconify/maximize/close buttons if using FlatLaf window decorations.
|
||||||
|
(PR #971)
|
||||||
|
- Added `libflatlaf-linux-arm64.so` for Linux on ARM64. (issue #899)
|
||||||
|
- 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)
|
||||||
|
- TextComponents: `selectAllOnFocusPolicy` related changes:
|
||||||
|
- No longer select all text if selection (or caret position) was changed by
|
||||||
|
application and `selectAllOnFocusPolicy` is `once` (the default). (issue
|
||||||
|
#983)
|
||||||
|
- FormattedTextField and Spinner: `selectAllOnFocusPolicy = once` behaves now
|
||||||
|
as `always` (was `never` before), which means that all text is selected when
|
||||||
|
component gains focus. This is because of special behavior of
|
||||||
|
`JFormattedTextField` that did not allow implementation of `once`.
|
||||||
|
- Client property `JTextField.selectAllOnFocusPolicy` now also works on
|
||||||
|
(editable) `JComboBox` and on `JSpinner`.
|
||||||
|
- Added client property `JTextField.selectAllOnMouseClick` to override UI
|
||||||
|
property `TextComponent.selectAllOnMouseClick`. (issue #961)
|
||||||
|
- For `selectAllOnMouseClick = true`, clicking with the mouse into the text
|
||||||
|
field, to focus it, now always selects all text, even if
|
||||||
|
`selectAllOnFocusPolicy` is `once`.
|
||||||
|
|
||||||
|
#### 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
|
## 3.5.3
|
||||||
|
|
||||||
#### Fixed bugs
|
#### Fixed bugs
|
||||||
|
|||||||
130
README.md
130
README.md
@@ -35,7 +35,11 @@ Sponsors
|
|||||||
|
|
||||||
### Current Sponsors
|
### Current Sponsors
|
||||||
|
|
||||||
[](https://www.formdev.com/flatlaf/sponsor/)
|
<a href="https://www.soptim.de/"><img src="https://www.formdev.com/flatlaf/sponsor/soptim.svg" width="200" alt="SOPTIM" title="SOPTIM - your expert in software solutions for the energy industry"></a>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
|
||||||
|
<!-- [](https://www.formdev.com/flatlaf/sponsor/) -->
|
||||||
|
|
||||||
[Become a Sponsor](https://www.formdev.com/flatlaf/sponsor/)
|
[Become a Sponsor](https://www.formdev.com/flatlaf/sponsor/)
|
||||||
|
|
||||||
@@ -70,21 +74,30 @@ build script:
|
|||||||
|
|
||||||
Otherwise, download `flatlaf-<version>.jar` here:
|
Otherwise, download `flatlaf-<version>.jar` here:
|
||||||
|
|
||||||
[](https://maven-badges.herokuapp.com/maven-central/com.formdev/flatlaf)
|
[](https://central.sonatype.com/artifact/com.formdev/flatlaf)
|
||||||
|
|
||||||
See also
|
- See
|
||||||
[Native Libraries distribution](https://www.formdev.com/flatlaf/native-libraries/)
|
[Native Libraries distribution](https://www.formdev.com/flatlaf/native-libraries/)
|
||||||
for instructions on how to redistribute FlatLaf native libraries with your
|
for instructions on how to redistribute FlatLaf native libraries with your
|
||||||
application.
|
application.
|
||||||
|
- Windows DLLs: Free code signing provided by
|
||||||
|
[SignPath.io](https://about.signpath.io/), certificate by
|
||||||
|
[SignPath Foundation](https://signpath.org/).
|
||||||
|
- If repackaging FlatLaf (and other) JARs into a single fat/uber JAR:
|
||||||
|
- add `Multi-Release: true` to `META-INF/MANIFEST.MF`
|
||||||
|
- keep `META-INF/versions/` and `META-INF/services/` directories
|
||||||
|
- merge content of equally named files in `META-INF/services/`
|
||||||
|
- If using obfuscation/minimizing/shrinking tools (e.g. **ProGuard** or
|
||||||
|
**Shadow**), exclude package `com.formdev.flatlaf` and all sub-packages.
|
||||||
|
|
||||||
|
|
||||||
### Snapshots
|
### Snapshots
|
||||||
|
|
||||||
FlatLaf snapshot binaries are available on
|
FlatLaf snapshot binaries are available on
|
||||||
[Sonatype OSSRH](https://oss.sonatype.org/content/repositories/snapshots/com/formdev/flatlaf/).
|
[Sonatype Central](https://central.sonatype.com/service/rest/repository/browse/maven-snapshots/com/formdev/flatlaf/).
|
||||||
To access the latest snapshot, change the FlatLaf version in your dependencies
|
To access the latest snapshot, change the FlatLaf version in your dependencies
|
||||||
to `<version>-SNAPSHOT` (e.g. `0.27-SNAPSHOT`) and add the repository
|
to `<version>-SNAPSHOT` (e.g. `3.7-SNAPSHOT`) and add the repository
|
||||||
`https://oss.sonatype.org/content/repositories/snapshots/` to your build (see
|
`https://central.sonatype.com/repository/maven-snapshots/` to your build (see
|
||||||
[Maven](https://maven.apache.org/guides/mini/guide-multiple-repositories.html)
|
[Maven](https://maven.apache.org/guides/mini/guide-multiple-repositories.html)
|
||||||
and
|
and
|
||||||
[Gradle](https://docs.gradle.org/current/userguide/declaring_repositories.html#sec:declaring_custom_repository)
|
[Gradle](https://docs.gradle.org/current/userguide/declaring_repositories.html#sec:declaring_custom_repository)
|
||||||
@@ -182,11 +195,18 @@ Applications using FlatLaf
|
|||||||
relational data browsing tool
|
relational data browsing tool
|
||||||
-  [MagicPlot](https://magicplot.com/) (**commercial**) -
|
-  [MagicPlot](https://magicplot.com/) (**commercial**) -
|
||||||
Software for nonlinear fitting, plotting and data analysis
|
Software for nonlinear fitting, plotting and data analysis
|
||||||
-  [Constellation](https://www.constellation-app.com/) -
|
- [Constellation](https://www.constellation-app.com/) - Data Visualization and
|
||||||
Data Visualization and Analytics (based on NetBeans platform)
|
Analytics (based on NetBeans platform)
|
||||||
- 
|
- [Kafka Visualizer](https://github.com/kumait/kafkavisualizer) - Kafka GUI
|
||||||
[Kafka Visualizer](https://github.com/kumait/kafkavisualizer) - Kafka GUI
|
|
||||||
client
|
client
|
||||||
|
- 
|
||||||
|
[RedisFront](https://github.com/dromara/RedisFront/blob/master/README_EN.md) -
|
||||||
|
Cross-platform redis GUI
|
||||||
|
- 
|
||||||
|
[Zettelkasten](https://github.com/Zettelkasten-Team/Zettelkasten) - knowledge
|
||||||
|
management tool
|
||||||
|
-  [QStudio](https://www.timestored.com/qstudio/) - free
|
||||||
|
SQL editor
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
|
|
||||||
@@ -195,11 +215,9 @@ Applications using FlatLaf
|
|||||||
- 
|
- 
|
||||||
[Burp Suite Professional and Community Edition](https://portswigger.net/burp/pro)
|
[Burp Suite Professional and Community Edition](https://portswigger.net/burp/pro)
|
||||||
(**commercial**) - the leading software for web security testing
|
(**commercial**) - the leading software for web security testing
|
||||||
- 
|
- [Ghidra](https://github.com/NationalSecurityAgency/ghidra) - a software
|
||||||
[Ghidra](https://github.com/NationalSecurityAgency/ghidra) - a software
|
|
||||||
reverse engineering (SRE) framework
|
reverse engineering (SRE) framework
|
||||||
-  [jadx](https://github.com/skylot/jadx) - Dex to Java
|
- [jadx](https://github.com/skylot/jadx) - Dex to Java decompiler
|
||||||
decompiler
|
|
||||||
- [BurpCustomizer](https://github.com/CoreyD97/BurpCustomizer) - adds more
|
- [BurpCustomizer](https://github.com/CoreyD97/BurpCustomizer) - adds more
|
||||||
FlatLaf themes to Burp Suite
|
FlatLaf themes to Burp Suite
|
||||||
- [Total Validator](https://www.totalvalidator.com/) (**commercial**) - checks
|
- [Total Validator](https://www.totalvalidator.com/) (**commercial**) - checks
|
||||||
@@ -211,19 +229,26 @@ Applications using FlatLaf
|
|||||||
|
|
||||||
- [jclasslib bytecode viewer](https://github.com/ingokegel/jclasslib)
|
- [jclasslib bytecode viewer](https://github.com/ingokegel/jclasslib)
|
||||||
- [KeyStore Explorer](https://keystore-explorer.org/)
|
- [KeyStore Explorer](https://keystore-explorer.org/)
|
||||||
- 
|
- [muCommander](https://github.com/mucommander/mucommander) - lightweight
|
||||||
[muCommander](https://github.com/mucommander/mucommander) - lightweight
|
|
||||||
cross-platform file manager
|
cross-platform file manager
|
||||||
-  [Guiffy](https://www.guiffy.com/) (**commercial**) -
|
- [Guiffy](https://www.guiffy.com/) (**commercial**) - advanced cross-platform
|
||||||
advanced cross-platform Diff/Merge
|
Diff/Merge
|
||||||
-  [HashGarten](https://github.com/jonelo/HashGarten) -
|
- [HashGarten](https://github.com/jonelo/HashGarten) - cross-platform Swing GUI
|
||||||
cross-platform Swing GUI for Jacksum
|
for Jacksum
|
||||||
- [Pseudo Assembler IDE](https://github.com/tomasz-herman/PseudoAssemblerIDE) -
|
- [Pseudo Assembler IDE](https://github.com/tomasz-herman/PseudoAssemblerIDE) -
|
||||||
IDE for Pseudo-Assembler
|
IDE for Pseudo-Assembler
|
||||||
- [Linotte](https://github.com/cpc6128/LangageLinotte) - French programming
|
- [Linotte](https://github.com/cpc6128/LangageLinotte) - French programming
|
||||||
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
|
||||||
|
-  [Consulo](https://github.com/consulo/consulo) - open
|
||||||
|
source cross-platform multi-language IDE (Java, .NET, JS, etc)
|
||||||
|
- [Convertigo](https://github.com/convertigo/convertigo) - low code & no code
|
||||||
|
mobile & web platform
|
||||||
|
-  [EduMIPS64](https://github.com/EduMIPS64/edumips64) -
|
||||||
|
visual MIPS64 CPU simulator
|
||||||
|
-  [Launch4j](https://launch4j.sourceforge.net/) -
|
||||||
|
cross-platform Java executable wrapper
|
||||||
|
|
||||||
### Electrical
|
### Electrical
|
||||||
|
|
||||||
@@ -231,6 +256,11 @@ Applications using FlatLaf
|
|||||||
designing, simulating and explaining digital circuits
|
designing, simulating and explaining digital circuits
|
||||||
- [Logisim-evolution](https://github.com/logisim-evolution/logisim-evolution) -
|
- [Logisim-evolution](https://github.com/logisim-evolution/logisim-evolution) -
|
||||||
Digital logic design tool and simulator
|
Digital logic design tool and simulator
|
||||||
|
-  [OpenPnP](https://github.com/openpnp/openpnp) - SMT
|
||||||
|
Pick and Place Hardware and Software
|
||||||
|
- 
|
||||||
|
[TrainControl](https://github.com/bob123456678/TrainControl) - control Marklin
|
||||||
|
/ Trix / DCC digital model train layout
|
||||||
- [Makelangelo Software](https://github.com/MarginallyClever/Makelangelo-software) -
|
- [Makelangelo Software](https://github.com/MarginallyClever/Makelangelo-software) -
|
||||||
for plotters, especially the wall-hanging polargraph
|
for plotters, especially the wall-hanging polargraph
|
||||||
- [GUIslice Builder](https://github.com/ImpulseAdventure/GUIslice-Builder) - GUI
|
- [GUIslice Builder](https://github.com/ImpulseAdventure/GUIslice-Builder) - GUI
|
||||||
@@ -245,8 +275,10 @@ Applications using FlatLaf
|
|||||||
|
|
||||||
-  [jAlbum](https://jalbum.net/) (**commercial**) -
|
-  [jAlbum](https://jalbum.net/) (**commercial**) -
|
||||||
creates photo album websites
|
creates photo album websites
|
||||||
-  [MediathekView](https://mediathekview.de/) - search in
|
- [MediathekView](https://mediathekview.de/) - search in media libraries of
|
||||||
media libraries of various German broadcasters
|
various German broadcasters
|
||||||
|
-  [Pixelitor](https://github.com/lbalazscs/Pixelitor) -
|
||||||
|
image editor
|
||||||
- [Cinecred](https://loadingbyte.com/cinecred/) - create beautiful film credit
|
- [Cinecred](https://loadingbyte.com/cinecred/) - create beautiful film credit
|
||||||
sequences
|
sequences
|
||||||
- [tinyMediaManager](https://www.tinymediamanager.org/) (**commercial**) - a
|
- [tinyMediaManager](https://www.tinymediamanager.org/) (**commercial**) - a
|
||||||
@@ -262,19 +294,31 @@ Applications using FlatLaf
|
|||||||
from any webnovel and lightnovel site
|
from any webnovel and lightnovel site
|
||||||
- [lectureStudio](https://www.lecturestudio.org/) - digitize your lectures with
|
- [lectureStudio](https://www.lecturestudio.org/) - digitize your lectures with
|
||||||
ease
|
ease
|
||||||
|
-  [Nortantis](https://jandjheydorn.com/nortantis) -
|
||||||
|
fantasy map generator and editor
|
||||||
|
|
||||||
### Modelling
|
### Modelling / Planning
|
||||||
|
|
||||||
-  [Astah](https://astah.net/) (**commercial**) - create
|
-  [OpenRocket](https://github.com/openrocket/openrocket) -
|
||||||
UML, ER Diagram, Flowchart, Data Flow Diagram, Requirement Diagram, SysML
|
model-rocketry aerodynamics and trajectory simulation software
|
||||||
diagrams and more
|
- 
|
||||||
|
[Warteschlangensimulator](https://github.com/A-Herzog/Warteschlangensimulator) -
|
||||||
|
discrete-event stochastic simulator
|
||||||
|
-  [Gephi](https://github.com/gephi/gephi) - the Open
|
||||||
|
Graph Viz Platform
|
||||||
|
- [Astah](https://astah.net/) (**commercial**) - create UML, ER Diagram,
|
||||||
|
Flowchart, Data Flow Diagram, Requirement Diagram, SysML diagrams and more
|
||||||
- [IGMAS+](https://www.gfz-potsdam.de/igmas) - Interactive Gravity and Magnetic
|
- [IGMAS+](https://www.gfz-potsdam.de/igmas) - Interactive Gravity and Magnetic
|
||||||
Application System
|
Application System
|
||||||
|
-  [StarPlan](https://www.progotec.de/) (**commercial**) -
|
||||||
|
die Stundenplan Software für Bildungseinrichtungen
|
||||||
|
-  [SSPlot](https://github.com/babaissarkar/ssplot) -
|
||||||
|
plotting utility for plotting CSV data
|
||||||
|
|
||||||
### Documents
|
### Documents
|
||||||
|
|
||||||
-  [Big Faceless (BFO) PDF Viewer](https://bfo.com/)
|
- [Big Faceless (BFO) PDF Viewer](https://bfo.com/) (**commercial**) - Swing PDF
|
||||||
(**commercial**) - Swing PDF Viewer
|
Viewer
|
||||||
- [PDF Studio](https://www.qoppa.com/pdfstudio/) (**commercial**) - create,
|
- [PDF Studio](https://www.qoppa.com/pdfstudio/) (**commercial**) - create,
|
||||||
review and edit PDF documents
|
review and edit PDF documents
|
||||||
- [XMLmind XML Editor](https://www.xmlmind.com/xmleditor/) (**commercial**)
|
- [XMLmind XML Editor](https://www.xmlmind.com/xmleditor/) (**commercial**)
|
||||||
@@ -292,6 +336,9 @@ Applications using FlatLaf
|
|||||||
|
|
||||||
### Business / Legal
|
### Business / Legal
|
||||||
|
|
||||||
|
-  
|
||||||
|
[Lisheane ERP](https://www.lisheane.ch/) (**commercial**) - backoffice
|
||||||
|
applikation
|
||||||
- 
|
- 
|
||||||
[j-lawyer](https://github.com/jlawyerorg/j-lawyer-org) - Kanzleisoftware
|
[j-lawyer](https://github.com/jlawyerorg/j-lawyer-org) - Kanzleisoftware
|
||||||
-  [Jeyla Studio](https://www.jeylastudio.com/) -
|
-  [Jeyla Studio](https://www.jeylastudio.com/) -
|
||||||
@@ -308,20 +355,20 @@ Applications using FlatLaf
|
|||||||
|
|
||||||
### Messaging
|
### Messaging
|
||||||
|
|
||||||
-  [Spark](https://github.com/igniterealtime/Spark) -
|
- [Spark](https://github.com/igniterealtime/Spark) - cross-platform IM client
|
||||||
cross-platform IM client optimized for businesses and organizations
|
optimized for businesses and organizations
|
||||||
-  [Chatty](https://github.com/chatty/chatty) - Twitch
|
- [Chatty](https://github.com/chatty/chatty) - Twitch Chat Client
|
||||||
Chat Client
|
|
||||||
|
|
||||||
### Gaming
|
### Gaming
|
||||||
|
|
||||||
-  
|
-  [BGBlitz](https://www.bgblitz.com/)
|
||||||
[BGBlitz](https://www.bgblitz.com/) (**commercial**) - professional Backgammon
|
(**commercial**) - professional Backgammon
|
||||||
-  [MCreator](https://github.com/MCreator/MCreator) -
|
-  [josé](https://peteschaefer.github.io/jose/) - a
|
||||||
software used to make Minecraft Java Edition mods, Minecraft Bedrock Edition Add-Ons,
|
graphical chess tool
|
||||||
and data packs without programming knowledge
|
-  [MCreator](https://github.com/MCreator/MCreator) - make
|
||||||
-  [MapTool](https://github.com/RPTools/maptool) - virtual
|
Minecraft Java Edition mods, Minecraft Bedrock Edition Add-Ons, and data packs
|
||||||
Tabletop for playing role-playing games
|
- [MapTool](https://github.com/RPTools/maptool) - virtual Tabletop for playing
|
||||||
|
role-playing games
|
||||||
- [MegaMek](https://github.com/MegaMek/megamek),
|
- [MegaMek](https://github.com/MegaMek/megamek),
|
||||||
[MegaMekLab](https://github.com/MegaMek/megameklab) and
|
[MegaMekLab](https://github.com/MegaMek/megameklab) and
|
||||||
[MekHQ](https://github.com/MegaMek/mekhq) - a sci-fi tabletop BattleTech
|
[MekHQ](https://github.com/MegaMek/mekhq) - a sci-fi tabletop BattleTech
|
||||||
@@ -333,8 +380,7 @@ Applications using FlatLaf
|
|||||||
|
|
||||||
- [MooInfo](https://github.com/rememberber/MooInfo) - visual implementation of
|
- [MooInfo](https://github.com/rememberber/MooInfo) - visual implementation of
|
||||||
OSHI, to view information about the system and hardware
|
OSHI, to view information about the system and hardware
|
||||||
- 
|
- [Linux Task Manager (LTM)](https://github.com/ajee10x/LTM-LinuxTaskManager) -
|
||||||
[Linux Task Manager (LTM)](https://github.com/ajee10x/LTM-LinuxTaskManager) -
|
|
||||||
GUI for monitoring and managing various aspects of a Linux system
|
GUI for monitoring and managing various aspects of a Linux system
|
||||||
- [Rest Suite](https://github.com/supanadit/restsuite) - Rest API testing
|
- [Rest Suite](https://github.com/supanadit/restsuite) - Rest API testing
|
||||||
- [SpringRemote](https://github.com/HaleyWang/SpringRemote) - remote Linux SSH
|
- [SpringRemote](https://github.com/HaleyWang/SpringRemote) - remote Linux SSH
|
||||||
@@ -343,6 +389,8 @@ Applications using FlatLaf
|
|||||||
easy
|
easy
|
||||||
- [Android Tool](https://github.com/fast-geek/Android-Tool) - makes popular adb
|
- [Android Tool](https://github.com/fast-geek/Android-Tool) - makes popular adb
|
||||||
and fastboot commands easier to use
|
and fastboot commands easier to use
|
||||||
|
-  [Termora](https://github.com/TermoraDev/termora) -
|
||||||
|
Terminal emulator and SSH client
|
||||||
|
|
||||||
### Miscellaneous
|
### Miscellaneous
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,13 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import io.github.gradlenexus.publishplugin.CloseNexusStagingRepository
|
||||||
import net.ltgt.gradle.errorprone.errorprone
|
import net.ltgt.gradle.errorprone.errorprone
|
||||||
|
import org.gradle.kotlin.dsl.withType
|
||||||
|
|
||||||
|
|
||||||
|
// initialize version
|
||||||
|
group = "com.formdev"
|
||||||
version = property( if( hasProperty( "release" ) ) "flatlaf.releaseVersion" else "flatlaf.developmentVersion" ) as String
|
version = property( if( hasProperty( "release" ) ) "flatlaf.releaseVersion" else "flatlaf.developmentVersion" ) as String
|
||||||
|
|
||||||
// for PR snapshots change version to 'PR-<pr_number>-SNAPSHOT'
|
// for PR snapshots change version to 'PR-<pr_number>-SNAPSHOT'
|
||||||
@@ -23,18 +28,16 @@ val pullRequestNumber = findProperty( "github.event.pull_request.number" )
|
|||||||
if( pullRequestNumber != null )
|
if( pullRequestNumber != null )
|
||||||
version = "PR-${pullRequestNumber}-SNAPSHOT"
|
version = "PR-${pullRequestNumber}-SNAPSHOT"
|
||||||
|
|
||||||
|
// apply version to all subprojects
|
||||||
allprojects {
|
subprojects {
|
||||||
version = rootProject.version
|
version = rootProject.version
|
||||||
|
|
||||||
repositories {
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check required Java version
|
|
||||||
if( JavaVersion.current() < JavaVersion.VERSION_1_8 )
|
// initialize toolchain version (default is Java 8)
|
||||||
throw RuntimeException( "Java 8 or later required (running ${System.getProperty( "java.version" )})" )
|
val toolchainJavaVersion: String by extra {
|
||||||
|
System.getProperty( "toolchain", "8" )
|
||||||
|
}
|
||||||
|
|
||||||
// log version, Gradle and Java versions
|
// log version, Gradle and Java versions
|
||||||
println()
|
println()
|
||||||
@@ -42,17 +45,20 @@ println( "----------------------------------------------------------------------
|
|||||||
println( "FlatLaf Version: ${version}" )
|
println( "FlatLaf Version: ${version}" )
|
||||||
println( "Gradle ${gradle.gradleVersion} at ${gradle.gradleHomeDir}" )
|
println( "Gradle ${gradle.gradleVersion} at ${gradle.gradleHomeDir}" )
|
||||||
println( "Java ${System.getProperty( "java.version" )}" )
|
println( "Java ${System.getProperty( "java.version" )}" )
|
||||||
val toolchainJavaVersion = System.getProperty( "toolchain" )
|
|
||||||
if( !toolchainJavaVersion.isNullOrEmpty() )
|
|
||||||
println( "Java toolchain ${toolchainJavaVersion}" )
|
println( "Java toolchain ${toolchainJavaVersion}" )
|
||||||
println()
|
println()
|
||||||
|
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
|
alias( libs.plugins.gradle.nexus.publish.plugin )
|
||||||
alias( libs.plugins.errorprone ) apply false
|
alias( libs.plugins.errorprone ) apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
tasks {
|
tasks {
|
||||||
withType<JavaCompile>().configureEach {
|
withType<JavaCompile>().configureEach {
|
||||||
sourceCompatibility = "1.8"
|
sourceCompatibility = "1.8"
|
||||||
@@ -76,6 +82,10 @@ allprojects {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
withType<AbstractArchiveTask>().configureEach {
|
||||||
|
isPreserveFileTimestamps = true
|
||||||
|
}
|
||||||
|
|
||||||
withType<Javadoc>().configureEach {
|
withType<Javadoc>().configureEach {
|
||||||
options {
|
options {
|
||||||
this as StandardJavadocDocletOptions
|
this as StandardJavadocDocletOptions
|
||||||
@@ -88,6 +98,23 @@ allprojects {
|
|||||||
links( "https://docs.oracle.com/en/java/javase/11/docs/api/" )
|
links( "https://docs.oracle.com/en/java/javase/11/docs/api/" )
|
||||||
}
|
}
|
||||||
isFailOnError = false
|
isFailOnError = false
|
||||||
|
|
||||||
|
// use Java 25 to generate javadoc
|
||||||
|
val javaToolchains = (project as ExtensionAware).extensions.getByName("javaToolchains") as JavaToolchainService
|
||||||
|
javadocTool.set( javaToolchains.javadocToolFor {
|
||||||
|
languageVersion.set( JavaLanguageVersion.of( 25 ) )
|
||||||
|
} )
|
||||||
|
}
|
||||||
|
|
||||||
|
// mark some publishing related tasks as not compatible with configuration cache
|
||||||
|
withType<Sign>().configureEach {
|
||||||
|
notCompatibleWithConfigurationCache( "not compatible" )
|
||||||
|
}
|
||||||
|
withType<PublishToMavenRepository>().configureEach {
|
||||||
|
notCompatibleWithConfigurationCache( "not compatible" )
|
||||||
|
}
|
||||||
|
withType<CloseNexusStagingRepository>().configureEach {
|
||||||
|
notCompatibleWithConfigurationCache( "not compatible" )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,7 +166,33 @@ allprojects {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Error Prone requires at lease Java 11
|
||||||
|
val java = (project as ExtensionAware).extensions.getByName("java") as JavaPluginExtension
|
||||||
|
val javaToolchains = (project as ExtensionAware).extensions.getByName("javaToolchains") as JavaToolchainService
|
||||||
|
if( java.toolchain.languageVersion.get().asInt() < 11 ) {
|
||||||
|
javaCompiler.set( javaToolchains.compilerFor {
|
||||||
|
languageVersion.set( JavaLanguageVersion.of( 11 ) )
|
||||||
|
} )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nexusPublishing {
|
||||||
|
repositories {
|
||||||
|
sonatype {
|
||||||
|
// see https://central.sonatype.org/publish/publish-portal-ossrh-staging-api/
|
||||||
|
nexusUrl = uri( "https://ossrh-staging-api.central.sonatype.com/service/local/" )
|
||||||
|
snapshotRepositoryUrl = uri( "https://central.sonatype.com/repository/maven-snapshots/" )
|
||||||
|
|
||||||
|
// get from gradle.properties
|
||||||
|
val sonatypeUsername: String? by project
|
||||||
|
val sonatypePassword: String? by project
|
||||||
|
|
||||||
|
username = System.getenv( "SONATYPE_USERNAME" ) ?: sonatypeUsername
|
||||||
|
password = System.getenv( "SONATYPE_PASSWORD" ) ?: sonatypePassword
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,6 +14,8 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import org.gradle.kotlin.dsl.support.serviceOf
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
`cpp-library`
|
`cpp-library`
|
||||||
}
|
}
|
||||||
@@ -37,6 +39,10 @@ tasks {
|
|||||||
doFirst {
|
doFirst {
|
||||||
println( "Used Tool Chain:" )
|
println( "Used Tool Chain:" )
|
||||||
println( " - ${toolChain.get()}" )
|
println( " - ${toolChain.get()}" )
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !project.gradle.serviceOf<BuildFeatures>().configurationCache.active.get() ) {
|
||||||
|
doFirst {
|
||||||
println( "Available Tool Chains:" )
|
println( "Available Tool Chains:" )
|
||||||
toolChains.forEach {
|
toolChains.forEach {
|
||||||
println( " - $it" )
|
println( " - $it" )
|
||||||
@@ -44,3 +50,4 @@ tasks {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,7 +18,14 @@ plugins {
|
|||||||
java
|
java
|
||||||
}
|
}
|
||||||
|
|
||||||
if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) {
|
// for Eclipse IDE project import, exclude if:
|
||||||
|
// - plugin "eclipse" is applied; e.g. if running in Eclipse IDE with buildship plugin
|
||||||
|
// - no taskNames specified at command line; e.g. if buildship synchronizes projects
|
||||||
|
val exclude =
|
||||||
|
rootProject.plugins.hasPlugin( "eclipse" ) &&
|
||||||
|
gradle.startParameter.taskNames.isEmpty()
|
||||||
|
|
||||||
|
if( !exclude ) {
|
||||||
sourceSets {
|
sourceSets {
|
||||||
create( "java9" ) {
|
create( "java9" ) {
|
||||||
java {
|
java {
|
||||||
@@ -35,6 +42,13 @@ if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) {
|
|||||||
named<JavaCompile>( "compileJava9Java" ) {
|
named<JavaCompile>( "compileJava9Java" ) {
|
||||||
sourceCompatibility = "9"
|
sourceCompatibility = "9"
|
||||||
targetCompatibility = "9"
|
targetCompatibility = "9"
|
||||||
|
|
||||||
|
// if global toolchain is Java 8, then use Java 11 to build
|
||||||
|
if( java.toolchain.languageVersion.get().asInt() < 9 ) {
|
||||||
|
javaCompiler.set( javaToolchains.compilerFor {
|
||||||
|
languageVersion.set( JavaLanguageVersion.of( 11 ) )
|
||||||
|
} )
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
|
|||||||
@@ -29,7 +29,14 @@ plugins {
|
|||||||
java
|
java
|
||||||
}
|
}
|
||||||
|
|
||||||
if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) {
|
// for Eclipse IDE project import, exclude if:
|
||||||
|
// - plugin "eclipse" is applied; e.g. if running in Eclipse IDE with buildship plugin
|
||||||
|
// - no taskNames specified at command line; e.g. if buildship synchronizes projects
|
||||||
|
val exclude =
|
||||||
|
rootProject.plugins.hasPlugin( "eclipse" ) &&
|
||||||
|
gradle.startParameter.taskNames.isEmpty()
|
||||||
|
|
||||||
|
if( !exclude ) {
|
||||||
sourceSets {
|
sourceSets {
|
||||||
create( "module-info" ) {
|
create( "module-info" ) {
|
||||||
java {
|
java {
|
||||||
@@ -38,10 +45,11 @@ if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) {
|
|||||||
setSrcDirs( listOf( "src/main/module-info", "src/main/java", "src/main/java9" ) )
|
setSrcDirs( listOf( "src/main/module-info", "src/main/java", "src/main/java9" ) )
|
||||||
|
|
||||||
// exclude Java 8 source file if an equally named Java 9+ source file exists
|
// exclude Java 8 source file if an equally named Java 9+ source file exists
|
||||||
|
val projectDir = projectDir // necessary for configuration cache
|
||||||
exclude {
|
exclude {
|
||||||
if( it.isDirectory )
|
if( it.isDirectory )
|
||||||
return@exclude false
|
return@exclude false
|
||||||
val java9file = file( "${projectDir}/src/main/java9/${it.path}" )
|
val java9file = File( "${projectDir}/src/main/java9/${it.path}" )
|
||||||
java9file.exists() && java9file != it.file
|
java9file.exists() && java9file != it.file
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,6 +66,13 @@ if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) {
|
|||||||
options.compilerArgs.add( "--module-path" )
|
options.compilerArgs.add( "--module-path" )
|
||||||
options.compilerArgs.add( configurations.runtimeClasspath.get().asPath
|
options.compilerArgs.add( configurations.runtimeClasspath.get().asPath
|
||||||
+ File.pathSeparator + configurations.compileClasspath.get().asPath )
|
+ File.pathSeparator + configurations.compileClasspath.get().asPath )
|
||||||
|
|
||||||
|
// if global toolchain is Java 8, then use Java 11 to build
|
||||||
|
if( java.toolchain.languageVersion.get().asInt() < 9 ) {
|
||||||
|
javaCompiler.set( javaToolchains.compilerFor {
|
||||||
|
languageVersion.set( JavaLanguageVersion.of( 11 ) )
|
||||||
|
} )
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
open class NativeArtifact( val fileName: String, val classifier: String, val type: String ) {}
|
open class NativeArtifact( val fileName: String, val classifier: String, val extension: String ) {}
|
||||||
|
|
||||||
open class PublishExtension {
|
open class PublishExtension {
|
||||||
var artifactId: String? = null
|
var artifactId: String? = null
|
||||||
@@ -77,32 +77,13 @@ publishing {
|
|||||||
|
|
||||||
afterEvaluate {
|
afterEvaluate {
|
||||||
extension.nativeArtifacts?.forEach {
|
extension.nativeArtifacts?.forEach {
|
||||||
artifact( artifacts.add( "archives", file( it.fileName ) ) {
|
artifact( file( it.fileName ) ) {
|
||||||
classifier = it.classifier
|
classifier = it.classifier
|
||||||
type = it.type
|
extension = it.extension
|
||||||
} )
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
|
||||||
maven {
|
|
||||||
name = "OSSRH"
|
|
||||||
|
|
||||||
val releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
|
|
||||||
val snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots/"
|
|
||||||
url = uri( if( rootProject.hasProperty( "release" ) ) releasesRepoUrl else snapshotsRepoUrl )
|
|
||||||
|
|
||||||
credentials {
|
|
||||||
// get from gradle.properties
|
|
||||||
val ossrhUsername: String? by project
|
|
||||||
val ossrhPassword: String? by project
|
|
||||||
|
|
||||||
username = System.getenv( "OSSRH_USERNAME" ) ?: ossrhUsername
|
|
||||||
password = System.getenv( "OSSRH_PASSWORD" ) ?: ossrhPassword
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,10 +104,22 @@ tasks.withType<Sign>().configureEach {
|
|||||||
onlyIf { rootProject.hasProperty( "release" ) }
|
onlyIf { rootProject.hasProperty( "release" ) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks {
|
||||||
// check whether parallel build is enabled
|
// check whether parallel build is enabled
|
||||||
tasks.withType<AbstractPublishToMaven>().configureEach {
|
withType<AbstractPublishToMaven>().configureEach {
|
||||||
doFirst {
|
doFirst {
|
||||||
if( System.getProperty( "org.gradle.parallel" ) == "true" )
|
if( System.getProperty( "org.gradle.parallel" ) == "true" )
|
||||||
throw RuntimeException( "Publishing does not work correctly with enabled parallel build. Disable parallel build with VM option '-Dorg.gradle.parallel=false'." )
|
throw RuntimeException( "Publishing does not work correctly with enabled parallel build. Disable parallel build with VM option '-Dorg.gradle.parallel=false'." )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
register( "publishToSonatypeAndCloseStagingRepo" ) {
|
||||||
|
group = "publishing"
|
||||||
|
description = "Publish to Sonatype Maven Central and close staging repository"
|
||||||
|
|
||||||
|
dependsOn(
|
||||||
|
"publishToSonatype",
|
||||||
|
":closeSonatypeStagingRepository"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,9 +18,8 @@ plugins {
|
|||||||
java
|
java
|
||||||
}
|
}
|
||||||
|
|
||||||
val toolchainJavaVersion = System.getProperty( "toolchain" )
|
val toolchainJavaVersion: String by rootProject.extra
|
||||||
if( !toolchainJavaVersion.isNullOrEmpty() ) {
|
|
||||||
java.toolchain {
|
java.toolchain {
|
||||||
languageVersion = JavaLanguageVersion.of( toolchainJavaVersion )
|
languageVersion = JavaLanguageVersion.of( toolchainJavaVersion )
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ tasks {
|
|||||||
useJUnitPlatform()
|
useJUnitPlatform()
|
||||||
testLogging.exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
|
testLogging.exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
|
||||||
|
|
||||||
if( JavaVersion.current() >= JavaVersion.VERSION_1_9 )
|
if( java.toolchain.languageVersion.get().asInt() >= 9 )
|
||||||
jvmArgs( listOf( "--add-opens", "java.desktop/javax.swing.plaf.basic=ALL-UNNAMED" ) )
|
jvmArgs( listOf( "--add-opens", "java.desktop/javax.swing.plaf.basic=ALL-UNNAMED" ) )
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,21 +98,31 @@ tasks {
|
|||||||
group = "verification"
|
group = "verification"
|
||||||
dependsOn( "jar" )
|
dependsOn( "jar" )
|
||||||
|
|
||||||
|
// necessary for configuration cache
|
||||||
|
val classpath = sigtest.asPath
|
||||||
|
val signatureFile = "${project.name}-sigtest.txt"
|
||||||
|
val jarPath = jar.get().outputs.files.asPath
|
||||||
|
val version = version
|
||||||
|
|
||||||
doLast {
|
doLast {
|
||||||
ant.withGroovyBuilder {
|
ant.withGroovyBuilder {
|
||||||
"taskdef"(
|
"taskdef"(
|
||||||
"name" to "sigtest",
|
"name" to "sigtest",
|
||||||
"classname" to "org.netbeans.apitest.Sigtest",
|
"classname" to "org.netbeans.apitest.Sigtest",
|
||||||
"classpath" to sigtest.asPath )
|
"classpath" to classpath )
|
||||||
|
|
||||||
"sigtest"(
|
"sigtest"(
|
||||||
"action" to "generate",
|
"action" to "generate",
|
||||||
"fileName" to "${project.name}-sigtest.txt",
|
"fileName" to signatureFile,
|
||||||
"classpath" to jar.get().outputs.files.asPath,
|
"classpath" to jarPath,
|
||||||
"packages" to "com.formdev.flatlaf,com.formdev.flatlaf.themes,com.formdev.flatlaf.util",
|
"packages" to "com.formdev.flatlaf,com.formdev.flatlaf.themes,com.formdev.flatlaf.util",
|
||||||
"version" to version,
|
"version" to version,
|
||||||
"release" to "1.8", // Java version
|
"release" to "1.8", // Java version
|
||||||
"failonerror" to "true" )
|
"failonerror" to "true" )
|
||||||
|
|
||||||
|
"fixcrlf"(
|
||||||
|
"file" to signatureFile,
|
||||||
|
"eol" to "lf" )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -121,17 +131,23 @@ tasks {
|
|||||||
group = "verification"
|
group = "verification"
|
||||||
dependsOn( "jar" )
|
dependsOn( "jar" )
|
||||||
|
|
||||||
|
// necessary for configuration cache
|
||||||
|
val classpath = sigtest.asPath
|
||||||
|
val signatureFile = "${project.name}-sigtest.txt"
|
||||||
|
val jarPath = jar.get().outputs.files.asPath
|
||||||
|
val version = version
|
||||||
|
|
||||||
doLast {
|
doLast {
|
||||||
ant.withGroovyBuilder {
|
ant.withGroovyBuilder {
|
||||||
"taskdef"(
|
"taskdef"(
|
||||||
"name" to "sigtest",
|
"name" to "sigtest",
|
||||||
"classname" to "org.netbeans.apitest.Sigtest",
|
"classname" to "org.netbeans.apitest.Sigtest",
|
||||||
"classpath" to sigtest.asPath )
|
"classpath" to classpath )
|
||||||
|
|
||||||
"sigtest"(
|
"sigtest"(
|
||||||
"action" to "check",
|
"action" to "check",
|
||||||
"fileName" to "${project.name}-sigtest.txt",
|
"fileName" to signatureFile,
|
||||||
"classpath" to jar.get().outputs.files.asPath,
|
"classpath" to jarPath,
|
||||||
"packages" to "com.formdev.flatlaf,com.formdev.flatlaf.util",
|
"packages" to "com.formdev.flatlaf,com.formdev.flatlaf.util",
|
||||||
"version" to version,
|
"version" to version,
|
||||||
"release" to "1.8", // Java version
|
"release" to "1.8", // Java version
|
||||||
@@ -156,5 +172,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" ),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#Signature file v4.1
|
#Signature file v4.1
|
||||||
#Version 3.5.2
|
#Version 3.7
|
||||||
|
|
||||||
CLSS public abstract interface com.formdev.flatlaf.FlatClientProperties
|
CLSS public abstract interface com.formdev.flatlaf.FlatClientProperties
|
||||||
fld public final static java.lang.String BUTTON_TYPE = "JButton.buttonType"
|
fld public final static java.lang.String BUTTON_TYPE = "JButton.buttonType"
|
||||||
@@ -24,6 +24,7 @@ fld public final static java.lang.String MINIMUM_HEIGHT = "JComponent.minimumHei
|
|||||||
fld public final static java.lang.String MINIMUM_WIDTH = "JComponent.minimumWidth"
|
fld public final static java.lang.String MINIMUM_WIDTH = "JComponent.minimumWidth"
|
||||||
fld public final static java.lang.String OUTLINE = "JComponent.outline"
|
fld public final static java.lang.String OUTLINE = "JComponent.outline"
|
||||||
fld public final static java.lang.String OUTLINE_ERROR = "error"
|
fld public final static java.lang.String OUTLINE_ERROR = "error"
|
||||||
|
fld public final static java.lang.String OUTLINE_SUCCESS = "success"
|
||||||
fld public final static java.lang.String OUTLINE_WARNING = "warning"
|
fld public final static java.lang.String OUTLINE_WARNING = "warning"
|
||||||
fld public final static java.lang.String PLACEHOLDER_TEXT = "JTextField.placeholderText"
|
fld public final static java.lang.String PLACEHOLDER_TEXT = "JTextField.placeholderText"
|
||||||
fld public final static java.lang.String POPUP_BORDER_CORNER_RADIUS = "Popup.borderCornerRadius"
|
fld public final static java.lang.String POPUP_BORDER_CORNER_RADIUS = "Popup.borderCornerRadius"
|
||||||
@@ -40,6 +41,7 @@ fld public final static java.lang.String SELECT_ALL_ON_FOCUS_POLICY = "JTextFiel
|
|||||||
fld public final static java.lang.String SELECT_ALL_ON_FOCUS_POLICY_ALWAYS = "always"
|
fld public final static java.lang.String SELECT_ALL_ON_FOCUS_POLICY_ALWAYS = "always"
|
||||||
fld public final static java.lang.String SELECT_ALL_ON_FOCUS_POLICY_NEVER = "never"
|
fld public final static java.lang.String SELECT_ALL_ON_FOCUS_POLICY_NEVER = "never"
|
||||||
fld public final static java.lang.String SELECT_ALL_ON_FOCUS_POLICY_ONCE = "once"
|
fld public final static java.lang.String SELECT_ALL_ON_FOCUS_POLICY_ONCE = "once"
|
||||||
|
fld public final static java.lang.String SELECT_ALL_ON_MOUSE_CLICK = "JTextField.selectAllOnMouseClick"
|
||||||
fld public final static java.lang.String SPLIT_PANE_EXPANDABLE_SIDE = "JSplitPane.expandableSide"
|
fld public final static java.lang.String SPLIT_PANE_EXPANDABLE_SIDE = "JSplitPane.expandableSide"
|
||||||
fld public final static java.lang.String SPLIT_PANE_EXPANDABLE_SIDE_LEFT = "left"
|
fld public final static java.lang.String SPLIT_PANE_EXPANDABLE_SIDE_LEFT = "left"
|
||||||
fld public final static java.lang.String SPLIT_PANE_EXPANDABLE_SIDE_RIGHT = "right"
|
fld public final static java.lang.String SPLIT_PANE_EXPANDABLE_SIDE_RIGHT = "right"
|
||||||
@@ -85,6 +87,7 @@ fld public final static java.lang.String TABBED_PANE_TAB_TYPE_UNDERLINED = "unde
|
|||||||
fld public final static java.lang.String TABBED_PANE_TAB_WIDTH_MODE = "JTabbedPane.tabWidthMode"
|
fld public final static java.lang.String TABBED_PANE_TAB_WIDTH_MODE = "JTabbedPane.tabWidthMode"
|
||||||
fld public final static java.lang.String TABBED_PANE_TAB_WIDTH_MODE_COMPACT = "compact"
|
fld public final static java.lang.String TABBED_PANE_TAB_WIDTH_MODE_COMPACT = "compact"
|
||||||
fld public final static java.lang.String TABBED_PANE_TAB_WIDTH_MODE_EQUAL = "equal"
|
fld public final static java.lang.String TABBED_PANE_TAB_WIDTH_MODE_EQUAL = "equal"
|
||||||
|
fld public final static java.lang.String TABBED_PANE_TAB_WIDTH_MODE_ICON_ONLY = "iconOnly"
|
||||||
fld public final static java.lang.String TABBED_PANE_TAB_WIDTH_MODE_PREFERRED = "preferred"
|
fld public final static java.lang.String TABBED_PANE_TAB_WIDTH_MODE_PREFERRED = "preferred"
|
||||||
fld public final static java.lang.String TABBED_PANE_TRAILING_COMPONENT = "JTabbedPane.trailingComponent"
|
fld public final static java.lang.String TABBED_PANE_TRAILING_COMPONENT = "JTabbedPane.trailingComponent"
|
||||||
fld public final static java.lang.String TAB_BUTTON_SELECTED_BACKGROUND = "JToggleButton.tab.selectedBackground"
|
fld public final static java.lang.String TAB_BUTTON_SELECTED_BACKGROUND = "JToggleButton.tab.selectedBackground"
|
||||||
@@ -107,6 +110,7 @@ fld public final static java.lang.String TITLE_BAR_SHOW_ICONIFFY = "JRootPane.ti
|
|||||||
fld public final static java.lang.String TITLE_BAR_SHOW_MAXIMIZE = "JRootPane.titleBarShowMaximize"
|
fld public final static java.lang.String TITLE_BAR_SHOW_MAXIMIZE = "JRootPane.titleBarShowMaximize"
|
||||||
fld public final static java.lang.String TITLE_BAR_SHOW_TITLE = "JRootPane.titleBarShowTitle"
|
fld public final static java.lang.String TITLE_BAR_SHOW_TITLE = "JRootPane.titleBarShowTitle"
|
||||||
fld public final static java.lang.String TREE_PAINT_SELECTION = "JTree.paintSelection"
|
fld public final static java.lang.String TREE_PAINT_SELECTION = "JTree.paintSelection"
|
||||||
|
fld public final static java.lang.String TREE_WIDE_CELL_RENDERER = "JTree.wideCellRenderer"
|
||||||
fld public final static java.lang.String TREE_WIDE_SELECTION = "JTree.wideSelection"
|
fld public final static java.lang.String TREE_WIDE_SELECTION = "JTree.wideSelection"
|
||||||
fld public final static java.lang.String USE_WINDOW_DECORATIONS = "JRootPane.useWindowDecorations"
|
fld public final static java.lang.String USE_WINDOW_DECORATIONS = "JRootPane.useWindowDecorations"
|
||||||
fld public final static java.lang.String WINDOW_STYLE = "Window.style"
|
fld public final static java.lang.String WINDOW_STYLE = "Window.style"
|
||||||
@@ -220,8 +224,11 @@ meth public static java.lang.String getPreferredFontFamily()
|
|||||||
meth public static java.lang.String getPreferredLightFontFamily()
|
meth public static java.lang.String getPreferredLightFontFamily()
|
||||||
meth public static java.lang.String getPreferredMonospacedFontFamily()
|
meth public static java.lang.String getPreferredMonospacedFontFamily()
|
||||||
meth public static java.lang.String getPreferredSemiboldFontFamily()
|
meth public static java.lang.String getPreferredSemiboldFontFamily()
|
||||||
|
meth public static java.lang.String getUIKeyLightOrDarkPrefix(boolean)
|
||||||
meth public static java.util.Map<java.lang.String,java.lang.Class<?>> getStyleableInfos(javax.swing.JComponent)
|
meth public static java.util.Map<java.lang.String,java.lang.Class<?>> getStyleableInfos(javax.swing.JComponent)
|
||||||
meth public static java.util.Map<java.lang.String,java.lang.String> getGlobalExtraDefaults()
|
meth public static java.util.Map<java.lang.String,java.lang.String> getGlobalExtraDefaults()
|
||||||
|
meth public static java.util.Set<java.lang.String> getUIKeyPlatformPrefixes()
|
||||||
|
meth public static java.util.Set<java.lang.String> getUIKeySpecialPrefixes()
|
||||||
meth public static java.util.function.Function<java.lang.String,java.awt.Color> getSystemColorGetter()
|
meth public static java.util.function.Function<java.lang.String,java.awt.Color> getSystemColorGetter()
|
||||||
meth public static javax.swing.UIDefaults$ActiveValue createActiveFontValue(float)
|
meth public static javax.swing.UIDefaults$ActiveValue createActiveFontValue(float)
|
||||||
meth public static void disableWindowsD3Donscreen()
|
meth public static void disableWindowsD3Donscreen()
|
||||||
@@ -255,7 +262,7 @@ meth public void setExtraDefaults(java.util.Map<java.lang.String,java.lang.Strin
|
|||||||
meth public void uninitialize()
|
meth public void uninitialize()
|
||||||
meth public void unregisterUIDefaultsGetter(java.util.function.Function<java.lang.Object,java.lang.Object>)
|
meth public void unregisterUIDefaultsGetter(java.util.function.Function<java.lang.Object,java.lang.Object>)
|
||||||
supr javax.swing.plaf.basic.BasicLookAndFeel
|
supr javax.swing.plaf.basic.BasicLookAndFeel
|
||||||
hfds DESKTOPFONTHINTS,aquaLoaded,customDefaultsSources,desktopPropertyListener,desktopPropertyName,desktopPropertyName2,extraDefaults,globalExtraDefaults,mnemonicHandler,oldPopupFactory,postInitialization,preferredFontFamily,preferredLightFontFamily,preferredMonospacedFontFamily,preferredSemiboldFontFamily,subMenuUsabilityHelperInstalled,systemColorGetter,uiDefaultsGetters,updateUIPending
|
hfds DESKTOPFONTHINTS,aquaLoaded,customDefaultsSources,desktopPropertyListener,desktopPropertyName,desktopPropertyName2,extraDefaults,globalExtraDefaults,linuxPopupMenuCanceler,mnemonicHandler,oldPopupFactory,postInitialization,preferredFontFamily,preferredLightFontFamily,preferredMonospacedFontFamily,preferredSemiboldFontFamily,subMenuUsabilityHelperInstalled,systemColorGetter,uiDefaultsGetters,uiKeyPlatformPrefixes,uiKeySpecialPrefixes,updateUIPending
|
||||||
hcls ActiveFont,FlatUIDefaults,ImageIconUIResource
|
hcls ActiveFont,FlatUIDefaults,ImageIconUIResource
|
||||||
|
|
||||||
CLSS public abstract interface static com.formdev.flatlaf.FlatLaf$DisabledIconProvider
|
CLSS public abstract interface static com.formdev.flatlaf.FlatLaf$DisabledIconProvider
|
||||||
@@ -291,6 +298,7 @@ CLSS public abstract interface com.formdev.flatlaf.FlatSystemProperties
|
|||||||
fld public final static java.lang.String ANIMATION = "flatlaf.animation"
|
fld public final static java.lang.String ANIMATION = "flatlaf.animation"
|
||||||
fld public final static java.lang.String MENUBAR_EMBEDDED = "flatlaf.menuBarEmbedded"
|
fld public final static java.lang.String MENUBAR_EMBEDDED = "flatlaf.menuBarEmbedded"
|
||||||
fld public final static java.lang.String NATIVE_LIBRARY_PATH = "flatlaf.nativeLibraryPath"
|
fld public final static java.lang.String NATIVE_LIBRARY_PATH = "flatlaf.nativeLibraryPath"
|
||||||
|
fld public final static java.lang.String REUSE_VISIBLE_POPUP_WINDOW = "flatlaf.reuseVisiblePopupWindow"
|
||||||
fld public final static java.lang.String UI_SCALE = "flatlaf.uiScale"
|
fld public final static java.lang.String UI_SCALE = "flatlaf.uiScale"
|
||||||
fld public final static java.lang.String UI_SCALE_ALLOW_SCALE_DOWN = "flatlaf.uiScale.allowScaleDown"
|
fld public final static java.lang.String UI_SCALE_ALLOW_SCALE_DOWN = "flatlaf.uiScale.allowScaleDown"
|
||||||
fld public final static java.lang.String UI_SCALE_ENABLED = "flatlaf.uiScale.enabled"
|
fld public final static java.lang.String UI_SCALE_ENABLED = "flatlaf.uiScale.enabled"
|
||||||
@@ -300,6 +308,7 @@ fld public final static java.lang.String USE_JETBRAINS_CUSTOM_DECORATIONS = "fla
|
|||||||
fld public final static java.lang.String USE_NATIVE_LIBRARY = "flatlaf.useNativeLibrary"
|
fld public final static java.lang.String USE_NATIVE_LIBRARY = "flatlaf.useNativeLibrary"
|
||||||
fld public final static java.lang.String USE_ROUNDED_POPUP_BORDER = "flatlaf.useRoundedPopupBorder"
|
fld public final static java.lang.String USE_ROUNDED_POPUP_BORDER = "flatlaf.useRoundedPopupBorder"
|
||||||
fld public final static java.lang.String USE_SUB_MENU_SAFE_TRIANGLE = "flatlaf.useSubMenuSafeTriangle"
|
fld public final static java.lang.String USE_SUB_MENU_SAFE_TRIANGLE = "flatlaf.useSubMenuSafeTriangle"
|
||||||
|
fld public final static java.lang.String USE_SYSTEM_FILE_CHOOSER = "flatlaf.useSystemFileChooser"
|
||||||
fld public final static java.lang.String USE_TEXT_Y_CORRECTION = "flatlaf.useTextYCorrection"
|
fld public final static java.lang.String USE_TEXT_Y_CORRECTION = "flatlaf.useTextYCorrection"
|
||||||
fld public final static java.lang.String USE_UBUNTU_FONT = "flatlaf.useUbuntuFont"
|
fld public final static java.lang.String USE_UBUNTU_FONT = "flatlaf.useUbuntuFont"
|
||||||
fld public final static java.lang.String USE_WINDOW_DECORATIONS = "flatlaf.useWindowDecorations"
|
fld public final static java.lang.String USE_WINDOW_DECORATIONS = "flatlaf.useWindowDecorations"
|
||||||
@@ -318,7 +327,7 @@ meth public static boolean setup(java.io.InputStream)
|
|||||||
meth public static com.formdev.flatlaf.FlatLaf createLaf(com.formdev.flatlaf.IntelliJTheme)
|
meth public static com.formdev.flatlaf.FlatLaf createLaf(com.formdev.flatlaf.IntelliJTheme)
|
||||||
meth public static com.formdev.flatlaf.FlatLaf createLaf(java.io.InputStream) throws java.io.IOException
|
meth public static com.formdev.flatlaf.FlatLaf createLaf(java.io.InputStream) throws java.io.IOException
|
||||||
supr java.lang.Object
|
supr java.lang.Object
|
||||||
hfds checkboxDuplicateColors,checkboxKeyMapping,colors,icons,isMaterialUILite,namedColors,ui,uiKeyCopying,uiKeyDoNotOverride,uiKeyExcludes,uiKeyInverseMapping,uiKeyMapping
|
hfds checkboxDuplicateColors,checkboxKeyMapping,jsonColors,jsonIcons,jsonUI,namedColors,uiKeyCopying,uiKeyDoNotOverride,uiKeyExcludesContains,uiKeyExcludesStartsWith,uiKeyInverseMapping,uiKeyMapping
|
||||||
|
|
||||||
CLSS public static com.formdev.flatlaf.IntelliJTheme$ThemeLaf
|
CLSS public static com.formdev.flatlaf.IntelliJTheme$ThemeLaf
|
||||||
outer com.formdev.flatlaf.IntelliJTheme
|
outer com.formdev.flatlaf.IntelliJTheme
|
||||||
@@ -413,6 +422,7 @@ innr public static Fade
|
|||||||
innr public static HSLChange
|
innr public static HSLChange
|
||||||
innr public static HSLIncreaseDecrease
|
innr public static HSLIncreaseDecrease
|
||||||
innr public static Mix
|
innr public static Mix
|
||||||
|
innr public static Mix2
|
||||||
meth public !varargs static java.awt.Color applyFunctions(java.awt.Color,com.formdev.flatlaf.util.ColorFunctions$ColorFunction[])
|
meth public !varargs static java.awt.Color applyFunctions(java.awt.Color,com.formdev.flatlaf.util.ColorFunctions$ColorFunction[])
|
||||||
meth public static float clamp(float)
|
meth public static float clamp(float)
|
||||||
meth public static float luma(java.awt.Color)
|
meth public static float luma(java.awt.Color)
|
||||||
@@ -474,6 +484,16 @@ meth public java.lang.String toString()
|
|||||||
meth public void apply(float[])
|
meth public void apply(float[])
|
||||||
supr java.lang.Object
|
supr java.lang.Object
|
||||||
|
|
||||||
|
CLSS public static com.formdev.flatlaf.util.ColorFunctions$Mix2
|
||||||
|
outer com.formdev.flatlaf.util.ColorFunctions
|
||||||
|
cons public init(java.awt.Color,float)
|
||||||
|
fld public final float weight
|
||||||
|
fld public final java.awt.Color color1
|
||||||
|
intf com.formdev.flatlaf.util.ColorFunctions$ColorFunction
|
||||||
|
meth public java.lang.String toString()
|
||||||
|
meth public void apply(float[])
|
||||||
|
supr java.lang.Object
|
||||||
|
|
||||||
CLSS public com.formdev.flatlaf.util.CubicBezierEasing
|
CLSS public com.formdev.flatlaf.util.CubicBezierEasing
|
||||||
cons public init(float,float,float,float)
|
cons public init(float,float,float,float)
|
||||||
fld public final static com.formdev.flatlaf.util.CubicBezierEasing EASE
|
fld public final static com.formdev.flatlaf.util.CubicBezierEasing EASE
|
||||||
@@ -752,9 +772,116 @@ cons public init()
|
|||||||
meth public static <%0 extends java.awt.Component> {%%0} getComponentByName(java.awt.Container,java.lang.String)
|
meth public static <%0 extends java.awt.Component> {%%0} getComponentByName(java.awt.Container,java.lang.String)
|
||||||
supr java.lang.Object
|
supr java.lang.Object
|
||||||
|
|
||||||
|
CLSS public com.formdev.flatlaf.util.SystemFileChooser
|
||||||
|
cons public init()
|
||||||
|
cons public init(java.io.File)
|
||||||
|
cons public init(java.lang.String)
|
||||||
|
fld public final static int APPROVE_OPTION = 0
|
||||||
|
fld public final static int CANCEL_OPTION = 1
|
||||||
|
fld public final static int DIRECTORIES_ONLY = 1
|
||||||
|
fld public final static int FILES_ONLY = 0
|
||||||
|
fld public final static int OPEN_DIALOG = 0
|
||||||
|
fld public final static int SAVE_DIALOG = 1
|
||||||
|
fld public final static java.lang.String LINUX_OPTIONS_CLEAR = "linux.optionsClear"
|
||||||
|
fld public final static java.lang.String LINUX_OPTIONS_SET = "linux.optionsSet"
|
||||||
|
fld public final static java.lang.String MAC_FILTER_FIELD_LABEL = "mac.filterFieldLabel"
|
||||||
|
fld public final static java.lang.String MAC_MESSAGE = "mac.message"
|
||||||
|
fld public final static java.lang.String MAC_NAME_FIELD_LABEL = "mac.nameFieldLabel"
|
||||||
|
fld public final static java.lang.String MAC_OPTIONS_CLEAR = "mac.optionsClear"
|
||||||
|
fld public final static java.lang.String MAC_OPTIONS_SET = "mac.optionsSet"
|
||||||
|
fld public final static java.lang.String MAC_TREATS_FILE_PACKAGES_AS_DIRECTORIES = "mac.treatsFilePackagesAsDirectories"
|
||||||
|
fld public final static java.lang.String WINDOWS_DEFAULT_EXTENSION = "windows.defaultExtension"
|
||||||
|
fld public final static java.lang.String WINDOWS_DEFAULT_FOLDER = "windows.defaultFolder"
|
||||||
|
fld public final static java.lang.String WINDOWS_FILE_NAME_LABEL = "windows.fileNameLabel"
|
||||||
|
fld public final static java.lang.String WINDOWS_OPTIONS_CLEAR = "windows.optionsClear"
|
||||||
|
fld public final static java.lang.String WINDOWS_OPTIONS_SET = "windows.optionsSet"
|
||||||
|
innr public abstract interface static ApproveCallback
|
||||||
|
innr public abstract interface static StateStore
|
||||||
|
innr public abstract static ApproveContext
|
||||||
|
innr public abstract static FileFilter
|
||||||
|
innr public final static FileNameExtensionFilter
|
||||||
|
meth public <%0 extends java.lang.Object> {%%0} getPlatformProperty(java.lang.String)
|
||||||
|
meth public boolean isAcceptAllFileFilterUsed()
|
||||||
|
meth public boolean isDirectorySelectionEnabled()
|
||||||
|
meth public boolean isFileHidingEnabled()
|
||||||
|
meth public boolean isFileSelectionEnabled()
|
||||||
|
meth public boolean isMultiSelectionEnabled()
|
||||||
|
meth public boolean removeChoosableFileFilter(com.formdev.flatlaf.util.SystemFileChooser$FileFilter)
|
||||||
|
meth public com.formdev.flatlaf.util.SystemFileChooser$ApproveCallback getApproveCallback()
|
||||||
|
meth public com.formdev.flatlaf.util.SystemFileChooser$FileFilter getAcceptAllFileFilter()
|
||||||
|
meth public com.formdev.flatlaf.util.SystemFileChooser$FileFilter getFileFilter()
|
||||||
|
meth public com.formdev.flatlaf.util.SystemFileChooser$FileFilter[] getChoosableFileFilters()
|
||||||
|
meth public int getApproveButtonMnemonic()
|
||||||
|
meth public int getDialogType()
|
||||||
|
meth public int getFileSelectionMode()
|
||||||
|
meth public int showDialog(java.awt.Component,java.lang.String)
|
||||||
|
meth public int showOpenDialog(java.awt.Component)
|
||||||
|
meth public int showSaveDialog(java.awt.Component)
|
||||||
|
meth public java.io.File getCurrentDirectory()
|
||||||
|
meth public java.io.File getSelectedFile()
|
||||||
|
meth public java.io.File[] getSelectedFiles()
|
||||||
|
meth public java.lang.String getApproveButtonText()
|
||||||
|
meth public java.lang.String getDialogTitle()
|
||||||
|
meth public java.lang.String getStateStoreID()
|
||||||
|
meth public static com.formdev.flatlaf.util.SystemFileChooser$StateStore getStateStore()
|
||||||
|
meth public static void setStateStore(com.formdev.flatlaf.util.SystemFileChooser$StateStore)
|
||||||
|
meth public void addChoosableFileFilter(com.formdev.flatlaf.util.SystemFileChooser$FileFilter)
|
||||||
|
meth public void putPlatformProperty(java.lang.String,java.lang.Object)
|
||||||
|
meth public void resetChoosableFileFilters()
|
||||||
|
meth public void setAcceptAllFileFilterUsed(boolean)
|
||||||
|
meth public void setApproveButtonMnemonic(char)
|
||||||
|
meth public void setApproveButtonMnemonic(int)
|
||||||
|
meth public void setApproveButtonText(java.lang.String)
|
||||||
|
meth public void setApproveCallback(com.formdev.flatlaf.util.SystemFileChooser$ApproveCallback)
|
||||||
|
meth public void setCurrentDirectory(java.io.File)
|
||||||
|
meth public void setDialogTitle(java.lang.String)
|
||||||
|
meth public void setDialogType(int)
|
||||||
|
meth public void setFileFilter(com.formdev.flatlaf.util.SystemFileChooser$FileFilter)
|
||||||
|
meth public void setFileHidingEnabled(boolean)
|
||||||
|
meth public void setFileSelectionMode(int)
|
||||||
|
meth public void setMultiSelectionEnabled(boolean)
|
||||||
|
meth public void setSelectedFile(java.io.File)
|
||||||
|
meth public void setSelectedFiles(java.io.File[])
|
||||||
|
meth public void setStateStoreID(java.lang.String)
|
||||||
|
supr java.lang.Object
|
||||||
|
hfds acceptAllFileFilter,approveButtonMnemonic,approveButtonText,approveCallback,approveResult,currentDirectory,dialogTitle,dialogType,fileFilter,fileSelectionMode,filters,inMemoryStateStore,keepAcceptAllAtEnd,multiSelection,platformProperties,selectedFile,selectedFiles,stateStore,stateStoreID,useAcceptAllFileFilter,useFileHiding
|
||||||
|
hcls AcceptAllFileFilter,FileChooserProvider,LinuxFileChooserProvider,MacFileChooserProvider,SwingFileChooserProvider,SystemFileChooserProvider,WindowsFileChooserProvider
|
||||||
|
|
||||||
|
CLSS public abstract interface static com.formdev.flatlaf.util.SystemFileChooser$ApproveCallback
|
||||||
|
outer com.formdev.flatlaf.util.SystemFileChooser
|
||||||
|
meth public abstract int approve(java.io.File[],com.formdev.flatlaf.util.SystemFileChooser$ApproveContext)
|
||||||
|
|
||||||
|
CLSS public abstract static com.formdev.flatlaf.util.SystemFileChooser$ApproveContext
|
||||||
|
outer com.formdev.flatlaf.util.SystemFileChooser
|
||||||
|
cons public init()
|
||||||
|
meth public abstract !varargs int showMessageDialog(int,java.lang.String,java.lang.String,int,java.lang.String[])
|
||||||
|
supr java.lang.Object
|
||||||
|
|
||||||
|
CLSS public abstract static com.formdev.flatlaf.util.SystemFileChooser$FileFilter
|
||||||
|
outer com.formdev.flatlaf.util.SystemFileChooser
|
||||||
|
cons public init()
|
||||||
|
meth public abstract java.lang.String getDescription()
|
||||||
|
supr java.lang.Object
|
||||||
|
|
||||||
|
CLSS public final static com.formdev.flatlaf.util.SystemFileChooser$FileNameExtensionFilter
|
||||||
|
outer com.formdev.flatlaf.util.SystemFileChooser
|
||||||
|
cons public !varargs init(java.lang.String,java.lang.String[])
|
||||||
|
meth public java.lang.String getDescription()
|
||||||
|
meth public java.lang.String toString()
|
||||||
|
meth public java.lang.String[] getExtensions()
|
||||||
|
supr com.formdev.flatlaf.util.SystemFileChooser$FileFilter
|
||||||
|
hfds description,extensions
|
||||||
|
|
||||||
|
CLSS public abstract interface static com.formdev.flatlaf.util.SystemFileChooser$StateStore
|
||||||
|
outer com.formdev.flatlaf.util.SystemFileChooser
|
||||||
|
fld public final static java.lang.String KEY_CURRENT_DIRECTORY = "currentDirectory"
|
||||||
|
meth public abstract java.lang.String get(java.lang.String,java.lang.String)
|
||||||
|
meth public abstract void put(java.lang.String,java.lang.String)
|
||||||
|
|
||||||
CLSS public com.formdev.flatlaf.util.SystemInfo
|
CLSS public com.formdev.flatlaf.util.SystemInfo
|
||||||
cons public init()
|
cons public init()
|
||||||
fld public final static boolean isAARCH64
|
fld public final static boolean isAARCH64
|
||||||
|
fld public final static boolean isGNOME
|
||||||
fld public final static boolean isJava_11_orLater
|
fld public final static boolean isJava_11_orLater
|
||||||
fld public final static boolean isJava_12_orLater
|
fld public final static boolean isJava_12_orLater
|
||||||
fld public final static boolean isJava_15_orLater
|
fld public final static boolean isJava_15_orLater
|
||||||
@@ -771,6 +898,7 @@ fld public final static boolean isMacOS_10_11_ElCapitan_orLater
|
|||||||
fld public final static boolean isMacOS_10_14_Mojave_orLater
|
fld public final static boolean isMacOS_10_14_Mojave_orLater
|
||||||
fld public final static boolean isMacOS_10_15_Catalina_orLater
|
fld public final static boolean isMacOS_10_15_Catalina_orLater
|
||||||
fld public final static boolean isProjector
|
fld public final static boolean isProjector
|
||||||
|
fld public final static boolean isUnknownOS
|
||||||
fld public final static boolean isWebswing
|
fld public final static boolean isWebswing
|
||||||
fld public final static boolean isWinPE
|
fld public final static boolean isWinPE
|
||||||
fld public final static boolean isWindows
|
fld public final static boolean isWindows
|
||||||
@@ -786,13 +914,21 @@ supr java.lang.Object
|
|||||||
|
|
||||||
CLSS public com.formdev.flatlaf.util.UIScale
|
CLSS public com.formdev.flatlaf.util.UIScale
|
||||||
cons public init()
|
cons public init()
|
||||||
|
fld public final static java.lang.String PROP_USER_SCALE_FACTOR = "userScaleFactor"
|
||||||
|
fld public final static java.lang.String PROP_ZOOM_FACTOR = "zoomFactor"
|
||||||
meth public static boolean isSystemScalingEnabled()
|
meth public static boolean isSystemScalingEnabled()
|
||||||
|
meth public static boolean setZoomFactor(float)
|
||||||
|
meth public static boolean zoomIn()
|
||||||
|
meth public static boolean zoomOut()
|
||||||
|
meth public static boolean zoomReset()
|
||||||
meth public static double getSystemScaleFactor(java.awt.Graphics2D)
|
meth public static double getSystemScaleFactor(java.awt.Graphics2D)
|
||||||
meth public static double getSystemScaleFactor(java.awt.GraphicsConfiguration)
|
meth public static double getSystemScaleFactor(java.awt.GraphicsConfiguration)
|
||||||
meth public static float computeFontScaleFactor(java.awt.Font)
|
meth public static float computeFontScaleFactor(java.awt.Font)
|
||||||
meth public static float getUserScaleFactor()
|
meth public static float getUserScaleFactor()
|
||||||
|
meth public static float getZoomFactor()
|
||||||
meth public static float scale(float)
|
meth public static float scale(float)
|
||||||
meth public static float unscale(float)
|
meth public static float unscale(float)
|
||||||
|
meth public static float[] getSupportedZoomFactors()
|
||||||
meth public static int scale(int)
|
meth public static int scale(int)
|
||||||
meth public static int scale2(int)
|
meth public static int scale2(int)
|
||||||
meth public static int unscale(int)
|
meth public static int unscale(int)
|
||||||
@@ -802,8 +938,9 @@ meth public static javax.swing.plaf.FontUIResource applyCustomScaleFactor(javax.
|
|||||||
meth public static void addPropertyChangeListener(java.beans.PropertyChangeListener)
|
meth public static void addPropertyChangeListener(java.beans.PropertyChangeListener)
|
||||||
meth public static void removePropertyChangeListener(java.beans.PropertyChangeListener)
|
meth public static void removePropertyChangeListener(java.beans.PropertyChangeListener)
|
||||||
meth public static void scaleGraphics(java.awt.Graphics2D)
|
meth public static void scaleGraphics(java.awt.Graphics2D)
|
||||||
|
meth public static void setSupportedZoomFactors(float[])
|
||||||
supr java.lang.Object
|
supr java.lang.Object
|
||||||
hfds DEBUG,changeSupport,initialized,jreHiDPI,scaleFactor
|
hfds DEBUG,changeSupport,ignoreFontChange,inUnitTests,initialized,jreHiDPI,listenerInitialized,scaleFactor,supportedZoomFactors,unzoomedScaleFactor,zoomFactor
|
||||||
|
|
||||||
CLSS public java.awt.Color
|
CLSS public java.awt.Color
|
||||||
cons public init(float,float,float)
|
cons public init(float,float,float)
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ import java.awt.IllegalComponentStateException;
|
|||||||
import java.awt.Window;
|
import java.awt.Window;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
|
import javax.swing.JFormattedTextField;
|
||||||
|
import javax.swing.JSpinner;
|
||||||
import javax.swing.SwingConstants;
|
import javax.swing.SwingConstants;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -220,6 +222,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 +243,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.
|
||||||
@@ -1075,8 +1086,9 @@ public interface FlatClientProperties
|
|||||||
* <strong>Value type</strong> {@link java.lang.String}<br>
|
* <strong>Value type</strong> {@link java.lang.String}<br>
|
||||||
* <strong>Allowed Values</strong>
|
* <strong>Allowed Values</strong>
|
||||||
* {@link #TABBED_PANE_TAB_WIDTH_MODE_PREFERRED} (default),
|
* {@link #TABBED_PANE_TAB_WIDTH_MODE_PREFERRED} (default),
|
||||||
* {@link #TABBED_PANE_TAB_WIDTH_MODE_EQUAL} or
|
* {@link #TABBED_PANE_TAB_WIDTH_MODE_EQUAL},
|
||||||
* {@link #TABBED_PANE_TAB_WIDTH_MODE_COMPACT}
|
* {@link #TABBED_PANE_TAB_WIDTH_MODE_COMPACT} or
|
||||||
|
* {@link #TABBED_PANE_TAB_WIDTH_MODE_ICON_ONLY}
|
||||||
*/
|
*/
|
||||||
String TABBED_PANE_TAB_WIDTH_MODE = "JTabbedPane.tabWidthMode";
|
String TABBED_PANE_TAB_WIDTH_MODE = "JTabbedPane.tabWidthMode";
|
||||||
|
|
||||||
@@ -1102,6 +1114,14 @@ public interface FlatClientProperties
|
|||||||
*/
|
*/
|
||||||
String TABBED_PANE_TAB_WIDTH_MODE_COMPACT = "compact";
|
String TABBED_PANE_TAB_WIDTH_MODE_COMPACT = "compact";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All tabs are smaller because they show only the tab icon, but no tab title.
|
||||||
|
*
|
||||||
|
* @see #TABBED_PANE_TAB_WIDTH_MODE
|
||||||
|
* @since 3.7
|
||||||
|
*/
|
||||||
|
String TABBED_PANE_TAB_WIDTH_MODE_ICON_ONLY = "iconOnly";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies the tab icon placement (relative to tab title).
|
* Specifies the tab icon placement (relative to tab title).
|
||||||
* <p>
|
* <p>
|
||||||
@@ -1200,12 +1220,15 @@ public interface FlatClientProperties
|
|||||||
/**
|
/**
|
||||||
* Specifies whether all text is selected when the text component gains focus.
|
* Specifies whether all text is selected when the text component gains focus.
|
||||||
* <p>
|
* <p>
|
||||||
* <strong>Component</strong> {@link javax.swing.JTextField} (and subclasses)<br>
|
* <strong>Components</strong> {@link javax.swing.text.JTextComponent} (and subclasses),
|
||||||
|
* {@link javax.swing.JComboBox} (since 3.6) and {@link javax.swing.JSpinner} (since 3.6)<br>
|
||||||
* <strong>Value type</strong> {@link java.lang.String}<br>
|
* <strong>Value type</strong> {@link java.lang.String}<br>
|
||||||
* <strong>Allowed Values</strong>
|
* <strong>Allowed Values</strong>
|
||||||
* {@link #SELECT_ALL_ON_FOCUS_POLICY_NEVER},
|
* {@link #SELECT_ALL_ON_FOCUS_POLICY_NEVER},
|
||||||
* {@link #SELECT_ALL_ON_FOCUS_POLICY_ONCE} (default) or
|
* {@link #SELECT_ALL_ON_FOCUS_POLICY_ONCE} (default) or
|
||||||
* {@link #SELECT_ALL_ON_FOCUS_POLICY_ALWAYS}
|
* {@link #SELECT_ALL_ON_FOCUS_POLICY_ALWAYS}
|
||||||
|
*
|
||||||
|
* @see #SELECT_ALL_ON_MOUSE_CLICK
|
||||||
*/
|
*/
|
||||||
String SELECT_ALL_ON_FOCUS_POLICY = "JTextField.selectAllOnFocusPolicy";
|
String SELECT_ALL_ON_FOCUS_POLICY = "JTextField.selectAllOnFocusPolicy";
|
||||||
|
|
||||||
@@ -1220,6 +1243,12 @@ public interface FlatClientProperties
|
|||||||
* Select all text when the text component gains focus for the first time
|
* Select all text when the text component gains focus for the first time
|
||||||
* and selection was not modified (is at end of text).
|
* and selection was not modified (is at end of text).
|
||||||
* This is the default.
|
* This is the default.
|
||||||
|
* <p>
|
||||||
|
* <b>Limitations:</b>
|
||||||
|
* For {@link JFormattedTextField} and {@link JSpinner} this behaves
|
||||||
|
* as {@link #SELECT_ALL_ON_FOCUS_POLICY_ALWAYS}.
|
||||||
|
* This is because of special behavior of {@link JFormattedTextField}
|
||||||
|
* that did not allow implementation of {@code "once"}.
|
||||||
*
|
*
|
||||||
* @see #SELECT_ALL_ON_FOCUS_POLICY
|
* @see #SELECT_ALL_ON_FOCUS_POLICY
|
||||||
*/
|
*/
|
||||||
@@ -1232,6 +1261,19 @@ public interface FlatClientProperties
|
|||||||
*/
|
*/
|
||||||
String SELECT_ALL_ON_FOCUS_POLICY_ALWAYS = "always";
|
String SELECT_ALL_ON_FOCUS_POLICY_ALWAYS = "always";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies whether all text is selected when when clicking with the mouse
|
||||||
|
* into the text field (and if "select all on focus" policy is enabled).
|
||||||
|
* <p>
|
||||||
|
* <strong>Components</strong> {@link javax.swing.text.JTextComponent} (and subclasses),
|
||||||
|
* {@link javax.swing.JComboBox} and {@link javax.swing.JSpinner}<br>
|
||||||
|
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||||
|
*
|
||||||
|
* @see #SELECT_ALL_ON_FOCUS_POLICY
|
||||||
|
* @since 3.6
|
||||||
|
*/
|
||||||
|
String SELECT_ALL_ON_MOUSE_CLICK = "JTextField.selectAllOnMouseClick";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Placeholder text that is only painted if the text field is empty.
|
* Placeholder text that is only painted if the text field is empty.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -1410,13 +1452,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.
|
||||||
|
|||||||
@@ -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:
|
||||||
@@ -359,6 +368,22 @@ public abstract class FlatLaf
|
|||||||
String.format( "a, address { color: #%06x; }", linkColor.getRGB() & 0xffffff ) );
|
String.format( "a, address { color: #%06x; }", linkColor.getRGB() & 0xffffff ) );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Initialize UIScale user scale factor immediately after FlatLaf was activated,
|
||||||
|
// which is necessary to ensure that UIScale.setZoomFactor(float)
|
||||||
|
// scales FlatLaf defaultDont correctly even if UIScale.scale() was not yet used.
|
||||||
|
// In other words: Without this, UIScale.setZoomFactor(float) would
|
||||||
|
// not work correctly if invoked between FlatLaf.setup() and crating UI.
|
||||||
|
PropertyChangeListener listener = new PropertyChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void propertyChange( PropertyChangeEvent e ) {
|
||||||
|
if( "lookAndFeel".equals( e.getPropertyName() ) ) {
|
||||||
|
UIManager.removePropertyChangeListener( this );
|
||||||
|
UIScale.getUserScaleFactor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
UIManager.addPropertyChangeListener( listener );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -397,6 +422,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 +541,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 +561,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 +570,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 +581,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() {
|
||||||
@@ -691,11 +723,22 @@ public abstract class FlatLaf
|
|||||||
uiFont = ((ActiveFont)defaultFont).derive( baseFont, fontSize -> {
|
uiFont = ((ActiveFont)defaultFont).derive( baseFont, fontSize -> {
|
||||||
return Math.round( fontSize * UIScale.computeFontScaleFactor( baseFont ) );
|
return Math.round( fontSize * UIScale.computeFontScaleFactor( baseFont ) );
|
||||||
} );
|
} );
|
||||||
}
|
} else if( defaultFont instanceof LazyValue )
|
||||||
|
uiFont = ActiveFont.toUIResource( (Font) ((LazyValue)defaultFont).createValue( defaults ) );
|
||||||
|
|
||||||
// increase font size if system property "flatlaf.uiScale" is set
|
// increase font size if system property "flatlaf.uiScale" is set
|
||||||
uiFont = UIScale.applyCustomScaleFactor( uiFont );
|
uiFont = UIScale.applyCustomScaleFactor( uiFont );
|
||||||
|
|
||||||
|
// apply zoom factor to font size
|
||||||
|
float zoomFactor = UIScale.getZoomFactor();
|
||||||
|
if( zoomFactor != 1 ) {
|
||||||
|
// see also UIScale.setZoomFactor()
|
||||||
|
int unzoomedFontSize = uiFont.getSize();
|
||||||
|
defaults.put( "defaultFont.unzoomedSize", unzoomedFontSize );
|
||||||
|
int newFontSize = Math.max( Math.round( unzoomedFontSize * zoomFactor ), 1 );
|
||||||
|
uiFont = new FontUIResource( uiFont.deriveFont( (float) newFontSize ) );
|
||||||
|
}
|
||||||
|
|
||||||
// set default font
|
// set default font
|
||||||
defaults.put( "defaultFont", uiFont );
|
defaults.put( "defaultFont", uiFont );
|
||||||
}
|
}
|
||||||
@@ -739,6 +782,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
|
||||||
@@ -848,8 +938,7 @@ public abstract class FlatLaf
|
|||||||
* <p>
|
* <p>
|
||||||
* Invoke this method before setting the look and feel.
|
* Invoke this method before setting the look and feel.
|
||||||
* <p>
|
* <p>
|
||||||
* If using Java modules, the package must be opened in {@code module-info.java}.
|
* If using Java modules, it is not necessary to open the package in {@code module-info.java}.
|
||||||
* Otherwise, use {@link #registerCustomDefaultsSource(URL)}.
|
|
||||||
*
|
*
|
||||||
* @param packageName a package name (e.g. "com.myapp.resources")
|
* @param packageName a package name (e.g. "com.myapp.resources")
|
||||||
*/
|
*/
|
||||||
@@ -896,9 +985,9 @@ public abstract class FlatLaf
|
|||||||
* <p>
|
* <p>
|
||||||
* See {@link #registerCustomDefaultsSource(String)} for details.
|
* See {@link #registerCustomDefaultsSource(String)} for details.
|
||||||
* <p>
|
* <p>
|
||||||
* This method is useful if using Java modules and the package containing the properties files
|
|
||||||
* is not opened in {@code module-info.java}.
|
|
||||||
* E.g. {@code FlatLaf.registerCustomDefaultsSource( MyApp.class.getResource( "/com/myapp/themes/" ) )}.
|
* E.g. {@code FlatLaf.registerCustomDefaultsSource( MyApp.class.getResource( "/com/myapp/themes/" ) )}.
|
||||||
|
* <p>
|
||||||
|
* If using Java modules, it is not necessary to open the package in {@code module-info.java}.
|
||||||
*
|
*
|
||||||
* @param packageUrl a package URL
|
* @param packageUrl a package URL
|
||||||
* @since 2
|
* @since 2
|
||||||
@@ -1063,6 +1152,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();
|
||||||
@@ -1620,7 +1795,7 @@ public abstract class FlatLaf
|
|||||||
return toUIResource( baseFont );
|
return toUIResource( baseFont );
|
||||||
}
|
}
|
||||||
|
|
||||||
private FontUIResource toUIResource( Font font ) {
|
private static FontUIResource toUIResource( Font font ) {
|
||||||
// make sure that font is a UIResource for LaF switching
|
// make sure that font is a UIResource for LaF switching
|
||||||
return (font instanceof FontUIResource)
|
return (font instanceof FontUIResource)
|
||||||
? (FontUIResource) font
|
? (FontUIResource) font
|
||||||
|
|||||||
@@ -20,6 +20,9 @@ import java.io.File;
|
|||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
@@ -62,8 +65,8 @@ public class FlatPropertiesLaf
|
|||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
Properties properties = new Properties();
|
Properties properties = new Properties();
|
||||||
try( InputStream in2 = in ) {
|
try( Reader reader = new InputStreamReader( in, StandardCharsets.UTF_8 )) {
|
||||||
properties.load( in2 );
|
properties.load( reader );
|
||||||
}
|
}
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,10 @@
|
|||||||
|
|
||||||
package com.formdev.flatlaf;
|
package com.formdev.flatlaf;
|
||||||
|
|
||||||
|
import javax.swing.JFileChooser;
|
||||||
|
import javax.swing.JPopupMenu;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
|
import com.formdev.flatlaf.util.SystemFileChooser;
|
||||||
import com.formdev.flatlaf.util.UIScale;
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -141,12 +144,31 @@ public interface FlatSystemProperties
|
|||||||
* (requires Windows 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
|
||||||
*/
|
*/
|
||||||
String USE_ROUNDED_POPUP_BORDER = "flatlaf.useRoundedPopupBorder";
|
String USE_ROUNDED_POPUP_BORDER = "flatlaf.useRoundedPopupBorder";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Species whether popup windows may be reused without (temporary) hiding them.
|
||||||
|
* E.g. if "moving" a tooltip to follow the mouse pointer, normally it is necessary
|
||||||
|
* to hide the tooltip and show it again at the new location, which causes some
|
||||||
|
* flicker with heavy-weight popup windows that FlatLaf uses on all platforms.
|
||||||
|
* <p>
|
||||||
|
* If {@code true}, hiding popup window is deferred for an event cycle,
|
||||||
|
* which allows reusing still visible popup window and avoids flicker when "moving" the popup.
|
||||||
|
* <p>
|
||||||
|
* Note that {@link JPopupMenu} popup windows (menus and combobox lists) are newer reused.
|
||||||
|
* <p>
|
||||||
|
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
||||||
|
* <strong>Default</strong> {@code true}
|
||||||
|
*
|
||||||
|
* @since 3.6.2
|
||||||
|
*/
|
||||||
|
String REUSE_VISIBLE_POPUP_WINDOW = "flatlaf.reuseVisiblePopupWindow";
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies whether vertical text position is corrected when UI is scaled on HiDPI screens.
|
* Specifies whether vertical text position is corrected when UI is scaled on HiDPI screens.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -226,6 +248,17 @@ public interface FlatSystemProperties
|
|||||||
*/
|
*/
|
||||||
String USE_SUB_MENU_SAFE_TRIANGLE = "flatlaf.useSubMenuSafeTriangle";
|
String USE_SUB_MENU_SAFE_TRIANGLE = "flatlaf.useSubMenuSafeTriangle";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies whether {@link SystemFileChooser} uses operating system file dialogs.
|
||||||
|
* If set to {@code false}, the {@link JFileChooser} is used instead.
|
||||||
|
* <p>
|
||||||
|
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
||||||
|
* <strong>Default</strong> {@code true}
|
||||||
|
*
|
||||||
|
* @since 3.7
|
||||||
|
*/
|
||||||
|
String USE_SYSTEM_FILE_CHOOSER = "flatlaf.useSystemFileChooser";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether a system property is set and returns {@code true} if its value
|
* Checks whether a system property is set and returns {@code true} if its value
|
||||||
* is {@code "true"} (case-insensitive), otherwise it returns {@code false}.
|
* is {@code "true"} (case-insensitive), otherwise it returns {@code false}.
|
||||||
|
|||||||
@@ -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 final Map<String, String> jsonColors;
|
||||||
|
private final Map<String, Object> jsonUI;
|
||||||
|
private final 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,
|
||||||
@@ -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,143 @@ 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
|
private String get( Properties properties, Map<String, String> themeSpecificProps, String key ) {
|
||||||
colors = null;
|
return themeSpecificProps.getOrDefault( key, (String) properties.get( key ) );
|
||||||
ui = null;
|
|
||||||
icons = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object get( UIDefaults defaults, Map<Object, Object> themeSpecificDefaults, String key ) {
|
private void put( Properties properties, Object key, Object value ) {
|
||||||
return themeSpecificDefaults.getOrDefault( key, defaults.get( key ) );
|
if( value != null )
|
||||||
|
properties.put( key, value );
|
||||||
|
else
|
||||||
|
properties.remove( key );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void putAll( UIDefaults defaults, Object value, String... keys ) {
|
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 +380,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 +388,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 ) )
|
||||||
@@ -408,25 +408,40 @@ public class IntelliJTheme
|
|||||||
key.equals( "Tree.rightChildIndent" ) )
|
key.equals( "Tree.rightChildIndent" ) )
|
||||||
return; // ignore
|
return; // ignore
|
||||||
|
|
||||||
|
// ignore icons
|
||||||
|
if( key.endsWith( "Icon" ) )
|
||||||
|
return; // ignore
|
||||||
|
|
||||||
// map keys
|
// map keys
|
||||||
key = uiKeyMapping.getOrDefault( key, key );
|
key = uiKeyMapping.getOrDefault( key, key );
|
||||||
if( key.isEmpty() )
|
if( key.isEmpty() )
|
||||||
return; // ignore key
|
return; // ignore key
|
||||||
|
|
||||||
// exclude properties
|
// exclude properties (1st level)
|
||||||
int dot = key.indexOf( '.' );
|
int dot = key.indexOf( '.' );
|
||||||
if( dot > 0 && uiKeyExcludes.contains( key.substring( 0, dot + 1 ) ) )
|
if( dot > 0 && uiKeyExcludesStartsWith.contains( key.substring( 0, dot + 1 ) ) )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if( uiKeyDoNotOverride.contains( key ) && uiKeys.contains( key ) )
|
// exclude properties (2st level)
|
||||||
|
int dot2 = (dot > 0) ? key.indexOf( '.', dot + 1 ) : -1;
|
||||||
|
if( dot2 > 0 && uiKeyExcludesStartsWith.contains( key.substring( 0, dot2 + 1 ) ) )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
uiKeys.add( key );
|
// exclude properties (contains)
|
||||||
|
for( String s : uiKeyExcludesContains ) {
|
||||||
|
if( key.contains( s ) )
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
String valueStr = value.toString();
|
if( uiKeyDoNotOverride.contains( key ) && jsonUIKeys.contains( key ) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
jsonUIKeys.add( key );
|
||||||
|
|
||||||
|
String valueStr = value.toString().trim();
|
||||||
|
|
||||||
// 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,45 +460,62 @@ 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
|
private boolean applyWildcard( Properties properties, String key, String value ) {
|
||||||
for( Object k : defaultsKeysCache ) {
|
if( !key.startsWith( "*." ) )
|
||||||
if( k.equals( "Desktop.background" ) ||
|
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( "DesktopIcon.background" ) ||
|
||||||
k.equals( "TabbedPane.focusColor" ) )
|
k.equals( "TabbedPane.focusColor" ) ||
|
||||||
|
k.endsWith( ".hoverBackground" ) ||
|
||||||
|
k.endsWith( ".pressedBackground" ) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if( k instanceof String ) {
|
|
||||||
// support replacing of mapped keys
|
// support replacing of mapped keys
|
||||||
// (e.g. set ComboBox.buttonEditableBackground to *.background
|
// (e.g. set ComboBox.buttonEditableBackground to *.background
|
||||||
// because it is mapped from ComboBox.ArrowButton.background)
|
// because it is mapped from ComboBox.ArrowButton.background)
|
||||||
String km = uiKeyInverseMapping.getOrDefault( k, (String) k );
|
String km = uiKeyInverseMapping.getOrDefault( k, k );
|
||||||
if( km.endsWith( tail ) && !((String)k).startsWith( "CheckBox.icon." ) )
|
if( km.endsWith( tail ) && !k.startsWith( "CheckBox.icon." ) )
|
||||||
defaults.put( k, uiValue );
|
put( properties, k, value );
|
||||||
}
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
defaults.put( key, uiValue );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 ) {
|
||||||
@@ -497,11 +529,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 +542,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 +605,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 +628,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 +639,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,22 +659,16 @@ 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 ) {
|
private static final Set<String> uiKeyExcludesStartsWith;
|
||||||
if( !uiKeys.contains( destKey ) )
|
private static final String[] uiKeyExcludesContains;
|
||||||
defaults.put( destKey, defaults.get( srcKey ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
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). */
|
||||||
private static final Map<String, String> uiKeyMapping = new HashMap<>();
|
private static final Map<String, String> uiKeyMapping = new HashMap<>();
|
||||||
@@ -650,29 +680,30 @@ public class IntelliJTheme
|
|||||||
|
|
||||||
static {
|
static {
|
||||||
// IntelliJ UI properties that are not used in FlatLaf
|
// IntelliJ UI properties that are not used in FlatLaf
|
||||||
uiKeyExcludes = new HashSet<>( Arrays.asList(
|
uiKeyExcludesStartsWith = 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.",
|
||||||
@@ -683,11 +714,24 @@ public class IntelliJTheme
|
|||||||
// possible typos in .theme.json files
|
// possible typos in .theme.json files
|
||||||
"Checkbox.", "Toolbar.", "Tooltip.", "UiDesigner.", "link."
|
"Checkbox.", "Toolbar.", "Tooltip.", "UiDesigner.", "link."
|
||||||
) );
|
) );
|
||||||
|
uiKeyExcludesContains = new String[] {
|
||||||
|
".darcula."
|
||||||
|
};
|
||||||
|
|
||||||
uiKeyDoNotOverride = new HashSet<>( Arrays.asList(
|
uiKeyDoNotOverride = new HashSet<>( Arrays.asList(
|
||||||
"TabbedPane.selectedForeground"
|
"TabbedPane.selectedForeground"
|
||||||
) );
|
) );
|
||||||
|
|
||||||
|
// "*."
|
||||||
|
uiKeyMapping.put( "*.fontFace", "" ); // ignore (used in OnePauintxi themes)
|
||||||
|
uiKeyMapping.put( "*.fontSize", "" ); // ignore (used in OnePauintxi themes)
|
||||||
|
|
||||||
|
// Button
|
||||||
|
uiKeyMapping.put( "Button.minimumSize", "" ); // ignore (used in Material Theme UI Lite)
|
||||||
|
|
||||||
|
// CheckBox.iconSize
|
||||||
|
uiKeyMapping.put( "CheckBox.iconSize", "" ); // ignore (used in Rider themes)
|
||||||
|
|
||||||
// ComboBox
|
// ComboBox
|
||||||
uiKeyMapping.put( "ComboBox.background", "" ); // ignore
|
uiKeyMapping.put( "ComboBox.background", "" ); // ignore
|
||||||
uiKeyMapping.put( "ComboBox.buttonBackground", "" ); // ignore
|
uiKeyMapping.put( "ComboBox.buttonBackground", "" ); // ignore
|
||||||
@@ -696,14 +740,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 +758,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 +766,14 @@ 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" );
|
// RadioButton
|
||||||
|
uiKeyMapping.put( "RadioButton.iconSize", "" ); // ignore (used in Rider themes)
|
||||||
|
|
||||||
// ScrollBar
|
// ScrollBar
|
||||||
uiKeyMapping.put( "ScrollBar.trackColor", "ScrollBar.track" );
|
uiKeyMapping.put( "ScrollBar.trackColor", "ScrollBar.track" );
|
||||||
@@ -738,34 +783,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 +859,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,166 @@
|
|||||||
|
/*
|
||||||
|
* 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 ) {
|
||||||
|
removeWindowListeners();
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,12 +25,15 @@ import java.io.FileInputStream;
|
|||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.Reader;
|
||||||
import java.io.StreamTokenizer;
|
import java.io.StreamTokenizer;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.Executable;
|
import java.lang.reflect.Executable;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
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;
|
||||||
@@ -41,6 +44,9 @@ 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.concurrent.atomic.AtomicReference;
|
||||||
|
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 +67,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 +90,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 +106,62 @@ 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 void load( InputStream in ) throws IOException {
|
||||||
|
// use UTF-8 to load properties file
|
||||||
|
try( Reader reader = new InputStreamReader( in, StandardCharsets.UTF_8 )) {
|
||||||
|
super.load( reader );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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 +188,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;
|
||||||
@@ -160,16 +210,46 @@ class UIDefaultsLoader
|
|||||||
if( classLoader == null )
|
if( classLoader == null )
|
||||||
classLoader = FlatLaf.class.getClassLoader();
|
classLoader = FlatLaf.class.getClassLoader();
|
||||||
|
|
||||||
|
boolean found = false;
|
||||||
for( Class<?> lafClass : lafClasses ) {
|
for( Class<?> lafClass : lafClasses ) {
|
||||||
String propertiesName = packageName + '/' + simpleClassName( lafClass ) + ".properties";
|
String propertiesName = packageName + '/' + simpleClassName( lafClass ) + ".properties";
|
||||||
try( InputStream in = classLoader.getResourceAsStream( propertiesName ) ) {
|
try( InputStream in = classLoader.getResourceAsStream( propertiesName ) ) {
|
||||||
if( in != null )
|
if( in != null ) {
|
||||||
properties.load( in );
|
properties.load( in );
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fallback for named Java modules
|
||||||
|
if( !found ) {
|
||||||
|
// Get package URL using ClassLoader.getResource(...) because this works
|
||||||
|
// also in named Java modules, even without opening the package in module-info.java.
|
||||||
|
// This extra step is necessary because ClassLoader.getResource("<package>/<file>.properties")
|
||||||
|
// does not work for named Java modules.
|
||||||
|
URL url = classLoader.getResource( packageName );
|
||||||
|
if( url == null )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
String packageUrl = url.toExternalForm();
|
||||||
|
if( !packageUrl.endsWith( "/" ) )
|
||||||
|
packageUrl = packageUrl.concat( "/" );
|
||||||
|
|
||||||
|
for( Class<?> lafClass : lafClasses ) {
|
||||||
|
URL propertiesUrl = new URL( packageUrl + simpleClassName( lafClass ) + ".properties" );
|
||||||
|
|
||||||
|
try( InputStream in = propertiesUrl.openStream() ) {
|
||||||
|
properties.load( in );
|
||||||
|
} catch( FileNotFoundException ex ) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if( source instanceof URL ) {
|
} else if( source instanceof URL ) {
|
||||||
// load from package URL
|
// load from package URL
|
||||||
URL packageUrl = (URL) source;
|
String packageUrl = ((URL)source).toExternalForm();
|
||||||
|
if( !packageUrl.endsWith( "/" ) )
|
||||||
|
packageUrl = packageUrl.concat( "/" );
|
||||||
for( Class<?> lafClass : lafClasses ) {
|
for( Class<?> lafClass : lafClasses ) {
|
||||||
URL propertiesUrl = new URL( packageUrl + simpleClassName( lafClass ) + ".properties" );
|
URL propertiesUrl = new URL( packageUrl + simpleClassName( lafClass ) + ".properties" );
|
||||||
|
|
||||||
@@ -198,41 +278,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 +332,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 ) {
|
||||||
@@ -378,7 +432,7 @@ class UIDefaultsLoader
|
|||||||
enum ValueType { UNKNOWN, STRING, BOOLEAN, CHARACTER, INTEGER, INTEGERORFLOAT, FLOAT, BORDER, ICON, INSETS, DIMENSION, COLOR, FONT,
|
enum ValueType { UNKNOWN, STRING, BOOLEAN, CHARACTER, INTEGER, INTEGERORFLOAT, FLOAT, BORDER, ICON, INSETS, DIMENSION, COLOR, FONT,
|
||||||
SCALEDINTEGER, SCALEDFLOAT, SCALEDINSETS, SCALEDDIMENSION, INSTANCE, CLASS, GRAYFILTER, NULL, LAZY }
|
SCALEDINTEGER, SCALEDFLOAT, SCALEDINSETS, SCALEDDIMENSION, INSTANCE, CLASS, GRAYFILTER, NULL, LAZY }
|
||||||
|
|
||||||
private static final ValueType[] tempResultValueType = new ValueType[1];
|
private static final AtomicReference<ValueType> tempResultValueType = new AtomicReference<>();
|
||||||
private static Map<Class<?>, ValueType> javaValueTypes;
|
private static Map<Class<?>, ValueType> javaValueTypes;
|
||||||
private static Map<String, ValueType> knownValueTypes;
|
private static Map<String, ValueType> knownValueTypes;
|
||||||
|
|
||||||
@@ -388,7 +442,7 @@ class UIDefaultsLoader
|
|||||||
return parseValue( key, value, valueType, null, v -> v, Collections.emptyList() );
|
return parseValue( key, value, valueType, null, v -> v, Collections.emptyList() );
|
||||||
}
|
}
|
||||||
|
|
||||||
static Object parseValue( String key, String value, Class<?> javaValueType, ValueType[] resultValueType,
|
static Object parseValue( String key, String value, Class<?> javaValueType, AtomicReference<ValueType> resultValueType,
|
||||||
Function<String, String> resolver, List<ClassLoader> addonClassLoaders )
|
Function<String, String> resolver, List<ClassLoader> addonClassLoaders )
|
||||||
throws IllegalArgumentException
|
throws IllegalArgumentException
|
||||||
{
|
{
|
||||||
@@ -397,7 +451,7 @@ class UIDefaultsLoader
|
|||||||
|
|
||||||
// do not parse styles here
|
// do not parse styles here
|
||||||
if( key.startsWith( "[style]" ) ) {
|
if( key.startsWith( "[style]" ) ) {
|
||||||
resultValueType[0] = ValueType.STRING;
|
resultValueType.set( ValueType.STRING );
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -405,7 +459,7 @@ class UIDefaultsLoader
|
|||||||
|
|
||||||
// null
|
// null
|
||||||
if( value.equals( "null" ) || value.isEmpty() ) {
|
if( value.equals( "null" ) || value.isEmpty() ) {
|
||||||
resultValueType[0] = ValueType.NULL;
|
resultValueType.set( ValueType.NULL );
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -461,14 +515,14 @@ class UIDefaultsLoader
|
|||||||
} else {
|
} else {
|
||||||
// false, true
|
// false, true
|
||||||
switch( value ) {
|
switch( value ) {
|
||||||
case "false": resultValueType[0] = ValueType.BOOLEAN; return false;
|
case "false": resultValueType.set( ValueType.BOOLEAN ); return false;
|
||||||
case "true": resultValueType[0] = ValueType.BOOLEAN; return true;
|
case "true": resultValueType.set( ValueType.BOOLEAN ); return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for function "lazy"
|
// check for function "lazy"
|
||||||
// Syntax: lazy(uiKey)
|
// Syntax: lazy(uiKey)
|
||||||
if( value.startsWith( "lazy(" ) && value.endsWith( ")" ) ) {
|
if( value.startsWith( "lazy(" ) && value.endsWith( ")" ) ) {
|
||||||
resultValueType[0] = ValueType.LAZY;
|
resultValueType.set( ValueType.LAZY );
|
||||||
String uiKey = StringUtils.substringTrimmed( value, 5, value.length() - 1 );
|
String uiKey = StringUtils.substringTrimmed( value, 5, value.length() - 1 );
|
||||||
return (LazyValue) t -> {
|
return (LazyValue) t -> {
|
||||||
return lazyUIManagerGet( uiKey );
|
return lazyUIManagerGet( uiKey );
|
||||||
@@ -549,7 +603,7 @@ class UIDefaultsLoader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resultValueType[0] = valueType;
|
resultValueType.set( valueType );
|
||||||
|
|
||||||
// parse value
|
// parse value
|
||||||
switch( valueType ) {
|
switch( valueType ) {
|
||||||
@@ -576,14 +630,14 @@ class UIDefaultsLoader
|
|||||||
default:
|
default:
|
||||||
// string
|
// string
|
||||||
if( value.startsWith( "\"" ) && value.endsWith( "\"" ) ) {
|
if( value.startsWith( "\"" ) && value.endsWith( "\"" ) ) {
|
||||||
resultValueType[0] = ValueType.STRING;
|
resultValueType.set( ValueType.STRING );
|
||||||
return value.substring( 1, value.length() - 1 );
|
return value.substring( 1, value.length() - 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
// colors
|
// colors
|
||||||
if( value.startsWith( "#" ) || value.endsWith( ")" ) ) {
|
if( value.startsWith( "#" ) || value.endsWith( ")" ) ) {
|
||||||
Object color = parseColorOrFunction( value, resolver );
|
Object color = parseColorOrFunction( value, resolver );
|
||||||
resultValueType[0] = (color != null) ? ValueType.COLOR : ValueType.NULL;
|
resultValueType.set( (color != null) ? ValueType.COLOR : ValueType.NULL );
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -595,7 +649,7 @@ class UIDefaultsLoader
|
|||||||
// integer
|
// integer
|
||||||
try {
|
try {
|
||||||
Integer integer = parseInteger( value );
|
Integer integer = parseInteger( value );
|
||||||
resultValueType[0] = ValueType.INTEGER;
|
resultValueType.set( ValueType.INTEGER );
|
||||||
return integer;
|
return integer;
|
||||||
} catch( NumberFormatException ex ) {
|
} catch( NumberFormatException ex ) {
|
||||||
// ignore
|
// ignore
|
||||||
@@ -604,7 +658,7 @@ class UIDefaultsLoader
|
|||||||
// float
|
// float
|
||||||
try {
|
try {
|
||||||
Float f = parseFloat( value );
|
Float f = parseFloat( value );
|
||||||
resultValueType[0] = ValueType.FLOAT;
|
resultValueType.set( ValueType.FLOAT );
|
||||||
return f;
|
return f;
|
||||||
} catch( NumberFormatException ex ) {
|
} catch( NumberFormatException ex ) {
|
||||||
// ignore
|
// ignore
|
||||||
@@ -612,7 +666,7 @@ class UIDefaultsLoader
|
|||||||
}
|
}
|
||||||
|
|
||||||
// string
|
// string
|
||||||
resultValueType[0] = ValueType.STRING;
|
resultValueType.set( ValueType.STRING );
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -637,6 +691,7 @@ class UIDefaultsLoader
|
|||||||
if( value.indexOf( ',' ) >= 0 ) {
|
if( value.indexOf( ',' ) >= 0 ) {
|
||||||
// Syntax: top,left,bottom,right[,lineColor[,lineThickness[,arc]]]
|
// Syntax: top,left,bottom,right[,lineColor[,lineThickness[,arc]]]
|
||||||
List<String> parts = splitFunctionParams( value, ',' );
|
List<String> parts = splitFunctionParams( value, ',' );
|
||||||
|
try {
|
||||||
Insets insets = parseInsets( value );
|
Insets insets = parseInsets( value );
|
||||||
ColorUIResource lineColor = (parts.size() >= 5 && !parts.get( 4 ).isEmpty())
|
ColorUIResource lineColor = (parts.size() >= 5 && !parts.get( 4 ).isEmpty())
|
||||||
? (ColorUIResource) parseColorOrFunction( resolver.apply( parts.get( 4 ) ), resolver )
|
? (ColorUIResource) parseColorOrFunction( resolver.apply( parts.get( 4 ) ), resolver )
|
||||||
@@ -653,6 +708,9 @@ class UIDefaultsLoader
|
|||||||
? new FlatLineBorder( insets, lineColor, lineThickness, arc )
|
? new FlatLineBorder( insets, lineColor, lineThickness, arc )
|
||||||
: new FlatEmptyBorder( insets );
|
: new FlatEmptyBorder( insets );
|
||||||
};
|
};
|
||||||
|
} catch( RuntimeException ex ) {
|
||||||
|
throw new IllegalArgumentException( "invalid border '" + value + "' (" + ex.getMessage() + ")" );
|
||||||
|
}
|
||||||
} else
|
} else
|
||||||
return parseInstance( value, resolver, addonClassLoaders );
|
return parseInstance( value, resolver, addonClassLoaders );
|
||||||
}
|
}
|
||||||
@@ -723,7 +781,7 @@ class UIDefaultsLoader
|
|||||||
Integer.parseInt( numbers.get( 1 ) ),
|
Integer.parseInt( numbers.get( 1 ) ),
|
||||||
Integer.parseInt( numbers.get( 2 ) ),
|
Integer.parseInt( numbers.get( 2 ) ),
|
||||||
Integer.parseInt( numbers.get( 3 ) ) );
|
Integer.parseInt( numbers.get( 3 ) ) );
|
||||||
} catch( NumberFormatException ex ) {
|
} catch( NumberFormatException | IndexOutOfBoundsException ex ) {
|
||||||
throw new IllegalArgumentException( "invalid insets '" + value + "'" );
|
throw new IllegalArgumentException( "invalid insets '" + value + "'" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -736,7 +794,7 @@ class UIDefaultsLoader
|
|||||||
return new DimensionUIResource(
|
return new DimensionUIResource(
|
||||||
Integer.parseInt( numbers.get( 0 ) ),
|
Integer.parseInt( numbers.get( 0 ) ),
|
||||||
Integer.parseInt( numbers.get( 1 ) ) );
|
Integer.parseInt( numbers.get( 1 ) ) );
|
||||||
} catch( NumberFormatException ex ) {
|
} catch( NumberFormatException | IndexOutOfBoundsException ex ) {
|
||||||
throw new IllegalArgumentException( "invalid size '" + value + "'" );
|
throw new IllegalArgumentException( "invalid size '" + value + "'" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -830,6 +888,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 +936,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 +1059,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 +1069,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 +1088,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 +1118,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 +1129,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 +1137,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 +1162,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 +1173,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 +1208,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 +1331,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]
|
||||||
*/
|
*/
|
||||||
@@ -1314,17 +1425,17 @@ class UIDefaultsLoader
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch( IOException ex ) {
|
} catch( RuntimeException | IOException ex ) {
|
||||||
throw new IllegalArgumentException( ex );
|
throw new IllegalArgumentException( "invalid font '" + value + "' (" + ex.getMessage() + ")" );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( style != -1 && styleChange != 0 )
|
if( style != -1 && styleChange != 0 )
|
||||||
throw new IllegalArgumentException( "can not mix absolute style (e.g. 'bold') with derived style (e.g. '+italic') in '" + value + "'" );
|
throw new IllegalArgumentException( "invalid font '" + value + "': can not mix absolute style (e.g. 'bold') with derived style (e.g. '+italic')" );
|
||||||
if( styleChange != 0 ) {
|
if( styleChange != 0 ) {
|
||||||
if( (styleChange & Font.BOLD) != 0 && (styleChange & (Font.BOLD << 16)) != 0 )
|
if( (styleChange & Font.BOLD) != 0 && (styleChange & (Font.BOLD << 16)) != 0 )
|
||||||
throw new IllegalArgumentException( "can not use '+bold' and '-bold' in '" + value + "'" );
|
throw new IllegalArgumentException( "invalid font '" + value + "': can not use '+bold' and '-bold'" );
|
||||||
if( (styleChange & Font.ITALIC) != 0 && (styleChange & (Font.ITALIC << 16)) != 0 )
|
if( (styleChange & Font.ITALIC) != 0 && (styleChange & (Font.ITALIC << 16)) != 0 )
|
||||||
throw new IllegalArgumentException( "can not use '+italic' and '-italic' in '" + value + "'" );
|
throw new IllegalArgumentException( "invalid font '" + value + "': can not use '+italic' and '-italic'" );
|
||||||
}
|
}
|
||||||
|
|
||||||
font = new FlatLaf.ActiveFont( baseFontKey, families, style, styleChange, absoluteSize, relativeSize, scaleSize );
|
font = new FlatLaf.ActiveFont( baseFontKey, families, style, styleChange, absoluteSize, relativeSize, scaleSize );
|
||||||
@@ -1464,7 +1575,7 @@ class UIDefaultsLoader
|
|||||||
return (LazyValue) t -> {
|
return (LazyValue) t -> {
|
||||||
return new GrayFilter( brightness, contrast, alpha );
|
return new GrayFilter( brightness, contrast, alpha );
|
||||||
};
|
};
|
||||||
} catch( NumberFormatException ex ) {
|
} catch( NumberFormatException | IndexOutOfBoundsException ex ) {
|
||||||
throw new IllegalArgumentException( "invalid gray filter '" + value + "'" );
|
throw new IllegalArgumentException( "invalid gray filter '" + value + "'" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package com.formdev.flatlaf.icons;
|
package com.formdev.flatlaf.icons;
|
||||||
|
|
||||||
import static com.formdev.flatlaf.util.UIScale.*;
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
@@ -29,7 +28,7 @@ import com.formdev.flatlaf.util.UIScale;
|
|||||||
/**
|
/**
|
||||||
* Base class for icons that scales width and height, creates and initializes
|
* Base class for icons that scales width and height, creates and initializes
|
||||||
* a scaled graphics context for icon painting.
|
* a scaled graphics context for icon painting.
|
||||||
*
|
* <p>
|
||||||
* Subclasses do not need to scale icon painting.
|
* Subclasses do not need to scale icon painting.
|
||||||
*
|
*
|
||||||
* @author Karl Tauber
|
* @author Karl Tauber
|
||||||
@@ -37,10 +36,15 @@ import com.formdev.flatlaf.util.UIScale;
|
|||||||
public abstract class FlatAbstractIcon
|
public abstract class FlatAbstractIcon
|
||||||
implements Icon, UIResource
|
implements Icon, UIResource
|
||||||
{
|
{
|
||||||
|
/** Unscaled icon width. */
|
||||||
protected final int width;
|
protected final int width;
|
||||||
|
/** Unscaled icon height. */
|
||||||
protected final int height;
|
protected final int height;
|
||||||
protected Color color;
|
protected Color color;
|
||||||
|
|
||||||
|
/** Additional icon scale factor. */
|
||||||
|
private float scale = 1;
|
||||||
|
|
||||||
public FlatAbstractIcon( int width, int height, Color color ) {
|
public FlatAbstractIcon( int width, int height, Color color ) {
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
@@ -61,6 +65,9 @@ public abstract class FlatAbstractIcon
|
|||||||
|
|
||||||
g2.translate( x, y );
|
g2.translate( x, y );
|
||||||
UIScale.scaleGraphics( g2 );
|
UIScale.scaleGraphics( g2 );
|
||||||
|
float scale = getScale();
|
||||||
|
if( scale != 1 )
|
||||||
|
g2.scale( scale, scale );
|
||||||
|
|
||||||
if( color != null )
|
if( color != null )
|
||||||
g2.setColor( color );
|
g2.setColor( color );
|
||||||
@@ -71,19 +78,71 @@ public abstract class FlatAbstractIcon
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @since 3.5.2 */
|
/**
|
||||||
|
* Paints icon background. Default implementation does nothing.
|
||||||
|
* Can be overridden to paint specific icon background.
|
||||||
|
* <p>
|
||||||
|
* The bounds of the area to be filled are:
|
||||||
|
* x, y, {@link #getIconWidth()}, {@link #getIconHeight()}.
|
||||||
|
* <p>
|
||||||
|
* In contrast to {@link #paintIcon(Component, Graphics2D)},
|
||||||
|
* the graphics context {@code g} is not translated and not scaled.
|
||||||
|
*
|
||||||
|
* @since 3.5.2
|
||||||
|
*/
|
||||||
protected void paintBackground( Component c, Graphics2D g, int x, int y ) {
|
protected void paintBackground( Component c, Graphics2D g, int x, int y ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Paints icon.
|
||||||
|
* <p>
|
||||||
|
* The graphics context is translated and scaled.
|
||||||
|
* This means that icon x,y coordinates are {@code 0,0}
|
||||||
|
* and it is not necessary to scale coordinates within this method.
|
||||||
|
* <p>
|
||||||
|
* The bounds to be used for icon painting are:
|
||||||
|
* 0, 0, {@link #width}, {@link #height}.
|
||||||
|
*/
|
||||||
protected abstract void paintIcon( Component c, Graphics2D g );
|
protected abstract void paintIcon( Component c, Graphics2D g );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the scaled icon width.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int getIconWidth() {
|
public int getIconWidth() {
|
||||||
return scale( width );
|
return scale( UIScale.scale( width ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the scaled icon height.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int getIconHeight() {
|
public int getIconHeight() {
|
||||||
return scale( height );
|
return scale( UIScale.scale( height ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @since 3.7 */
|
||||||
|
public float getScale() {
|
||||||
|
return scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @since 3.7 */
|
||||||
|
public void setScale( float scale ) {
|
||||||
|
this.scale = scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multiplies the given value by the icon scale factor {@link #getScale()} and rounds the result.
|
||||||
|
* <p>
|
||||||
|
* If you want scale a {@code float} or {@code double} value,
|
||||||
|
* simply use: {@code myFloatValue * }{@link #getScale()}.
|
||||||
|
* <p>
|
||||||
|
* Do not use this method when painting icon in {@link #paintIcon(Component, Graphics2D)}.
|
||||||
|
*
|
||||||
|
* @since 3.7
|
||||||
|
*/
|
||||||
|
protected int scale( int size ) {
|
||||||
|
float scale = getScale();
|
||||||
|
return (scale == 1) ? size : Math.round( size * scale );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
package com.formdev.flatlaf.icons;
|
package com.formdev.flatlaf.icons;
|
||||||
|
|
||||||
import java.awt.BasicStroke;
|
import java.awt.BasicStroke;
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.RenderingHints;
|
import java.awt.RenderingHints;
|
||||||
@@ -26,7 +25,8 @@ import java.awt.geom.Path2D;
|
|||||||
import java.awt.geom.Rectangle2D;
|
import java.awt.geom.Rectangle2D;
|
||||||
import java.awt.geom.RoundRectangle2D;
|
import java.awt.geom.RoundRectangle2D;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableField;
|
||||||
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableObject;
|
||||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -36,8 +36,11 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
|||||||
*
|
*
|
||||||
* @author Karl Tauber
|
* @author Karl Tauber
|
||||||
*/
|
*/
|
||||||
|
@StyleableField( cls=FlatAbstractIcon.class, key="capsLockIconScale", fieldName="scale" )
|
||||||
|
@StyleableField( cls=FlatAbstractIcon.class, key="capsLockIconColor", fieldName="color" )
|
||||||
public class FlatCapsLockIcon
|
public class FlatCapsLockIcon
|
||||||
extends FlatAbstractIcon
|
extends FlatAbstractIcon
|
||||||
|
implements StyleableObject
|
||||||
{
|
{
|
||||||
private Path2D path;
|
private Path2D path;
|
||||||
|
|
||||||
@@ -45,23 +48,6 @@ public class FlatCapsLockIcon
|
|||||||
super( 16, 16, UIManager.getColor( "PasswordField.capsLockIconColor" ) );
|
super( 16, 16, UIManager.getColor( "PasswordField.capsLockIconColor" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @since 2 */
|
|
||||||
public Object applyStyleProperty( String key, Object value ) {
|
|
||||||
Object oldValue;
|
|
||||||
switch( key ) {
|
|
||||||
case "capsLockIconColor": oldValue = color; color = (Color) value; return oldValue;
|
|
||||||
default: throw new UnknownStyleException( key );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @since 2.5 */
|
|
||||||
public Object getStyleableValue( String key ) {
|
|
||||||
switch( key ) {
|
|
||||||
case "capsLockIconColor": return color;
|
|
||||||
default: return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void paintIcon( Component c, Graphics2D g ) {
|
protected void paintIcon( Component c, Graphics2D g ) {
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -17,19 +17,20 @@
|
|||||||
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;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.geom.Path2D;
|
import java.awt.geom.Path2D;
|
||||||
import java.awt.geom.RoundRectangle2D;
|
import java.awt.geom.RoundRectangle2D;
|
||||||
import java.util.Map;
|
|
||||||
import javax.swing.AbstractButton;
|
import javax.swing.AbstractButton;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import com.formdev.flatlaf.ui.FlatButtonUI;
|
import com.formdev.flatlaf.ui.FlatButtonUI;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport;
|
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||||
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableField;
|
||||||
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableObject;
|
||||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -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,35 +59,52 @@ 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
|
||||||
*/
|
*/
|
||||||
|
@StyleableField( cls=FlatAbstractIcon.class, key="scale" )
|
||||||
public class FlatCheckBoxIcon
|
public class FlatCheckBoxIcon
|
||||||
extends FlatAbstractIcon
|
extends FlatAbstractIcon
|
||||||
|
implements StyleableObject
|
||||||
{
|
{
|
||||||
protected final String style = UIManager.getString( getPropertyPrefix() + "icon.style" );
|
protected final String style = UIManager.getString( getPropertyPrefix() + "icon.style" );
|
||||||
@Styleable protected float focusWidth = getUIFloat( "CheckBox.icon.focusWidth", UIManager.getInt( "Component.focusWidth" ), style );
|
@Styleable protected float focusWidth = getUIFloat( "CheckBox.icon.focusWidth", UIManager.getInt( "Component.focusWidth" ), style );
|
||||||
@@ -92,6 +112,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 +122,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 +132,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 +142,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 +152,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 +162,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.";
|
||||||
@@ -162,31 +199,22 @@ public class FlatCheckBoxIcon
|
|||||||
super( ICON_SIZE, ICON_SIZE, null );
|
super( ICON_SIZE, ICON_SIZE, null );
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @since 2 */
|
|
||||||
public Object applyStyleProperty( String key, Object value ) {
|
|
||||||
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @since 2 */
|
|
||||||
public Map<String, Class<?>> getStyleableInfos() {
|
|
||||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @since 2.5 */
|
|
||||||
public Object getStyleableValue( String key ) {
|
|
||||||
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void paintIcon( Component c, Graphics2D g ) {
|
protected void paintIcon( Component c, Graphics2D g ) {
|
||||||
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 +223,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 +239,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
|
||||||
@@ -265,37 +293,40 @@ public class FlatCheckBoxIcon
|
|||||||
|
|
||||||
/** @since 2 */
|
/** @since 2 */
|
||||||
public float getFocusWidth() {
|
public float getFocusWidth() {
|
||||||
return focusWidth;
|
return focusWidth * getScale();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Color getFocusColor( Component c ) {
|
protected Color getFocusColor( Component c ) {
|
||||||
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 ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,12 +21,12 @@ import java.awt.Color;
|
|||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.geom.Path2D;
|
import java.awt.geom.Path2D;
|
||||||
import java.util.Map;
|
|
||||||
import javax.swing.AbstractButton;
|
import javax.swing.AbstractButton;
|
||||||
import javax.swing.JMenuItem;
|
import javax.swing.JMenuItem;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport;
|
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||||
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableField;
|
||||||
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Icon for {@link javax.swing.JCheckBoxMenuItem}.
|
* Icon for {@link javax.swing.JCheckBoxMenuItem}.
|
||||||
@@ -38,8 +38,10 @@ import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
|||||||
*
|
*
|
||||||
* @author Karl Tauber
|
* @author Karl Tauber
|
||||||
*/
|
*/
|
||||||
|
@StyleableField( cls=FlatAbstractIcon.class, key="scale" )
|
||||||
public class FlatCheckBoxMenuItemIcon
|
public class FlatCheckBoxMenuItemIcon
|
||||||
extends FlatAbstractIcon
|
extends FlatAbstractIcon
|
||||||
|
implements StyleableObject
|
||||||
{
|
{
|
||||||
@Styleable protected Color checkmarkColor = UIManager.getColor( "CheckBoxMenuItem.icon.checkmarkColor" );
|
@Styleable protected Color checkmarkColor = UIManager.getColor( "CheckBoxMenuItem.icon.checkmarkColor" );
|
||||||
@Styleable protected Color disabledCheckmarkColor = UIManager.getColor( "CheckBoxMenuItem.icon.disabledCheckmarkColor" );
|
@Styleable protected Color disabledCheckmarkColor = UIManager.getColor( "CheckBoxMenuItem.icon.disabledCheckmarkColor" );
|
||||||
@@ -49,21 +51,6 @@ public class FlatCheckBoxMenuItemIcon
|
|||||||
super( 15, 15, null );
|
super( 15, 15, null );
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @since 2 */
|
|
||||||
public Object applyStyleProperty( String key, Object value ) {
|
|
||||||
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @since 2 */
|
|
||||||
public Map<String, Class<?>> getStyleableInfos() {
|
|
||||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @since 2.5 */
|
|
||||||
public Object getStyleableValue( String key ) {
|
|
||||||
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void paintIcon( Component c, Graphics2D g2 ) {
|
protected void paintIcon( Component c, Graphics2D g2 ) {
|
||||||
boolean selected = (c instanceof AbstractButton) && ((AbstractButton)c).isSelected();
|
boolean selected = (c instanceof AbstractButton) && ((AbstractButton)c).isSelected();
|
||||||
|
|||||||
@@ -21,12 +21,12 @@ import java.awt.Component;
|
|||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.geom.Ellipse2D;
|
import java.awt.geom.Ellipse2D;
|
||||||
import java.awt.geom.Path2D;
|
import java.awt.geom.Path2D;
|
||||||
import java.util.Map;
|
|
||||||
import javax.swing.AbstractButton;
|
import javax.swing.AbstractButton;
|
||||||
import javax.swing.ButtonModel;
|
import javax.swing.ButtonModel;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport;
|
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||||
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableField;
|
||||||
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableObject;
|
||||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -39,8 +39,10 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
|||||||
* @author Karl Tauber
|
* @author Karl Tauber
|
||||||
* @since 1.5
|
* @since 1.5
|
||||||
*/
|
*/
|
||||||
|
@StyleableField( cls=FlatAbstractIcon.class, key="clearIconScale", fieldName="scale" )
|
||||||
public class FlatClearIcon
|
public class FlatClearIcon
|
||||||
extends FlatAbstractIcon
|
extends FlatAbstractIcon
|
||||||
|
implements StyleableObject
|
||||||
{
|
{
|
||||||
@Styleable protected Color clearIconColor = UIManager.getColor( "SearchField.clearIconColor" );
|
@Styleable protected Color clearIconColor = UIManager.getColor( "SearchField.clearIconColor" );
|
||||||
@Styleable protected Color clearIconHoverColor = UIManager.getColor( "SearchField.clearIconHoverColor" );
|
@Styleable protected Color clearIconHoverColor = UIManager.getColor( "SearchField.clearIconHoverColor" );
|
||||||
@@ -58,21 +60,6 @@ public class FlatClearIcon
|
|||||||
this.ignoreButtonState = ignoreButtonState;
|
this.ignoreButtonState = ignoreButtonState;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @since 2 */
|
|
||||||
public Object applyStyleProperty( String key, Object value ) {
|
|
||||||
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @since 2 */
|
|
||||||
public Map<String, Class<?>> getStyleableInfos() {
|
|
||||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @since 2.5 */
|
|
||||||
public Object getStyleableValue( String key ) {
|
|
||||||
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void paintIcon( Component c, Graphics2D g ) {
|
protected void paintIcon( Component c, Graphics2D g ) {
|
||||||
if( !ignoreButtonState && c instanceof AbstractButton ) {
|
if( !ignoreButtonState && c instanceof AbstractButton ) {
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package com.formdev.flatlaf.icons;
|
package com.formdev.flatlaf.icons;
|
||||||
|
|
||||||
import static com.formdev.flatlaf.util.UIScale.*;
|
|
||||||
import java.awt.BasicStroke;
|
import java.awt.BasicStroke;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
@@ -24,11 +23,12 @@ import java.awt.Graphics2D;
|
|||||||
import java.awt.RenderingHints;
|
import java.awt.RenderingHints;
|
||||||
import java.awt.geom.Ellipse2D;
|
import java.awt.geom.Ellipse2D;
|
||||||
import java.awt.geom.Path2D;
|
import java.awt.geom.Path2D;
|
||||||
import java.util.Map;
|
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import com.formdev.flatlaf.ui.FlatButtonUI;
|
import com.formdev.flatlaf.ui.FlatButtonUI;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport;
|
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||||
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableField;
|
||||||
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableObject;
|
||||||
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -52,8 +52,10 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
|||||||
*
|
*
|
||||||
* @author Karl Tauber
|
* @author Karl Tauber
|
||||||
*/
|
*/
|
||||||
|
@StyleableField( cls=FlatAbstractIcon.class, key="scale" )
|
||||||
public class FlatHelpButtonIcon
|
public class FlatHelpButtonIcon
|
||||||
extends FlatAbstractIcon
|
extends FlatAbstractIcon
|
||||||
|
implements StyleableObject
|
||||||
{
|
{
|
||||||
@Styleable protected int focusWidth = UIManager.getInt( "Component.focusWidth" );
|
@Styleable protected int focusWidth = UIManager.getInt( "Component.focusWidth" );
|
||||||
@Styleable protected Color focusColor = UIManager.getColor( "Component.focusColor" );
|
@Styleable protected Color focusColor = UIManager.getColor( "Component.focusColor" );
|
||||||
@@ -76,21 +78,6 @@ public class FlatHelpButtonIcon
|
|||||||
super( 0, 0, null );
|
super( 0, 0, null );
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @since 2 */
|
|
||||||
public Object applyStyleProperty( String key, Object value ) {
|
|
||||||
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @since 2 */
|
|
||||||
public Map<String, Class<?>> getStyleableInfos() {
|
|
||||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @since 2.5 */
|
|
||||||
public Object getStyleableValue( String key ) {
|
|
||||||
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void paintIcon( Component c, Graphics2D g2 ) {
|
protected void paintIcon( Component c, Graphics2D g2 ) {
|
||||||
/*
|
/*
|
||||||
@@ -167,12 +154,12 @@ public class FlatHelpButtonIcon
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getIconWidth() {
|
public int getIconWidth() {
|
||||||
return scale( iconSize() );
|
return scale( UIScale.scale( iconSize() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getIconHeight() {
|
public int getIconHeight() {
|
||||||
return scale( iconSize() );
|
return scale( UIScale.scale( iconSize() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
private int iconSize() {
|
private int iconSize() {
|
||||||
|
|||||||
@@ -21,12 +21,12 @@ import java.awt.Color;
|
|||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.geom.Path2D;
|
import java.awt.geom.Path2D;
|
||||||
import java.util.Map;
|
|
||||||
import javax.swing.JMenu;
|
import javax.swing.JMenu;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport;
|
|
||||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||||
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableField;
|
||||||
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* "arrow" icon for {@link javax.swing.JMenu}.
|
* "arrow" icon for {@link javax.swing.JMenu}.
|
||||||
@@ -39,8 +39,10 @@ import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
|||||||
*
|
*
|
||||||
* @author Karl Tauber
|
* @author Karl Tauber
|
||||||
*/
|
*/
|
||||||
|
@StyleableField( cls=FlatAbstractIcon.class, key="scale" )
|
||||||
public class FlatMenuArrowIcon
|
public class FlatMenuArrowIcon
|
||||||
extends FlatAbstractIcon
|
extends FlatAbstractIcon
|
||||||
|
implements StyleableObject
|
||||||
{
|
{
|
||||||
@Styleable protected String arrowType = UIManager.getString( "Component.arrowType" );
|
@Styleable protected String arrowType = UIManager.getString( "Component.arrowType" );
|
||||||
@Styleable protected Color arrowColor = UIManager.getColor( "Menu.icon.arrowColor" );
|
@Styleable protected Color arrowColor = UIManager.getColor( "Menu.icon.arrowColor" );
|
||||||
@@ -51,21 +53,6 @@ public class FlatMenuArrowIcon
|
|||||||
super( 6, 10, null );
|
super( 6, 10, null );
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @since 2 */
|
|
||||||
public Object applyStyleProperty( String key, Object value ) {
|
|
||||||
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @since 2 */
|
|
||||||
public Map<String, Class<?>> getStyleableInfos() {
|
|
||||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @since 2.5 */
|
|
||||||
public Object getStyleableValue( String key ) {
|
|
||||||
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void paintIcon( Component c, Graphics2D g ) {
|
protected void paintIcon( Component c, Graphics2D g ) {
|
||||||
if( c != null && !c.getComponentOrientation().isLeftToRight() )
|
if( c != null && !c.getComponentOrientation().isLeftToRight() )
|
||||||
|
|||||||
@@ -21,11 +21,11 @@ import java.awt.Component;
|
|||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.geom.Area;
|
import java.awt.geom.Area;
|
||||||
import java.awt.geom.Ellipse2D;
|
import java.awt.geom.Ellipse2D;
|
||||||
import java.util.Map;
|
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import com.formdev.flatlaf.ui.FlatButtonUI;
|
import com.formdev.flatlaf.ui.FlatButtonUI;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport;
|
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||||
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableField;
|
||||||
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableObject;
|
||||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -38,8 +38,10 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
|||||||
* @author Karl Tauber
|
* @author Karl Tauber
|
||||||
* @since 1.5
|
* @since 1.5
|
||||||
*/
|
*/
|
||||||
|
@StyleableField( cls=FlatAbstractIcon.class, key="searchIconScale", fieldName="scale" )
|
||||||
public class FlatSearchIcon
|
public class FlatSearchIcon
|
||||||
extends FlatAbstractIcon
|
extends FlatAbstractIcon
|
||||||
|
implements StyleableObject
|
||||||
{
|
{
|
||||||
@Styleable protected Color searchIconColor = UIManager.getColor( "SearchField.searchIconColor" );
|
@Styleable protected Color searchIconColor = UIManager.getColor( "SearchField.searchIconColor" );
|
||||||
@Styleable protected Color searchIconHoverColor = UIManager.getColor( "SearchField.searchIconHoverColor" );
|
@Styleable protected Color searchIconHoverColor = UIManager.getColor( "SearchField.searchIconHoverColor" );
|
||||||
@@ -58,21 +60,6 @@ public class FlatSearchIcon
|
|||||||
this.ignoreButtonState = ignoreButtonState;
|
this.ignoreButtonState = ignoreButtonState;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @since 2 */
|
|
||||||
public Object applyStyleProperty( String key, Object value ) {
|
|
||||||
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @since 2 */
|
|
||||||
public Map<String, Class<?>> getStyleableInfos() {
|
|
||||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @since 2.5 */
|
|
||||||
public Object getStyleableValue( String key ) {
|
|
||||||
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void paintIcon( Component c, Graphics2D g ) {
|
protected void paintIcon( Component c, Graphics2D g ) {
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -22,11 +22,11 @@ import java.awt.Component;
|
|||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.geom.Path2D;
|
import java.awt.geom.Path2D;
|
||||||
import java.util.Map;
|
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import com.formdev.flatlaf.ui.FlatButtonUI;
|
import com.formdev.flatlaf.ui.FlatButtonUI;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport;
|
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||||
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableField;
|
||||||
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableObject;
|
||||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -46,8 +46,10 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
|||||||
*
|
*
|
||||||
* @author Karl Tauber
|
* @author Karl Tauber
|
||||||
*/
|
*/
|
||||||
|
@StyleableField( cls=FlatAbstractIcon.class, key="closeScale", fieldName="scale" )
|
||||||
public class FlatTabbedPaneCloseIcon
|
public class FlatTabbedPaneCloseIcon
|
||||||
extends FlatAbstractIcon
|
extends FlatAbstractIcon
|
||||||
|
implements StyleableObject
|
||||||
{
|
{
|
||||||
@Styleable protected Dimension closeSize = UIManager.getDimension( "TabbedPane.closeSize" );
|
@Styleable protected Dimension closeSize = UIManager.getDimension( "TabbedPane.closeSize" );
|
||||||
@Styleable protected int closeArc = UIManager.getInt( "TabbedPane.closeArc" );
|
@Styleable protected int closeArc = UIManager.getInt( "TabbedPane.closeArc" );
|
||||||
@@ -65,21 +67,6 @@ public class FlatTabbedPaneCloseIcon
|
|||||||
super( 16, 16, null );
|
super( 16, 16, null );
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @since 2 */
|
|
||||||
public Object applyStyleProperty( String key, Object value ) {
|
|
||||||
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @since 2 */
|
|
||||||
public Map<String, Class<?>> getStyleableInfos() {
|
|
||||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @since 2.5 */
|
|
||||||
public Object getStyleableValue( String key ) {
|
|
||||||
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void paintIcon( Component c, Graphics2D g ) {
|
protected void paintIcon( Component c, Graphics2D g ) {
|
||||||
// paint background
|
// paint background
|
||||||
|
|||||||
@@ -18,44 +18,95 @@ package com.formdev.flatlaf.icons;
|
|||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
|
import java.awt.Container;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.RenderingHints;
|
import java.awt.Insets;
|
||||||
|
import java.awt.Window;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
import com.formdev.flatlaf.ui.FlatButtonUI;
|
import com.formdev.flatlaf.ui.FlatButtonUI;
|
||||||
|
import com.formdev.flatlaf.ui.FlatTitlePane;
|
||||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||||
|
import com.formdev.flatlaf.util.DerivedColor;
|
||||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||||
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for window icons.
|
* Base class for window icons.
|
||||||
*
|
*
|
||||||
* @uiDefault TitlePane.buttonSize Dimension
|
* @uiDefault TitlePane.buttonSize Dimension
|
||||||
|
* @uiDefault TitlePane.buttonInsets Insets optional
|
||||||
|
* @uiDefault TitlePane.buttonArc int optional
|
||||||
* @uiDefault TitlePane.buttonSymbolHeight int
|
* @uiDefault TitlePane.buttonSymbolHeight int
|
||||||
* @uiDefault TitlePane.buttonHoverBackground Color
|
* @uiDefault TitlePane.buttonBackground Color optional
|
||||||
* @uiDefault TitlePane.buttonPressedBackground Color
|
* @uiDefault TitlePane.buttonForeground Color optional
|
||||||
|
* @uiDefault TitlePane.buttonInactiveBackground Color optional
|
||||||
|
* @uiDefault TitlePane.buttonInactiveForeground Color optional
|
||||||
|
* @uiDefault TitlePane.buttonHoverBackground Color optional
|
||||||
|
* @uiDefault TitlePane.buttonHoverForeground Color optional
|
||||||
|
* @uiDefault TitlePane.buttonPressedBackground Color optional
|
||||||
|
* @uiDefault TitlePane.buttonPressedForeground Color optional
|
||||||
*
|
*
|
||||||
* @author Karl Tauber
|
* @author Karl Tauber
|
||||||
*/
|
*/
|
||||||
public abstract class FlatWindowAbstractIcon
|
public abstract class FlatWindowAbstractIcon
|
||||||
extends FlatAbstractIcon
|
extends FlatAbstractIcon
|
||||||
{
|
{
|
||||||
private final int symbolHeight;
|
/** @since 3.6 */ protected final Insets insets;
|
||||||
private final Color hoverBackground;
|
/** @since 3.6 */ protected final int arc;
|
||||||
private final Color pressedBackground;
|
/** @since 3.6 */ protected final int symbolHeight;
|
||||||
|
|
||||||
|
/** @since 3.6 */ protected final Color background;
|
||||||
|
/** @since 3.6 */ protected final Color foreground;
|
||||||
|
/** @since 3.6 */ protected final Color inactiveBackground;
|
||||||
|
/** @since 3.6 */ protected final Color inactiveForeground;
|
||||||
|
protected final Color hoverBackground;
|
||||||
|
/** @since 3.6 */ protected final Color hoverForeground;
|
||||||
|
protected final Color pressedBackground;
|
||||||
|
/** @since 3.6 */ protected final Color pressedForeground;
|
||||||
|
|
||||||
/** @since 3.2 */
|
/** @since 3.2 */
|
||||||
protected FlatWindowAbstractIcon( String windowStyle ) {
|
protected FlatWindowAbstractIcon( String windowStyle ) {
|
||||||
this( FlatUIUtils.getSubUIDimension( "TitlePane.buttonSize", windowStyle ),
|
this( windowStyle, null, null, null, null, null, null, null, null );
|
||||||
FlatUIUtils.getSubUIInt( "TitlePane.buttonSymbolHeight", windowStyle, 10 ),
|
|
||||||
FlatUIUtils.getSubUIColor( "TitlePane.buttonHoverBackground", windowStyle ),
|
|
||||||
FlatUIUtils.getSubUIColor( "TitlePane.buttonPressedBackground", windowStyle ) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @since 3.2 */
|
/** @since 3.6 */
|
||||||
protected FlatWindowAbstractIcon( Dimension size, int symbolHeight, Color hoverBackground, Color pressedBackground ) {
|
protected FlatWindowAbstractIcon( String windowStyle,
|
||||||
|
Color background, Color foreground, Color inactiveBackground, Color inactiveForeground,
|
||||||
|
Color hoverBackground, Color hoverForeground, Color pressedBackground, Color pressedForeground )
|
||||||
|
{
|
||||||
|
this( FlatUIUtils.getSubUIDimension( "TitlePane.buttonSize", windowStyle ),
|
||||||
|
FlatUIUtils.getSubUIInsets( "TitlePane.buttonInsets", windowStyle ),
|
||||||
|
FlatUIUtils.getSubUIInt( "TitlePane.buttonArc", windowStyle, 0 ),
|
||||||
|
FlatUIUtils.getSubUIInt( "TitlePane.buttonSymbolHeight", windowStyle, 10 ),
|
||||||
|
(background != null) ? background : FlatUIUtils.getSubUIColor( "TitlePane.buttonBackground", windowStyle ),
|
||||||
|
(foreground != null) ? foreground : FlatUIUtils.getSubUIColor( "TitlePane.buttonForeground", windowStyle ),
|
||||||
|
(inactiveBackground != null) ? inactiveBackground : FlatUIUtils.getSubUIColor( "TitlePane.buttonInactiveBackground", windowStyle ),
|
||||||
|
(inactiveForeground != null) ? inactiveForeground : FlatUIUtils.getSubUIColor( "TitlePane.buttonInactiveForeground", windowStyle ),
|
||||||
|
(hoverBackground != null) ? hoverBackground : FlatUIUtils.getSubUIColor( "TitlePane.buttonHoverBackground", windowStyle ),
|
||||||
|
(hoverForeground != null) ? hoverForeground : FlatUIUtils.getSubUIColor( "TitlePane.buttonHoverForeground", windowStyle ),
|
||||||
|
(pressedBackground != null) ? pressedBackground : FlatUIUtils.getSubUIColor( "TitlePane.buttonPressedBackground", windowStyle ),
|
||||||
|
(pressedForeground != null) ? pressedForeground : FlatUIUtils.getSubUIColor( "TitlePane.buttonPressedForeground", windowStyle ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @since 3.6 */
|
||||||
|
protected FlatWindowAbstractIcon( Dimension size, Insets insets, int arc, int symbolHeight,
|
||||||
|
Color background, Color foreground, Color inactiveBackground, Color inactiveForeground,
|
||||||
|
Color hoverBackground, Color hoverForeground, Color pressedBackground, Color pressedForeground )
|
||||||
|
{
|
||||||
super( size.width, size.height, null );
|
super( size.width, size.height, null );
|
||||||
|
this.insets = (insets != null) ? insets : new Insets( 0, 0, 0, 0 );
|
||||||
|
this.arc = arc;
|
||||||
this.symbolHeight = symbolHeight;
|
this.symbolHeight = symbolHeight;
|
||||||
|
|
||||||
|
this.background = background;
|
||||||
|
this.foreground = foreground;
|
||||||
|
this.inactiveBackground = inactiveBackground;
|
||||||
|
this.inactiveForeground = inactiveForeground;
|
||||||
this.hoverBackground = hoverBackground;
|
this.hoverBackground = hoverBackground;
|
||||||
|
this.hoverForeground = hoverForeground;
|
||||||
this.pressedBackground = pressedBackground;
|
this.pressedBackground = pressedBackground;
|
||||||
|
this.pressedForeground = pressedForeground;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -69,26 +120,39 @@ public abstract class FlatWindowAbstractIcon
|
|||||||
/** @since 3.5.2 */
|
/** @since 3.5.2 */
|
||||||
@Override
|
@Override
|
||||||
protected void paintBackground( Component c, Graphics2D g, int x, int y ) {
|
protected void paintBackground( Component c, Graphics2D g, int x, int y ) {
|
||||||
Color background = FlatButtonUI.buttonStateColor( c, null, null, null, hoverBackground, pressedBackground );
|
Color bg = null;
|
||||||
|
if( background != null || inactiveBackground != null ) {
|
||||||
|
Window window = SwingUtilities.windowForComponent( c );
|
||||||
|
bg = (window == null || window.isActive()) ? background : inactiveBackground;
|
||||||
|
}
|
||||||
|
|
||||||
|
Color background = FlatButtonUI.buttonStateColor( c, bg, null, null, hoverBackground, pressedBackground );
|
||||||
if( background != null ) {
|
if( background != null ) {
|
||||||
// disable antialiasing for background rectangle painting to avoid blurry edges when scaled (e.g. at 125% or 175%)
|
Insets insets = UIScale.scale( this.insets );
|
||||||
Object oldHint = g.getRenderingHint( RenderingHints.KEY_ANTIALIASING );
|
float arc = UIScale.scale( (float) this.arc );
|
||||||
g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF );
|
|
||||||
|
|
||||||
// fill background of whole component
|
// derive color from title pane background
|
||||||
g.setColor( FlatUIUtils.deriveColor( background, c.getBackground() ) );
|
if( background instanceof DerivedColor ) {
|
||||||
g.fillRect( 0, 0, c.getWidth(), c.getHeight() );
|
Container titlePane = SwingUtilities.getAncestorOfClass( FlatTitlePane.class, c );
|
||||||
|
Component baseComp = (titlePane != null) ? titlePane : c;
|
||||||
|
background = FlatUIUtils.deriveColor( background, baseComp.getBackground() );
|
||||||
|
}
|
||||||
|
|
||||||
g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, oldHint );
|
g.setColor( background );
|
||||||
|
FlatUIUtils.paintComponentBackground( g, insets.left, insets.top,
|
||||||
|
c.getWidth() - insets.left - insets.right,
|
||||||
|
c.getHeight() - insets.top - insets.bottom,
|
||||||
|
0, arc );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Color getForeground( Component c ) {
|
protected Color getForeground( Component c ) {
|
||||||
return c.getForeground();
|
Color fg = null;
|
||||||
|
if( foreground != null || inactiveForeground != null ) {
|
||||||
|
Window window = SwingUtilities.windowForComponent( c );
|
||||||
|
fg = (window == null || window.isActive()) ? foreground : inactiveForeground;
|
||||||
}
|
}
|
||||||
|
return FlatButtonUI.buttonStateColor( c, (fg != null) ? fg : c.getForeground(),
|
||||||
/** @since 3.2 */
|
null, null, hoverForeground, pressedForeground );
|
||||||
protected int getSymbolHeight() {
|
|
||||||
return symbolHeight;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,53 +17,54 @@
|
|||||||
package com.formdev.flatlaf.icons;
|
package com.formdev.flatlaf.icons;
|
||||||
|
|
||||||
import java.awt.BasicStroke;
|
import java.awt.BasicStroke;
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Component;
|
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.geom.Path2D;
|
import java.awt.geom.Path2D;
|
||||||
import com.formdev.flatlaf.ui.FlatButtonUI;
|
|
||||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||||
import com.formdev.flatlaf.util.SystemInfo;
|
import com.formdev.flatlaf.util.SystemInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* "close" icon for windows (frames and dialogs).
|
* "close" icon for windows (frames and dialogs).
|
||||||
*
|
*
|
||||||
* @uiDefault TitlePane.closeHoverBackground Color
|
* @uiDefault TitlePane.closeBackground Color optional
|
||||||
* @uiDefault TitlePane.closePressedBackground Color
|
* @uiDefault TitlePane.closeForeground Color optional
|
||||||
* @uiDefault TitlePane.closeHoverForeground Color
|
* @uiDefault TitlePane.closeInactiveBackground Color optional
|
||||||
* @uiDefault TitlePane.closePressedForeground Color
|
* @uiDefault TitlePane.closeInactiveForeground Color optional
|
||||||
|
* @uiDefault TitlePane.closeHoverBackground Color optional
|
||||||
|
* @uiDefault TitlePane.closeHoverForeground Color optional
|
||||||
|
* @uiDefault TitlePane.closePressedBackground Color optional
|
||||||
|
* @uiDefault TitlePane.closePressedForeground Color optional
|
||||||
*
|
*
|
||||||
* @author Karl Tauber
|
* @author Karl Tauber
|
||||||
*/
|
*/
|
||||||
public class FlatWindowCloseIcon
|
public class FlatWindowCloseIcon
|
||||||
extends FlatWindowAbstractIcon
|
extends FlatWindowAbstractIcon
|
||||||
{
|
{
|
||||||
private final Color hoverForeground;
|
|
||||||
private final Color pressedForeground;
|
|
||||||
|
|
||||||
public FlatWindowCloseIcon() {
|
public FlatWindowCloseIcon() {
|
||||||
this( null );
|
this( null );
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @since 3.2 */
|
/** @since 3.2 */
|
||||||
public FlatWindowCloseIcon( String windowStyle ) {
|
public FlatWindowCloseIcon( String windowStyle ) {
|
||||||
super( FlatUIUtils.getSubUIDimension( "TitlePane.buttonSize", windowStyle ),
|
super( windowStyle,
|
||||||
FlatUIUtils.getSubUIInt( "TitlePane.buttonSymbolHeight", windowStyle, 10 ),
|
FlatUIUtils.getSubUIColor( "TitlePane.closeBackground", windowStyle ),
|
||||||
|
FlatUIUtils.getSubUIColor( "TitlePane.closeForeground", windowStyle ),
|
||||||
|
FlatUIUtils.getSubUIColor( "TitlePane.closeInactiveBackground", windowStyle ),
|
||||||
|
FlatUIUtils.getSubUIColor( "TitlePane.closeInactiveForeground", windowStyle ),
|
||||||
FlatUIUtils.getSubUIColor( "TitlePane.closeHoverBackground", windowStyle ),
|
FlatUIUtils.getSubUIColor( "TitlePane.closeHoverBackground", windowStyle ),
|
||||||
FlatUIUtils.getSubUIColor( "TitlePane.closePressedBackground", windowStyle ) );
|
FlatUIUtils.getSubUIColor( "TitlePane.closeHoverForeground", windowStyle ),
|
||||||
|
FlatUIUtils.getSubUIColor( "TitlePane.closePressedBackground", windowStyle ),
|
||||||
hoverForeground = FlatUIUtils.getSubUIColor( "TitlePane.closeHoverForeground", windowStyle );
|
FlatUIUtils.getSubUIColor( "TitlePane.closePressedForeground", windowStyle ) );
|
||||||
pressedForeground = FlatUIUtils.getSubUIColor( "TitlePane.closePressedForeground", windowStyle );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@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 iwh = (int) (getSymbolHeight() * scaleFactor);
|
int iwh = (int) (symbolHeight * 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);
|
||||||
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;
|
boolean isWindows10 = SystemInfo.isWindows_10_orLater && !SystemInfo.isWindows_11_orLater;
|
||||||
|
float thickness = Math.max( isWindows10 ? (int) scaleFactor : (float) 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 );
|
||||||
@@ -73,9 +74,4 @@ public class FlatWindowCloseIcon
|
|||||||
g.setStroke( new BasicStroke( thickness ) );
|
g.setStroke( new BasicStroke( thickness ) );
|
||||||
g.draw( path );
|
g.draw( path );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Color getForeground( Component c ) {
|
|
||||||
return FlatButtonUI.buttonStateColor( c, c.getForeground(), null, null, hoverForeground, pressedForeground );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ 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) (symbolHeight * 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);
|
||||||
|
|
||||||
|
|||||||
@@ -39,10 +39,11 @@ public class FlatWindowMaximizeIcon
|
|||||||
|
|
||||||
@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 iwh = (int) (getSymbolHeight() * scaleFactor);
|
int iwh = (int) (symbolHeight * 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;
|
boolean isWindows10 = SystemInfo.isWindows_10_orLater && !SystemInfo.isWindows_11_orLater;
|
||||||
|
float thickness = Math.max( isWindows10 ? (int) scaleFactor : (float) 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
|
||||||
|
|||||||
@@ -42,14 +42,15 @@ public class FlatWindowRestoreIcon
|
|||||||
|
|
||||||
@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 iwh = (int) (getSymbolHeight() * scaleFactor);
|
int iwh = (int) (symbolHeight * 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;
|
boolean isWindows10 = SystemInfo.isWindows_10_orLater && !SystemInfo.isWindows_11_orLater;
|
||||||
|
float thickness = Math.max( isWindows10 ? (int) scaleFactor : (float) 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));
|
||||||
|
|
||||||
int rwh = (int) ((getSymbolHeight() - 2) * scaleFactor);
|
int rwh = (int) ((symbolHeight - 2) * scaleFactor);
|
||||||
int ro2 = iwh - rwh;
|
int ro2 = iwh - rwh;
|
||||||
|
|
||||||
// upper-right rectangle
|
// upper-right rectangle
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import java.awt.Graphics;
|
|||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.Insets;
|
import java.awt.Insets;
|
||||||
import java.awt.Paint;
|
import java.awt.Paint;
|
||||||
import java.util.Map;
|
|
||||||
import javax.swing.JComboBox;
|
import javax.swing.JComboBox;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JScrollPane;
|
import javax.swing.JScrollPane;
|
||||||
@@ -32,7 +31,7 @@ import javax.swing.UIManager;
|
|||||||
import javax.swing.plaf.basic.BasicBorders;
|
import javax.swing.plaf.basic.BasicBorders;
|
||||||
import com.formdev.flatlaf.FlatClientProperties;
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableBorder;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableObject;
|
||||||
import com.formdev.flatlaf.util.DerivedColor;
|
import com.formdev.flatlaf.util.DerivedColor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -59,13 +58,15 @@ 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
|
||||||
*/
|
*/
|
||||||
public class FlatBorder
|
public class FlatBorder
|
||||||
extends BasicBorders.MarginBorder
|
extends BasicBorders.MarginBorder
|
||||||
implements StyleableBorder
|
implements StyleableObject
|
||||||
{
|
{
|
||||||
@Styleable protected int focusWidth = UIManager.getInt( "Component.focusWidth" );
|
@Styleable protected int focusWidth = UIManager.getInt( "Component.focusWidth" );
|
||||||
@Styleable protected float innerFocusWidth = FlatUIUtils.getUIFloat( "Component.innerFocusWidth", 0 );
|
@Styleable protected float innerFocusWidth = FlatUIUtils.getUIFloat( "Component.innerFocusWidth", 0 );
|
||||||
@@ -81,6 +82,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)
|
||||||
@@ -88,24 +91,6 @@ public class FlatBorder
|
|||||||
/** @since 2 */ @Styleable protected Color outlineColor;
|
/** @since 2 */ @Styleable protected Color outlineColor;
|
||||||
/** @since 2 */ @Styleable protected Color outlineFocusedColor;
|
/** @since 2 */ @Styleable protected Color outlineFocusedColor;
|
||||||
|
|
||||||
/** @since 2 */
|
|
||||||
@Override
|
|
||||||
public Object applyStyleProperty( String key, Object value ) {
|
|
||||||
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @since 2 */
|
|
||||||
@Override
|
|
||||||
public Map<String, Class<?>> getStyleableInfos() {
|
|
||||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @since 2.5 */
|
|
||||||
@Override
|
|
||||||
public Object getStyleableValue( String key ) {
|
|
||||||
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||||
Graphics2D g2 = (Graphics2D) g.create();
|
Graphics2D g2 = (Graphics2D) g.create();
|
||||||
@@ -168,6 +153,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;
|
||||||
|
|||||||
@@ -58,8 +58,8 @@ import javax.swing.plaf.basic.BasicHTML;
|
|||||||
import javax.swing.text.View;
|
import javax.swing.text.View;
|
||||||
import com.formdev.flatlaf.FlatClientProperties;
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
import com.formdev.flatlaf.FlatLaf;
|
import com.formdev.flatlaf.FlatLaf;
|
||||||
import com.formdev.flatlaf.icons.FlatHelpButtonIcon;
|
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||||
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableObject;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
|
||||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||||
@@ -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 );
|
||||||
@@ -358,8 +369,8 @@ public class FlatButtonUI
|
|||||||
/** @since 2 */
|
/** @since 2 */
|
||||||
protected Object applyStyleProperty( AbstractButton b, String key, Object value ) {
|
protected Object applyStyleProperty( AbstractButton b, String key, Object value ) {
|
||||||
if( key.startsWith( "help." ) ) {
|
if( key.startsWith( "help." ) ) {
|
||||||
if( !(helpButtonIcon instanceof FlatHelpButtonIcon) )
|
if( !(helpButtonIcon instanceof StyleableObject) )
|
||||||
return new UnknownStyleException( key );
|
throw new UnknownStyleException( key );
|
||||||
|
|
||||||
if( helpButtonIconShared ) {
|
if( helpButtonIconShared ) {
|
||||||
helpButtonIcon = FlatStylingSupport.cloneIcon( helpButtonIcon );
|
helpButtonIcon = FlatStylingSupport.cloneIcon( helpButtonIcon );
|
||||||
@@ -367,7 +378,13 @@ public class FlatButtonUI
|
|||||||
}
|
}
|
||||||
|
|
||||||
key = key.substring( "help.".length() );
|
key = key.substring( "help.".length() );
|
||||||
return ((FlatHelpButtonIcon)helpButtonIcon).applyStyleProperty( key, value );
|
return ((StyleableObject)helpButtonIcon).applyStyleProperty( key, value );
|
||||||
|
}
|
||||||
|
|
||||||
|
// update internal values; otherwise isCustomBackground() and isCustomForeground() would return wrong results
|
||||||
|
switch( key ) {
|
||||||
|
case "background": background = (Color) value; break;
|
||||||
|
case "foreground": foreground = (Color) value; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( "iconTextGap".equals( key ) && value instanceof Integer )
|
if( "iconTextGap".equals( key ) && value instanceof Integer )
|
||||||
@@ -382,8 +399,8 @@ public class FlatButtonUI
|
|||||||
@Override
|
@Override
|
||||||
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||||
Map<String, Class<?>> infos = FlatStylingSupport.getAnnotatedStyleableInfos( this, c.getBorder() );
|
Map<String, Class<?>> infos = FlatStylingSupport.getAnnotatedStyleableInfos( this, c.getBorder() );
|
||||||
if( helpButtonIcon instanceof FlatHelpButtonIcon )
|
if( helpButtonIcon instanceof StyleableObject )
|
||||||
FlatStylingSupport.putAllPrefixKey( infos, "help.", ((FlatHelpButtonIcon)helpButtonIcon).getStyleableInfos() );
|
FlatStylingSupport.putAllPrefixKey( infos, "help.", ((StyleableObject)helpButtonIcon).getStyleableInfos() );
|
||||||
return infos;
|
return infos;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,8 +408,8 @@ public class FlatButtonUI
|
|||||||
@Override
|
@Override
|
||||||
public Object getStyleableValue( JComponent c, String key ) {
|
public Object getStyleableValue( JComponent c, String key ) {
|
||||||
if( key.startsWith( "help." ) ) {
|
if( key.startsWith( "help." ) ) {
|
||||||
return (helpButtonIcon instanceof FlatHelpButtonIcon)
|
return (helpButtonIcon instanceof StyleableObject)
|
||||||
? ((FlatHelpButtonIcon)helpButtonIcon).getStyleableValue( key.substring( "help.".length() ) )
|
? ((StyleableObject)helpButtonIcon).getStyleableValue( key.substring( "help.".length() ) )
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -653,7 +670,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 +699,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 +750,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 +777,6 @@ public class FlatButtonUI
|
|||||||
toolbarPressedForeground );
|
toolbarPressedForeground );
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean def = isDefaultButton( c );
|
|
||||||
return buttonStateColor( c,
|
return buttonStateColor( c,
|
||||||
getForegroundBase( c, def ),
|
getForegroundBase( c, def ),
|
||||||
disabledText,
|
disabledText,
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package com.formdev.flatlaf.ui;
|
package com.formdev.flatlaf.ui;
|
||||||
|
|
||||||
import static com.formdev.flatlaf.FlatClientProperties.*;
|
import static com.formdev.flatlaf.FlatClientProperties.*;
|
||||||
|
import java.awt.Container;
|
||||||
import java.awt.EventQueue;
|
import java.awt.EventQueue;
|
||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
@@ -24,7 +25,9 @@ import java.awt.event.FocusEvent;
|
|||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
import javax.swing.ActionMap;
|
import javax.swing.ActionMap;
|
||||||
|
import javax.swing.JComboBox;
|
||||||
import javax.swing.JFormattedTextField;
|
import javax.swing.JFormattedTextField;
|
||||||
|
import javax.swing.JSpinner;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.plaf.UIResource;
|
import javax.swing.plaf.UIResource;
|
||||||
@@ -33,6 +36,7 @@ import javax.swing.text.DefaultCaret;
|
|||||||
import javax.swing.text.DefaultEditorKit;
|
import javax.swing.text.DefaultEditorKit;
|
||||||
import javax.swing.text.Document;
|
import javax.swing.text.Document;
|
||||||
import javax.swing.text.JTextComponent;
|
import javax.swing.text.JTextComponent;
|
||||||
|
import javax.swing.text.Position;
|
||||||
import javax.swing.text.Utilities;
|
import javax.swing.text.Utilities;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -48,12 +52,15 @@ public class FlatCaret
|
|||||||
{
|
{
|
||||||
private static final String KEY_CARET_INFO = "FlatLaf.internal.caretInfo";
|
private static final String KEY_CARET_INFO = "FlatLaf.internal.caretInfo";
|
||||||
|
|
||||||
|
// selectAllOnFocusPolicy
|
||||||
|
private static final int NEVER = 0, ONCE = 1, ALWAYS = 2;
|
||||||
|
|
||||||
private final String selectAllOnFocusPolicy;
|
private final String selectAllOnFocusPolicy;
|
||||||
private final boolean selectAllOnMouseClick;
|
private final boolean selectAllOnMouseClick;
|
||||||
|
|
||||||
private boolean inInstall;
|
private boolean inInstall;
|
||||||
private boolean wasFocused;
|
private boolean wasFocused;
|
||||||
private boolean wasTemporaryLost;
|
private boolean wasFocusTemporaryLost;
|
||||||
private boolean isMousePressed;
|
private boolean isMousePressed;
|
||||||
private boolean isWordSelection;
|
private boolean isWordSelection;
|
||||||
private boolean isLineSelection;
|
private boolean isLineSelection;
|
||||||
@@ -94,6 +101,9 @@ public class FlatCaret
|
|||||||
// restore selection
|
// restore selection
|
||||||
select( (int) ci[1], (int) ci[0] );
|
select( (int) ci[1], (int) ci[0] );
|
||||||
|
|
||||||
|
if( ci[4] != 0 )
|
||||||
|
wasFocused = true;
|
||||||
|
|
||||||
// if text component is focused, then caret and selection are visible,
|
// if text component is focused, then caret and selection are visible,
|
||||||
// but when switching theme, the component does not yet have
|
// but when switching theme, the component does not yet have
|
||||||
// a highlighter and the selection is not painted
|
// a highlighter and the selection is not painted
|
||||||
@@ -121,6 +131,7 @@ public class FlatCaret
|
|||||||
getMark(),
|
getMark(),
|
||||||
getBlinkRate(),
|
getBlinkRate(),
|
||||||
System.currentTimeMillis(),
|
System.currentTimeMillis(),
|
||||||
|
wasFocused ? 1 : 0,
|
||||||
} );
|
} );
|
||||||
|
|
||||||
super.deinstall( c );
|
super.deinstall( c );
|
||||||
@@ -140,11 +151,36 @@ public class FlatCaret
|
|||||||
super.adjustVisibility( nloc );
|
super.adjustVisibility( nloc );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDot( int dot ) {
|
||||||
|
super.setDot( dot );
|
||||||
|
|
||||||
|
// mark as focused if invoked from JTextComponent.setCaretPosition()
|
||||||
|
// to disable SELECT_ALL_ON_FOCUS_POLICY_ONCE if application explicitly changes selection
|
||||||
|
if( !wasFocused &&
|
||||||
|
getSelectAllOnFocusPolicy() == ONCE &&
|
||||||
|
StackUtils.wasInvokedFrom( JTextComponent.class.getName(), "setCaretPosition", 6 ) )
|
||||||
|
wasFocused = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void moveDot( int dot ) {
|
||||||
|
super.moveDot( dot );
|
||||||
|
|
||||||
|
// mark as focused if invoked from JTextComponent.moveCaretPosition()
|
||||||
|
// to disable SELECT_ALL_ON_FOCUS_POLICY_ONCE if application explicitly changes selection
|
||||||
|
if( !wasFocused &&
|
||||||
|
getSelectAllOnFocusPolicy() == ONCE &&
|
||||||
|
StackUtils.wasInvokedFrom( JTextComponent.class.getName(), "moveCaretPosition", 6 ) )
|
||||||
|
wasFocused = true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void focusGained( FocusEvent e ) {
|
public void focusGained( FocusEvent e ) {
|
||||||
if( !inInstall && !wasTemporaryLost && (!isMousePressed || selectAllOnMouseClick) )
|
if( !inInstall && !wasFocusTemporaryLost && (!isMousePressed || isSelectAllOnMouseClick()) )
|
||||||
selectAllOnFocusGained();
|
selectAllOnFocusGained();
|
||||||
wasTemporaryLost = false;
|
|
||||||
|
wasFocusTemporaryLost = false;
|
||||||
wasFocused = true;
|
wasFocused = true;
|
||||||
|
|
||||||
super.focusGained( e );
|
super.focusGained( e );
|
||||||
@@ -152,7 +188,7 @@ public class FlatCaret
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void focusLost( FocusEvent e ) {
|
public void focusLost( FocusEvent e ) {
|
||||||
wasTemporaryLost = e.isTemporary();
|
wasFocusTemporaryLost = e.isTemporary();
|
||||||
super.focusLost( e );
|
super.focusLost( e );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,24 +268,13 @@ public class FlatCaret
|
|||||||
if( doc == null || !c.isEnabled() || !c.isEditable() || FlatUIUtils.isCellEditor( c ) )
|
if( doc == null || !c.isEnabled() || !c.isEditable() || FlatUIUtils.isCellEditor( c ) )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Object selectAllOnFocusPolicy = c.getClientProperty( SELECT_ALL_ON_FOCUS_POLICY );
|
int selectAllOnFocusPolicy = getSelectAllOnFocusPolicy();
|
||||||
if( selectAllOnFocusPolicy == null )
|
if( selectAllOnFocusPolicy == NEVER )
|
||||||
selectAllOnFocusPolicy = this.selectAllOnFocusPolicy;
|
|
||||||
|
|
||||||
if( selectAllOnFocusPolicy == null || SELECT_ALL_ON_FOCUS_POLICY_NEVER.equals( selectAllOnFocusPolicy ) )
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if( !SELECT_ALL_ON_FOCUS_POLICY_ALWAYS.equals( selectAllOnFocusPolicy ) ) {
|
if( selectAllOnFocusPolicy == ONCE && !isMousePressed ) {
|
||||||
// policy is "once" (or null or unknown)
|
|
||||||
|
|
||||||
// was already focused?
|
// was already focused?
|
||||||
if( wasFocused )
|
if( wasFocused && !(c instanceof JFormattedTextField) )
|
||||||
return;
|
|
||||||
|
|
||||||
// check whether selection was modified before gaining focus
|
|
||||||
int dot = getDot();
|
|
||||||
int mark = getMark();
|
|
||||||
if( dot != mark || dot != doc.getLength() )
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,16 +290,51 @@ public class FlatCaret
|
|||||||
|
|
||||||
select( 0, c2.getDocument().getLength() );
|
select( 0, c2.getDocument().getLength() );
|
||||||
} );
|
} );
|
||||||
} else {
|
} else
|
||||||
select( 0, doc.getLength() );
|
select( 0, doc.getLength() );
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void select( int mark, int dot ) {
|
private void select( int mark, int dot ) {
|
||||||
if( mark != getMark() )
|
if( mark != getMark() )
|
||||||
setDot( mark );
|
setDot( mark, Position.Bias.Forward );
|
||||||
if( dot != getDot() )
|
if( dot != getDot() )
|
||||||
moveDot( dot );
|
moveDot( dot, Position.Bias.Forward );
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getSelectAllOnFocusPolicy() {
|
||||||
|
Object value = getClientProperty( SELECT_ALL_ON_FOCUS_POLICY );
|
||||||
|
// Note: using String.valueOf() because selectAllOnFocusPolicy may be null
|
||||||
|
switch( String.valueOf( value instanceof String ? value : selectAllOnFocusPolicy ) ) {
|
||||||
|
default:
|
||||||
|
case SELECT_ALL_ON_FOCUS_POLICY_NEVER: return NEVER;
|
||||||
|
case SELECT_ALL_ON_FOCUS_POLICY_ONCE: return ONCE;
|
||||||
|
case SELECT_ALL_ON_FOCUS_POLICY_ALWAYS: return ALWAYS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSelectAllOnMouseClick() {
|
||||||
|
Object value = getClientProperty( SELECT_ALL_ON_MOUSE_CLICK );
|
||||||
|
return (value instanceof Boolean) ? (boolean) value : selectAllOnMouseClick;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object getClientProperty( String key ) {
|
||||||
|
JTextComponent c = getComponent();
|
||||||
|
if( c == null )
|
||||||
|
return null;
|
||||||
|
|
||||||
|
Object value = c.getClientProperty( key );
|
||||||
|
if( value != null )
|
||||||
|
return value;
|
||||||
|
|
||||||
|
Container parent = c.getParent();
|
||||||
|
if( parent instanceof JComboBox )
|
||||||
|
return ((JComboBox<?>)parent).getClientProperty( key );
|
||||||
|
if( parent instanceof JSpinner.DefaultEditor ) {
|
||||||
|
parent = parent.getParent();
|
||||||
|
if( parent instanceof JSpinner )
|
||||||
|
return ((JSpinner)parent).getClientProperty( key );
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @since 1.4 */
|
/** @since 1.4 */
|
||||||
|
|||||||
@@ -113,6 +113,7 @@ import com.formdev.flatlaf.util.SystemInfo;
|
|||||||
* @uiDefault ComboBox.buttonBackground Color optional
|
* @uiDefault ComboBox.buttonBackground Color optional
|
||||||
* @uiDefault ComboBox.buttonEditableBackground Color optional
|
* @uiDefault ComboBox.buttonEditableBackground Color optional
|
||||||
* @uiDefault ComboBox.buttonFocusedBackground Color optional; defaults to ComboBox.focusedBackground
|
* @uiDefault ComboBox.buttonFocusedBackground Color optional; defaults to ComboBox.focusedBackground
|
||||||
|
* @uiDefault ComboBox.buttonFocusedEditableBackground Color optional; defaults to ComboBox.buttonEditableBackground
|
||||||
* @uiDefault ComboBox.buttonSeparatorWidth int or float optional; defaults to Component.borderWidth
|
* @uiDefault ComboBox.buttonSeparatorWidth int or float optional; defaults to Component.borderWidth
|
||||||
* @uiDefault ComboBox.buttonSeparatorColor Color optional
|
* @uiDefault ComboBox.buttonSeparatorColor Color optional
|
||||||
* @uiDefault ComboBox.buttonDisabledSeparatorColor Color optional
|
* @uiDefault ComboBox.buttonDisabledSeparatorColor Color optional
|
||||||
@@ -147,6 +148,7 @@ public class FlatComboBoxUI
|
|||||||
@Styleable protected Color buttonBackground;
|
@Styleable protected Color buttonBackground;
|
||||||
@Styleable protected Color buttonEditableBackground;
|
@Styleable protected Color buttonEditableBackground;
|
||||||
@Styleable protected Color buttonFocusedBackground;
|
@Styleable protected Color buttonFocusedBackground;
|
||||||
|
/** @since 3.7.1 */ @Styleable protected Color buttonFocusedEditableBackground;
|
||||||
/** @since 2 */ @Styleable protected float buttonSeparatorWidth;
|
/** @since 2 */ @Styleable protected float buttonSeparatorWidth;
|
||||||
/** @since 2 */ @Styleable protected Color buttonSeparatorColor;
|
/** @since 2 */ @Styleable protected Color buttonSeparatorColor;
|
||||||
/** @since 2 */ @Styleable protected Color buttonDisabledSeparatorColor;
|
/** @since 2 */ @Styleable protected Color buttonDisabledSeparatorColor;
|
||||||
@@ -225,6 +227,8 @@ public class FlatComboBoxUI
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
comboBox.addMouseListener( hoverListener );
|
comboBox.addMouseListener( hoverListener );
|
||||||
|
|
||||||
|
MigLayoutVisualPadding.install( comboBox );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -233,6 +237,8 @@ public class FlatComboBoxUI
|
|||||||
|
|
||||||
comboBox.removeMouseListener( hoverListener );
|
comboBox.removeMouseListener( hoverListener );
|
||||||
hoverListener = null;
|
hoverListener = null;
|
||||||
|
|
||||||
|
MigLayoutVisualPadding.uninstall( comboBox );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -254,6 +260,7 @@ public class FlatComboBoxUI
|
|||||||
|
|
||||||
buttonBackground = UIManager.getColor( "ComboBox.buttonBackground" );
|
buttonBackground = UIManager.getColor( "ComboBox.buttonBackground" );
|
||||||
buttonFocusedBackground = UIManager.getColor( "ComboBox.buttonFocusedBackground" );
|
buttonFocusedBackground = UIManager.getColor( "ComboBox.buttonFocusedBackground" );
|
||||||
|
buttonFocusedEditableBackground = UIManager.getColor( "ComboBox.buttonFocusedEditableBackground" );
|
||||||
buttonEditableBackground = UIManager.getColor( "ComboBox.buttonEditableBackground" );
|
buttonEditableBackground = UIManager.getColor( "ComboBox.buttonEditableBackground" );
|
||||||
buttonSeparatorWidth = FlatUIUtils.getUIFloat( "ComboBox.buttonSeparatorWidth", FlatUIUtils.getUIFloat( "Component.borderWidth", 1 ) );
|
buttonSeparatorWidth = FlatUIUtils.getUIFloat( "ComboBox.buttonSeparatorWidth", FlatUIUtils.getUIFloat( "Component.borderWidth", 1 ) );
|
||||||
buttonSeparatorColor = UIManager.getColor( "ComboBox.buttonSeparatorColor" );
|
buttonSeparatorColor = UIManager.getColor( "ComboBox.buttonSeparatorColor" );
|
||||||
@@ -274,8 +281,6 @@ public class FlatComboBoxUI
|
|||||||
comboBox.setMaximumRowCount( maximumRowCount );
|
comboBox.setMaximumRowCount( maximumRowCount );
|
||||||
|
|
||||||
paddingBorder = new CellPaddingBorder( padding );
|
paddingBorder = new CellPaddingBorder( padding );
|
||||||
|
|
||||||
MigLayoutVisualPadding.install( comboBox );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -291,6 +296,7 @@ public class FlatComboBoxUI
|
|||||||
buttonBackground = null;
|
buttonBackground = null;
|
||||||
buttonEditableBackground = null;
|
buttonEditableBackground = null;
|
||||||
buttonFocusedBackground = null;
|
buttonFocusedBackground = null;
|
||||||
|
buttonFocusedEditableBackground = null;
|
||||||
buttonSeparatorColor = null;
|
buttonSeparatorColor = null;
|
||||||
buttonDisabledSeparatorColor = null;
|
buttonDisabledSeparatorColor = null;
|
||||||
buttonArrowColor = null;
|
buttonArrowColor = null;
|
||||||
@@ -304,8 +310,6 @@ public class FlatComboBoxUI
|
|||||||
|
|
||||||
oldStyleValues = null;
|
oldStyleValues = null;
|
||||||
borderShared = null;
|
borderShared = null;
|
||||||
|
|
||||||
MigLayoutVisualPadding.uninstall( comboBox );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -587,7 +591,7 @@ public class FlatComboBoxUI
|
|||||||
// paint arrow button background
|
// paint arrow button background
|
||||||
if( enabled && !isCellRenderer && arrowButton.isVisible() ) {
|
if( enabled && !isCellRenderer && arrowButton.isVisible() ) {
|
||||||
Color buttonColor = paintButton
|
Color buttonColor = paintButton
|
||||||
? buttonEditableBackground
|
? (buttonFocusedEditableBackground != null && isPermanentFocusOwner( comboBox ) ? buttonFocusedEditableBackground : buttonEditableBackground)
|
||||||
: (buttonFocusedBackground != null || focusedBackground != null) && isPermanentFocusOwner( comboBox )
|
: (buttonFocusedBackground != null || focusedBackground != null) && isPermanentFocusOwner( comboBox )
|
||||||
? (buttonFocusedBackground != null ? buttonFocusedBackground : focusedBackground)
|
? (buttonFocusedBackground != null ? buttonFocusedBackground : focusedBackground)
|
||||||
: buttonBackground;
|
: buttonBackground;
|
||||||
@@ -882,7 +886,7 @@ public class FlatComboBoxUI
|
|||||||
GraphicsConfiguration gc = comboBox.getGraphicsConfiguration();
|
GraphicsConfiguration gc = comboBox.getGraphicsConfiguration();
|
||||||
if( gc != null ) {
|
if( gc != null ) {
|
||||||
Rectangle screenBounds = gc.getBounds();
|
Rectangle screenBounds = gc.getBounds();
|
||||||
Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets( gc );
|
Insets screenInsets = FlatUIUtils.getScreenInsets( gc );
|
||||||
displayWidth = Math.min( displayWidth, screenBounds.width - screenInsets.left - screenInsets.right );
|
displayWidth = Math.min( displayWidth, screenBounds.width - screenInsets.left - screenInsets.right );
|
||||||
} else {
|
} else {
|
||||||
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
|
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
|
||||||
|
|||||||
@@ -24,9 +24,8 @@ import java.awt.Image;
|
|||||||
import java.awt.Insets;
|
import java.awt.Insets;
|
||||||
import java.awt.RadialGradientPaint;
|
import java.awt.RadialGradientPaint;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.util.Map;
|
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableBorder;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableObject;
|
||||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||||
import com.formdev.flatlaf.util.UIScale;
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
|
|
||||||
@@ -43,7 +42,7 @@ import com.formdev.flatlaf.util.UIScale;
|
|||||||
*/
|
*/
|
||||||
public class FlatDropShadowBorder
|
public class FlatDropShadowBorder
|
||||||
extends FlatEmptyBorder
|
extends FlatEmptyBorder
|
||||||
implements StyleableBorder
|
implements StyleableObject
|
||||||
{
|
{
|
||||||
@Styleable protected Color shadowColor;
|
@Styleable protected Color shadowColor;
|
||||||
@Styleable protected Insets shadowInsets;
|
@Styleable protected Insets shadowInsets;
|
||||||
@@ -74,7 +73,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 );
|
||||||
}
|
}
|
||||||
@@ -93,7 +92,7 @@ public class FlatDropShadowBorder
|
|||||||
/** @since 2 */
|
/** @since 2 */
|
||||||
@Override
|
@Override
|
||||||
public Object applyStyleProperty( String key, Object value ) {
|
public Object applyStyleProperty( String key, Object value ) {
|
||||||
Object oldValue = FlatStylingSupport.applyToAnnotatedObject( this, key, value );
|
Object oldValue = StyleableObject.super.applyStyleProperty( key, value );
|
||||||
if( key.equals( "shadowInsets" ) ) {
|
if( key.equals( "shadowInsets" ) ) {
|
||||||
applyStyleProperty( nonNegativeInsets( shadowInsets ) );
|
applyStyleProperty( nonNegativeInsets( shadowInsets ) );
|
||||||
shadowSize = maxInset( shadowInsets );
|
shadowSize = maxInset( shadowInsets );
|
||||||
@@ -101,18 +100,6 @@ public class FlatDropShadowBorder
|
|||||||
return oldValue;
|
return oldValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @since 2 */
|
|
||||||
@Override
|
|
||||||
public Map<String, Class<?>> getStyleableInfos() {
|
|
||||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @since 2.5 */
|
|
||||||
@Override
|
|
||||||
public Object getStyleableValue( String key ) {
|
|
||||||
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||||
if( shadowSize <= 0 )
|
if( shadowSize <= 0 )
|
||||||
|
|||||||
@@ -376,31 +376,68 @@ public class FlatFileChooserUI
|
|||||||
if( icon != null )
|
if( icon != null )
|
||||||
return icon;
|
return icon;
|
||||||
|
|
||||||
|
// new proxy icon
|
||||||
|
//
|
||||||
|
// Note: Since this is a super light weight icon object, we do not add it
|
||||||
|
// to the icon cache here. This keeps cache small in case of large directories
|
||||||
|
// with thousands of files when icons of all files are only needed to compute
|
||||||
|
// the layout of list/table, but never painted because located outside of visible area.
|
||||||
|
// When an icon needs to be painted, the proxy adds it to the icon cache
|
||||||
|
// and loads the real icon.
|
||||||
|
return new FlatFileViewIcon( f );
|
||||||
|
}
|
||||||
|
|
||||||
|
//---- class FlatFileViewIcon -----------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A proxy icon that has a fixed (scaled) width/height (16x16) and
|
||||||
|
* gets/loads the real (system) icon only for painting.
|
||||||
|
* Avoids unnecessary getting/loading system icons.
|
||||||
|
*/
|
||||||
|
private class FlatFileViewIcon
|
||||||
|
implements Icon
|
||||||
|
{
|
||||||
|
private final File f;
|
||||||
|
private Icon realIcon;
|
||||||
|
|
||||||
|
FlatFileViewIcon( File f ) {
|
||||||
|
this.f = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getIconWidth() {
|
||||||
|
return UIScale.scale( 16 );
|
||||||
|
}
|
||||||
|
|
||||||
|
@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
|
// get system icon
|
||||||
if( f != null ) {
|
|
||||||
try {
|
try {
|
||||||
icon = getFileChooser().getFileSystemView().getSystemIcon( f );
|
if( f != null )
|
||||||
|
realIcon = getFileChooser().getFileSystemView().getSystemIcon( f );
|
||||||
} catch( NullPointerException ex ) {
|
} catch( NullPointerException ex ) {
|
||||||
// Java 21 may throw a NPE for exe files that use default Windows exe icon
|
// Java 21 may throw a NPE for exe files that use default Windows exe icon
|
||||||
}
|
}
|
||||||
|
|
||||||
if( icon != null ) {
|
|
||||||
if( icon instanceof ImageIcon )
|
|
||||||
icon = new ScaledImageIcon( (ImageIcon) icon );
|
|
||||||
cacheIcon( f, icon );
|
|
||||||
return icon;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// get default icon
|
// get default icon
|
||||||
icon = super.getIcon( f );
|
if( realIcon == null )
|
||||||
|
realIcon = FlatFileView.super.getIcon( f );
|
||||||
|
|
||||||
if( icon instanceof ImageIcon ) {
|
if( realIcon instanceof ImageIcon )
|
||||||
icon = new ScaledImageIcon( (ImageIcon) icon );
|
realIcon = new ScaledImageIcon( (ImageIcon) realIcon );
|
||||||
cacheIcon( f, icon );
|
|
||||||
|
cacheIcon( f, this );
|
||||||
}
|
}
|
||||||
|
|
||||||
return icon;
|
realIcon.paintIcon( c, g, x, y );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
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;
|
||||||
@@ -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
|
||||||
@@ -97,7 +98,7 @@ debug*/
|
|||||||
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 = "";
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ import javax.swing.event.MouseInputAdapter;
|
|||||||
import javax.swing.plaf.ComponentUI;
|
import javax.swing.plaf.ComponentUI;
|
||||||
import javax.swing.plaf.basic.BasicInternalFrameUI;
|
import javax.swing.plaf.basic.BasicInternalFrameUI;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableBorder;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableObject;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||||
import com.formdev.flatlaf.util.LoggingFacade;
|
import com.formdev.flatlaf.util.LoggingFacade;
|
||||||
|
|
||||||
@@ -209,7 +209,7 @@ public class FlatInternalFrameUI
|
|||||||
|
|
||||||
public static class FlatInternalFrameBorder
|
public static class FlatInternalFrameBorder
|
||||||
extends FlatEmptyBorder
|
extends FlatEmptyBorder
|
||||||
implements StyleableBorder
|
implements StyleableObject
|
||||||
{
|
{
|
||||||
@Styleable protected Color activeBorderColor = UIManager.getColor( "InternalFrame.activeBorderColor" );
|
@Styleable protected Color activeBorderColor = UIManager.getColor( "InternalFrame.activeBorderColor" );
|
||||||
@Styleable protected Color inactiveBorderColor = UIManager.getColor( "InternalFrame.inactiveBorderColor" );
|
@Styleable protected Color inactiveBorderColor = UIManager.getColor( "InternalFrame.inactiveBorderColor" );
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
@@ -298,6 +302,18 @@ public class FlatListUI
|
|||||||
ListModel dataModel, ListSelectionModel selModel, int leadIndex )
|
ListModel dataModel, ListSelectionModel selModel, int leadIndex )
|
||||||
{
|
{
|
||||||
boolean isSelected = selModel.isSelectedIndex( row );
|
boolean isSelected = selModel.isSelectedIndex( row );
|
||||||
|
boolean isDropRow = isDropRow( 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" )
|
||||||
@@ -305,7 +321,7 @@ public class FlatListUI
|
|||||||
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 ) {
|
||||||
@@ -320,7 +336,7 @@ public class FlatListUI
|
|||||||
}
|
}
|
||||||
|
|
||||||
// rounded selection or selection insets
|
// rounded selection or selection insets
|
||||||
if( isSelected &&
|
if( (isSelected || isDropRow) &&
|
||||||
!isFileList && // rounded selection is not supported for file list
|
!isFileList && // rounded selection is not supported for file list
|
||||||
(rendererComponent instanceof DefaultListCellRenderer ||
|
(rendererComponent instanceof DefaultListCellRenderer ||
|
||||||
rendererComponent instanceof BasicComboBoxRenderer) &&
|
rendererComponent instanceof BasicComboBoxRenderer) &&
|
||||||
@@ -361,6 +377,21 @@ public class FlatListUI
|
|||||||
this.getColor() == rendererComponent.getBackground() )
|
this.getColor() == rendererComponent.getBackground() )
|
||||||
{
|
{
|
||||||
inPaintSelection = true;
|
inPaintSelection = true;
|
||||||
|
if( isDropRow ) {
|
||||||
|
// for rounded drop background, it is necessary to first
|
||||||
|
// paint selection background because may be not rounded on some corners
|
||||||
|
if( isSelected ) {
|
||||||
|
Color oldColor = getColor();
|
||||||
|
setColor( list.getSelectionBackground() );
|
||||||
|
paintCellSelection( this, row, x, y, width, height );
|
||||||
|
setColor( oldColor );
|
||||||
|
}
|
||||||
|
|
||||||
|
// paint drop background
|
||||||
|
float arc = UIScale.scale( selectionArc / 2f );
|
||||||
|
FlatUIUtils.paintSelection( this, x, y, width, height,
|
||||||
|
UIScale.scale( selectionInsets ), arc, arc, arc, arc, 0 );
|
||||||
|
} else
|
||||||
paintCellSelection( this, row, x, y, width, height );
|
paintCellSelection( this, row, x, y, width, height );
|
||||||
inPaintSelection = false;
|
inPaintSelection = false;
|
||||||
} else
|
} else
|
||||||
@@ -460,4 +491,15 @@ public class FlatListUI
|
|||||||
FlatListUI ui = (FlatListUI) list.getUI();
|
FlatListUI ui = (FlatListUI) list.getUI();
|
||||||
ui.paintCellSelection( g, row, x, y, width, height );
|
ui.paintCellSelection( g, row, x, y, width, height );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether dropping on a row.
|
||||||
|
* See DefaultListCellRenderer.getListCellRendererComponent().
|
||||||
|
*/
|
||||||
|
private boolean isDropRow( int row ) {
|
||||||
|
JList.DropLocation dropLocation = list.getDropLocation();
|
||||||
|
return dropLocation != null &&
|
||||||
|
!dropLocation.isInsert() &&
|
||||||
|
dropLocation.getIndex() == row;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,11 +21,10 @@ import java.awt.Color;
|
|||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.Insets;
|
import java.awt.Insets;
|
||||||
import java.util.Map;
|
|
||||||
import javax.swing.JMenuBar;
|
import javax.swing.JMenuBar;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableBorder;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Border for {@link javax.swing.JMenuBar}.
|
* Border for {@link javax.swing.JMenuBar}.
|
||||||
@@ -36,27 +35,10 @@ import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableBorder;
|
|||||||
*/
|
*/
|
||||||
public class FlatMenuBarBorder
|
public class FlatMenuBarBorder
|
||||||
extends FlatMarginBorder
|
extends FlatMarginBorder
|
||||||
implements StyleableBorder
|
implements StyleableObject
|
||||||
{
|
{
|
||||||
@Styleable protected Color borderColor = UIManager.getColor( "MenuBar.borderColor" );
|
@Styleable protected Color borderColor = UIManager.getColor( "MenuBar.borderColor" );
|
||||||
|
|
||||||
/** @since 2 */
|
|
||||||
@Override
|
|
||||||
public Object applyStyleProperty( String key, Object value ) {
|
|
||||||
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, Class<?>> getStyleableInfos() {
|
|
||||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @since 2.5 */
|
|
||||||
@Override
|
|
||||||
public Object getStyleableValue( String key ) {
|
|
||||||
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||||
if( !showBottomSeparator( c ) )
|
if( !showBottomSeparator( c ) )
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
if( !unknownArch ) {
|
||||||
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Native library '" + System.mapLibraryName( libraryName )
|
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Native library '" + System.mapLibraryName( libraryName )
|
||||||
+ "' not found in java.library.path '" + System.getProperty( "java.library.path" )
|
+ "' not found in java.library.path '" + System.getProperty( "java.library.path" )
|
||||||
+ "'. Using extracted native library instead.", null );
|
+ "'. 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,6 +166,7 @@ class FlatNativeLibrary
|
|||||||
return new NativeLibrary( libraryFile2, true );
|
return new NativeLibrary( libraryFile2, true );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( !unknownArch ) {
|
||||||
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Native library '"
|
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Native library '"
|
||||||
+ libraryFile.getName()
|
+ libraryFile.getName()
|
||||||
+ (libraryName2 != null ? ("' or '" + libraryName2) : "")
|
+ (libraryName2 != null ? ("' or '" + libraryName2) : "")
|
||||||
@@ -167,6 +174,7 @@ class FlatNativeLibrary
|
|||||||
+ "'. Using extracted native library instead.", null );
|
+ "'. Using extracted native library instead.", null );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// load from beside the FlatLaf jar
|
// load from beside the FlatLaf jar
|
||||||
// e.g. for flatlaf-3.1.jar, load flatlaf-3.1-windows-x86_64.dll (from same directory)
|
// e.g. for flatlaf-3.1.jar, load flatlaf-3.1-windows-x86_64.dll (from same directory)
|
||||||
@@ -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" );
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import java.awt.event.MouseEvent;
|
|||||||
import java.awt.geom.AffineTransform;
|
import java.awt.geom.AffineTransform;
|
||||||
import javax.swing.JDialog;
|
import javax.swing.JDialog;
|
||||||
import javax.swing.JFrame;
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
import com.formdev.flatlaf.util.SystemInfo;
|
import com.formdev.flatlaf.util.SystemInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -34,9 +35,9 @@ import com.formdev.flatlaf.util.SystemInfo;
|
|||||||
* @author Karl Tauber
|
* @author Karl Tauber
|
||||||
* @since 2.5
|
* @since 2.5
|
||||||
*/
|
*/
|
||||||
class FlatNativeLinuxLibrary
|
public class FlatNativeLinuxLibrary
|
||||||
{
|
{
|
||||||
private static int API_VERSION_LINUX = 3001;
|
private static int API_VERSION_LINUX = 3003;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether native library is loaded/available.
|
* Checks whether native library is loaded/available.
|
||||||
@@ -44,13 +45,25 @@ class FlatNativeLinuxLibrary
|
|||||||
* <b>Note</b>: It is required to invoke this method before invoking any other
|
* <b>Note</b>: It is required to invoke this method before invoking any other
|
||||||
* method of this class. Otherwise, the native library may not be loaded.
|
* method of this class. Otherwise, the native library may not be loaded.
|
||||||
*/
|
*/
|
||||||
static boolean isLoaded() {
|
public static boolean isLoaded() {
|
||||||
return SystemInfo.isLinux && FlatNativeLibrary.isLoaded( API_VERSION_LINUX );
|
return SystemInfo.isLinux && FlatNativeLibrary.isLoaded( API_VERSION_LINUX );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//---- X Window System ----------------------------------------------------
|
||||||
|
|
||||||
// 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;
|
||||||
|
|
||||||
@@ -115,4 +128,110 @@ class FlatNativeLinuxLibrary
|
|||||||
return (window instanceof JFrame && JFrame.isDefaultLookAndFeelDecorated() && ((JFrame)window).isUndecorated()) ||
|
return (window instanceof JFrame && JFrame.isDefaultLookAndFeelDecorated() && ((JFrame)window).isUndecorated()) ||
|
||||||
(window instanceof JDialog && JDialog.isDefaultLookAndFeelDecorated() && ((JDialog)window).isUndecorated());
|
(window instanceof JDialog && JDialog.isDefaultLookAndFeelDecorated() && ((JDialog)window).isUndecorated());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//---- GTK ----------------------------------------------------------------
|
||||||
|
|
||||||
|
private static Boolean isGtk3Available;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether GTK 3 is available.
|
||||||
|
* Use this before invoking any native method that uses GTK.
|
||||||
|
* Otherwise the app may terminate immediately if GTK is not installed.
|
||||||
|
* <p>
|
||||||
|
* This works because Java uses {@code dlopen(RTLD_LAZY)} to load JNI libraries,
|
||||||
|
* which only resolves symbols as the code that references them is executed.
|
||||||
|
*
|
||||||
|
* @since 3.7
|
||||||
|
*/
|
||||||
|
public static boolean isGtk3Available() {
|
||||||
|
if( isGtk3Available == null )
|
||||||
|
isGtk3Available = isLibAvailable( "libgtk-3.so.0" ) || isLibAvailable( "libgtk-3.so" );
|
||||||
|
return isGtk3Available;
|
||||||
|
}
|
||||||
|
|
||||||
|
private native static boolean isLibAvailable( String libname );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://docs.gtk.org/gtk3/iface.FileChooser.html#properties
|
||||||
|
*
|
||||||
|
* @since 3.7
|
||||||
|
*/
|
||||||
|
public static final int
|
||||||
|
FC_select_folder = 1 << 0,
|
||||||
|
FC_select_multiple = 1 << 1,
|
||||||
|
FC_show_hidden = 1 << 2,
|
||||||
|
FC_local_only = 1 << 3, // default
|
||||||
|
FC_do_overwrite_confirmation = 1 << 4, // GTK 3 only; removed and always-on in GTK 4
|
||||||
|
FC_create_folders = 1 << 5; // default for Save
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows the Linux/GTK system file dialog
|
||||||
|
* <a href="https://docs.gtk.org/gtk3/class.FileChooserDialog.html">GtkFileChooserDialog</a>.
|
||||||
|
* <p>
|
||||||
|
* Uses {@code GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER} if {@link #FC_select_folder} is set in parameter {@code optionsSet}.
|
||||||
|
* Otherwise uses {@code GTK_FILE_CHOOSER_ACTION_OPEN} if parameter {@code open} is {@code true},
|
||||||
|
* or {@code GTK_FILE_CHOOSER_ACTION_SAVE} if {@code false}.
|
||||||
|
* <p>
|
||||||
|
* <b>Note:</b> This method blocks the current thread until the user closes
|
||||||
|
* the file dialog. It is highly recommended to invoke it from a new thread
|
||||||
|
* to avoid blocking the AWT event dispatching thread.
|
||||||
|
*
|
||||||
|
* @param owner the owner of the file dialog; or {@code null}
|
||||||
|
* @param dark preferred appearance of the file dialog: {@code 1} = prefer dark, {@code 0} = prefer light, {@code -1} = default
|
||||||
|
* @param open if {@code true}, shows the open dialog; if {@code false}, shows the save dialog
|
||||||
|
* @param title text displayed in dialog title; or {@code null}
|
||||||
|
* @param okButtonLabel text displayed in default button; or {@code null}.
|
||||||
|
* Use '_' for mnemonics (e.g. "_Choose")
|
||||||
|
* Use '__' for '_' character (e.g. "Choose__and__Quit").
|
||||||
|
* @param currentName user-editable filename currently shown in the filename field in save dialog; or {@code null}
|
||||||
|
* @param currentFolder current directory shown in the dialog; or {@code null}
|
||||||
|
* @param optionsSet options to set; see {@code FOS_*} constants
|
||||||
|
* @param optionsClear options to clear; see {@code FOS_*} constants
|
||||||
|
* @param callback approve callback; or {@code null}
|
||||||
|
* @param fileTypeIndex the file type that appears as selected (zero-based)
|
||||||
|
* @param fileTypes file types that the dialog can open or save.
|
||||||
|
* Two or more strings and {@code null} are required for each filter.
|
||||||
|
* First string is the display name of the filter shown in the combobox (e.g. "Text Files").
|
||||||
|
* Subsequent strings are the filter patterns (e.g. "*.txt" or "*").
|
||||||
|
* {@code null} is required to mark end of filter.
|
||||||
|
* @return file path(s) that the user selected; an empty array if canceled;
|
||||||
|
* or {@code null} on failures (no dialog shown)
|
||||||
|
*
|
||||||
|
* @since 3.7
|
||||||
|
*/
|
||||||
|
public native static String[] showFileChooser( Window owner, int dark, boolean open,
|
||||||
|
String title, String okButtonLabel, String currentName, String currentFolder,
|
||||||
|
int optionsSet, int optionsClear, FileChooserCallback callback,
|
||||||
|
int fileTypeIndex, String... fileTypes );
|
||||||
|
|
||||||
|
/** @since 3.7 */
|
||||||
|
public interface FileChooserCallback {
|
||||||
|
boolean approve( String[] files, long hwndFileDialog );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows a GTK message box
|
||||||
|
* <a href="https://docs.gtk.org/gtk3/class.MessageDialog.html">GtkMessageDialog</a>.
|
||||||
|
* <p>
|
||||||
|
* For use in {@link FileChooserCallback} only.
|
||||||
|
*
|
||||||
|
* @param hwndParent the parent of the message box
|
||||||
|
* @param messageType type of message being displayed:
|
||||||
|
* {@link JOptionPane#ERROR_MESSAGE}, {@link JOptionPane#INFORMATION_MESSAGE},
|
||||||
|
* {@link JOptionPane#WARNING_MESSAGE}, {@link JOptionPane#QUESTION_MESSAGE} or
|
||||||
|
* {@link JOptionPane#PLAIN_MESSAGE}
|
||||||
|
* @param primaryText primary text; if the dialog has a secondary text,
|
||||||
|
* this will appear as title in a larger bold font
|
||||||
|
* @param secondaryText secondary text; shown below of primary text; or {@code null}
|
||||||
|
* @param defaultButton index of the default button, which can be pressed using ENTER key
|
||||||
|
* @param buttons texts of the buttons; if no buttons given the a default "OK" button is shown.
|
||||||
|
* Use '_' for mnemonics (e.g. "_Choose")
|
||||||
|
* Use '__' for '_' character (e.g. "Choose__and__Quit").
|
||||||
|
* @return index of pressed button; or -1 for ESC key
|
||||||
|
*
|
||||||
|
* @since 3.7
|
||||||
|
*/
|
||||||
|
public native static int showMessageDialog( long hwndParent, int messageType,
|
||||||
|
String primaryText, String secondaryText, int defaultButton, String... buttons );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package com.formdev.flatlaf.ui;
|
|||||||
|
|
||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
import java.awt.Window;
|
import java.awt.Window;
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
import com.formdev.flatlaf.util.SystemInfo;
|
import com.formdev.flatlaf.util.SystemInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -44,7 +45,7 @@ import com.formdev.flatlaf.util.SystemInfo;
|
|||||||
*/
|
*/
|
||||||
public class FlatNativeMacLibrary
|
public class FlatNativeMacLibrary
|
||||||
{
|
{
|
||||||
private static int API_VERSION_MACOS = 2001;
|
private static int API_VERSION_MACOS = 2002;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether native library is loaded/available.
|
* Checks whether native library is loaded/available.
|
||||||
@@ -68,4 +69,88 @@ public class FlatNativeMacLibrary
|
|||||||
/** @since 3.4 */ public native static Rectangle getWindowButtonsBounds( Window window );
|
/** @since 3.4 */ public native static Rectangle getWindowButtonsBounds( Window window );
|
||||||
/** @since 3.4 */ public native static boolean isWindowFullScreen( Window window );
|
/** @since 3.4 */ public native static boolean isWindowFullScreen( Window window );
|
||||||
/** @since 3.4 */ public native static boolean toggleWindowFullScreen( Window window );
|
/** @since 3.4 */ public native static boolean toggleWindowFullScreen( Window window );
|
||||||
|
|
||||||
|
|
||||||
|
/** @since 3.7 */
|
||||||
|
public static final int
|
||||||
|
// NSOpenPanel (extends NSSavePanel)
|
||||||
|
FC_canChooseFiles = 1 << 0, // default
|
||||||
|
FC_canChooseDirectories = 1 << 1,
|
||||||
|
FC_resolvesAliases = 1 << 2, // default
|
||||||
|
FC_allowsMultipleSelection = 1 << 3,
|
||||||
|
FC_accessoryViewDisclosed = 1 << 4,
|
||||||
|
// NSSavePanel
|
||||||
|
FC_showsTagField = 1 << 8, // default for Save
|
||||||
|
FC_canCreateDirectories = 1 << 9, // default for Save
|
||||||
|
FC_canSelectHiddenExtension = 1 << 10,
|
||||||
|
FC_showsHiddenFiles = 1 << 11,
|
||||||
|
FC_extensionHidden = 1 << 12,
|
||||||
|
FC_allowsOtherFileTypes = 1 << 13,
|
||||||
|
FC_treatsFilePackagesAsDirectories = 1 << 14,
|
||||||
|
// custom
|
||||||
|
FC_showSingleFilterField = 1 << 24;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows the macOS system file dialogs
|
||||||
|
* <a href="https://developer.apple.com/documentation/appkit/nsopenpanel?language=objc">NSOpenPanel</a> or
|
||||||
|
* <a href="https://developer.apple.com/documentation/appkit/nssavepanel?language=objc">NSSavePanel</a>.
|
||||||
|
* <p>
|
||||||
|
* <b>Note:</b> This method blocks the current thread until the user closes
|
||||||
|
* the file dialog. It is highly recommended to invoke it from a new thread
|
||||||
|
* to avoid blocking the AWT event dispatching thread.
|
||||||
|
*
|
||||||
|
* @param owner the owner of the file dialog; or {@code null}
|
||||||
|
* @param dark appearance of the file dialog: {@code 1} = dark, {@code 0} = light, {@code -1} = default
|
||||||
|
* @param open if {@code true}, shows the open dialog; if {@code false}, shows the save dialog
|
||||||
|
* @param title text displayed at top of save dialog (not used in open dialog); or {@code null}
|
||||||
|
* @param prompt text displayed in default button; or {@code null}
|
||||||
|
* @param message text displayed at top of open/save dialogs; or {@code null}
|
||||||
|
* @param filterFieldLabel text displayed in front of the filter combobox; or {@code null}
|
||||||
|
* @param nameFieldLabel text displayed in front of the filename text field in save dialog (not used in open dialog); or {@code null}
|
||||||
|
* @param nameFieldStringValue user-editable filename currently shown in the name field in save dialog (not used in open dialog); or {@code null}
|
||||||
|
* @param directoryURL current directory shown in the dialog; or {@code null}
|
||||||
|
* @param optionsSet options to set; see {@code FC_*} constants
|
||||||
|
* @param optionsClear options to clear; see {@code FC_*} constants
|
||||||
|
* @param fileTypeIndex the file type that appears as selected (zero-based)
|
||||||
|
* @param fileTypes file types that the dialog can open or save.
|
||||||
|
* Two or more strings and {@code null} are required for each filter.
|
||||||
|
* First string is the display name of the filter shown in the combobox (e.g. "Text Files").
|
||||||
|
* Subsequent strings are the filter patterns (e.g. "txt" or "*").
|
||||||
|
* {@code null} is required to mark end of filter.
|
||||||
|
* @return file path(s) that the user selected; an empty array if canceled;
|
||||||
|
* or {@code null} on failures (no dialog shown)
|
||||||
|
*
|
||||||
|
* @since 3.7
|
||||||
|
*/
|
||||||
|
public native static String[] showFileChooser( Window owner, int dark, boolean open,
|
||||||
|
String title, String prompt, String message, String filterFieldLabel,
|
||||||
|
String nameFieldLabel, String nameFieldStringValue, String directoryURL,
|
||||||
|
int optionsSet, int optionsClear, FileChooserCallback callback,
|
||||||
|
int fileTypeIndex, String... fileTypes );
|
||||||
|
|
||||||
|
/** @since 3.7 */
|
||||||
|
public interface FileChooserCallback {
|
||||||
|
boolean approve( String[] files, long hwndFileDialog );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows a macOS alert
|
||||||
|
* <a href="https://developer.apple.com/documentation/appkit/nsalert?language=objc">NSAlert</a>.
|
||||||
|
* <p>
|
||||||
|
* For use in {@link FileChooserCallback} only.
|
||||||
|
*
|
||||||
|
* @param hwndParent the parent of the message box
|
||||||
|
* @param alertStyle type of alert being displayed:
|
||||||
|
* {@link JOptionPane#ERROR_MESSAGE}, {@link JOptionPane#INFORMATION_MESSAGE} or
|
||||||
|
* {@link JOptionPane#WARNING_MESSAGE}
|
||||||
|
* @param messageText main message of the alert
|
||||||
|
* @param informativeText additional information about the alert; shown below of main message; or {@code null}
|
||||||
|
* @param defaultButton index of the default button, which can be pressed using ENTER key
|
||||||
|
* @param buttons texts of the buttons; if no buttons given the a default "OK" button is shown
|
||||||
|
* @return index of pressed button
|
||||||
|
*
|
||||||
|
* @since 3.7
|
||||||
|
*/
|
||||||
|
public native static int showMessageDialog( long hwndParent, int alertStyle,
|
||||||
|
String messageText, String informativeText, int defaultButton, String... buttons );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package com.formdev.flatlaf.ui;
|
|||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.Window;
|
import java.awt.Window;
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
import com.formdev.flatlaf.util.SystemInfo;
|
import com.formdev.flatlaf.util.SystemInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,7 +31,7 @@ import com.formdev.flatlaf.util.SystemInfo;
|
|||||||
*/
|
*/
|
||||||
public class FlatNativeWindowsLibrary
|
public class FlatNativeWindowsLibrary
|
||||||
{
|
{
|
||||||
private static int API_VERSION_WINDOWS = 1001;
|
private static int API_VERSION_WINDOWS = 1002;
|
||||||
|
|
||||||
private static long osBuildNumber = Long.MIN_VALUE;
|
private static long osBuildNumber = Long.MIN_VALUE;
|
||||||
|
|
||||||
@@ -158,4 +159,125 @@ public class FlatNativeWindowsLibrary
|
|||||||
// DwmSetWindowAttribute() expects COLORREF as attribute value, which is defined as DWORD
|
// DwmSetWindowAttribute() expects COLORREF as attribute value, which is defined as DWORD
|
||||||
return dwmSetWindowAttributeDWORD( hwnd, attribute, rgb );
|
return dwmSetWindowAttributeDWORD( hwnd, attribute, rgb );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FILEOPENDIALOGOPTIONS
|
||||||
|
* see https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/ne-shobjidl_core-_fileopendialogoptions
|
||||||
|
*
|
||||||
|
* @since 3.7
|
||||||
|
*/
|
||||||
|
public static final int
|
||||||
|
FOS_OVERWRITEPROMPT = 0x2, // default for Save
|
||||||
|
FOS_STRICTFILETYPES = 0x4,
|
||||||
|
FOS_NOCHANGEDIR = 0x8, // default
|
||||||
|
FOS_PICKFOLDERS = 0x20,
|
||||||
|
FOS_FORCEFILESYSTEM = 0x40,
|
||||||
|
FOS_ALLNONSTORAGEITEMS = 0x80,
|
||||||
|
FOS_NOVALIDATE = 0x100,
|
||||||
|
FOS_ALLOWMULTISELECT = 0x200,
|
||||||
|
FOS_PATHMUSTEXIST = 0x800, // default
|
||||||
|
FOS_FILEMUSTEXIST = 0x1000, // default for Open
|
||||||
|
FOS_CREATEPROMPT = 0x2000,
|
||||||
|
FOS_SHAREAWARE = 0x4000,
|
||||||
|
FOS_NOREADONLYRETURN = 0x8000, // default for Save
|
||||||
|
FOS_NOTESTFILECREATE = 0x10000,
|
||||||
|
FOS_HIDEMRUPLACES = 0x20000,
|
||||||
|
FOS_HIDEPINNEDPLACES = 0x40000,
|
||||||
|
FOS_NODEREFERENCELINKS = 0x100000,
|
||||||
|
FOS_OKBUTTONNEEDSINTERACTION = 0x200000,
|
||||||
|
FOS_DONTADDTORECENT = 0x2000000,
|
||||||
|
FOS_FORCESHOWHIDDEN = 0x10000000,
|
||||||
|
FOS_DEFAULTNOMINIMODE = 0x20000000,
|
||||||
|
FOS_FORCEPREVIEWPANEON = 0x40000000,
|
||||||
|
FOS_SUPPORTSTREAMABLEITEMS = 0x80000000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows the Windows system
|
||||||
|
* <a href="https://learn.microsoft.com/en-us/windows/win32/shell/common-file-dialog">file dialogs</a>
|
||||||
|
* <a href="https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nn-shobjidl_core-ifileopendialog">IFileOpenDialog</a> or
|
||||||
|
* <a href="https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nn-shobjidl_core-ifilesavedialog">IFileSaveDialog</a>.
|
||||||
|
* <p>
|
||||||
|
* <b>Note:</b> This method blocks the current thread until the user closes
|
||||||
|
* the file dialog. It is highly recommended to invoke it from a new thread
|
||||||
|
* to avoid blocking the AWT event dispatching thread.
|
||||||
|
*
|
||||||
|
* @param owner the owner of the file dialog; or {@code null}
|
||||||
|
* @param open if {@code true}, shows the open dialog; if {@code false}, shows the save dialog
|
||||||
|
* @param title text displayed in dialog title; or {@code null}
|
||||||
|
* @param okButtonLabel text displayed in default button; or {@code null}.
|
||||||
|
* Use '&' for mnemonics (e.g. "&Choose").
|
||||||
|
* Use '&&' for '&' character (e.g. "Choose && Quit").
|
||||||
|
* @param fileNameLabel text displayed in front of the filename text field; or {@code null}
|
||||||
|
* @param fileName user-editable filename currently shown in the filename field; or {@code null}
|
||||||
|
* @param folder current directory shown in the dialog; or {@code null}
|
||||||
|
* @param saveAsItem file to be used as the initial entry in a Save As dialog; or {@code null}.
|
||||||
|
* File name is shown in filename text field, folder is selected in view.
|
||||||
|
* To be used for saving files that already exist. For new files use {@code fileName}.
|
||||||
|
* @param defaultFolder folder used as a default if there is not a recently used folder value available; or {@code null}.
|
||||||
|
* Windows somewhere stores default folder on a per-app basis.
|
||||||
|
* So this is probably used only once when the app opens a file dialog for first time.
|
||||||
|
* @param defaultExtension default extension to be added to file name in save dialog; or {@code null}
|
||||||
|
* @param optionsSet options to set; see {@code FOS_*} constants
|
||||||
|
* @param optionsClear options to clear; see {@code FOS_*} constants
|
||||||
|
* @param callback approve callback; or {@code null}
|
||||||
|
* @param fileTypeIndex the file type that appears as selected (zero-based)
|
||||||
|
* @param fileTypes file types that the dialog can open or save.
|
||||||
|
* Pairs of strings are required for each filter.
|
||||||
|
* First string is the display name of the filter shown in the combobox (e.g. "Text Files").
|
||||||
|
* Second string is the filter pattern (e.g. "*.txt", "*.exe;*.dll" or "*.*").
|
||||||
|
* @return file path(s) that the user selected; an empty array if canceled;
|
||||||
|
* or {@code null} on failures (no dialog shown)
|
||||||
|
*
|
||||||
|
* @since 3.7
|
||||||
|
*/
|
||||||
|
public native static String[] showFileChooser( Window owner, boolean open,
|
||||||
|
String title, String okButtonLabel, String fileNameLabel, String fileName,
|
||||||
|
String folder, String saveAsItem, String defaultFolder, String defaultExtension,
|
||||||
|
int optionsSet, int optionsClear, FileChooserCallback callback,
|
||||||
|
int fileTypeIndex, String... fileTypes );
|
||||||
|
|
||||||
|
/** @since 3.7 */
|
||||||
|
public interface FileChooserCallback {
|
||||||
|
boolean approve( String[] files, long hwndFileDialog );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows a modal Windows message dialog.
|
||||||
|
* <p>
|
||||||
|
* For use in {@link FileChooserCallback} only.
|
||||||
|
*
|
||||||
|
* @param hwndParent the parent of the message box
|
||||||
|
* @param messageType type of message being displayed:
|
||||||
|
* {@link JOptionPane#ERROR_MESSAGE}, {@link JOptionPane#INFORMATION_MESSAGE},
|
||||||
|
* {@link JOptionPane#WARNING_MESSAGE}, {@link JOptionPane#QUESTION_MESSAGE} or
|
||||||
|
* {@link JOptionPane#PLAIN_MESSAGE}
|
||||||
|
* @param title dialog box title; or {@code null} to use title from parent window
|
||||||
|
* @param text message to be displayed
|
||||||
|
* @param defaultButton index of the default button, which can be pressed using ENTER key
|
||||||
|
* @param buttons texts of the buttons.
|
||||||
|
* Use '&' for mnemonics (e.g. "&Choose").
|
||||||
|
* Use '&&' for '&' character (e.g. "Choose && Quit").
|
||||||
|
* @return index of pressed button; or -1 for ESC key
|
||||||
|
*
|
||||||
|
* @since 3.7
|
||||||
|
*/
|
||||||
|
public native static int showMessageDialog( long hwndParent, int messageType,
|
||||||
|
String title, String text, int defaultButton, String... buttons );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows a Windows message box
|
||||||
|
* <a href="https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messagebox">MessageBox</a>.
|
||||||
|
* <p>
|
||||||
|
* For use in {@link FileChooserCallback} only.
|
||||||
|
*
|
||||||
|
* @param hwndParent the parent of the message box
|
||||||
|
* @param text message to be displayed
|
||||||
|
* @param caption dialog box title
|
||||||
|
* @param type see <a href="https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messagebox#parameters">MessageBox parameter uType</a>
|
||||||
|
* @return see <a href="https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messagebox#return-value">MessageBox Return value</a>
|
||||||
|
*
|
||||||
|
* @since 3.7
|
||||||
|
*/
|
||||||
|
public native static int showMessageBox( long hwndParent, String text, String caption, int type );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package com.formdev.flatlaf.ui;
|
package com.formdev.flatlaf.ui;
|
||||||
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
import java.awt.Toolkit;
|
import java.awt.Toolkit;
|
||||||
@@ -41,8 +40,8 @@ import javax.swing.text.JTextComponent;
|
|||||||
import javax.swing.text.PasswordView;
|
import javax.swing.text.PasswordView;
|
||||||
import javax.swing.text.View;
|
import javax.swing.text.View;
|
||||||
import com.formdev.flatlaf.FlatClientProperties;
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
import com.formdev.flatlaf.icons.FlatCapsLockIcon;
|
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||||
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableObject;
|
||||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||||
import com.formdev.flatlaf.util.UIScale;
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
|
|
||||||
@@ -215,12 +214,12 @@ public class FlatPasswordFieldUI
|
|||||||
/** @since 2 */
|
/** @since 2 */
|
||||||
@Override
|
@Override
|
||||||
protected Object applyStyleProperty( String key, Object value ) {
|
protected Object applyStyleProperty( String key, Object value ) {
|
||||||
if( key.equals( "capsLockIconColor" ) && capsLockIcon instanceof FlatCapsLockIcon ) {
|
if( key.startsWith( "capsLockIcon" ) && capsLockIcon instanceof StyleableObject ) {
|
||||||
if( capsLockIconShared ) {
|
if( capsLockIconShared ) {
|
||||||
capsLockIcon = FlatStylingSupport.cloneIcon( capsLockIcon );
|
capsLockIcon = FlatStylingSupport.cloneIcon( capsLockIcon );
|
||||||
capsLockIconShared = false;
|
capsLockIconShared = false;
|
||||||
}
|
}
|
||||||
return ((FlatCapsLockIcon)capsLockIcon).applyStyleProperty( key, value );
|
return ((StyleableObject)capsLockIcon).applyStyleProperty( key, value );
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.applyStyleProperty( key, value );
|
return super.applyStyleProperty( key, value );
|
||||||
@@ -230,14 +229,15 @@ public class FlatPasswordFieldUI
|
|||||||
@Override
|
@Override
|
||||||
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||||
Map<String, Class<?>> infos = super.getStyleableInfos( c );
|
Map<String, Class<?>> infos = super.getStyleableInfos( c );
|
||||||
infos.put( "capsLockIconColor", Color.class );
|
if( capsLockIcon instanceof StyleableObject )
|
||||||
|
infos.putAll( ((StyleableObject)capsLockIcon).getStyleableInfos() );
|
||||||
return infos;
|
return infos;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getStyleableValue( JComponent c, String key ) {
|
public Object getStyleableValue( JComponent c, String key ) {
|
||||||
if( key.equals( "capsLockIconColor" ) && capsLockIcon instanceof FlatCapsLockIcon )
|
if( key.startsWith( "capsLockIcon" ) && capsLockIcon instanceof StyleableObject )
|
||||||
return ((FlatCapsLockIcon)capsLockIcon).getStyleableValue( key );
|
return ((StyleableObject)capsLockIcon).getStyleableValue( key );
|
||||||
|
|
||||||
return super.getStyleableValue( c, key );
|
return super.getStyleableValue( c, key );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ import java.awt.Panel;
|
|||||||
import java.awt.Point;
|
import java.awt.Point;
|
||||||
import java.awt.PointerInfo;
|
import java.awt.PointerInfo;
|
||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
import java.awt.Toolkit;
|
|
||||||
import java.awt.Window;
|
import java.awt.Window;
|
||||||
import java.awt.event.ComponentEvent;
|
import java.awt.event.ComponentEvent;
|
||||||
import java.awt.event.ComponentListener;
|
import java.awt.event.ComponentListener;
|
||||||
@@ -109,10 +108,8 @@ public class FlatPopupFactory
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean forceHeavyWeight = isOptionEnabled( owner, contents, FlatClientProperties.POPUP_FORCE_HEAVY_WEIGHT, "Popup.forceHeavyWeight" );
|
|
||||||
|
|
||||||
if( !isOptionEnabled( owner, contents, FlatClientProperties.POPUP_DROP_SHADOW_PAINTED, "Popup.dropShadowPainted" ) || SystemInfo.isProjector || SystemInfo.isWebswing )
|
if( !isOptionEnabled( owner, contents, FlatClientProperties.POPUP_DROP_SHADOW_PAINTED, "Popup.dropShadowPainted" ) || SystemInfo.isProjector || SystemInfo.isWebswing )
|
||||||
return new NonFlashingPopup( getPopupForScreenOfOwner( owner, contents, x, y, forceHeavyWeight ), owner, contents );
|
return new NonFlashingPopup( getPopupForScreenOfOwner( owner, contents, x, y, isForceHeavyWeight( owner, contents, x, y ) ), owner, contents );
|
||||||
|
|
||||||
// macOS and Linux adds drop shadow to heavy weight popups
|
// macOS and Linux adds drop shadow to heavy weight popups
|
||||||
if( SystemInfo.isMacOS || SystemInfo.isLinux ) {
|
if( SystemInfo.isMacOS || SystemInfo.isLinux ) {
|
||||||
@@ -132,13 +129,9 @@ public class FlatPopupFactory
|
|||||||
return popup;
|
return popup;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check whether popup overlaps a heavy weight component
|
|
||||||
if( !forceHeavyWeight && overlapsHeavyWeightComponent( owner, contents, x, y ) )
|
|
||||||
forceHeavyWeight = true;
|
|
||||||
|
|
||||||
// create drop shadow popup
|
// create drop shadow popup
|
||||||
Popup popupForScreenOfOwner = getPopupForScreenOfOwner( owner, contents, x, y, forceHeavyWeight );
|
Popup popupForScreenOfOwner = getPopupForScreenOfOwner( owner, contents, x, y, isForceHeavyWeight( owner, contents, x, y ) );
|
||||||
GraphicsConfiguration gc = owner.getGraphicsConfiguration();
|
GraphicsConfiguration gc = (owner != null) ? owner.getGraphicsConfiguration() : null;
|
||||||
return (gc != null && gc.isTranslucencyCapable())
|
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 );
|
||||||
@@ -227,6 +220,11 @@ public class FlatPopupFactory
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isForceHeavyWeight( Component owner, Component contents, int x, int y ) {
|
||||||
|
boolean forceHeavyWeight = isOptionEnabled( owner, contents, FlatClientProperties.POPUP_FORCE_HEAVY_WEIGHT, "Popup.forceHeavyWeight" );
|
||||||
|
return forceHeavyWeight || hasVisibleGlassPane( owner ) || overlapsHeavyWeightComponent( owner, contents, x, y );
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean isOptionEnabled( Component owner, Component contents, String clientKey, String uiKey ) {
|
private static boolean isOptionEnabled( Component owner, Component contents, String clientKey, String uiKey ) {
|
||||||
Object value = getOption( owner, contents, clientKey, uiKey );
|
Object value = getOption( owner, contents, clientKey, uiKey );
|
||||||
return (value instanceof Boolean) ? (Boolean) value : false;
|
return (value instanceof Boolean) ? (Boolean) value : false;
|
||||||
@@ -306,13 +304,13 @@ 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;
|
||||||
|
|
||||||
Rectangle screenBounds = gc.getBounds();
|
Rectangle screenBounds = gc.getBounds();
|
||||||
Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets( gc );
|
Insets screenInsets = FlatUIUtils.getScreenInsets( gc );
|
||||||
int screenTop = screenBounds.y + screenInsets.top;
|
int screenTop = screenBounds.y + screenInsets.top;
|
||||||
|
|
||||||
// place tooltip above mouse location if there is enough space
|
// place tooltip above mouse location if there is enough space
|
||||||
@@ -365,14 +363,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();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -476,6 +468,18 @@ public class FlatPopupFactory
|
|||||||
|
|
||||||
//---- fixes --------------------------------------------------------------
|
//---- fixes --------------------------------------------------------------
|
||||||
|
|
||||||
|
private static boolean hasVisibleGlassPane( Component owner ) {
|
||||||
|
if( owner == null )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Window window = SwingUtilities.windowForComponent( owner );
|
||||||
|
if( !(window instanceof RootPaneContainer) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Component glassPane = ((RootPaneContainer)window).getGlassPane();
|
||||||
|
return (glassPane != null && glassPane.isVisible());
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean overlapsHeavyWeightComponent( Component owner, Component contents, int x, int y ) {
|
private static boolean overlapsHeavyWeightComponent( Component owner, Component contents, int x, int y ) {
|
||||||
if( owner == null )
|
if( owner == null )
|
||||||
return false;
|
return false;
|
||||||
@@ -553,7 +557,15 @@ public class FlatPopupFactory
|
|||||||
int x = popupWindow.getX();
|
int x = popupWindow.getX();
|
||||||
int y = popupWindow.getY();
|
int y = popupWindow.getY();
|
||||||
|
|
||||||
|
if( !popupWindow.isVisible() )
|
||||||
popup.show();
|
popup.show();
|
||||||
|
else {
|
||||||
|
// if the popup window is already visible (because it is reused),
|
||||||
|
// do not invoke Popup.show() because this would invoke Window.toFront(),
|
||||||
|
// which may have the side effect that an inactive owner window
|
||||||
|
// would be also moved to front and maybe hide previously active window
|
||||||
|
popupWindow.pack();
|
||||||
|
}
|
||||||
|
|
||||||
// restore popup window location if it has changed
|
// restore popup window location if it has changed
|
||||||
// (probably scaled when screens use different scale factors)
|
// (probably scaled when screens use different scale factors)
|
||||||
@@ -625,6 +637,29 @@ public class FlatPopupFactory
|
|||||||
|
|
||||||
void showImpl() {
|
void showImpl() {
|
||||||
if( delegate != null ) {
|
if( delegate != null ) {
|
||||||
|
// On macOS and Linux, the empty popup window is shown in popup.show()
|
||||||
|
// (in peer.setVisible(true) invoked from Component.show()),
|
||||||
|
// but the popup content is painted later via repaint manager.
|
||||||
|
// This may cause some flicker, especially during JVM warm-up or
|
||||||
|
// when running JVM in interpreter mode (option -Xint).
|
||||||
|
// To reduce flicker, immediately paint popup content as soon as popup window becomes visible.
|
||||||
|
// This also fixes a problem with JetBrainsRuntime JVM, where sometimes the popups were empty.
|
||||||
|
if( (SystemInfo.isMacOS || SystemInfo.isLinux) && popupWindow instanceof JWindow ) {
|
||||||
|
HierarchyListener l = e -> {
|
||||||
|
if( e.getID() == HierarchyEvent.HIERARCHY_CHANGED &&
|
||||||
|
(e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0 )
|
||||||
|
{
|
||||||
|
((JWindow)popupWindow).getRootPane().paintImmediately(
|
||||||
|
0, 0, popupWindow.getWidth(), popupWindow.getHeight() );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
popupWindow.addHierarchyListener( l );
|
||||||
|
try {
|
||||||
|
showPopupAndFixLocation( delegate, popupWindow );
|
||||||
|
} finally {
|
||||||
|
popupWindow.removeHierarchyListener( l );
|
||||||
|
}
|
||||||
|
} else
|
||||||
showPopupAndFixLocation( delegate, popupWindow );
|
showPopupAndFixLocation( delegate, popupWindow );
|
||||||
|
|
||||||
// increase tooltip size if necessary because it may be too small on HiDPI screens
|
// increase tooltip size if necessary because it may be too small on HiDPI screens
|
||||||
@@ -652,8 +687,11 @@ public class FlatPopupFactory
|
|||||||
return;
|
return;
|
||||||
disposed = true;
|
disposed = true;
|
||||||
|
|
||||||
// immediately hide non-heavy weight popups or combobox popups
|
// immediately hide non-heavy weight popups, popup menus and combobox popups
|
||||||
if( !(popupWindow instanceof JWindow) || contents instanceof BasicComboPopup ) {
|
// of if system property is false
|
||||||
|
if( !(popupWindow instanceof JWindow) || contents instanceof JPopupMenu ||
|
||||||
|
!FlatSystemProperties.getBoolean( FlatSystemProperties.REUSE_VISIBLE_POPUP_WINDOW, true ) )
|
||||||
|
{
|
||||||
hideImpl();
|
hideImpl();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -684,6 +722,21 @@ public class FlatPopupFactory
|
|||||||
// restore background so that it can not affect other LaFs (when switching)
|
// restore background so that it can not affect other LaFs (when switching)
|
||||||
// because popup windows are cached and reused
|
// because popup windows are cached and reused
|
||||||
popupWindow.setBackground( oldPopupWindowBackground );
|
popupWindow.setBackground( oldPopupWindowBackground );
|
||||||
|
|
||||||
|
// On macOS, popupWindow.setBackground(...) invoked from constructor,
|
||||||
|
// has no affect if the popup window peer (a NSWindow) is already created,
|
||||||
|
// which is the case when reusing a cached popup window
|
||||||
|
// (see class PopupFactory.HeavyWeightPopup).
|
||||||
|
// This may result in flicker when e.g. showing a popup in a light theme,
|
||||||
|
// then switching to a dark theme and again showing a popup,
|
||||||
|
// because the underling NSWindow still has a light background,
|
||||||
|
// which may be shown shortly before the actual dark popup content is shown.
|
||||||
|
// To fix this, dispose the popup window, which disposes the NSWindow.
|
||||||
|
// The AWT popup window stays in the popup cache, but when reusing it later,
|
||||||
|
// a new peer and a new NSWindow is created and gets the correct background.
|
||||||
|
if( SystemInfo.isMacOS )
|
||||||
|
popupWindow.dispose();
|
||||||
|
|
||||||
popupWindow = null;
|
popupWindow = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -715,6 +768,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;
|
||||||
@@ -774,7 +828,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 );
|
||||||
@@ -844,10 +898,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;
|
||||||
@@ -947,23 +1009,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 ) );
|
|
||||||
dropShadowPanel2.invalidate();
|
|
||||||
dropShadowWindow.pack();
|
|
||||||
|
|
||||||
// update drop shadow popup window location
|
private void updateDropShadowWindowBounds() {
|
||||||
|
if( dropShadowWindow == null )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// calculate size of drop shadow window
|
||||||
|
Dimension size = popupWindow.getSize();
|
||||||
|
Insets insets = dropShadowPanel2.getInsets();
|
||||||
|
int w = size.width + insets.left + insets.right;
|
||||||
|
int h = size.height + insets.top + insets.bottom;
|
||||||
|
|
||||||
|
// update drop shadow popup window bounds
|
||||||
int x = popupWindow.getX() - insets.left;
|
int x = popupWindow.getX() - insets.left;
|
||||||
int y = popupWindow.getY() - insets.top;
|
int y = popupWindow.getY() - insets.top;
|
||||||
dropShadowWindow.setLocation( x, y );
|
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 ) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import java.awt.Insets;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.swing.JScrollPane;
|
import javax.swing.JScrollPane;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableBorder;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableObject;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
|
||||||
import com.formdev.flatlaf.util.UIScale;
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ import com.formdev.flatlaf.util.UIScale;
|
|||||||
*/
|
*/
|
||||||
public class FlatPopupMenuBorder
|
public class FlatPopupMenuBorder
|
||||||
extends FlatLineBorder
|
extends FlatLineBorder
|
||||||
implements StyleableBorder
|
implements StyleableObject
|
||||||
{
|
{
|
||||||
private Color borderColor;
|
private Color borderColor;
|
||||||
|
|
||||||
|
|||||||
@@ -246,7 +246,7 @@ public class FlatPopupMenuUI
|
|||||||
// (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())
|
||||||
Rectangle screenBounds = gc.getBounds();
|
Rectangle screenBounds = gc.getBounds();
|
||||||
Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets( gc );
|
Insets screenInsets = FlatUIUtils.getScreenInsets( gc );
|
||||||
return FlatUIUtils.subtractInsets( screenBounds, screenInsets );
|
return FlatUIUtils.subtractInsets( screenBounds, screenInsets );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ import javax.swing.plaf.basic.BasicRadioButtonUI;
|
|||||||
import com.formdev.flatlaf.FlatClientProperties;
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
import com.formdev.flatlaf.icons.FlatCheckBoxIcon;
|
import com.formdev.flatlaf.icons.FlatCheckBoxIcon;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||||
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableObject;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
|
||||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||||
@@ -203,16 +204,17 @@ public class FlatRadioButtonUI
|
|||||||
protected Object applyStyleProperty( AbstractButton b, String key, Object value ) {
|
protected Object applyStyleProperty( AbstractButton b, String key, Object value ) {
|
||||||
// style icon
|
// style icon
|
||||||
if( key.startsWith( "icon." ) ) {
|
if( key.startsWith( "icon." ) ) {
|
||||||
if( !(icon instanceof FlatCheckBoxIcon) )
|
Icon icon = getRealIcon( b );
|
||||||
return new UnknownStyleException( key );
|
if( !(icon instanceof StyleableObject) )
|
||||||
|
throw new UnknownStyleException( key );
|
||||||
|
|
||||||
if( iconShared ) {
|
if( icon == this.icon && iconShared ) {
|
||||||
icon = FlatStylingSupport.cloneIcon( icon );
|
this.icon = icon = FlatStylingSupport.cloneIcon( icon );
|
||||||
iconShared = false;
|
iconShared = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
key = key.substring( "icon.".length() );
|
key = key.substring( "icon.".length() );
|
||||||
return ((FlatCheckBoxIcon)icon).applyStyleProperty( key, value );
|
return ((StyleableObject)icon).applyStyleProperty( key, value );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( "iconTextGap".equals( key ) && value instanceof Integer )
|
if( "iconTextGap".equals( key ) && value instanceof Integer )
|
||||||
@@ -225,10 +227,9 @@ public class FlatRadioButtonUI
|
|||||||
@Override
|
@Override
|
||||||
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||||
Map<String, Class<?>> infos = FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
Map<String, Class<?>> infos = FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
||||||
if( icon instanceof FlatCheckBoxIcon ) {
|
Icon icon = getRealIcon( c );
|
||||||
for( Map.Entry<String, Class<?>> e : ((FlatCheckBoxIcon)icon).getStyleableInfos().entrySet() )
|
if( icon instanceof StyleableObject )
|
||||||
infos.put( "icon.".concat( e.getKey() ), e.getValue() );
|
FlatStylingSupport.putAllPrefixKey( infos, "icon.", ((StyleableObject)icon).getStyleableInfos() );
|
||||||
}
|
|
||||||
return infos;
|
return infos;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,8 +238,9 @@ public class FlatRadioButtonUI
|
|||||||
public Object getStyleableValue( JComponent c, String key ) {
|
public Object getStyleableValue( JComponent c, String key ) {
|
||||||
// style icon
|
// style icon
|
||||||
if( key.startsWith( "icon." ) ) {
|
if( key.startsWith( "icon." ) ) {
|
||||||
return (icon instanceof FlatCheckBoxIcon)
|
Icon icon = getRealIcon( c );
|
||||||
? ((FlatCheckBoxIcon)icon).getStyleableValue( key.substring( "icon.".length() ) )
|
return (icon instanceof StyleableObject)
|
||||||
|
? ((StyleableObject)icon).getStyleableValue( key.substring( "icon.".length() ) )
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,16 +334,18 @@ public class FlatRadioButtonUI
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int getIconFocusWidth( JComponent c ) {
|
private int getIconFocusWidth( JComponent c ) {
|
||||||
AbstractButton b = (AbstractButton) c;
|
Icon icon = getRealIcon( c );
|
||||||
Icon icon = b.getIcon();
|
|
||||||
if( icon == null )
|
|
||||||
icon = getDefaultIcon();
|
|
||||||
|
|
||||||
return (icon instanceof FlatCheckBoxIcon)
|
return (icon instanceof FlatCheckBoxIcon)
|
||||||
? Math.round( UIScale.scale( ((FlatCheckBoxIcon)icon).getFocusWidth() ) )
|
? Math.round( UIScale.scale( ((FlatCheckBoxIcon)icon).getFocusWidth() ) )
|
||||||
: 0;
|
: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Icon getRealIcon( JComponent c ) {
|
||||||
|
AbstractButton b = (AbstractButton) c;
|
||||||
|
Icon icon = b.getIcon();
|
||||||
|
return (icon != null) ? icon : getDefaultIcon();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getBaseline( JComponent c, int width, int height ) {
|
public int getBaseline( JComponent c, int width, int height ) {
|
||||||
return FlatButtonUI.getBaselineImpl( c, width, height );
|
return FlatButtonUI.getBaselineImpl( c, width, height );
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import java.awt.Color;
|
|||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Container;
|
import java.awt.Container;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
|
import java.awt.EventQueue;
|
||||||
import java.awt.Frame;
|
import java.awt.Frame;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
@@ -31,6 +32,7 @@ import java.awt.Window;
|
|||||||
import java.awt.event.ComponentListener;
|
import java.awt.event.ComponentListener;
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JDialog;
|
import javax.swing.JDialog;
|
||||||
@@ -152,8 +154,28 @@ public class FlatRootPaneUI
|
|||||||
Container parent = c.getParent();
|
Container parent = c.getParent();
|
||||||
if( parent instanceof JFrame || parent instanceof JDialog ) {
|
if( parent instanceof JFrame || parent instanceof JDialog ) {
|
||||||
Color background = parent.getBackground();
|
Color background = parent.getBackground();
|
||||||
if( background == null || background instanceof UIResource )
|
if( background == null || background instanceof UIResource ) {
|
||||||
|
if( SystemInfo.isMacOS ) {
|
||||||
|
// Setting window background on macOS immediately fills the whole window
|
||||||
|
// with that color, and slightly delayed, the Swing repaint manager
|
||||||
|
// repaints the actual window content. This results in some flashing
|
||||||
|
// when switching from a light to a dark theme (or vice versa).
|
||||||
|
// --> delay setting window background and immediately repaint window content
|
||||||
|
Runnable r = () -> {
|
||||||
parent.setBackground( UIManager.getColor( "control" ) );
|
parent.setBackground( UIManager.getColor( "control" ) );
|
||||||
|
c.paintImmediately( 0, 0, c.getWidth(), c.getHeight() );
|
||||||
|
};
|
||||||
|
|
||||||
|
// for class FlatAnimatedLafChange:
|
||||||
|
// if animated Laf change is in progress, set background color when
|
||||||
|
// animation has finished to avoid/reduce flashing
|
||||||
|
if( c.getClientProperty( "FlatLaf.internal.animatedLafChange" ) != null )
|
||||||
|
c.putClientProperty( "FlatLaf.internal.animatedLafChange.runWhenFinished", r );
|
||||||
|
else
|
||||||
|
EventQueue.invokeLater( r );
|
||||||
|
} else
|
||||||
|
parent.setBackground( UIManager.getColor( "control" ) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macClearBackgroundForTranslucentWindow( c );
|
macClearBackgroundForTranslucentWindow( c );
|
||||||
@@ -485,8 +507,12 @@ public class FlatRootPaneUI
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case "ancestor":
|
case "ancestor":
|
||||||
if( e.getNewValue() instanceof Window )
|
if( e.getNewValue() instanceof Window ) {
|
||||||
|
if( titlePane != null && !Objects.equals( titlePane.windowStyle, FlatTitlePane.getWindowStyle( rootPane ) ) )
|
||||||
|
setTitlePane( createTitlePane() );
|
||||||
|
|
||||||
macClearBackgroundForTranslucentWindow( rootPane );
|
macClearBackgroundForTranslucentWindow( rootPane );
|
||||||
|
}
|
||||||
|
|
||||||
macUninstallWindowBackgroundListener( rootPane );
|
macUninstallWindowBackgroundListener( rootPane );
|
||||||
macInstallWindowBackgroundListener( rootPane );
|
macInstallWindowBackgroundListener( rootPane );
|
||||||
@@ -684,7 +710,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 +743,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 ) {
|
||||||
|
|||||||
@@ -227,7 +227,13 @@ public class FlatSliderUI
|
|||||||
|
|
||||||
/** @since 2 */
|
/** @since 2 */
|
||||||
protected void applyStyle( Object style ) {
|
protected void applyStyle( Object style ) {
|
||||||
|
Dimension oldThumbSize = thumbSize;
|
||||||
|
int oldFocusWidth = focusWidth;
|
||||||
|
|
||||||
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
|
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
|
||||||
|
|
||||||
|
if( !thumbSize.equals( oldThumbSize ) || focusWidth != oldFocusWidth )
|
||||||
|
calculateGeometry();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @since 2 */
|
/** @since 2 */
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
@@ -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.
|
||||||
@@ -52,6 +51,9 @@ import com.formdev.flatlaf.util.SystemInfo;
|
|||||||
*/
|
*/
|
||||||
public class FlatStylingSupport
|
public class FlatStylingSupport
|
||||||
{
|
{
|
||||||
|
|
||||||
|
//---- annotations --------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates that a field is intended to be used by FlatLaf styling support.
|
* Indicates that a field is intended to be used by FlatLaf styling support.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -99,17 +101,56 @@ public class FlatStylingSupport
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//---- interfaces ---------------------------------------------------------
|
||||||
|
|
||||||
/** @since 2 */
|
/** @since 2 */
|
||||||
public interface StyleableUI {
|
public interface StyleableUI {
|
||||||
Map<String, Class<?>> getStyleableInfos( JComponent c ) throws IllegalArgumentException;
|
Map<String, Class<?>> getStyleableInfos( JComponent c ) throws IllegalArgumentException;
|
||||||
/** @since 2.5 */ Object getStyleableValue( JComponent c, String key ) throws IllegalArgumentException;
|
/** @since 2.5 */ Object getStyleableValue( JComponent c, String key ) throws IllegalArgumentException;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @since 2 */
|
/**
|
||||||
public interface StyleableBorder {
|
* An object that implements this interface is intended to support FlatLaf styling.
|
||||||
Object applyStyleProperty( String key, Object value );
|
*
|
||||||
Map<String, Class<?>> getStyleableInfos() throws IllegalArgumentException;
|
* @since 3.7
|
||||||
/** @since 2.5 */ Object getStyleableValue( String key ) throws IllegalArgumentException;
|
*/
|
||||||
|
public interface StyleableObject {
|
||||||
|
/**
|
||||||
|
* Applies the given value to this object.
|
||||||
|
* <p>
|
||||||
|
* The default implementation invokes {@link FlatStylingSupport#applyToAnnotatedObject(Object, String, Object)}.
|
||||||
|
*
|
||||||
|
* @param key the name of the property
|
||||||
|
* @param value the new value
|
||||||
|
* @return the old value of the property
|
||||||
|
*/
|
||||||
|
default Object applyStyleProperty( String key, Object value )
|
||||||
|
throws UnknownStyleException, IllegalArgumentException
|
||||||
|
{
|
||||||
|
return applyToAnnotatedObject( this, key, value );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a map of all styleable properties.
|
||||||
|
* The key is the name of the property and the value the type of the property.
|
||||||
|
* <p>
|
||||||
|
* The default implementation invokes {@link FlatStylingSupport#getAnnotatedStyleableInfos(Object)}.
|
||||||
|
*/
|
||||||
|
default Map<String, Class<?>> getStyleableInfos() throws IllegalArgumentException {
|
||||||
|
return getAnnotatedStyleableInfos( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current value for the given property key.
|
||||||
|
* <p>
|
||||||
|
* The default implementation invokes {@link FlatStylingSupport#getAnnotatedStyleableValue(Object, String)}.
|
||||||
|
*
|
||||||
|
* @param key the name of the property
|
||||||
|
* @return the current value of the property
|
||||||
|
*/
|
||||||
|
default Object getStyleableValue( String key ) throws IllegalArgumentException {
|
||||||
|
return getAnnotatedStyleableValue( this, key );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @since 2.5 */
|
/** @since 2.5 */
|
||||||
@@ -118,6 +159,8 @@ public class FlatStylingSupport
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//---- methods ------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the style specified in client property {@link FlatClientProperties#STYLE}.
|
* Returns the style specified in client property {@link FlatClientProperties#STYLE}.
|
||||||
*/
|
*/
|
||||||
@@ -325,22 +368,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() );
|
||||||
|
if( !lightOrDarkPrefix.equals( prefix ) && !FlatLaf.getUIKeyPlatformPrefixes().contains( prefix ) )
|
||||||
|
continue outer;
|
||||||
|
|
||||||
// prefix is known and enabled --> remove prefix
|
// prefix is known and enabled --> remove prefix
|
||||||
key = key.substring( key.indexOf( ']' ) + 1 );
|
key = key.substring( closeIndex + 1 );
|
||||||
} else
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Object oldValue = applyProperty.apply( key, newValue );
|
Object oldValue = applyProperty.apply( key, newValue );
|
||||||
@@ -674,7 +719,7 @@ public class FlatStylingSupport
|
|||||||
} catch( UnknownStyleException ex ) {
|
} catch( UnknownStyleException ex ) {
|
||||||
// apply to border
|
// apply to border
|
||||||
Border border = c.getBorder();
|
Border border = c.getBorder();
|
||||||
if( border instanceof StyleableBorder ) {
|
if( border instanceof StyleableObject ) {
|
||||||
if( borderShared.get() ) {
|
if( borderShared.get() ) {
|
||||||
border = cloneBorder( border );
|
border = cloneBorder( border );
|
||||||
c.setBorder( border );
|
c.setBorder( border );
|
||||||
@@ -682,7 +727,7 @@ public class FlatStylingSupport
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return ((StyleableBorder)border).applyStyleProperty( key, value );
|
return ((StyleableObject)border).applyStyleProperty( key, value );
|
||||||
} catch( UnknownStyleException ex2 ) {
|
} catch( UnknownStyleException ex2 ) {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
@@ -832,8 +877,8 @@ public class FlatStylingSupport
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void collectStyleableInfos( Border border, Map<String, Class<?>> infos ) {
|
public static void collectStyleableInfos( Border border, Map<String, Class<?>> infos ) {
|
||||||
if( border instanceof StyleableBorder )
|
if( border instanceof StyleableObject )
|
||||||
infos.putAll( ((StyleableBorder)border).getStyleableInfos() );
|
infos.putAll( ((StyleableObject)border).getStyleableInfos() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void putAllPrefixKey( Map<String, Class<?>> infos, String keyPrefix, Map<String, Class<?>> infos2 ) {
|
public static void putAllPrefixKey( Map<String, Class<?>> infos, String keyPrefix, Map<String, Class<?>> infos2 ) {
|
||||||
@@ -881,8 +926,8 @@ public class FlatStylingSupport
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Object getAnnotatedStyleableValue( Object obj, Border border, String key ) {
|
public static Object getAnnotatedStyleableValue( Object obj, Border border, String key ) {
|
||||||
if( border instanceof StyleableBorder ) {
|
if( border instanceof StyleableObject ) {
|
||||||
Object value = ((StyleableBorder)border).getStyleableValue( key );
|
Object value = ((StyleableObject)border).getStyleableValue( key );
|
||||||
if( value != null )
|
if( value != null )
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,8 +92,8 @@ import javax.swing.text.JTextComponent;
|
|||||||
import javax.swing.text.View;
|
import javax.swing.text.View;
|
||||||
import com.formdev.flatlaf.FlatClientProperties;
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
import com.formdev.flatlaf.FlatLaf;
|
import com.formdev.flatlaf.FlatLaf;
|
||||||
import com.formdev.flatlaf.icons.FlatTabbedPaneCloseIcon;
|
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||||
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableObject;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
|
||||||
import com.formdev.flatlaf.util.Animator;
|
import com.formdev.flatlaf.util.Animator;
|
||||||
@@ -205,6 +205,7 @@ public class FlatTabbedPaneUI
|
|||||||
protected static final int WIDTH_MODE_PREFERRED = 0;
|
protected static final int WIDTH_MODE_PREFERRED = 0;
|
||||||
protected static final int WIDTH_MODE_EQUAL = 1;
|
protected static final int WIDTH_MODE_EQUAL = 1;
|
||||||
protected static final int WIDTH_MODE_COMPACT = 2;
|
protected static final int WIDTH_MODE_COMPACT = 2;
|
||||||
|
/** @since 3.7 */ protected static final int WIDTH_MODE_ICON_ONLY = 3;
|
||||||
|
|
||||||
// tab rotation
|
// tab rotation
|
||||||
/** @since 3.3 */ protected static final int NONE = -1;
|
/** @since 3.3 */ protected static final int NONE = -1;
|
||||||
@@ -670,15 +671,15 @@ public class FlatTabbedPaneUI
|
|||||||
protected Object applyStyleProperty( String key, Object value ) {
|
protected Object applyStyleProperty( String key, Object value ) {
|
||||||
// close icon
|
// close icon
|
||||||
if( key.startsWith( "close" ) ) {
|
if( key.startsWith( "close" ) ) {
|
||||||
if( !(closeIcon instanceof FlatTabbedPaneCloseIcon) )
|
if( !(closeIcon instanceof StyleableObject) )
|
||||||
return new UnknownStyleException( key );
|
throw new UnknownStyleException( key );
|
||||||
|
|
||||||
if( closeIconShared ) {
|
if( closeIconShared ) {
|
||||||
closeIcon = FlatStylingSupport.cloneIcon( closeIcon );
|
closeIcon = FlatStylingSupport.cloneIcon( closeIcon );
|
||||||
closeIconShared = false;
|
closeIconShared = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ((FlatTabbedPaneCloseIcon)closeIcon).applyStyleProperty( key, value );
|
return ((StyleableObject)closeIcon).applyStyleProperty( key, value );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( value instanceof String ) {
|
if( value instanceof String ) {
|
||||||
@@ -720,8 +721,8 @@ public class FlatTabbedPaneUI
|
|||||||
infos.put( "tabAreaInsets", Insets.class );
|
infos.put( "tabAreaInsets", Insets.class );
|
||||||
infos.put( "textIconGap", int.class );
|
infos.put( "textIconGap", int.class );
|
||||||
FlatStylingSupport.collectAnnotatedStyleableInfos( this, infos );
|
FlatStylingSupport.collectAnnotatedStyleableInfos( this, infos );
|
||||||
if( closeIcon instanceof FlatTabbedPaneCloseIcon )
|
if( closeIcon instanceof StyleableObject )
|
||||||
infos.putAll( ((FlatTabbedPaneCloseIcon)closeIcon).getStyleableInfos() );
|
infos.putAll( ((StyleableObject)closeIcon).getStyleableInfos() );
|
||||||
return infos;
|
return infos;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -730,8 +731,8 @@ public class FlatTabbedPaneUI
|
|||||||
public Object getStyleableValue( JComponent c, String key ) {
|
public Object getStyleableValue( JComponent c, String key ) {
|
||||||
// close icon
|
// close icon
|
||||||
if( key.startsWith( "close" ) ) {
|
if( key.startsWith( "close" ) ) {
|
||||||
return (closeIcon instanceof FlatTabbedPaneCloseIcon)
|
return (closeIcon instanceof StyleableObject)
|
||||||
? ((FlatTabbedPaneCloseIcon)closeIcon).getStyleableValue( key )
|
? ((StyleableObject)closeIcon).getStyleableValue( key )
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -780,6 +781,7 @@ public class FlatTabbedPaneUI
|
|||||||
case WIDTH_MODE_PREFERRED: return TABBED_PANE_TAB_WIDTH_MODE_PREFERRED;
|
case WIDTH_MODE_PREFERRED: return TABBED_PANE_TAB_WIDTH_MODE_PREFERRED;
|
||||||
case WIDTH_MODE_EQUAL: return TABBED_PANE_TAB_WIDTH_MODE_EQUAL;
|
case WIDTH_MODE_EQUAL: return TABBED_PANE_TAB_WIDTH_MODE_EQUAL;
|
||||||
case WIDTH_MODE_COMPACT: return TABBED_PANE_TAB_WIDTH_MODE_COMPACT;
|
case WIDTH_MODE_COMPACT: return TABBED_PANE_TAB_WIDTH_MODE_COMPACT;
|
||||||
|
case WIDTH_MODE_ICON_ONLY: return TABBED_PANE_TAB_WIDTH_MODE_ICON_ONLY;
|
||||||
}
|
}
|
||||||
|
|
||||||
case "tabRotation":
|
case "tabRotation":
|
||||||
@@ -926,9 +928,10 @@ public class FlatTabbedPaneUI
|
|||||||
|
|
||||||
int tabWidth;
|
int tabWidth;
|
||||||
Icon icon;
|
Icon icon;
|
||||||
if( tabWidthMode == WIDTH_MODE_COMPACT &&
|
if( ((tabWidthMode == WIDTH_MODE_COMPACT &&
|
||||||
tabIndex != tabPane.getSelectedIndex() &&
|
tabIndex != tabPane.getSelectedIndex() &&
|
||||||
isHorizontalOrRotated( tabPlacement ) &&
|
isHorizontalOrRotated( tabPlacement )) ||
|
||||||
|
tabWidthMode == WIDTH_MODE_ICON_ONLY) &&
|
||||||
tabPane.getTabComponentAt( tabIndex ) == null &&
|
tabPane.getTabComponentAt( tabIndex ) == null &&
|
||||||
(icon = getIconForTab( tabIndex )) != null )
|
(icon = getIconForTab( tabIndex )) != null )
|
||||||
{
|
{
|
||||||
@@ -1247,7 +1250,8 @@ public class FlatTabbedPaneUI
|
|||||||
Font font = tabPane.getFont();
|
Font font = tabPane.getFont();
|
||||||
FontMetrics metrics = tabPane.getFontMetrics( font );
|
FontMetrics metrics = tabPane.getFontMetrics( font );
|
||||||
boolean isCompact = (icon != null && !isSelected && getTabWidthMode() == WIDTH_MODE_COMPACT && isHorizontalOrRotated( tabPlacement ));
|
boolean isCompact = (icon != null && !isSelected && getTabWidthMode() == WIDTH_MODE_COMPACT && isHorizontalOrRotated( tabPlacement ));
|
||||||
if( isCompact )
|
boolean isIconOnly = (icon != null && getTabWidthMode() == WIDTH_MODE_ICON_ONLY);
|
||||||
|
if( isCompact || isIconOnly )
|
||||||
title = null;
|
title = null;
|
||||||
String clippedTitle = layoutAndClipLabel( tabPlacement, metrics, tabIndex, title, icon, tabRect, iconRect, textRect, isSelected );
|
String clippedTitle = layoutAndClipLabel( tabPlacement, metrics, tabIndex, title, icon, tabRect, iconRect, textRect, isSelected );
|
||||||
|
|
||||||
@@ -1283,7 +1287,7 @@ debug*/
|
|||||||
}
|
}
|
||||||
|
|
||||||
// paint title and icon
|
// paint title and icon
|
||||||
if( !isCompact )
|
if( !isCompact || isIconOnly )
|
||||||
paintText( g, tabPlacement, font, metrics, tabIndex, clippedTitle, textRect, isSelected );
|
paintText( g, tabPlacement, font, metrics, tabIndex, clippedTitle, textRect, isSelected );
|
||||||
paintIcon( g, tabPlacement, tabIndex, icon, iconRect, isSelected );
|
paintIcon( g, tabPlacement, tabIndex, icon, iconRect, isSelected );
|
||||||
}
|
}
|
||||||
@@ -2160,6 +2164,7 @@ debug*/
|
|||||||
case TABBED_PANE_TAB_WIDTH_MODE_PREFERRED: return WIDTH_MODE_PREFERRED;
|
case TABBED_PANE_TAB_WIDTH_MODE_PREFERRED: return WIDTH_MODE_PREFERRED;
|
||||||
case TABBED_PANE_TAB_WIDTH_MODE_EQUAL: return WIDTH_MODE_EQUAL;
|
case TABBED_PANE_TAB_WIDTH_MODE_EQUAL: return WIDTH_MODE_EQUAL;
|
||||||
case TABBED_PANE_TAB_WIDTH_MODE_COMPACT: return WIDTH_MODE_COMPACT;
|
case TABBED_PANE_TAB_WIDTH_MODE_COMPACT: return WIDTH_MODE_COMPACT;
|
||||||
|
case TABBED_PANE_TAB_WIDTH_MODE_ICON_ONLY: return WIDTH_MODE_ICON_ONLY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2508,7 +2513,7 @@ debug*/
|
|||||||
// 2. text of label or text component in custom tab component (including children)
|
// 2. text of label or text component in custom tab component (including children)
|
||||||
// 3. accessible name of tab
|
// 3. accessible name of tab
|
||||||
// 4. accessible name of custom tab component (including children)
|
// 4. accessible name of custom tab component (including children)
|
||||||
// 5. string "n. Tab"
|
// 5. string "n. Tab", if tab does not have an icon
|
||||||
String title = tabPane.getTitleAt( tabIndex );
|
String title = tabPane.getTitleAt( tabIndex );
|
||||||
if( StringUtils.isEmpty( title ) ) {
|
if( StringUtils.isEmpty( title ) ) {
|
||||||
Component tabComp = tabPane.getTabComponentAt( tabIndex );
|
Component tabComp = tabPane.getTabComponentAt( tabIndex );
|
||||||
@@ -2518,7 +2523,7 @@ debug*/
|
|||||||
title = tabPane.getAccessibleContext().getAccessibleChild( tabIndex ).getAccessibleContext().getAccessibleName();
|
title = tabPane.getAccessibleContext().getAccessibleChild( tabIndex ).getAccessibleContext().getAccessibleName();
|
||||||
if( StringUtils.isEmpty( title ) && tabComp instanceof Accessible )
|
if( StringUtils.isEmpty( title ) && tabComp instanceof Accessible )
|
||||||
title = findTabTitleInAccessible( (Accessible) tabComp );
|
title = findTabTitleInAccessible( (Accessible) tabComp );
|
||||||
if( StringUtils.isEmpty( title ) )
|
if( StringUtils.isEmpty( title ) && tabPane.getIconAt( tabIndex ) == null )
|
||||||
title = (tabIndex + 1) + ". Tab";
|
title = (tabIndex + 1) + ". Tab";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2539,6 +2544,12 @@ debug*/
|
|||||||
if( !tabPane.isEnabled() || !tabPane.isEnabledAt( tabIndex ) )
|
if( !tabPane.isEnabled() || !tabPane.isEnabledAt( tabIndex ) )
|
||||||
menuItem.setEnabled( false );
|
menuItem.setEnabled( false );
|
||||||
|
|
||||||
|
// make menu item smaller if it contains icon only
|
||||||
|
if( StringUtils.isEmpty( title ) ) {
|
||||||
|
menuItem.putClientProperty( FlatClientProperties.STYLE,
|
||||||
|
"minimumWidth: 0; textNoAcceleratorGap: 0; acceleratorArrowGap: 0" );
|
||||||
|
}
|
||||||
|
|
||||||
menuItem.addActionListener( e -> selectTab( tabIndex ) );
|
menuItem.addActionListener( e -> selectTab( tabIndex ) );
|
||||||
return menuItem;
|
return menuItem;
|
||||||
}
|
}
|
||||||
@@ -2707,8 +2718,13 @@ debug*/
|
|||||||
|
|
||||||
// because this listener receives mouse events for the whole tabbed pane,
|
// because this listener receives mouse events for the whole tabbed pane,
|
||||||
// we have to check whether the mouse is located over the viewport
|
// we have to check whether the mouse is located over the viewport
|
||||||
if( !isInViewport( e.getX(), e.getY() ) )
|
if( !isInViewport( e.getX(), e.getY() ) ) {
|
||||||
|
// if it is not in the viewport, retarget the event to a parent container
|
||||||
|
// which might support scrolling (e.g. a surrounding ScrollPane)
|
||||||
|
Container parent = tabPane.getParent();
|
||||||
|
parent.dispatchEvent( SwingUtilities.convertMouseEvent( tabPane, e, parent ) );
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
lastMouseX = e.getX();
|
lastMouseX = e.getX();
|
||||||
lastMouseY = e.getY();
|
lastMouseY = e.getY();
|
||||||
|
|||||||
@@ -34,11 +34,11 @@ import java.awt.event.ComponentListener;
|
|||||||
import java.awt.event.FocusEvent;
|
import java.awt.event.FocusEvent;
|
||||||
import java.awt.event.FocusListener;
|
import java.awt.event.FocusListener;
|
||||||
import java.awt.geom.Rectangle2D;
|
import java.awt.geom.Rectangle2D;
|
||||||
import java.beans.PropertyChangeEvent;
|
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
import javax.swing.ActionMap;
|
import javax.swing.ActionMap;
|
||||||
|
import javax.swing.Icon;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JScrollPane;
|
import javax.swing.JScrollPane;
|
||||||
import javax.swing.JTable;
|
import javax.swing.JTable;
|
||||||
@@ -65,6 +65,7 @@ import com.formdev.flatlaf.FlatClientProperties;
|
|||||||
import com.formdev.flatlaf.icons.FlatCheckBoxIcon;
|
import com.formdev.flatlaf.icons.FlatCheckBoxIcon;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||||
|
import com.formdev.flatlaf.ui.FlatUIUtils.FlatPropertyWatcher;
|
||||||
import com.formdev.flatlaf.util.Graphics2DProxy;
|
import com.formdev.flatlaf.util.Graphics2DProxy;
|
||||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||||
import com.formdev.flatlaf.util.LoggingFacade;
|
import com.formdev.flatlaf.util.LoggingFacade;
|
||||||
@@ -188,29 +189,26 @@ public class FlatTableUI
|
|||||||
if( rowHeight > 0 )
|
if( rowHeight > 0 )
|
||||||
LookAndFeel.installProperty( table, "rowHeight", UIScale.scale( rowHeight ) );
|
LookAndFeel.installProperty( table, "rowHeight", UIScale.scale( rowHeight ) );
|
||||||
|
|
||||||
FlatTablePropertyWatcher watcher = FlatTablePropertyWatcher.get( table );
|
if( !showHorizontalLines ) {
|
||||||
if( watcher != null )
|
FlatPropertyWatcher.runIfNotChanged( table, "showHorizontalLines", () -> {
|
||||||
watcher.enabled = false;
|
|
||||||
|
|
||||||
if( !showHorizontalLines && (watcher == null || !watcher.showHorizontalLinesChanged) ) {
|
|
||||||
oldShowHorizontalLines = table.getShowHorizontalLines();
|
oldShowHorizontalLines = table.getShowHorizontalLines();
|
||||||
table.setShowHorizontalLines( false );
|
table.setShowHorizontalLines( false );
|
||||||
|
} );
|
||||||
}
|
}
|
||||||
if( !showVerticalLines && (watcher == null || !watcher.showVerticalLinesChanged) ) {
|
if( !showVerticalLines ) {
|
||||||
|
FlatPropertyWatcher.runIfNotChanged( table, "showVerticalLines", () -> {
|
||||||
oldShowVerticalLines = table.getShowVerticalLines();
|
oldShowVerticalLines = table.getShowVerticalLines();
|
||||||
table.setShowVerticalLines( false );
|
table.setShowVerticalLines( false );
|
||||||
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( intercellSpacing != null && (watcher == null || !watcher.intercellSpacingChanged) ) {
|
if( intercellSpacing != null ) {
|
||||||
|
FlatPropertyWatcher.runIfNotChanged( table, "rowMargin", () -> {
|
||||||
oldIntercellSpacing = table.getIntercellSpacing();
|
oldIntercellSpacing = table.getIntercellSpacing();
|
||||||
table.setIntercellSpacing( intercellSpacing );
|
table.setIntercellSpacing( intercellSpacing );
|
||||||
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( watcher != null )
|
|
||||||
watcher.enabled = true;
|
|
||||||
else
|
|
||||||
table.addPropertyChangeListener( new FlatTablePropertyWatcher() );
|
|
||||||
|
|
||||||
// install boolean renderer
|
// install boolean renderer
|
||||||
oldBooleanRenderer = table.getDefaultRenderer( Boolean.class );
|
oldBooleanRenderer = table.getDefaultRenderer( Boolean.class );
|
||||||
if( oldBooleanRenderer instanceof UIResource )
|
if( oldBooleanRenderer instanceof UIResource )
|
||||||
@@ -230,25 +228,24 @@ public class FlatTableUI
|
|||||||
|
|
||||||
oldStyleValues = null;
|
oldStyleValues = null;
|
||||||
|
|
||||||
FlatTablePropertyWatcher watcher = FlatTablePropertyWatcher.get( table );
|
|
||||||
if( watcher != null )
|
|
||||||
watcher.enabled = false;
|
|
||||||
|
|
||||||
// restore old show horizontal/vertical lines (if not modified)
|
// restore old show horizontal/vertical lines (if not modified)
|
||||||
if( !showHorizontalLines && oldShowHorizontalLines && !table.getShowHorizontalLines() &&
|
if( !showHorizontalLines && oldShowHorizontalLines && !table.getShowHorizontalLines() ) {
|
||||||
(watcher == null || !watcher.showHorizontalLinesChanged) )
|
FlatPropertyWatcher.runIfNotChanged( table, "showHorizontalLines", () -> {
|
||||||
table.setShowHorizontalLines( true );
|
table.setShowHorizontalLines( true );
|
||||||
if( !showVerticalLines && oldShowVerticalLines && !table.getShowVerticalLines() &&
|
} );
|
||||||
(watcher == null || !watcher.showVerticalLinesChanged) )
|
}
|
||||||
|
if( !showVerticalLines && oldShowVerticalLines && !table.getShowVerticalLines() ) {
|
||||||
|
FlatPropertyWatcher.runIfNotChanged( table, "showVerticalLines", () -> {
|
||||||
table.setShowVerticalLines( true );
|
table.setShowVerticalLines( true );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
// restore old intercell spacing (if not modified)
|
// restore old intercell spacing (if not modified)
|
||||||
if( intercellSpacing != null && table.getIntercellSpacing().equals( intercellSpacing ) &&
|
if( intercellSpacing != null && table.getIntercellSpacing().equals( intercellSpacing ) ) {
|
||||||
(watcher == null || !watcher.intercellSpacingChanged) )
|
FlatPropertyWatcher.runIfNotChanged( table, "rowMargin", () -> {
|
||||||
table.setIntercellSpacing( oldIntercellSpacing );
|
table.setIntercellSpacing( oldIntercellSpacing );
|
||||||
|
} );
|
||||||
if( watcher != null )
|
}
|
||||||
watcher.enabled = true;
|
|
||||||
|
|
||||||
// uninstall boolean renderer
|
// uninstall boolean renderer
|
||||||
if( table.getDefaultRenderer( Boolean.class ) instanceof FlatBooleanRenderer ) {
|
if( table.getDefaultRenderer( Boolean.class ) instanceof FlatBooleanRenderer ) {
|
||||||
@@ -937,48 +934,6 @@ public class FlatTableUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//---- class FlatTablePropertyWatcher -------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Listener that watches for change of some table properties from application code.
|
|
||||||
* This information is used in {@link FlatTableUI#installDefaults()} and
|
|
||||||
* {@link FlatTableUI#uninstallDefaults()} to decide whether FlatLaf modifies those properties.
|
|
||||||
* If they are modified in application code, FlatLaf no longer changes them.
|
|
||||||
*
|
|
||||||
* The listener is added once for each table, but never removed.
|
|
||||||
* So switching Laf/theme reuses existing listener.
|
|
||||||
*/
|
|
||||||
private static class FlatTablePropertyWatcher
|
|
||||||
implements PropertyChangeListener
|
|
||||||
{
|
|
||||||
boolean enabled = true;
|
|
||||||
boolean showHorizontalLinesChanged;
|
|
||||||
boolean showVerticalLinesChanged;
|
|
||||||
boolean intercellSpacingChanged;
|
|
||||||
|
|
||||||
static FlatTablePropertyWatcher get( JTable table ) {
|
|
||||||
for( PropertyChangeListener l : table.getPropertyChangeListeners() ) {
|
|
||||||
if( l instanceof FlatTablePropertyWatcher )
|
|
||||||
return (FlatTablePropertyWatcher) l;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
//---- interface PropertyChangeListener ----
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void propertyChange( PropertyChangeEvent e ) {
|
|
||||||
if( !enabled )
|
|
||||||
return;
|
|
||||||
|
|
||||||
switch( e.getPropertyName() ) {
|
|
||||||
case "showHorizontalLines": showHorizontalLinesChanged = true; break;
|
|
||||||
case "showVerticalLines": showVerticalLinesChanged = true; break;
|
|
||||||
case "rowMargin": intercellSpacingChanged = true; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//---- class FlatBooleanRenderer ------------------------------------------
|
//---- class FlatBooleanRenderer ------------------------------------------
|
||||||
|
|
||||||
private static class FlatBooleanRenderer
|
private static class FlatBooleanRenderer
|
||||||
@@ -989,12 +944,14 @@ public class FlatTableUI
|
|||||||
|
|
||||||
FlatBooleanRenderer() {
|
FlatBooleanRenderer() {
|
||||||
setHorizontalAlignment( SwingConstants.CENTER );
|
setHorizontalAlignment( SwingConstants.CENTER );
|
||||||
setIcon( new FlatCheckBoxIcon() {
|
Icon icon = new FlatCheckBoxIcon() {
|
||||||
@Override
|
@Override
|
||||||
protected boolean isSelected( Component c ) {
|
protected boolean isSelected( Component c ) {
|
||||||
return selected;
|
return selected;
|
||||||
}
|
}
|
||||||
} );
|
};
|
||||||
|
setIcon( icon );
|
||||||
|
setDisabledIcon( icon );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -628,7 +628,7 @@ debug*/
|
|||||||
/**
|
/**
|
||||||
* Returns the rectangle used to paint leading and trailing icons.
|
* Returns the rectangle used to paint leading and trailing icons.
|
||||||
* It invokes {@code super.getVisibleEditorRect()} and reduces left and/or
|
* It invokes {@code super.getVisibleEditorRect()} and reduces left and/or
|
||||||
* right margin if the text field has leading or trailing icons or components.
|
* right insets if the text field has leading or trailing icons or components.
|
||||||
* Also, the preferred widths of leading and trailing components are removed.
|
* Also, the preferred widths of leading and trailing components are removed.
|
||||||
*
|
*
|
||||||
* @since 2
|
* @since 2
|
||||||
@@ -660,24 +660,24 @@ debug*/
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if a leading/trailing icons (or components) are shown, then the left/right margins are reduced
|
// if a leading/trailing icons (or components) are shown, then the left/right insets are reduced
|
||||||
// to the top margin, which places the icon nicely centered on left/right side
|
// to the top inset, which places the icon nicely centered on left/right side
|
||||||
if( leftVisible || (ltr ? hasLeadingIcon() : hasTrailingIcon()) ) {
|
if( leftVisible || (ltr ? hasLeadingIcon() : hasTrailingIcon()) ) {
|
||||||
// reduce left margin
|
// reduce left inset
|
||||||
Insets margin = getComponent().getMargin();
|
Insets insets = getComponent().getInsets();
|
||||||
int newLeftMargin = Math.min( margin.left, margin.top );
|
int newLeftInset = Math.min( insets.left, insets.top );
|
||||||
if( newLeftMargin < margin.left ) {
|
if( newLeftInset < insets.left ) {
|
||||||
int diff = scale( margin.left - newLeftMargin );
|
int diff = insets.left - newLeftInset;
|
||||||
r.x -= diff;
|
r.x -= diff;
|
||||||
r.width += diff;
|
r.width += diff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( rightVisible || (ltr ? hasTrailingIcon() : hasLeadingIcon()) ) {
|
if( rightVisible || (ltr ? hasTrailingIcon() : hasLeadingIcon()) ) {
|
||||||
// reduce right margin
|
// reduce right inset
|
||||||
Insets margin = getComponent().getMargin();
|
Insets insets = getComponent().getInsets();
|
||||||
int newRightMargin = Math.min( margin.right, margin.top );
|
int newRightInset = Math.min( insets.right, insets.top );
|
||||||
if( newRightMargin < margin.left )
|
if( newRightInset < insets.left )
|
||||||
r.width += scale( margin.right - newRightMargin );
|
r.width += insets.right - newRightInset;
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure that width and height are not negative
|
// make sure that width and height are not negative
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -90,13 +89,16 @@ import com.formdev.flatlaf.util.UIScale;
|
|||||||
* @uiDefault TitlePane.iconSize Dimension
|
* @uiDefault TitlePane.iconSize Dimension
|
||||||
* @uiDefault TitlePane.iconMargins Insets
|
* @uiDefault TitlePane.iconMargins Insets
|
||||||
* @uiDefault TitlePane.titleMargins Insets
|
* @uiDefault TitlePane.titleMargins Insets
|
||||||
* @uiDefault TitlePane.menuBarEmbedded boolean
|
|
||||||
* @uiDefault TitlePane.titleMinimumWidth int
|
* @uiDefault TitlePane.titleMinimumWidth int
|
||||||
* @uiDefault TitlePane.buttonMinimumWidth int
|
* @uiDefault TitlePane.buttonMinimumWidth int
|
||||||
* @uiDefault TitlePane.buttonMaximizedHeight int
|
* @uiDefault TitlePane.buttonMaximizedHeight int
|
||||||
|
* @uiDefault TitlePane.buttonsGap int
|
||||||
|
* @uiDefault TitlePane.buttonsMargins Insets
|
||||||
|
* @uiDefault TitlePane.buttonsFillVertically boolean
|
||||||
* @uiDefault TitlePane.centerTitle boolean
|
* @uiDefault TitlePane.centerTitle boolean
|
||||||
* @uiDefault TitlePane.centerTitleIfMenuBarEmbedded boolean
|
* @uiDefault TitlePane.centerTitleIfMenuBarEmbedded boolean
|
||||||
* @uiDefault TitlePane.showIconBesideTitle boolean
|
* @uiDefault TitlePane.showIconBesideTitle boolean
|
||||||
|
* @uiDefault TitlePane.menuBarEmbedded boolean
|
||||||
* @uiDefault TitlePane.menuBarTitleGap int
|
* @uiDefault TitlePane.menuBarTitleGap int
|
||||||
* @uiDefault TitlePane.menuBarTitleMinimumGap int
|
* @uiDefault TitlePane.menuBarTitleMinimumGap int
|
||||||
* @uiDefault TitlePane.closeIcon Icon
|
* @uiDefault TitlePane.closeIcon Icon
|
||||||
@@ -124,9 +126,14 @@ public class FlatTitlePane
|
|||||||
/** @since 2.5 */ protected final boolean showIconInDialogs;
|
/** @since 2.5 */ protected final boolean showIconInDialogs;
|
||||||
/** @since 2 */ protected final int noIconLeftGap;
|
/** @since 2 */ protected final int noIconLeftGap;
|
||||||
protected final Dimension iconSize;
|
protected final Dimension iconSize;
|
||||||
|
/** @since 3.6 */ protected final Insets iconMargins;
|
||||||
|
/** @since 3.6 */ protected final Insets titleMargins;
|
||||||
/** @since 2.4 */ protected final int titleMinimumWidth;
|
/** @since 2.4 */ protected final int titleMinimumWidth;
|
||||||
/** @since 2.4 */ protected final int buttonMinimumWidth;
|
/** @since 2.4 */ protected final int buttonMinimumWidth;
|
||||||
protected final int buttonMaximizedHeight;
|
protected final int buttonMaximizedHeight;
|
||||||
|
/** @since 3.6 */ protected final int buttonsGap;
|
||||||
|
/** @since 3.6 */ protected final Insets buttonsMargins;
|
||||||
|
/** @since 3.6 */ protected final boolean buttonsFillVertically;
|
||||||
protected final boolean centerTitle;
|
protected final boolean centerTitle;
|
||||||
protected final boolean centerTitleIfMenuBarEmbedded;
|
protected final boolean centerTitleIfMenuBarEmbedded;
|
||||||
/** @since 2.4 */ protected final boolean showIconBesideTitle;
|
/** @since 2.4 */ protected final boolean showIconBesideTitle;
|
||||||
@@ -146,6 +153,9 @@ public class FlatTitlePane
|
|||||||
protected JButton restoreButton;
|
protected JButton restoreButton;
|
||||||
protected JButton closeButton;
|
protected JButton closeButton;
|
||||||
|
|
||||||
|
private JComponent iconifyMaximizeGapComp;
|
||||||
|
private JComponent maximizeCloseGapComp;
|
||||||
|
|
||||||
protected Window window;
|
protected Window window;
|
||||||
|
|
||||||
private final Handler handler;
|
private final Handler handler;
|
||||||
@@ -180,9 +190,7 @@ public class FlatTitlePane
|
|||||||
public FlatTitlePane( JRootPane rootPane ) {
|
public FlatTitlePane( JRootPane rootPane ) {
|
||||||
this.rootPane = rootPane;
|
this.rootPane = rootPane;
|
||||||
|
|
||||||
Window w = SwingUtilities.getWindowAncestor( rootPane );
|
windowStyle = getWindowStyle( rootPane );
|
||||||
String defaultWindowStyle = (w != null && w.getType() == Window.Type.UTILITY) ? WINDOW_STYLE_SMALL : null;
|
|
||||||
windowStyle = clientProperty( rootPane, WINDOW_STYLE, defaultWindowStyle, String.class );
|
|
||||||
|
|
||||||
titleFont = FlatUIUtils.getSubUIFont( "TitlePane.font", windowStyle );
|
titleFont = FlatUIUtils.getSubUIFont( "TitlePane.font", windowStyle );
|
||||||
activeBackground = FlatUIUtils.getSubUIColor( "TitlePane.background", windowStyle );
|
activeBackground = FlatUIUtils.getSubUIColor( "TitlePane.background", windowStyle );
|
||||||
@@ -197,9 +205,14 @@ public class FlatTitlePane
|
|||||||
showIconInDialogs = FlatUIUtils.getSubUIBoolean( "TitlePane.showIconInDialogs", windowStyle, true );
|
showIconInDialogs = FlatUIUtils.getSubUIBoolean( "TitlePane.showIconInDialogs", windowStyle, true );
|
||||||
noIconLeftGap = FlatUIUtils.getSubUIInt( "TitlePane.noIconLeftGap", windowStyle, 8 );
|
noIconLeftGap = FlatUIUtils.getSubUIInt( "TitlePane.noIconLeftGap", windowStyle, 8 );
|
||||||
iconSize = FlatUIUtils.getSubUIDimension( "TitlePane.iconSize", windowStyle );
|
iconSize = FlatUIUtils.getSubUIDimension( "TitlePane.iconSize", windowStyle );
|
||||||
|
iconMargins = FlatUIUtils.getSubUIInsets( "TitlePane.iconMargins", windowStyle );
|
||||||
|
titleMargins = FlatUIUtils.getSubUIInsets( "TitlePane.titleMargins", windowStyle );
|
||||||
titleMinimumWidth = FlatUIUtils.getSubUIInt( "TitlePane.titleMinimumWidth", windowStyle, 60 );
|
titleMinimumWidth = FlatUIUtils.getSubUIInt( "TitlePane.titleMinimumWidth", windowStyle, 60 );
|
||||||
buttonMinimumWidth = FlatUIUtils.getSubUIInt( "TitlePane.buttonMinimumWidth", windowStyle, 30 );
|
buttonMinimumWidth = FlatUIUtils.getSubUIInt( "TitlePane.buttonMinimumWidth", windowStyle, 30 );
|
||||||
buttonMaximizedHeight = FlatUIUtils.getSubUIInt( "TitlePane.buttonMaximizedHeight", windowStyle, 0 );
|
buttonMaximizedHeight = FlatUIUtils.getSubUIInt( "TitlePane.buttonMaximizedHeight", windowStyle, 0 );
|
||||||
|
buttonsGap = FlatUIUtils.getSubUIInt( "TitlePane.buttonsGap", windowStyle, 0 );
|
||||||
|
buttonsMargins = FlatUIUtils.getSubUIInsets( "TitlePane.buttonsMargins", windowStyle );
|
||||||
|
buttonsFillVertically = FlatUIUtils.getSubUIBoolean( "TitlePane.buttonsFillVertically", windowStyle, true );
|
||||||
centerTitle = FlatUIUtils.getSubUIBoolean( "TitlePane.centerTitle", windowStyle, false );
|
centerTitle = FlatUIUtils.getSubUIBoolean( "TitlePane.centerTitle", windowStyle, false );
|
||||||
centerTitleIfMenuBarEmbedded = FlatUIUtils.getSubUIBoolean( "TitlePane.centerTitleIfMenuBarEmbedded", windowStyle, true );
|
centerTitleIfMenuBarEmbedded = FlatUIUtils.getSubUIBoolean( "TitlePane.centerTitleIfMenuBarEmbedded", windowStyle, true );
|
||||||
showIconBesideTitle = FlatUIUtils.getSubUIBoolean( "TitlePane.showIconBesideTitle", windowStyle, false );
|
showIconBesideTitle = FlatUIUtils.getSubUIBoolean( "TitlePane.showIconBesideTitle", windowStyle, false );
|
||||||
@@ -229,6 +242,12 @@ public class FlatTitlePane
|
|||||||
applyComponentOrientation( rootPane.getComponentOrientation() );
|
applyComponentOrientation( rootPane.getComponentOrientation() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static String getWindowStyle( JRootPane rootPane ) {
|
||||||
|
Window w = SwingUtilities.getWindowAncestor( rootPane );
|
||||||
|
String defaultWindowStyle = (w != null && w.getType() == Window.Type.UTILITY) ? WINDOW_STYLE_SMALL : null;
|
||||||
|
return clientProperty( rootPane, WINDOW_STYLE, defaultWindowStyle, String.class );
|
||||||
|
}
|
||||||
|
|
||||||
protected FlatTitlePaneBorder createTitlePaneBorder() {
|
protected FlatTitlePaneBorder createTitlePaneBorder() {
|
||||||
return new FlatTitlePaneBorder();
|
return new FlatTitlePaneBorder();
|
||||||
}
|
}
|
||||||
@@ -246,8 +265,8 @@ public class FlatTitlePane
|
|||||||
setUI( new FlatTitleLabelUI() );
|
setUI( new FlatTitleLabelUI() );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
iconLabel.setBorder( new FlatEmptyBorder( FlatUIUtils.getSubUIInsets( "TitlePane.iconMargins", windowStyle ) ) );
|
iconLabel.setBorder( new FlatEmptyBorder( iconMargins ) );
|
||||||
titleLabel.setBorder( new FlatEmptyBorder( FlatUIUtils.getSubUIInsets( "TitlePane.titleMargins", windowStyle ) ) );
|
titleLabel.setBorder( new FlatEmptyBorder( titleMargins ) );
|
||||||
|
|
||||||
leftPanel.setLayout( new BoxLayout( leftPanel, BoxLayout.LINE_AXIS ) );
|
leftPanel.setLayout( new BoxLayout( leftPanel, BoxLayout.LINE_AXIS ) );
|
||||||
leftPanel.setOpaque( false );
|
leftPanel.setOpaque( false );
|
||||||
@@ -350,10 +369,15 @@ public class FlatTitlePane
|
|||||||
restoreButton = createButton( "TitlePane.restoreIcon", "Restore", e -> restore() );
|
restoreButton = createButton( "TitlePane.restoreIcon", "Restore", e -> restore() );
|
||||||
closeButton = createButton( "TitlePane.closeIcon", "Close", e -> close() );
|
closeButton = createButton( "TitlePane.closeIcon", "Close", e -> close() );
|
||||||
|
|
||||||
|
iconifyMaximizeGapComp = createButtonsGapComp();
|
||||||
|
maximizeCloseGapComp = createButtonsGapComp();
|
||||||
|
|
||||||
// initially hide buttons that are only supported in frames
|
// initially hide buttons that are only supported in frames
|
||||||
iconifyButton.setVisible( false );
|
iconifyButton.setVisible( false );
|
||||||
maximizeButton.setVisible( false );
|
maximizeButton.setVisible( false );
|
||||||
restoreButton.setVisible( false );
|
restoreButton.setVisible( false );
|
||||||
|
iconifyMaximizeGapComp.setVisible( false );
|
||||||
|
maximizeCloseGapComp.setVisible( false );
|
||||||
|
|
||||||
buttonPanel = new JPanel() {
|
buttonPanel = new JPanel() {
|
||||||
@Override
|
@Override
|
||||||
@@ -365,12 +389,13 @@ public class FlatTitlePane
|
|||||||
|
|
||||||
if( buttonMaximizedHeight > 0 && isWindowMaximized() && !hasVisibleEmbeddedMenuBar( rootPane.getJMenuBar() ) ) {
|
if( buttonMaximizedHeight > 0 && isWindowMaximized() && !hasVisibleEmbeddedMenuBar( rootPane.getJMenuBar() ) ) {
|
||||||
// make title pane height smaller when frame is maximized
|
// make title pane height smaller when frame is maximized
|
||||||
size = new Dimension( size.width, Math.min( size.height, UIScale.scale( buttonMaximizedHeight ) ) );
|
size = new Dimension( size.width, Math.min( size.height, UIScale.scale( buttonMaximizedHeight + buttonsMargins.top + buttonsMargins.bottom ) ) );
|
||||||
}
|
}
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
buttonPanel.setOpaque( false );
|
buttonPanel.setOpaque( false );
|
||||||
|
buttonPanel.setBorder( FlatUIUtils.nonUIResource( new FlatEmptyBorder( buttonsMargins ) ) );
|
||||||
buttonPanel.setLayout( new BoxLayout( buttonPanel, BoxLayout.LINE_AXIS ) );
|
buttonPanel.setLayout( new BoxLayout( buttonPanel, BoxLayout.LINE_AXIS ) );
|
||||||
if( rootPane.getWindowDecorationStyle() == JRootPane.FRAME ) {
|
if( rootPane.getWindowDecorationStyle() == JRootPane.FRAME ) {
|
||||||
// JRootPane.FRAME works only for frames (and not for dialogs)
|
// JRootPane.FRAME works only for frames (and not for dialogs)
|
||||||
@@ -379,8 +404,10 @@ public class FlatTitlePane
|
|||||||
// later in frameStateChanged(), which is invoked from addNotify()
|
// later in frameStateChanged(), which is invoked from addNotify()
|
||||||
|
|
||||||
buttonPanel.add( iconifyButton );
|
buttonPanel.add( iconifyButton );
|
||||||
|
buttonPanel.add( iconifyMaximizeGapComp );
|
||||||
buttonPanel.add( maximizeButton );
|
buttonPanel.add( maximizeButton );
|
||||||
buttonPanel.add( restoreButton );
|
buttonPanel.add( restoreButton );
|
||||||
|
buttonPanel.add( maximizeCloseGapComp );
|
||||||
}
|
}
|
||||||
buttonPanel.add( closeButton );
|
buttonPanel.add( closeButton );
|
||||||
|
|
||||||
@@ -397,13 +424,17 @@ public class FlatTitlePane
|
|||||||
@Override
|
@Override
|
||||||
public Dimension getMinimumSize() {
|
public Dimension getMinimumSize() {
|
||||||
// allow the button to shrink if space is rare
|
// allow the button to shrink if space is rare
|
||||||
return new Dimension( UIScale.scale( buttonMinimumWidth ), super.getMinimumSize().height );
|
return new Dimension(
|
||||||
|
Math.min( UIScale.scale( buttonMinimumWidth ), super.getPreferredSize().width ),
|
||||||
|
super.getMinimumSize().height );
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public Dimension getMaximumSize() {
|
public Dimension getMaximumSize() {
|
||||||
// allow the button to fill whole button area height
|
// allow the button to fill whole button area height
|
||||||
// see also BasicMenuUI.getMaximumSize()
|
// see also BasicMenuUI.getMaximumSize()
|
||||||
return new Dimension( super.getMaximumSize().width, Short.MAX_VALUE );
|
return buttonsFillVertically
|
||||||
|
? new Dimension( super.getMaximumSize().width, Short.MAX_VALUE )
|
||||||
|
: super.getMaximumSize();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
button.setFocusable( false );
|
button.setFocusable( false );
|
||||||
@@ -414,6 +445,14 @@ public class FlatTitlePane
|
|||||||
return button;
|
return button;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private JComponent createButtonsGapComp() {
|
||||||
|
JComponent gapComp = new JPanel();
|
||||||
|
gapComp.setOpaque( false );
|
||||||
|
gapComp.setMinimumSize( new Dimension( 0, 0 ) );
|
||||||
|
gapComp.setPreferredSize( new Dimension( UIScale.scale( buttonsGap ), 0 ) );
|
||||||
|
return gapComp;
|
||||||
|
}
|
||||||
|
|
||||||
protected void activeChanged( boolean active ) {
|
protected void activeChanged( boolean active ) {
|
||||||
Color background = clientPropertyColor( rootPane, TITLE_BAR_BACKGROUND, null );
|
Color background = clientPropertyColor( rootPane, TITLE_BAR_BACKGROUND, null );
|
||||||
Color foreground = clientPropertyColor( rootPane, TITLE_BAR_FOREGROUND, null );
|
Color foreground = clientPropertyColor( rootPane, TITLE_BAR_FOREGROUND, null );
|
||||||
@@ -435,6 +474,9 @@ public class FlatTitlePane
|
|||||||
closeButton.setForeground( foreground );
|
closeButton.setForeground( foreground );
|
||||||
|
|
||||||
// this is necessary because hover/pressed colors are derived from background color
|
// this is necessary because hover/pressed colors are derived from background color
|
||||||
|
// (since FlatWindowAbstractIcon now invokes FlatTitlePane.getBackground()
|
||||||
|
// to get base color, this is no longer necessary, but keep it for compatibility;
|
||||||
|
// e.g. for custom window icons)
|
||||||
iconifyButton.setBackground( background );
|
iconifyButton.setBackground( background );
|
||||||
maximizeButton.setBackground( background );
|
maximizeButton.setBackground( background );
|
||||||
restoreButton.setBackground( background );
|
restoreButton.setBackground( background );
|
||||||
@@ -494,6 +536,13 @@ public class FlatTitlePane
|
|||||||
maximizeButton.setVisible( false );
|
maximizeButton.setVisible( false );
|
||||||
restoreButton.setVisible( false );
|
restoreButton.setVisible( false );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean iconifyVisible = iconifyButton.isVisible();
|
||||||
|
boolean maximizeVisible = maximizeButton.isVisible();
|
||||||
|
boolean restoreVisible = restoreButton.isVisible();
|
||||||
|
boolean closeVisible = closeButton.isVisible();
|
||||||
|
iconifyMaximizeGapComp.setVisible( iconifyVisible && (maximizeVisible || restoreVisible || closeVisible) );
|
||||||
|
maximizeCloseGapComp.setVisible( closeVisible && (maximizeVisible || restoreVisible) );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void updateIcon() {
|
protected void updateIcon() {
|
||||||
@@ -747,12 +796,17 @@ public class FlatTitlePane
|
|||||||
if( isFullWindowContent() )
|
if( isFullWindowContent() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
g.setColor( getBackground() );
|
||||||
|
g.fillRect( 0, 0, getWidth(), getHeight() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Color getBackground() {
|
||||||
// not storing value of "TitlePane.unifiedBackground" in class to allow changing at runtime
|
// not storing value of "TitlePane.unifiedBackground" in class to allow changing at runtime
|
||||||
g.setColor( (UIManager.getBoolean( "TitlePane.unifiedBackground" ) &&
|
return (UIManager.getBoolean( "TitlePane.unifiedBackground" ) &&
|
||||||
clientPropertyColor( rootPane, TITLE_BAR_BACKGROUND, null ) == null)
|
clientPropertyColor( rootPane, TITLE_BAR_BACKGROUND, null ) == null)
|
||||||
? FlatUIUtils.getParentBackground( this )
|
? FlatUIUtils.getParentBackground( this )
|
||||||
: getBackground() );
|
: super.getBackground();
|
||||||
g.fillRect( 0, 0, getWidth(), getHeight() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -860,7 +914,7 @@ public class FlatTitlePane
|
|||||||
// screen insets are in physical size, except for Java 15+
|
// screen insets are in physical size, except for Java 15+
|
||||||
// (see https://bugs.openjdk.java.net/browse/JDK-8243925)
|
// (see https://bugs.openjdk.java.net/browse/JDK-8243925)
|
||||||
// and except for Java 8 on secondary screens where primary screen is scaled
|
// and except for Java 8 on secondary screens where primary screen is scaled
|
||||||
Insets screenInsets = window.getToolkit().getScreenInsets( gc );
|
Insets screenInsets = FlatUIUtils.getScreenInsets( gc );
|
||||||
|
|
||||||
// maximized bounds are required in physical size, except for Java 15+
|
// maximized bounds are required in physical size, except for Java 15+
|
||||||
// (see https://bugs.openjdk.java.net/browse/JDK-8231564 and
|
// (see https://bugs.openjdk.java.net/browse/JDK-8231564 and
|
||||||
@@ -1094,6 +1148,7 @@ public class FlatTitlePane
|
|||||||
if( !c.isDisplayable() || !c.isVisible() || !contains( c, x, y ) || c == mouseLayer )
|
if( !c.isDisplayable() || !c.isVisible() || !contains( c, x, y ) || c == mouseLayer )
|
||||||
return true; // continue checking with next component
|
return true; // continue checking with next component
|
||||||
|
|
||||||
|
// check enabled component that has mouse listeners
|
||||||
if( c.isEnabled() &&
|
if( c.isEnabled() &&
|
||||||
(c.getMouseListeners().length > 0 ||
|
(c.getMouseListeners().length > 0 ||
|
||||||
c.getMouseMotionListeners().length > 0) )
|
c.getMouseMotionListeners().length > 0) )
|
||||||
@@ -1417,22 +1472,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
|
||||||
@@ -1463,42 +1505,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 ) {}
|
||||||
@@ -1521,6 +1527,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;
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ import javax.swing.plaf.basic.BasicToolBarUI;
|
|||||||
import com.formdev.flatlaf.FlatClientProperties;
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||||
|
import com.formdev.flatlaf.ui.FlatUIUtils.FlatPropertyWatcher;
|
||||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||||
import com.formdev.flatlaf.util.LoggingFacade;
|
import com.formdev.flatlaf.util.LoggingFacade;
|
||||||
import com.formdev.flatlaf.util.UIScale;
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
@@ -144,11 +145,13 @@ public class FlatToolBarUI
|
|||||||
hoverButtonGroupBackground = UIManager.getColor( "ToolBar.hoverButtonGroupBackground" );
|
hoverButtonGroupBackground = UIManager.getColor( "ToolBar.hoverButtonGroupBackground" );
|
||||||
|
|
||||||
// floatable
|
// floatable
|
||||||
|
oldFloatable = null;
|
||||||
if( !UIManager.getBoolean( "ToolBar.floatable" ) ) {
|
if( !UIManager.getBoolean( "ToolBar.floatable" ) ) {
|
||||||
|
FlatPropertyWatcher.runIfNotChanged( toolBar, "floatable", () -> {
|
||||||
oldFloatable = toolBar.isFloatable();
|
oldFloatable = toolBar.isFloatable();
|
||||||
toolBar.setFloatable( false );
|
toolBar.setFloatable( false );
|
||||||
} else
|
} );
|
||||||
oldFloatable = null;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -158,7 +161,9 @@ public class FlatToolBarUI
|
|||||||
hoverButtonGroupBackground = null;
|
hoverButtonGroupBackground = null;
|
||||||
|
|
||||||
if( oldFloatable != null ) {
|
if( oldFloatable != null ) {
|
||||||
|
FlatPropertyWatcher.runIfNotChanged( toolBar, "floatable", () -> {
|
||||||
toolBar.setFloatable( oldFloatable );
|
toolBar.setFloatable( oldFloatable );
|
||||||
|
} );
|
||||||
oldFloatable = null;
|
oldFloatable = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -569,7 +577,27 @@ public class FlatTreeUI
|
|||||||
boolean isEditing = (editingComponent != null && editingRow == row);
|
boolean isEditing = (editingComponent != null && editingRow == row);
|
||||||
boolean isSelected = tree.isRowSelected( row );
|
boolean isSelected = tree.isRowSelected( row );
|
||||||
boolean isDropRow = isDropRow( row );
|
boolean isDropRow = isDropRow( row );
|
||||||
boolean needsSelectionPainting = (isSelected || isDropRow) && isPaintSelection();
|
|
||||||
|
// paint alternating rows
|
||||||
|
if( alternateRowColor != null && row % 2 != 0 ) {
|
||||||
|
g.setColor( alternateRowColor );
|
||||||
|
|
||||||
|
float arc = UIScale.scale( selectionArc / 2f );
|
||||||
|
FlatUIUtils.paintSelection( (Graphics2D) g, 0, bounds.y, tree.getWidth(), bounds.height,
|
||||||
|
UIScale.scale( selectionInsets ), arc, arc, arc, arc, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// update bounds for wide cell renderer
|
||||||
|
if( isWideSelection() && isWideCellRenderer() ) {
|
||||||
|
Rectangle wideBounds = new Rectangle( bounds );
|
||||||
|
if( tree.getComponentOrientation().isLeftToRight() )
|
||||||
|
wideBounds.width = tree.getWidth() - bounds.x - insets.right;
|
||||||
|
else {
|
||||||
|
wideBounds.x = insets.left;
|
||||||
|
wideBounds.width = bounds.x + bounds.width - insets.left;
|
||||||
|
}
|
||||||
|
bounds = wideBounds;
|
||||||
|
}
|
||||||
|
|
||||||
// do not paint row if editing
|
// do not paint row if editing
|
||||||
if( isEditing ) {
|
if( isEditing ) {
|
||||||
@@ -579,7 +607,7 @@ public class FlatTreeUI
|
|||||||
if( isSelected && isWideSelection() ) {
|
if( isSelected && isWideSelection() ) {
|
||||||
Color oldColor = g.getColor();
|
Color oldColor = g.getColor();
|
||||||
g.setColor( selectionInactiveBackground );
|
g.setColor( selectionInactiveBackground );
|
||||||
paintWideSelection( g, bounds, row );
|
paintWideSelection( g, bounds, row, false );
|
||||||
g.setColor( oldColor );
|
g.setColor( oldColor );
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -599,7 +627,7 @@ public class FlatTreeUI
|
|||||||
|
|
||||||
// renderer background/foreground
|
// renderer background/foreground
|
||||||
Color oldBackgroundSelectionColor = null;
|
Color oldBackgroundSelectionColor = null;
|
||||||
if( isSelected && !hasFocus && !isDropRow ) {
|
if( isSelected && !hasFocus ) {
|
||||||
// apply inactive selection background/foreground if tree is not focused
|
// apply inactive selection background/foreground if tree is not focused
|
||||||
oldBackgroundSelectionColor = setRendererBackgroundSelectionColor( rendererComponent, selectionInactiveBackground );
|
oldBackgroundSelectionColor = setRendererBackgroundSelectionColor( rendererComponent, selectionInactiveBackground );
|
||||||
setRendererForeground( rendererComponent, selectionInactiveForeground );
|
setRendererForeground( rendererComponent, selectionInactiveForeground );
|
||||||
@@ -626,26 +654,12 @@ public class FlatTreeUI
|
|||||||
}
|
}
|
||||||
|
|
||||||
// paint selection background
|
// paint selection background
|
||||||
if( needsSelectionPainting ) {
|
if( isSelected && isPaintSelection() ) {
|
||||||
// set selection color
|
Color selectionColor = rendererComponent instanceof DefaultTreeCellRenderer
|
||||||
Color oldColor = g.getColor();
|
|
||||||
g.setColor( isDropRow
|
|
||||||
? UIManager.getColor( "Tree.dropCellBackground" )
|
|
||||||
: (rendererComponent instanceof DefaultTreeCellRenderer
|
|
||||||
? ((DefaultTreeCellRenderer)rendererComponent).getBackgroundSelectionColor()
|
? ((DefaultTreeCellRenderer)rendererComponent).getBackgroundSelectionColor()
|
||||||
: (hasFocus ? selectionBackground : selectionInactiveBackground)) );
|
: (hasFocus ? selectionBackground : selectionInactiveBackground);
|
||||||
|
|
||||||
if( isWideSelection() ) {
|
paintRowSelection( g, selectionColor, rendererComponent, bounds, row, false );
|
||||||
// wide selection
|
|
||||||
paintWideSelection( g, bounds, row );
|
|
||||||
} else {
|
|
||||||
// non-wide selection
|
|
||||||
paintCellBackground( g, rendererComponent, bounds, row, true );
|
|
||||||
}
|
|
||||||
|
|
||||||
// this is actually not necessary because renderer should always set color
|
|
||||||
// before painting, but doing anyway to avoid any side effect (in bad renderers)
|
|
||||||
g.setColor( oldColor );
|
|
||||||
} else {
|
} else {
|
||||||
// paint cell background if DefaultTreeCellRenderer.getBackgroundNonSelectionColor() is set
|
// paint cell background if DefaultTreeCellRenderer.getBackgroundNonSelectionColor() is set
|
||||||
if( rendererComponent instanceof DefaultTreeCellRenderer ) {
|
if( rendererComponent instanceof DefaultTreeCellRenderer ) {
|
||||||
@@ -654,12 +668,19 @@ public class FlatTreeUI
|
|||||||
if( bg != null && !bg.equals( defaultCellNonSelectionBackground ) ) {
|
if( bg != null && !bg.equals( defaultCellNonSelectionBackground ) ) {
|
||||||
Color oldColor = g.getColor();
|
Color oldColor = g.getColor();
|
||||||
g.setColor( bg );
|
g.setColor( bg );
|
||||||
paintCellBackground( g, rendererComponent, bounds, row, false );
|
paintCellBackground( g, rendererComponent, bounds, row, false, false );
|
||||||
g.setColor( oldColor );
|
g.setColor( oldColor );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// paint drop background
|
||||||
|
// (this needs to be an extra step for rounded selection)
|
||||||
|
if( isDropRow && isPaintSelection() ) {
|
||||||
|
paintRowSelection( g, UIManager.getColor( "Tree.dropCellBackground" ),
|
||||||
|
rendererComponent, bounds, row, true );
|
||||||
|
}
|
||||||
|
|
||||||
// paint renderer
|
// paint renderer
|
||||||
rendererPane.paintComponent( g, rendererComponent, tree, bounds.x, bounds.y, bounds.width, bounds.height, true );
|
rendererPane.paintComponent( g, rendererComponent, tree, bounds.x, bounds.y, bounds.width, bounds.height, true );
|
||||||
|
|
||||||
@@ -670,6 +691,26 @@ public class FlatTreeUI
|
|||||||
((DefaultTreeCellRenderer)rendererComponent).setBorderSelectionColor( oldBorderSelectionColor );
|
((DefaultTreeCellRenderer)rendererComponent).setBorderSelectionColor( oldBorderSelectionColor );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void paintRowSelection( Graphics g, Color color, Component rendererComponent,
|
||||||
|
Rectangle bounds, int row, boolean paintDropSelection )
|
||||||
|
{
|
||||||
|
// set selection color
|
||||||
|
Color oldColor = g.getColor();
|
||||||
|
g.setColor( color );
|
||||||
|
|
||||||
|
if( isWideSelection() ) {
|
||||||
|
// wide selection
|
||||||
|
paintWideSelection( g, bounds, row, paintDropSelection );
|
||||||
|
} else {
|
||||||
|
// non-wide selection
|
||||||
|
paintCellBackground( g, rendererComponent, bounds, row, true, paintDropSelection );
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is actually not necessary because renderer should always set color
|
||||||
|
// before painting, but doing anyway to avoid any side effect (in bad renderers)
|
||||||
|
g.setColor( oldColor );
|
||||||
|
}
|
||||||
|
|
||||||
private Color setRendererBackgroundSelectionColor( Component rendererComponent, Color color ) {
|
private Color setRendererBackgroundSelectionColor( Component rendererComponent, Color color ) {
|
||||||
Color oldColor = null;
|
Color oldColor = null;
|
||||||
|
|
||||||
@@ -706,11 +747,11 @@ public class FlatTreeUI
|
|||||||
return oldColor;
|
return oldColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void paintWideSelection( Graphics g, Rectangle bounds, int row ) {
|
private void paintWideSelection( Graphics g, Rectangle bounds, int row, boolean paintDropSelection ) {
|
||||||
float arcTop, arcBottom;
|
float arcTop, arcBottom;
|
||||||
arcTop = arcBottom = UIScale.scale( selectionArc / 2f );
|
arcTop = arcBottom = UIScale.scale( selectionArc / 2f );
|
||||||
|
|
||||||
if( useUnitedRoundedSelection() ) {
|
if( useUnitedRoundedSelection() && !paintDropSelection ) {
|
||||||
if( row > 0 && tree.isRowSelected( row - 1 ) )
|
if( row > 0 && tree.isRowSelected( row - 1 ) )
|
||||||
arcTop = 0;
|
arcTop = 0;
|
||||||
if( row < tree.getRowCount() - 1 && tree.isRowSelected( row + 1 ) )
|
if( row < tree.getRowCount() - 1 && tree.isRowSelected( row + 1 ) )
|
||||||
@@ -722,7 +763,7 @@ public class FlatTreeUI
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void paintCellBackground( Graphics g, Component rendererComponent, Rectangle bounds,
|
private void paintCellBackground( Graphics g, Component rendererComponent, Rectangle bounds,
|
||||||
int row, boolean paintSelection )
|
int row, boolean paintSelection, boolean paintDropSelection )
|
||||||
{
|
{
|
||||||
int xOffset = 0;
|
int xOffset = 0;
|
||||||
int imageOffset = 0;
|
int imageOffset = 0;
|
||||||
@@ -740,7 +781,7 @@ public class FlatTreeUI
|
|||||||
float arcTopLeft, arcTopRight, arcBottomLeft, arcBottomRight;
|
float arcTopLeft, arcTopRight, arcBottomLeft, arcBottomRight;
|
||||||
arcTopLeft = arcTopRight = arcBottomLeft = arcBottomRight = UIScale.scale( selectionArc / 2f );
|
arcTopLeft = arcTopRight = arcBottomLeft = arcBottomRight = UIScale.scale( selectionArc / 2f );
|
||||||
|
|
||||||
if( useUnitedRoundedSelection() ) {
|
if( useUnitedRoundedSelection() && !paintDropSelection ) {
|
||||||
if( row > 0 && tree.isRowSelected( row - 1 ) ) {
|
if( row > 0 && tree.isRowSelected( row - 1 ) ) {
|
||||||
Rectangle r = getPathBounds( tree, tree.getPathForRow( row - 1 ) );
|
Rectangle r = getPathBounds( tree, tree.getPathForRow( row - 1 ) );
|
||||||
arcTopLeft = Math.min( arcTopLeft, r.x - bounds.x );
|
arcTopLeft = Math.min( arcTopLeft, r.x - bounds.x );
|
||||||
@@ -795,6 +836,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 );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import java.awt.Graphics;
|
|||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.GraphicsConfiguration;
|
import java.awt.GraphicsConfiguration;
|
||||||
import java.awt.GraphicsDevice;
|
import java.awt.GraphicsDevice;
|
||||||
|
import java.awt.GraphicsEnvironment;
|
||||||
import java.awt.Insets;
|
import java.awt.Insets;
|
||||||
import java.awt.KeyboardFocusManager;
|
import java.awt.KeyboardFocusManager;
|
||||||
import java.awt.Paint;
|
import java.awt.Paint;
|
||||||
@@ -34,6 +35,7 @@ import java.awt.RenderingHints;
|
|||||||
import java.awt.Shape;
|
import java.awt.Shape;
|
||||||
import java.awt.Stroke;
|
import java.awt.Stroke;
|
||||||
import java.awt.SystemColor;
|
import java.awt.SystemColor;
|
||||||
|
import java.awt.Toolkit;
|
||||||
import java.awt.Window;
|
import java.awt.Window;
|
||||||
import java.awt.event.FocusEvent;
|
import java.awt.event.FocusEvent;
|
||||||
import java.awt.event.FocusListener;
|
import java.awt.event.FocusListener;
|
||||||
@@ -42,6 +44,8 @@ import java.awt.geom.Path2D;
|
|||||||
import java.awt.geom.Point2D;
|
import java.awt.geom.Point2D;
|
||||||
import java.awt.geom.Rectangle2D;
|
import java.awt.geom.Rectangle2D;
|
||||||
import java.awt.geom.RoundRectangle2D;
|
import java.awt.geom.RoundRectangle2D;
|
||||||
|
import java.beans.PropertyChangeEvent;
|
||||||
|
import java.beans.PropertyChangeListener;
|
||||||
import java.util.IdentityHashMap;
|
import java.util.IdentityHashMap;
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
@@ -129,6 +133,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 );
|
||||||
@@ -400,6 +418,17 @@ public class FlatUIUtils
|
|||||||
return (fullScreenWindow != null && fullScreenWindow == SwingUtilities.windowForComponent( c ));
|
return (fullScreenWindow != null && fullScreenWindow == SwingUtilities.windowForComponent( c ));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @since 3.6.1 */
|
||||||
|
public static Insets getScreenInsets( GraphicsConfiguration gc ) {
|
||||||
|
// on Linux, getScreenInsets() may report wrong values in multi-screen setups
|
||||||
|
// see https://github.com/apache/netbeans/issues/8532#issuecomment-2909687016
|
||||||
|
if( SystemInfo.isLinux &&
|
||||||
|
GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices().length > 1 )
|
||||||
|
return new Insets( 0, 0, 0, 0 );
|
||||||
|
|
||||||
|
return Toolkit.getDefaultToolkit().getScreenInsets( gc );
|
||||||
|
}
|
||||||
|
|
||||||
public static Boolean isRoundRect( Component c ) {
|
public static Boolean isRoundRect( Component c ) {
|
||||||
return (c instanceof JComponent)
|
return (c instanceof JComponent)
|
||||||
? FlatClientProperties.clientPropertyBooleanStrict(
|
? FlatClientProperties.clientPropertyBooleanStrict(
|
||||||
@@ -447,6 +476,9 @@ public class FlatUIUtils
|
|||||||
* Returns the scaled arc diameter of the border for the given component.
|
* Returns the scaled arc diameter of the border for the given component.
|
||||||
*/
|
*/
|
||||||
public static float getBorderArc( JComponent c ) {
|
public static float getBorderArc( JComponent c ) {
|
||||||
|
if( c.getBorder() instanceof FlatLineBorder )
|
||||||
|
return UIScale.scale( ((FlatLineBorder)c.getBorder()).getArc() );
|
||||||
|
|
||||||
FlatBorder border = getOutsideFlatBorder( c );
|
FlatBorder border = getOutsideFlatBorder( c );
|
||||||
return (border != null)
|
return (border != null)
|
||||||
? UIScale.scale( (float) border.getArc( c ) )
|
? UIScale.scale( (float) border.getArc( c ) )
|
||||||
@@ -1383,4 +1415,47 @@ debug*/
|
|||||||
return delegate.isBorderOpaque();
|
return delegate.isBorderOpaque();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---- class FlatPropertyWatcher ------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener that watches for change of a property from application code.
|
||||||
|
* This information can be used to decide whether FlatLaf modifies the property.
|
||||||
|
* If it is modified in application code, FlatLaf no longer changes it.
|
||||||
|
* <p>
|
||||||
|
* The listener is added once for a property, but never removed.
|
||||||
|
* So switching Laf/theme reuses existing listener.
|
||||||
|
*/
|
||||||
|
static class FlatPropertyWatcher
|
||||||
|
implements PropertyChangeListener
|
||||||
|
{
|
||||||
|
private boolean changed;
|
||||||
|
|
||||||
|
static void runIfNotChanged( JComponent c, String propName, Runnable runnable ) {
|
||||||
|
FlatPropertyWatcher watcher = getOrInstall( c, propName );
|
||||||
|
if( watcher.changed )
|
||||||
|
return;
|
||||||
|
|
||||||
|
runnable.run();
|
||||||
|
watcher.changed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FlatPropertyWatcher getOrInstall( JComponent c, String propName ) {
|
||||||
|
for( PropertyChangeListener l : c.getPropertyChangeListeners( propName ) ) {
|
||||||
|
if( l instanceof FlatPropertyWatcher )
|
||||||
|
return (FlatPropertyWatcher) l;
|
||||||
|
}
|
||||||
|
|
||||||
|
FlatPropertyWatcher watcher = new FlatPropertyWatcher();
|
||||||
|
c.addPropertyChangeListener( propName, watcher );
|
||||||
|
return watcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---- interface PropertyChangeListener ----
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void propertyChange( PropertyChangeEvent e ) {
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ 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.JPanel;
|
||||||
import javax.swing.JRootPane;
|
import javax.swing.JRootPane;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
@@ -60,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 );
|
||||||
@@ -82,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 );
|
||||||
@@ -106,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() {
|
||||||
@@ -121,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();
|
||||||
@@ -192,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 resizeDir ) {}
|
protected void beginResizing( int resizeDir, MouseEvent e ) {}
|
||||||
protected void endResizing() {}
|
protected void endResizing() {}
|
||||||
|
|
||||||
//---- interface PropertyChangeListener ----
|
//---- interface PropertyChangeListener ----
|
||||||
@@ -251,8 +247,7 @@ public abstract class FlatWindowResizer
|
|||||||
centerComp = new JPanel();
|
centerComp = new JPanel();
|
||||||
centerComp.setOpaque( false );
|
centerComp.setOpaque( false );
|
||||||
centerComp.setVisible( false );
|
centerComp.setVisible( false );
|
||||||
Container cont = rootPane.getLayeredPane();
|
rootPane.add( centerComp, 5 );
|
||||||
cont.add( centerComp, WINDOW_RESIZER_LAYER, 4 );
|
|
||||||
|
|
||||||
// On Linux, limit window resizing to screen bounds because otherwise
|
// On Linux, limit window resizing to screen bounds because otherwise
|
||||||
// there would be a strange effect when the mouse is moved over a sidebar
|
// there would be a strange effect when the mouse is moved over a sidebar
|
||||||
@@ -262,8 +257,7 @@ public abstract class FlatWindowResizer
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void uninstall() {
|
public void uninstall() {
|
||||||
Container cont = topDragComp.getParent();
|
resizeComp.remove( centerComp );
|
||||||
cont.remove( centerComp );
|
|
||||||
|
|
||||||
super.uninstall();
|
super.uninstall();
|
||||||
}
|
}
|
||||||
@@ -272,6 +266,7 @@ public abstract class FlatWindowResizer
|
|||||||
public void doLayout() {
|
public void doLayout() {
|
||||||
super.doLayout();
|
super.doLayout();
|
||||||
|
|
||||||
|
if( centerComp != null && centerComp.isVisible() )
|
||||||
centerComp.setBounds( 0, 0, resizeComp.getWidth(), resizeComp.getHeight() );
|
centerComp.setBounds( 0, 0, resizeComp.getWidth(), resizeComp.getHeight() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -336,7 +331,7 @@ public abstract class FlatWindowResizer
|
|||||||
protected Rectangle getParentBounds() {
|
protected Rectangle getParentBounds() {
|
||||||
GraphicsConfiguration gc = window.getGraphicsConfiguration();
|
GraphicsConfiguration gc = window.getGraphicsConfiguration();
|
||||||
Rectangle bounds = gc.getBounds();
|
Rectangle bounds = gc.getBounds();
|
||||||
Insets insets = window.getToolkit().getScreenInsets( gc );
|
Insets insets = FlatUIUtils.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 );
|
||||||
@@ -375,7 +370,26 @@ public abstract class FlatWindowResizer
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void beginResizing( int resizeDir ) {
|
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.setCursor( getPredefinedCursor( resizeDir ) );
|
||||||
centerComp.setVisible( true );
|
centerComp.setVisible( true );
|
||||||
}
|
}
|
||||||
@@ -466,7 +480,7 @@ public abstract class FlatWindowResizer
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void beginResizing( int resizeDir ) {
|
protected void beginResizing( int resizeDir, MouseEvent e ) {
|
||||||
int direction = 0;
|
int direction = 0;
|
||||||
switch( resizeDir ) {
|
switch( resizeDir ) {
|
||||||
case N_RESIZE_CURSOR: direction = NORTH; break;
|
case N_RESIZE_CURSOR: direction = NORTH; break;
|
||||||
@@ -585,7 +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;
|
||||||
|
|
||||||
beginResizing( resizeDir );
|
beginResizing( resizeDir, e );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import java.awt.Dialog;
|
|||||||
import java.awt.EventQueue;
|
import java.awt.EventQueue;
|
||||||
import java.awt.Frame;
|
import java.awt.Frame;
|
||||||
import java.awt.GraphicsConfiguration;
|
import java.awt.GraphicsConfiguration;
|
||||||
|
import java.awt.Insets;
|
||||||
import java.awt.Point;
|
import java.awt.Point;
|
||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
import java.awt.Window;
|
import java.awt.Window;
|
||||||
@@ -39,6 +40,7 @@ import javax.swing.event.ChangeListener;
|
|||||||
import javax.swing.event.EventListenerList;
|
import javax.swing.event.EventListenerList;
|
||||||
import com.formdev.flatlaf.util.LoggingFacade;
|
import com.formdev.flatlaf.util.LoggingFacade;
|
||||||
import com.formdev.flatlaf.util.SystemInfo;
|
import com.formdev.flatlaf.util.SystemInfo;
|
||||||
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Interesting resources:
|
// Interesting resources:
|
||||||
@@ -282,6 +284,8 @@ class FlatWindowsNativeWindowBorder
|
|||||||
HTMINBUTTON = 8,
|
HTMINBUTTON = 8,
|
||||||
HTMAXBUTTON = 9,
|
HTMAXBUTTON = 9,
|
||||||
HTTOP = 12,
|
HTTOP = 12,
|
||||||
|
HTTOPLEFT = 13,
|
||||||
|
HTTOPRIGHT = 14,
|
||||||
HTCLOSE = 20;
|
HTCLOSE = 20;
|
||||||
|
|
||||||
private Window window;
|
private Window window;
|
||||||
@@ -341,6 +345,31 @@ class FlatWindowsNativeWindowBorder
|
|||||||
// scale-down mouse x/y because Swing coordinates/values may be scaled on a HiDPI screen
|
// scale-down mouse x/y because Swing coordinates/values may be scaled on a HiDPI screen
|
||||||
Point pt = scaleDown( x, y );
|
Point pt = scaleDown( x, y );
|
||||||
|
|
||||||
|
// limit top resize border to 4px, which seems to be standard for modern WinUI apps
|
||||||
|
if( isOnResizeBorder && pt.y > UIScale.scale( 4 ) )
|
||||||
|
isOnResizeBorder = false;
|
||||||
|
|
||||||
|
if( isOnResizeBorder ) {
|
||||||
|
Insets insets = window.getInsets();
|
||||||
|
|
||||||
|
// return HTTOPLEFT if mouse is over top resize border on left side
|
||||||
|
// - hovering mouse shows top-left resize cursor
|
||||||
|
// - left-click-and-drag resizes window
|
||||||
|
if( pt.x <= insets.left + UIScale.scale( 12 ) )
|
||||||
|
return HTTOPLEFT;
|
||||||
|
|
||||||
|
// return HTTOPRIGHT if mouse is over top resize border on right side
|
||||||
|
// - hovering mouse shows top-right resize cursor
|
||||||
|
// - left-click-and-drag resizes window
|
||||||
|
if( pt.x >= window.getWidth() - insets.right - UIScale.scale( 12 ) )
|
||||||
|
return HTTOPRIGHT;
|
||||||
|
|
||||||
|
// return HTTOP if mouse is over top resize border
|
||||||
|
// - hovering mouse shows vertical resize cursor
|
||||||
|
// - left-click-and-drag vertically resizes window
|
||||||
|
return HTTOP;
|
||||||
|
}
|
||||||
|
|
||||||
// return HTSYSMENU if mouse is over application icon
|
// return HTSYSMENU if mouse is over application icon
|
||||||
// - left-click on HTSYSMENU area shows system menu
|
// - left-click on HTSYSMENU area shows system menu
|
||||||
// - double-left-click sends WM_CLOSE
|
// - double-left-click sends WM_CLOSE
|
||||||
@@ -364,12 +393,6 @@ class FlatWindowsNativeWindowBorder
|
|||||||
if( contains( closeButtonBounds, pt ) )
|
if( contains( closeButtonBounds, pt ) )
|
||||||
return HTCLOSE;
|
return HTCLOSE;
|
||||||
|
|
||||||
// return HTTOP if mouse is over top resize border
|
|
||||||
// - hovering mouse shows vertical resize cursor
|
|
||||||
// - left-click and drag vertically resizes window
|
|
||||||
if( isOnResizeBorder )
|
|
||||||
return HTTOP;
|
|
||||||
|
|
||||||
boolean isOnTitleBar = (pt.y < titleBarHeight);
|
boolean isOnTitleBar = (pt.y < titleBarHeight);
|
||||||
if( isOnTitleBar ) {
|
if( isOnTitleBar ) {
|
||||||
// return HTCLIENT if mouse is over any Swing component in title bar
|
// return HTCLIENT if mouse is over any Swing component in title bar
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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 );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 );
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -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" );
|
||||||
|
|||||||
@@ -27,7 +27,9 @@ import java.beans.PropertyChangeEvent;
|
|||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.beans.PropertyChangeSupport;
|
import java.beans.PropertyChangeSupport;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Arrays;
|
||||||
import javax.swing.LookAndFeel;
|
import javax.swing.LookAndFeel;
|
||||||
|
import javax.swing.UIDefaults;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.plaf.DimensionUIResource;
|
import javax.swing.plaf.DimensionUIResource;
|
||||||
import javax.swing.plaf.FontUIResource;
|
import javax.swing.plaf.FontUIResource;
|
||||||
@@ -61,16 +63,28 @@ import com.formdev.flatlaf.FlatSystemProperties;
|
|||||||
* or if the default font is changed.
|
* or if the default font is changed.
|
||||||
* The user scale factor is computed based on the used font.
|
* The user scale factor is computed based on the used font.
|
||||||
* The JRE does not scale anything.
|
* The JRE does not scale anything.
|
||||||
* So we have to invoke {@link #scale(float)} where necessary.
|
* So we have to invoke {@link #scale(int)} where necessary.
|
||||||
* There is only one user scale factor for all displays.
|
* There is only one user scale factor for all displays.
|
||||||
* The user scale factor may change if the active LaF, "defaultFont" or "Label.font" has changed.
|
* The user scale factor may change if the active LaF, "defaultFont" or "Label.font" has changed.
|
||||||
* If system scaling mode is available the user scale factor is usually 1,
|
* If system scaling mode is available the user scale factor is usually 1,
|
||||||
* but may be larger on Linux or if the default font is changed.
|
* but may be larger on Linux or if the default font is changed.
|
||||||
*
|
*
|
||||||
|
* <h2>Zooming</h2>
|
||||||
|
*
|
||||||
|
* Zooming allows appliations to easily zoom their UI, if FlatLaf is active Laf.
|
||||||
|
* This is done by changing user scale factor and default font.
|
||||||
|
* There are methods to increase, decrease and reset zoom factor.
|
||||||
|
* <p>
|
||||||
|
* Note: Only standard Swing components are zoomed.
|
||||||
|
* Custom components need to use {@link #scale(int)} to zoom their UI.
|
||||||
|
*
|
||||||
* @author Karl Tauber
|
* @author Karl Tauber
|
||||||
*/
|
*/
|
||||||
public class UIScale
|
public class UIScale
|
||||||
{
|
{
|
||||||
|
/** @since 3.7 */ public static final String PROP_USER_SCALE_FACTOR = "userScaleFactor";
|
||||||
|
/** @since 3.7 */ public static final String PROP_ZOOM_FACTOR = "zoomFactor";
|
||||||
|
|
||||||
private static final boolean DEBUG = false;
|
private static final boolean DEBUG = false;
|
||||||
|
|
||||||
private static PropertyChangeSupport changeSupport;
|
private static PropertyChangeSupport changeSupport;
|
||||||
@@ -87,7 +101,7 @@ public class UIScale
|
|||||||
changeSupport.removePropertyChangeListener( listener );
|
changeSupport.removePropertyChangeListener( listener );
|
||||||
}
|
}
|
||||||
|
|
||||||
//---- system scaling (Java 9) --------------------------------------------
|
//---- system scaling (Java 9+) -------------------------------------------
|
||||||
|
|
||||||
private static Boolean jreHiDPI;
|
private static Boolean jreHiDPI;
|
||||||
|
|
||||||
@@ -135,10 +149,13 @@ public class UIScale
|
|||||||
return (isSystemScalingEnabled() && gc != null) ? gc.getDefaultTransform().getScaleX() : 1;
|
return (isSystemScalingEnabled() && gc != null) ? gc.getDefaultTransform().getScaleX() : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//---- user scaling (Java 8) ----------------------------------------------
|
//---- user scaling (Java 8 / zooming) ------------------------------------
|
||||||
|
|
||||||
|
private static float unzoomedScaleFactor = 1;
|
||||||
private static float scaleFactor = 1;
|
private static float scaleFactor = 1;
|
||||||
private static boolean initialized;
|
private static boolean initialized;
|
||||||
|
private static boolean listenerInitialized; // use extra flag for unit tests
|
||||||
|
private static boolean ignoreFontChange;
|
||||||
|
|
||||||
private static void initialize() {
|
private static void initialize() {
|
||||||
if( initialized )
|
if( initialized )
|
||||||
@@ -148,33 +165,43 @@ public class UIScale
|
|||||||
if( !isUserScalingEnabled() )
|
if( !isUserScalingEnabled() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
initializeListener();
|
||||||
|
|
||||||
|
updateScaleFactor( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void initializeListener() {
|
||||||
|
if( listenerInitialized )
|
||||||
|
return;
|
||||||
|
listenerInitialized = true;
|
||||||
|
|
||||||
// listener to update scale factor if LaF changed, "defaultFont" or "Label.font" changed
|
// listener to update scale factor if LaF changed, "defaultFont" or "Label.font" changed
|
||||||
PropertyChangeListener listener = new PropertyChangeListener() {
|
PropertyChangeListener listener = new PropertyChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void propertyChange( PropertyChangeEvent e ) {
|
public void propertyChange( PropertyChangeEvent e ) {
|
||||||
switch( e.getPropertyName() ) {
|
switch( e.getPropertyName() ) {
|
||||||
case "lookAndFeel":
|
case "lookAndFeel":
|
||||||
// it is not necessary (and possible) to remove listener of old LaF defaults
|
// it is not possible (and necessary) to remove listener of old LaF defaults
|
||||||
|
// because it is not possible to access the UIDefault object of the old LaF
|
||||||
if( e.getNewValue() instanceof LookAndFeel )
|
if( e.getNewValue() instanceof LookAndFeel )
|
||||||
UIManager.getLookAndFeelDefaults().addPropertyChangeListener( this );
|
UIManager.getLookAndFeelDefaults().addPropertyChangeListener( this );
|
||||||
updateScaleFactor();
|
updateScaleFactor( true );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "defaultFont":
|
case "defaultFont":
|
||||||
case "Label.font":
|
case "Label.font":
|
||||||
updateScaleFactor();
|
if( !ignoreFontChange )
|
||||||
|
updateScaleFactor( false );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
UIManager.addPropertyChangeListener( listener );
|
|
||||||
UIManager.getDefaults().addPropertyChangeListener( listener );
|
UIManager.getDefaults().addPropertyChangeListener( listener );
|
||||||
UIManager.getLookAndFeelDefaults().addPropertyChangeListener( listener );
|
UIManager.getLookAndFeelDefaults().addPropertyChangeListener( listener );
|
||||||
|
UIManager.addPropertyChangeListener( listener );
|
||||||
updateScaleFactor();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void updateScaleFactor() {
|
private static void updateScaleFactor( boolean lafChanged ) {
|
||||||
if( !isUserScalingEnabled() )
|
if( !isUserScalingEnabled() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -185,17 +212,20 @@ public class UIScale
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// use font size to calculate scale factor (instead of DPI)
|
// get font that is used to calculate scale factor
|
||||||
// because even if we are on a HiDPI display it is not sure
|
|
||||||
// that a larger font size is set by the current LaF
|
|
||||||
// (e.g. can avoid large icons with small text)
|
|
||||||
Font font = null;
|
Font font = null;
|
||||||
if( UIManager.getLookAndFeel() instanceof FlatLaf )
|
if( UIManager.getLookAndFeel() instanceof FlatLaf )
|
||||||
font = UIManager.getFont( "defaultFont" );
|
font = UIManager.getFont( "defaultFont" );
|
||||||
if( font == null )
|
if( font == null )
|
||||||
font = UIManager.getFont( "Label.font" );
|
font = UIManager.getFont( "Label.font" );
|
||||||
|
|
||||||
setUserScaleFactor( computeFontScaleFactor( font ), true );
|
float fontScaleFactor = computeFontScaleFactor( font );
|
||||||
|
if( lafChanged && UIManager.getLookAndFeel() instanceof FlatLaf ) {
|
||||||
|
// FlatLaf has applied zoom factor in FlatLaf.initDefaultFont() to defaultFont,
|
||||||
|
// so we need to take it into account to get correct user scale factor
|
||||||
|
fontScaleFactor /= zoomFactor;
|
||||||
|
}
|
||||||
|
setUserScaleFactor( fontScaleFactor, true );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -204,7 +234,7 @@ public class UIScale
|
|||||||
* @since 2
|
* @since 2
|
||||||
*/
|
*/
|
||||||
public static float computeFontScaleFactor( Font font ) {
|
public static float computeFontScaleFactor( Font font ) {
|
||||||
if( SystemInfo.isWindows ) {
|
if( SystemInfo.isWindows && !inUnitTests ) {
|
||||||
// Special handling for Windows to be compatible with OS scaling,
|
// Special handling for Windows to be compatible with OS scaling,
|
||||||
// which distinguish between "screen scaling" and "text scaling".
|
// which distinguish between "screen scaling" and "text scaling".
|
||||||
// - Windows "screen scaling" scales everything (text, icon, gaps, etc.)
|
// - Windows "screen scaling" scales everything (text, icon, gaps, etc.)
|
||||||
@@ -335,7 +365,7 @@ public class UIScale
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the user scale factor.
|
* Returns the user scale factor (including zoom factor).
|
||||||
*/
|
*/
|
||||||
public static float getUserScaleFactor() {
|
public static float getUserScaleFactor() {
|
||||||
initialize();
|
initialize();
|
||||||
@@ -345,27 +375,49 @@ public class UIScale
|
|||||||
/**
|
/**
|
||||||
* Sets the user scale factor.
|
* Sets the user scale factor.
|
||||||
*/
|
*/
|
||||||
private static void setUserScaleFactor( float scaleFactor, boolean normalize ) {
|
private static void setUserScaleFactor( float unzoomedScaleFactor, boolean normalize ) {
|
||||||
if( normalize ) {
|
if( normalize )
|
||||||
if( scaleFactor < 1f ) {
|
unzoomedScaleFactor = normalizeScaleFactor( unzoomedScaleFactor );
|
||||||
scaleFactor = FlatSystemProperties.getBoolean( FlatSystemProperties.UI_SCALE_ALLOW_SCALE_DOWN, false )
|
|
||||||
? Math.round( scaleFactor * 10f ) / 10f // round small scale factor to 1/10
|
|
||||||
: 1f;
|
|
||||||
} else if( scaleFactor > 1f ) // round scale factor to 1/4
|
|
||||||
scaleFactor = Math.round( scaleFactor * 4f ) / 4f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// minimum scale factor
|
// minimum scale factor
|
||||||
scaleFactor = Math.max( scaleFactor, 0.1f );
|
unzoomedScaleFactor = Math.max( unzoomedScaleFactor, 0.1f );
|
||||||
|
|
||||||
|
if( unzoomedScaleFactor == UIScale.unzoomedScaleFactor )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( DEBUG )
|
||||||
|
System.out.println( "Unzoomed scale factor " + UIScale.unzoomedScaleFactor + " --> " + unzoomedScaleFactor );
|
||||||
|
|
||||||
|
UIScale.unzoomedScaleFactor = unzoomedScaleFactor;
|
||||||
|
setScaleFactor( unzoomedScaleFactor * zoomFactor );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void setScaleFactor( float scaleFactor ) {
|
||||||
|
// round scale factor to 1/100
|
||||||
|
scaleFactor = Math.round( scaleFactor * 100f ) / 100f;
|
||||||
|
|
||||||
|
if( scaleFactor == UIScale.scaleFactor )
|
||||||
|
return;
|
||||||
|
|
||||||
float oldScaleFactor = UIScale.scaleFactor;
|
float oldScaleFactor = UIScale.scaleFactor;
|
||||||
UIScale.scaleFactor = scaleFactor;
|
UIScale.scaleFactor = scaleFactor;
|
||||||
|
|
||||||
if( DEBUG )
|
if( DEBUG )
|
||||||
System.out.println( "HiDPI scale factor " + scaleFactor );
|
System.out.println( "Scale factor " + oldScaleFactor + " --> " + scaleFactor + " (unzoomed " + UIScale.unzoomedScaleFactor + ")" );
|
||||||
|
|
||||||
if( changeSupport != null )
|
if( changeSupport != null )
|
||||||
changeSupport.firePropertyChange( "userScaleFactor", oldScaleFactor, scaleFactor );
|
changeSupport.firePropertyChange( PROP_USER_SCALE_FACTOR, oldScaleFactor, scaleFactor );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float normalizeScaleFactor( float scaleFactor ) {
|
||||||
|
if( scaleFactor < 1f ) {
|
||||||
|
return FlatSystemProperties.getBoolean( FlatSystemProperties.UI_SCALE_ALLOW_SCALE_DOWN, false )
|
||||||
|
? Math.round( scaleFactor * 10f ) / 10f // round small scale factor to 1/10
|
||||||
|
: 1f;
|
||||||
|
} else if( scaleFactor > 1f ) // round scale factor to 1/4
|
||||||
|
return Math.round( scaleFactor * 4f ) / 4f;
|
||||||
|
else
|
||||||
|
return scaleFactor;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -451,4 +503,185 @@ public class UIScale
|
|||||||
? new InsetsUIResource( scale( insets.top ), scale( insets.left ), scale( insets.bottom ), scale( insets.right ) )
|
? new InsetsUIResource( scale( insets.top ), scale( insets.left ), scale( insets.bottom ), scale( insets.right ) )
|
||||||
: new Insets ( scale( insets.top ), scale( insets.left ), scale( insets.bottom ), scale( insets.right ) ));
|
: new Insets ( scale( insets.top ), scale( insets.left ), scale( insets.bottom ), scale( insets.right ) ));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---- zoom ---------------------------------------------------------------
|
||||||
|
|
||||||
|
private static float zoomFactor = 1;
|
||||||
|
private static float[] supportedZoomFactors = { 1f, 1.1f, 1.25f, 1.5f, 1.75f, 2f };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current zoom factor. Default is {@code 1}.
|
||||||
|
*
|
||||||
|
* @since 3.7
|
||||||
|
*/
|
||||||
|
public static float getZoomFactor() {
|
||||||
|
return zoomFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the zoom factor.
|
||||||
|
* Also updates user scale factor and default font (if FlatLaf is active Laf).
|
||||||
|
* <p>
|
||||||
|
* UI needs to be updated if zoom factor has changed. E.g.:
|
||||||
|
* <pre>{@code
|
||||||
|
* if( UIScale.setZoomFactor( newZoomFactor ) )
|
||||||
|
* FlatLaf.updateUI();
|
||||||
|
* }</pre>
|
||||||
|
*
|
||||||
|
* @param zoomFactor new zoom factor
|
||||||
|
* @return {@code true} if zoom factor has changed
|
||||||
|
* @since 3.7
|
||||||
|
*/
|
||||||
|
public static boolean setZoomFactor( float zoomFactor ) {
|
||||||
|
// minimum zoom factor
|
||||||
|
zoomFactor = Math.max( zoomFactor, 0.1f );
|
||||||
|
|
||||||
|
if( UIScale.zoomFactor == zoomFactor )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
float oldZoomFactor = UIScale.zoomFactor;
|
||||||
|
UIScale.zoomFactor = zoomFactor;
|
||||||
|
|
||||||
|
if( DEBUG )
|
||||||
|
System.out.println( "Zoom factor " + oldZoomFactor + " --> " + zoomFactor );
|
||||||
|
|
||||||
|
setScaleFactor( UIScale.unzoomedScaleFactor * zoomFactor );
|
||||||
|
|
||||||
|
if( initialized && UIManager.getLookAndFeel() instanceof FlatLaf ) {
|
||||||
|
// see also FlatLaf.initDefaultFont()
|
||||||
|
UIDefaults defaults = UIManager.getLookAndFeelDefaults();
|
||||||
|
Font font = defaults.getFont( "defaultFont" );
|
||||||
|
int unzoomedSize = defaults.getInt( "defaultFont.unzoomedSize" );
|
||||||
|
if( unzoomedSize == 0 ) {
|
||||||
|
unzoomedSize = font.getSize();
|
||||||
|
defaults.put( "defaultFont.unzoomedSize", unzoomedSize );
|
||||||
|
}
|
||||||
|
|
||||||
|
// update "defaultFont"
|
||||||
|
ignoreFontChange = true;
|
||||||
|
try {
|
||||||
|
// get application default font before updating Laf default font
|
||||||
|
Font appFont = UIManager.getFont( "defaultFont" );
|
||||||
|
|
||||||
|
// update Laf default font
|
||||||
|
int newFontSize = Math.max( Math.round( unzoomedSize * zoomFactor ), 1 );
|
||||||
|
defaults.put( "defaultFont", new FontUIResource( font.deriveFont( (float) newFontSize ) ) );
|
||||||
|
|
||||||
|
if( DEBUG )
|
||||||
|
System.out.println( "Zoom Laf font " + font.getSize() + " --> " + newFontSize + " (unzoomed " + unzoomedSize + ")" );
|
||||||
|
|
||||||
|
// check whether application has changed default font
|
||||||
|
if( appFont != font ) {
|
||||||
|
// application has own default font --> also zoom it
|
||||||
|
int newAppFontSize = Math.max( Math.round( (appFont.getSize() / oldZoomFactor) * zoomFactor ), 1 );
|
||||||
|
UIManager.put( "defaultFont", appFont.deriveFont( (float) newAppFontSize ) );
|
||||||
|
|
||||||
|
if( DEBUG )
|
||||||
|
System.out.println( "Zoom app font " + appFont.getSize() + " --> " + newAppFontSize );
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
ignoreFontChange = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( changeSupport != null )
|
||||||
|
changeSupport.firePropertyChange( PROP_ZOOM_FACTOR, oldZoomFactor, zoomFactor );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increases zoom factor using next greater factor in supported factors array.
|
||||||
|
* <p>
|
||||||
|
* UI needs to be updated if zoom factor has changed. E.g.:
|
||||||
|
* <pre>{@code
|
||||||
|
* if( UIScale.zoomIn() )
|
||||||
|
* FlatLaf.updateUI();
|
||||||
|
* }</pre>
|
||||||
|
*
|
||||||
|
* @return {@code true} if zoom factor has changed
|
||||||
|
* @see #getSupportedZoomFactors()
|
||||||
|
* @since 3.7
|
||||||
|
*/
|
||||||
|
public static boolean zoomIn() {
|
||||||
|
int i = Arrays.binarySearch( supportedZoomFactors, zoomFactor );
|
||||||
|
int next = (i >= 0) ? i + 1 : -i - 1;
|
||||||
|
if( next >= supportedZoomFactors.length )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return setZoomFactor( supportedZoomFactors[next] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decreases zoom factor using next smaller factor in supported factors array.
|
||||||
|
* <p>
|
||||||
|
* UI needs to be updated if zoom factor has changed. E.g.:
|
||||||
|
* <pre>{@code
|
||||||
|
* if( UIScale.zoomOut() )
|
||||||
|
* FlatLaf.updateUI();
|
||||||
|
* }</pre>
|
||||||
|
*
|
||||||
|
* @return {@code true} if zoom factor has changed
|
||||||
|
* @see #getSupportedZoomFactors()
|
||||||
|
* @since 3.7
|
||||||
|
*/
|
||||||
|
public static boolean zoomOut() {
|
||||||
|
int i = Arrays.binarySearch( supportedZoomFactors, zoomFactor );
|
||||||
|
int prev = (i >= 0) ? i - 1 : -i - 2;
|
||||||
|
if( prev < 0 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return setZoomFactor( supportedZoomFactors[prev] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets zoom factor to {@code 1}.
|
||||||
|
* <p>
|
||||||
|
* UI needs to be updated if zoom factor has changed. E.g.:
|
||||||
|
* <pre>{@code
|
||||||
|
* if( UIScale.zoomReset() )
|
||||||
|
* FlatLaf.updateUI();
|
||||||
|
* }</pre>
|
||||||
|
*
|
||||||
|
* @return {@code true} if zoom factor has changed
|
||||||
|
* @since 3.7
|
||||||
|
*/
|
||||||
|
public static boolean zoomReset() {
|
||||||
|
return setZoomFactor( 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the supported zoom factors used for {@link #zoomIn()} and {@link #zoomOut()}.
|
||||||
|
* <p>
|
||||||
|
* Default is {@code [ 1f, 1.1f, 1.25f, 1.5f, 1.75f, 2f ]}.
|
||||||
|
*
|
||||||
|
* @since 3.7
|
||||||
|
*/
|
||||||
|
public static float[] getSupportedZoomFactors() {
|
||||||
|
return supportedZoomFactors.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the supported zoom factors used for {@link #zoomIn()} and {@link #zoomOut()}.
|
||||||
|
*
|
||||||
|
* @since 3.7
|
||||||
|
*/
|
||||||
|
public static void setSupportedZoomFactors( float[] supportedZoomFactors ) {
|
||||||
|
UIScale.supportedZoomFactors = supportedZoomFactors.clone();
|
||||||
|
Arrays.sort( UIScale.supportedZoomFactors );
|
||||||
|
|
||||||
|
if( Arrays.binarySearch( UIScale.supportedZoomFactors, 1f ) < 0 )
|
||||||
|
throw new IllegalArgumentException( "supportedZoomFactors array must contain value 1f" );
|
||||||
|
}
|
||||||
|
|
||||||
|
//---- unit testing -------------------------------------------------------
|
||||||
|
|
||||||
|
static boolean inUnitTests;
|
||||||
|
|
||||||
|
static void tests_uninitialize() {
|
||||||
|
initialized = false;
|
||||||
|
unzoomedScaleFactor = 1;
|
||||||
|
scaleFactor = 1;
|
||||||
|
zoomFactor = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,7 +61,6 @@ Component.arrowType = triangle
|
|||||||
#---- ProgressBar ----
|
#---- ProgressBar ----
|
||||||
|
|
||||||
ProgressBar.foreground = darken(@foreground,10%)
|
ProgressBar.foreground = darken(@foreground,10%)
|
||||||
ProgressBar.selectionForeground = @background
|
|
||||||
|
|
||||||
|
|
||||||
#---- RadioButton ----
|
#---- RadioButton ----
|
||||||
|
|||||||
@@ -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 ----
|
||||||
@@ -274,7 +276,7 @@ RootPane.inactiveBorderColor = lighten(@background,5%,derived)
|
|||||||
#---- ScrollBar ----
|
#---- ScrollBar ----
|
||||||
|
|
||||||
ScrollBar.track = lighten(@background,1%,derived noAutoInverse)
|
ScrollBar.track = lighten(@background,1%,derived noAutoInverse)
|
||||||
ScrollBar.thumb = lighten($ScrollBar.track,10%,derived noAutoInverse)
|
ScrollBar.thumb = lighten($ScrollBar.track,15%,derived noAutoInverse)
|
||||||
ScrollBar.hoverTrackColor = lighten($ScrollBar.track,4%,derived noAutoInverse)
|
ScrollBar.hoverTrackColor = lighten($ScrollBar.track,4%,derived noAutoInverse)
|
||||||
ScrollBar.hoverThumbColor = lighten($ScrollBar.thumb,10%,derived noAutoInverse)
|
ScrollBar.hoverThumbColor = lighten($ScrollBar.thumb,10%,derived noAutoInverse)
|
||||||
ScrollBar.pressedThumbColor = lighten($ScrollBar.thumb,15%,derived noAutoInverse)
|
ScrollBar.pressedThumbColor = lighten($ScrollBar.thumb,15%,derived noAutoInverse)
|
||||||
@@ -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 ----
|
||||||
@@ -341,8 +343,13 @@ TableHeader.bottomSeparatorColor = $TableHeader.separatorColor
|
|||||||
#---- TitlePane ----
|
#---- TitlePane ----
|
||||||
|
|
||||||
TitlePane.embeddedForeground = darken($TitlePane.foreground,15%)
|
TitlePane.embeddedForeground = darken($TitlePane.foreground,15%)
|
||||||
TitlePane.buttonHoverBackground = lighten($TitlePane.background,15%,derived)
|
TitlePane.buttonHoverBackground = lighten($TitlePane.background,10%,derived)
|
||||||
TitlePane.buttonPressedBackground = lighten($TitlePane.background,10%,derived)
|
TitlePane.buttonPressedBackground = lighten($TitlePane.background,6%,derived)
|
||||||
|
|
||||||
|
# Linux
|
||||||
|
[linux]TitlePane.buttonBackground = lighten($TitlePane.background,5%,derived)
|
||||||
|
[linux]TitlePane.buttonHoverBackground = lighten($TitlePane.background,10%,derived)
|
||||||
|
[linux]TitlePane.buttonPressedBackground = lighten($TitlePane.background,15%,derived)
|
||||||
|
|
||||||
|
|
||||||
#---- ToggleButton ----
|
#---- ToggleButton ----
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
@@ -574,12 +574,12 @@ RootPane.honorDialogMinimumSizeOnResize = true
|
|||||||
|
|
||||||
ScrollBar.width = 10
|
ScrollBar.width = 10
|
||||||
ScrollBar.minimumButtonSize = 12,12
|
ScrollBar.minimumButtonSize = 12,12
|
||||||
ScrollBar.minimumThumbSize = 10,10
|
ScrollBar.minimumThumbSize = 18,18
|
||||||
ScrollBar.maximumThumbSize = 100000,100000
|
ScrollBar.maximumThumbSize = 100000,100000
|
||||||
ScrollBar.trackInsets = 0,0,0,0
|
ScrollBar.trackInsets = 0,0,0,0
|
||||||
ScrollBar.thumbInsets = 0,0,0,0
|
ScrollBar.thumbInsets = 2,2,2,2
|
||||||
ScrollBar.trackArc = 0
|
ScrollBar.trackArc = 0
|
||||||
ScrollBar.thumbArc = 0
|
ScrollBar.thumbArc = 999
|
||||||
ScrollBar.hoverThumbWithTrack = false
|
ScrollBar.hoverThumbWithTrack = false
|
||||||
ScrollBar.pressedThumbWithTrack = false
|
ScrollBar.pressedThumbWithTrack = false
|
||||||
ScrollBar.showButtons = false
|
ScrollBar.showButtons = false
|
||||||
@@ -588,15 +588,8 @@ ScrollBar.buttonArrowColor = @buttonArrowColor
|
|||||||
ScrollBar.buttonDisabledArrowColor = @buttonDisabledArrowColor
|
ScrollBar.buttonDisabledArrowColor = @buttonDisabledArrowColor
|
||||||
ScrollBar.allowsAbsolutePositioning = true
|
ScrollBar.allowsAbsolutePositioning = true
|
||||||
|
|
||||||
[mac]ScrollBar.minimumThumbSize = 18,18
|
|
||||||
[mac]ScrollBar.thumbInsets = 2,2,2,2
|
|
||||||
[mac]ScrollBar.thumbArc = 999
|
|
||||||
[mac]ScrollBar.hoverThumbWithTrack = true
|
[mac]ScrollBar.hoverThumbWithTrack = true
|
||||||
|
|
||||||
[linux]ScrollBar.minimumThumbSize = 18,18
|
|
||||||
[linux]ScrollBar.thumbInsets = 2,2,2,2
|
|
||||||
[linux]ScrollBar.thumbArc = 999
|
|
||||||
|
|
||||||
|
|
||||||
#---- ScrollPane ----
|
#---- ScrollPane ----
|
||||||
|
|
||||||
@@ -703,7 +696,7 @@ TabbedPane.hiddenTabsNavigation = moreTabsButton
|
|||||||
TabbedPane.tabAreaAlignment = leading
|
TabbedPane.tabAreaAlignment = leading
|
||||||
# allowed values: leading, trailing or center
|
# allowed values: leading, trailing or center
|
||||||
TabbedPane.tabAlignment = center
|
TabbedPane.tabAlignment = center
|
||||||
# allowed values: preferred, equal or compact
|
# allowed values: preferred, equal, compact or iconsOnly
|
||||||
TabbedPane.tabWidthMode = preferred
|
TabbedPane.tabWidthMode = preferred
|
||||||
# allowed values: none, auto, left or right
|
# allowed values: none, auto, left or right
|
||||||
TabbedPane.tabRotation = none
|
TabbedPane.tabRotation = none
|
||||||
@@ -823,9 +816,14 @@ TitlePane.iconMargins = 3,8,3,8
|
|||||||
TitlePane.titleMargins = 3,0,3,0
|
TitlePane.titleMargins = 3,0,3,0
|
||||||
TitlePane.titleMinimumWidth = 60
|
TitlePane.titleMinimumWidth = 60
|
||||||
TitlePane.buttonSize = 44,30
|
TitlePane.buttonSize = 44,30
|
||||||
|
TitlePane.buttonInsets = 0,0,0,0
|
||||||
|
TitlePane.buttonArc = 0
|
||||||
TitlePane.buttonMinimumWidth = 30
|
TitlePane.buttonMinimumWidth = 30
|
||||||
TitlePane.buttonMaximizedHeight = 22
|
TitlePane.buttonMaximizedHeight = 22
|
||||||
TitlePane.buttonSymbolHeight = 10
|
TitlePane.buttonSymbolHeight = 10
|
||||||
|
TitlePane.buttonsGap = 0
|
||||||
|
TitlePane.buttonsMargins = 0,0,0,0
|
||||||
|
TitlePane.buttonsFillVertically = true
|
||||||
TitlePane.centerTitle = false
|
TitlePane.centerTitle = false
|
||||||
TitlePane.centerTitleIfMenuBarEmbedded = true
|
TitlePane.centerTitleIfMenuBarEmbedded = true
|
||||||
TitlePane.showIconBesideTitle = false
|
TitlePane.showIconBesideTitle = false
|
||||||
@@ -856,6 +854,27 @@ TitlePane.small.iconifyIcon = com.formdev.flatlaf.icons.FlatWindowIconifyIcon, s
|
|||||||
TitlePane.small.maximizeIcon = com.formdev.flatlaf.icons.FlatWindowMaximizeIcon, small
|
TitlePane.small.maximizeIcon = com.formdev.flatlaf.icons.FlatWindowMaximizeIcon, small
|
||||||
TitlePane.small.restoreIcon = com.formdev.flatlaf.icons.FlatWindowRestoreIcon, small
|
TitlePane.small.restoreIcon = com.formdev.flatlaf.icons.FlatWindowRestoreIcon, small
|
||||||
|
|
||||||
|
# Linux
|
||||||
|
[linux]TitlePane.buttonSize = 26,26
|
||||||
|
[linux]TitlePane.buttonInsets = 2,2,2,2
|
||||||
|
[linux]TitlePane.buttonArc = 999
|
||||||
|
[linux]TitlePane.buttonMaximizedHeight = -1
|
||||||
|
[linux]TitlePane.buttonSymbolHeight = 8
|
||||||
|
[linux]TitlePane.buttonsGap = 8
|
||||||
|
[linux]TitlePane.buttonsMargins = 4,4,4,4
|
||||||
|
[linux]TitlePane.buttonsFillVertically = false
|
||||||
|
[linux]TitlePane.small.buttonSize = 20,20
|
||||||
|
[linux]TitlePane.small.buttonInsets = 1,1,1,1
|
||||||
|
[linux]TitlePane.small.buttonSymbolHeight = 6
|
||||||
|
[linux]TitlePane.small.buttonsGap = 4
|
||||||
|
[linux]TitlePane.small.buttonsMargins = 2,2,2,2
|
||||||
|
[linux]TitlePane.closeBackground = $?TitlePane.buttonBackground
|
||||||
|
[linux]TitlePane.closeInactiveBackground = $?TitlePane.buttonInactiveBackground
|
||||||
|
[linux]TitlePane.closeHoverBackground = $?TitlePane.buttonHoverBackground
|
||||||
|
[linux]TitlePane.closePressedBackground = $?TitlePane.buttonPressedBackground
|
||||||
|
[linux]TitlePane.closeHoverForeground = $?TitlePane.foreground
|
||||||
|
[linux]TitlePane.closePressedForeground = $?TitlePane.foreground
|
||||||
|
|
||||||
|
|
||||||
#---- ToggleButton ----
|
#---- ToggleButton ----
|
||||||
|
|
||||||
@@ -934,6 +953,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
|
||||||
@@ -957,6 +977,24 @@ Tree.icon.openColor = @icon
|
|||||||
|
|
||||||
#---- Styles ------------------------------------------------------------------
|
#---- Styles ------------------------------------------------------------------
|
||||||
|
|
||||||
|
#---- scale icons ----
|
||||||
|
|
||||||
|
@largeScale = 1.125
|
||||||
|
@mediumScale = 0.875
|
||||||
|
@smallScale = 0.8125
|
||||||
|
@miniScale = 0.75
|
||||||
|
|
||||||
|
[style]CheckBox.large = icon.scale: @largeScale; iconTextGap: 5
|
||||||
|
[style]CheckBox.medium = icon.scale: @mediumScale
|
||||||
|
[style]CheckBox.small = icon.scale: @smallScale; iconTextGap: 3
|
||||||
|
[style]CheckBox.mini = icon.scale: @miniScale; iconTextGap: 3
|
||||||
|
|
||||||
|
[style]RadioButton.large = icon.scale: @largeScale; iconTextGap: 5
|
||||||
|
[style]RadioButton.medium = icon.scale: @mediumScale
|
||||||
|
[style]RadioButton.small = icon.scale: @smallScale; iconTextGap: 3
|
||||||
|
[style]RadioButton.mini = icon.scale: @miniScale; iconTextGap: 3
|
||||||
|
|
||||||
|
|
||||||
#---- inTextField ----
|
#---- inTextField ----
|
||||||
# for leading/trailing components in text fields
|
# for leading/trailing components in text fields
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|
||||||
@@ -280,7 +282,7 @@ RootPane.inactiveBorderColor = darken(@background,30%,derived)
|
|||||||
#---- ScrollBar ----
|
#---- ScrollBar ----
|
||||||
|
|
||||||
ScrollBar.track = lighten(@background,1%,derived noAutoInverse)
|
ScrollBar.track = lighten(@background,1%,derived noAutoInverse)
|
||||||
ScrollBar.thumb = darken($ScrollBar.track,10%,derived noAutoInverse)
|
ScrollBar.thumb = darken($ScrollBar.track,15%,derived noAutoInverse)
|
||||||
ScrollBar.hoverTrackColor = darken($ScrollBar.track,3%,derived noAutoInverse)
|
ScrollBar.hoverTrackColor = darken($ScrollBar.track,3%,derived noAutoInverse)
|
||||||
ScrollBar.hoverThumbColor = darken($ScrollBar.thumb,10%,derived noAutoInverse)
|
ScrollBar.hoverThumbColor = darken($ScrollBar.thumb,10%,derived noAutoInverse)
|
||||||
ScrollBar.pressedThumbColor = darken($ScrollBar.thumb,20%,derived noAutoInverse)
|
ScrollBar.pressedThumbColor = darken($ScrollBar.thumb,20%,derived noAutoInverse)
|
||||||
@@ -347,8 +349,13 @@ TableHeader.bottomSeparatorColor = $TableHeader.separatorColor
|
|||||||
#---- TitlePane ----
|
#---- TitlePane ----
|
||||||
|
|
||||||
TitlePane.embeddedForeground = lighten($TitlePane.foreground,35%)
|
TitlePane.embeddedForeground = lighten($TitlePane.foreground,35%)
|
||||||
TitlePane.buttonHoverBackground = darken($TitlePane.background,10%,derived)
|
TitlePane.buttonHoverBackground = darken($TitlePane.background,5%,derived)
|
||||||
TitlePane.buttonPressedBackground = darken($TitlePane.background,8%,derived)
|
TitlePane.buttonPressedBackground = darken($TitlePane.background,3%,derived)
|
||||||
|
|
||||||
|
# Linux
|
||||||
|
[linux]TitlePane.buttonBackground = darken($TitlePane.background,5%,derived)
|
||||||
|
[linux]TitlePane.buttonHoverBackground = darken($TitlePane.background,10%,derived)
|
||||||
|
[linux]TitlePane.buttonPressedBackground = darken($TitlePane.background,15%,derived)
|
||||||
|
|
||||||
|
|
||||||
#---- ToggleButton ----
|
#---- ToggleButton ----
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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
|
||||||
@@ -183,6 +184,7 @@ MenuBar.selectionEmbeddedInsets = 3,0,3,0
|
|||||||
MenuBar.selectionArc = 8
|
MenuBar.selectionArc = 8
|
||||||
MenuBar.selectionBackground = lighten(@menuBackground,15%,derived)
|
MenuBar.selectionBackground = lighten(@menuBackground,15%,derived)
|
||||||
MenuBar.selectionForeground = @foreground
|
MenuBar.selectionForeground = @foreground
|
||||||
|
MenuBar.borderColor = over($Separator.foreground,$MenuBar.background)
|
||||||
|
|
||||||
|
|
||||||
#---- MenuItem ----
|
#---- MenuItem ----
|
||||||
@@ -293,6 +295,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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -184,6 +184,7 @@ MenuBar.selectionEmbeddedInsets = 3,0,3,0
|
|||||||
MenuBar.selectionArc = 8
|
MenuBar.selectionArc = 8
|
||||||
MenuBar.selectionBackground = darken(@menuBackground,15%,derived)
|
MenuBar.selectionBackground = darken(@menuBackground,15%,derived)
|
||||||
MenuBar.selectionForeground = @foreground
|
MenuBar.selectionForeground = @foreground
|
||||||
|
MenuBar.borderColor = over($Separator.foreground,$MenuBar.background)
|
||||||
|
|
||||||
|
|
||||||
#---- MenuItem ----
|
#---- MenuItem ----
|
||||||
|
|||||||
@@ -17,6 +17,9 @@
|
|||||||
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.assertThrowsExactly;
|
||||||
|
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;
|
||||||
@@ -27,8 +30,16 @@ import javax.swing.border.Border;
|
|||||||
import javax.swing.UIDefaults.ActiveValue;
|
import javax.swing.UIDefaults.ActiveValue;
|
||||||
import javax.swing.UIDefaults.LazyValue;
|
import javax.swing.UIDefaults.LazyValue;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.function.Executable;
|
||||||
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 +191,336 @@ 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 );
|
||||||
|
}
|
||||||
|
|
||||||
|
//---- invalid values -----------------------------------------------------
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void parseInvalidValue() {
|
||||||
|
assertThrows( new IllegalArgumentException( "invalid character 'abc'" ), () -> UIDefaultsLoader.parseValue( "dummyChar", "abc", null ) );
|
||||||
|
assertThrows( new NumberFormatException( "invalid integer or float '123abc'" ), () -> UIDefaultsLoader.parseValue( "dummyWidth", "123abc", null ) );
|
||||||
|
assertThrows( new NumberFormatException( "invalid integer or float '1.23abc'" ), () -> UIDefaultsLoader.parseValue( "dummyWidth", "1.23abc", null ) );
|
||||||
|
|
||||||
|
assertThrows( new IllegalArgumentException( "invalid insets '1,abc,3,4'" ), () -> UIDefaultsLoader.parseValue( "dummyInsets", "1,abc,3,4", null ) );
|
||||||
|
assertThrows( new IllegalArgumentException( "invalid insets '1,2,3'" ), () -> UIDefaultsLoader.parseValue( "dummyInsets", "1,2,3", null ) );
|
||||||
|
assertThrows( new IllegalArgumentException( "invalid size '1abc'" ), () -> UIDefaultsLoader.parseValue( "dummySize", "1abc", null ) );
|
||||||
|
assertThrows( new IllegalArgumentException( "invalid size '1'" ), () -> UIDefaultsLoader.parseValue( "dummySize", "1", null ) );
|
||||||
|
assertThrows( new IllegalArgumentException( "invalid color '#f0'" ), () -> UIDefaultsLoader.parseValue( "dummy", "#f0", null ) );
|
||||||
|
assertThrows( new IllegalArgumentException( "invalid color '#f0'" ), () -> UIDefaultsLoader.parseValue( "dummyColor", "#f0", null ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void parseInvalidValueWithJavaType() {
|
||||||
|
assertThrows( new IllegalArgumentException( "invalid boolean 'falseyy'" ), () -> UIDefaultsLoader.parseValue( "dummy", "falseyy", boolean.class ) );
|
||||||
|
assertThrows( new IllegalArgumentException( "invalid boolean 'falseyy'" ), () -> UIDefaultsLoader.parseValue( "dummy", "falseyy", Boolean.class ) );
|
||||||
|
|
||||||
|
assertThrows( new IllegalArgumentException( "invalid character 'abc'" ), () -> UIDefaultsLoader.parseValue( "dummyChar", "abc", char.class ) );
|
||||||
|
assertThrows( new IllegalArgumentException( "invalid character 'abc'" ), () -> UIDefaultsLoader.parseValue( "dummyChar", "abc", Character.class ) );
|
||||||
|
assertThrows( new NumberFormatException( "invalid integer '123abc'" ), () -> UIDefaultsLoader.parseValue( "dummyWidth", "123abc", int.class ) );
|
||||||
|
assertThrows( new NumberFormatException( "invalid integer '123abc'" ), () -> UIDefaultsLoader.parseValue( "dummyWidth", "123abc", Integer.class ) );
|
||||||
|
assertThrows( new NumberFormatException( "invalid float '1.23abc'" ), () -> UIDefaultsLoader.parseValue( "dummyWidth", "1.23abc", float.class ) );
|
||||||
|
assertThrows( new NumberFormatException( "invalid float '1.23abc'" ), () -> UIDefaultsLoader.parseValue( "dummyWidth", "1.23abc", Float.class ) );
|
||||||
|
|
||||||
|
assertThrows( new IllegalArgumentException( "invalid insets '1,abc,3'" ), () -> UIDefaultsLoader.parseValue( "dummyInsets", "1,abc,3", Insets.class ) );
|
||||||
|
assertThrows( new IllegalArgumentException( "invalid insets '1,2,3'" ), () -> UIDefaultsLoader.parseValue( "dummyInsets", "1,2,3", Insets.class ) );
|
||||||
|
assertThrows( new IllegalArgumentException( "invalid size '1abc'" ), () -> UIDefaultsLoader.parseValue( "dummySize", "1abc", Dimension.class ) );
|
||||||
|
assertThrows( new IllegalArgumentException( "invalid size '1'" ), () -> UIDefaultsLoader.parseValue( "dummySize", "1", Dimension.class ) );
|
||||||
|
assertThrows( new IllegalArgumentException( "invalid color '#f0'" ), () -> UIDefaultsLoader.parseValue( "dummy", "#f0", Color.class ) );
|
||||||
|
assertThrows( new IllegalArgumentException( "invalid color '#f0'" ), () -> UIDefaultsLoader.parseValue( "dummyColor", "#f0", Color.class ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void parseInvalidBorders() {
|
||||||
|
assertThrows( new IllegalArgumentException( "invalid border '1,abc,3,4' (invalid insets '1,abc,3,4')" ), () -> UIDefaultsLoader.parseValue( "dummyBorder", "1,abc,3,4", null ) );
|
||||||
|
assertThrows( new IllegalArgumentException( "invalid border '1,2,3' (invalid insets '1,2,3')" ), () -> UIDefaultsLoader.parseValue( "dummyBorder", "1,2,3", null ) );
|
||||||
|
assertThrows( new IllegalArgumentException( "invalid border '1,2,3,,,' (invalid insets '1,2,3,,,')" ), () -> UIDefaultsLoader.parseValue( "dummyBorder", "1,2,3,,,", null ) );
|
||||||
|
assertThrows( new IllegalArgumentException( "invalid border '1,2,3,4,#f0' (invalid color '#f0')" ), () -> UIDefaultsLoader.parseValue( "dummyBorder", "1,2,3,4,#f0", null ) );
|
||||||
|
assertThrows( new IllegalArgumentException( "invalid border '1,2,3,4,#f00,2.5abc' (invalid float '2.5abc')" ), () -> UIDefaultsLoader.parseValue( "dummyBorder", "1,2,3,4,#f00,2.5abc", null ) );
|
||||||
|
assertThrows( new IllegalArgumentException( "invalid border '1,2,3,4,#f00,2.5,6abc' (invalid integer '6abc')" ), () -> UIDefaultsLoader.parseValue( "dummyBorder", "1,2,3,4,#f00,2.5,6abc", null ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void parseInvalidFonts() {
|
||||||
|
// size
|
||||||
|
assertThrows( new IllegalArgumentException( "invalid font '12abc' (invalid integer '12abc')" ), () -> UIDefaultsLoader.parseValue( "dummyFont", "12abc", null ) );
|
||||||
|
assertThrows( new IllegalArgumentException( "invalid font '+12abc' (invalid integer '+12abc')" ), () -> UIDefaultsLoader.parseValue( "dummyFont", "+12abc", null ) );
|
||||||
|
assertThrows( new IllegalArgumentException( "invalid font '+3abc' (invalid integer '+3abc')" ), () -> UIDefaultsLoader.parseValue( "dummyFont", "+3abc", null ) );
|
||||||
|
assertThrows( new IllegalArgumentException( "invalid font '-4abc' (invalid integer '-4abc')" ), () -> UIDefaultsLoader.parseValue( "dummyFont", "-4abc", null ) );
|
||||||
|
assertThrows( new IllegalArgumentException( "invalid font '150abc%' (invalid integer '150abc')" ), () -> UIDefaultsLoader.parseValue( "dummyFont", "150abc%", null ) );
|
||||||
|
assertThrows( new IllegalArgumentException( "invalid font 'bold 13abc Monospaced' (invalid integer '13abc')" ), () -> UIDefaultsLoader.parseValue( "dummyFont", "bold 13abc Monospaced", null ) );
|
||||||
|
|
||||||
|
// invalid combinations of styles
|
||||||
|
assertThrows( new IllegalArgumentException( "invalid font 'bold +italic': can not mix absolute style (e.g. 'bold') with derived style (e.g. '+italic')" ), () -> UIDefaultsLoader.parseValue( "dummyFont", "bold +italic", null ) );
|
||||||
|
assertThrows( new IllegalArgumentException( "invalid font '+bold -bold': can not use '+bold' and '-bold'" ), () -> UIDefaultsLoader.parseValue( "dummyFont", "+bold -bold", null ) );
|
||||||
|
assertThrows( new IllegalArgumentException( "invalid font '+italic -italic': can not use '+italic' and '-italic'" ), () -> UIDefaultsLoader.parseValue( "dummyFont", "+italic -italic", null ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertThrows( Throwable expected, Executable executable ) {
|
||||||
|
Throwable actual = assertThrowsExactly( expected.getClass(), executable );
|
||||||
|
assertEquals( expected.getMessage(), actual.getMessage() );
|
||||||
|
}
|
||||||
|
|
||||||
//---- class TestInstance -------------------------------------------------
|
//---- class TestInstance -------------------------------------------------
|
||||||
|
|
||||||
@SuppressWarnings( "EqualsHashCode" ) // Error Prone
|
@SuppressWarnings( "EqualsHashCode" ) // Error Prone
|
||||||
|
|||||||
@@ -0,0 +1,404 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2025 FormDev Software GmbH
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.formdev.flatlaf.ui;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JComponent;
|
||||||
|
import javax.swing.JRootPane;
|
||||||
|
import javax.swing.UIManager;
|
||||||
|
import org.junit.jupiter.api.AfterAll;
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
|
import com.formdev.flatlaf.FlatLaf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Karl Tauber
|
||||||
|
*/
|
||||||
|
public class TestFlatButton
|
||||||
|
{
|
||||||
|
@BeforeAll
|
||||||
|
static void setup() {
|
||||||
|
String[] defs = {
|
||||||
|
"Button.background", "#000001",
|
||||||
|
"Button.foreground", "#000002",
|
||||||
|
"Button.focusedBackground", "#000003",
|
||||||
|
"Button.focusedForeground", "#000004",
|
||||||
|
"Button.hoverBackground", "#000005",
|
||||||
|
"Button.hoverForeground", "#000006",
|
||||||
|
"Button.pressedBackground", "#000007",
|
||||||
|
"Button.pressedForeground", "#000008",
|
||||||
|
"Button.selectedBackground", "#000009",
|
||||||
|
"Button.selectedForeground", "#00000a",
|
||||||
|
"Button.disabledBackground", "#00000b",
|
||||||
|
"Button.disabledText", "#00000c",
|
||||||
|
"Button.disabledSelectedBackground", "#00000d",
|
||||||
|
"Button.disabledSelectedForeground", "#00000e",
|
||||||
|
|
||||||
|
"Button.default.background", "#000101",
|
||||||
|
"Button.default.foreground", "#000102",
|
||||||
|
"Button.default.focusedBackground", "#000103",
|
||||||
|
"Button.default.focusedForeground", "#000104",
|
||||||
|
"Button.default.hoverBackground", "#000105",
|
||||||
|
"Button.default.hoverForeground", "#000106",
|
||||||
|
"Button.default.pressedBackground", "#000107",
|
||||||
|
"Button.default.pressedForeground", "#000108",
|
||||||
|
|
||||||
|
"Button.toolbar.hoverBackground", "#000201",
|
||||||
|
"Button.toolbar.hoverForeground", "#000202",
|
||||||
|
"Button.toolbar.pressedBackground", "#000203",
|
||||||
|
"Button.toolbar.pressedForeground", "#000204",
|
||||||
|
"Button.toolbar.selectedBackground", "#000205",
|
||||||
|
"Button.toolbar.selectedForeground", "#000206",
|
||||||
|
"Button.toolbar.disabledSelectedBackground", "#000207",
|
||||||
|
"Button.toolbar.disabledSelectedForeground", "#000208",
|
||||||
|
};
|
||||||
|
|
||||||
|
HashMap<String, String> globalExtraDefaults = new HashMap<>();
|
||||||
|
for( int i = 0; i < defs.length; i += 2 )
|
||||||
|
globalExtraDefaults.put( defs[i], defs[i+1] );
|
||||||
|
FlatLaf.setGlobalExtraDefaults( globalExtraDefaults );
|
||||||
|
|
||||||
|
TestUtils.setup( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterAll
|
||||||
|
static void cleanup() {
|
||||||
|
TestUtils.cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void background() {
|
||||||
|
JButton b = new JButton();
|
||||||
|
|
||||||
|
testButtonColors( b, b2 -> ((FlatButtonUI)b2.getUI()).getBackground( b2 ),
|
||||||
|
UIManager.getColor( "Button.background" ),
|
||||||
|
UIManager.getColor( "Button.disabledBackground" ),
|
||||||
|
UIManager.getColor( "Button.focusedBackground" ),
|
||||||
|
UIManager.getColor( "Button.hoverBackground" ),
|
||||||
|
UIManager.getColor( "Button.pressedBackground" ) );
|
||||||
|
|
||||||
|
// selected
|
||||||
|
b.setSelected( true );
|
||||||
|
testButtonColors( b, b2 -> ((FlatButtonUI)b2.getUI()).getBackground( b2 ),
|
||||||
|
UIManager.getColor( "Button.selectedBackground" ),
|
||||||
|
UIManager.getColor( "Button.disabledSelectedBackground" ),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
UIManager.getColor( "Button.pressedBackground" ) );
|
||||||
|
b.setSelected( false );
|
||||||
|
|
||||||
|
// default
|
||||||
|
JRootPane rootPane = new JRootPane();
|
||||||
|
rootPane.getContentPane().add( b );
|
||||||
|
rootPane.setDefaultButton( b );
|
||||||
|
testButtonColors( b, b2 -> ((FlatButtonUI)b2.getUI()).getBackground( b2 ),
|
||||||
|
UIManager.getColor( "Button.default.background" ),
|
||||||
|
UIManager.getColor( "Button.disabledBackground" ),
|
||||||
|
UIManager.getColor( "Button.default.focusedBackground" ),
|
||||||
|
UIManager.getColor( "Button.default.hoverBackground" ),
|
||||||
|
UIManager.getColor( "Button.default.pressedBackground" ) );
|
||||||
|
rootPane.getContentPane().remove( b );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void foreground() {
|
||||||
|
JButton b = new JButton();
|
||||||
|
|
||||||
|
testButtonColors( b, b2 -> ((FlatButtonUI)b2.getUI()).getForeground( b2 ),
|
||||||
|
UIManager.getColor( "Button.foreground" ),
|
||||||
|
UIManager.getColor( "Button.disabledText" ),
|
||||||
|
UIManager.getColor( "Button.focusedForeground" ),
|
||||||
|
UIManager.getColor( "Button.hoverForeground" ),
|
||||||
|
UIManager.getColor( "Button.pressedForeground" ) );
|
||||||
|
|
||||||
|
// selected
|
||||||
|
b.setSelected( true );
|
||||||
|
testButtonColors( b, b2 -> ((FlatButtonUI)b2.getUI()).getForeground( b2 ),
|
||||||
|
UIManager.getColor( "Button.selectedForeground" ),
|
||||||
|
FlatUIUtils.getUIColor( "Button.disabledSelectedForeground", "Button.disabledText" ),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
UIManager.getColor( "Button.pressedForeground" ) );
|
||||||
|
b.setSelected( false );
|
||||||
|
|
||||||
|
// default
|
||||||
|
JRootPane rootPane = new JRootPane();
|
||||||
|
rootPane.getContentPane().add( b );
|
||||||
|
rootPane.setDefaultButton( b );
|
||||||
|
testButtonColors( b, b2 -> ((FlatButtonUI)b2.getUI()).getForeground( b2 ),
|
||||||
|
UIManager.getColor( "Button.default.foreground" ),
|
||||||
|
UIManager.getColor( "Button.disabledText" ),
|
||||||
|
UIManager.getColor( "Button.default.focusedForeground" ),
|
||||||
|
UIManager.getColor( "Button.default.hoverForeground" ),
|
||||||
|
UIManager.getColor( "Button.default.pressedForeground" ) );
|
||||||
|
rootPane.getContentPane().remove( b );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void backgroundExplicit() {
|
||||||
|
JButton b = new JButton();
|
||||||
|
|
||||||
|
Color c = new Color( 0x020001 );
|
||||||
|
b.setBackground( c );
|
||||||
|
|
||||||
|
testButtonColors( b, b2 -> ((FlatButtonUI)b2.getUI()).getBackground( b2 ),
|
||||||
|
c,
|
||||||
|
UIManager.getColor( "Button.disabledBackground" ),
|
||||||
|
null,
|
||||||
|
UIManager.getColor( "Button.hoverBackground" ),
|
||||||
|
UIManager.getColor( "Button.pressedBackground" ) );
|
||||||
|
|
||||||
|
// selected
|
||||||
|
b.setSelected( true );
|
||||||
|
testButtonColors( b, b2 -> ((FlatButtonUI)b2.getUI()).getBackground( b2 ),
|
||||||
|
UIManager.getColor( "Button.selectedBackground" ),
|
||||||
|
UIManager.getColor( "Button.disabledSelectedBackground" ),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
UIManager.getColor( "Button.pressedBackground" ) );
|
||||||
|
b.setSelected( false );
|
||||||
|
|
||||||
|
// default
|
||||||
|
JRootPane rootPane = new JRootPane();
|
||||||
|
rootPane.getContentPane().add( b );
|
||||||
|
rootPane.setDefaultButton( b );
|
||||||
|
testButtonColors( b, b2 -> ((FlatButtonUI)b2.getUI()).getBackground( b2 ),
|
||||||
|
c,
|
||||||
|
UIManager.getColor( "Button.disabledBackground" ),
|
||||||
|
null,
|
||||||
|
UIManager.getColor( "Button.default.hoverBackground" ),
|
||||||
|
UIManager.getColor( "Button.default.pressedBackground" ) );
|
||||||
|
rootPane.getContentPane().remove( b );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void foregroundExplicit() {
|
||||||
|
JButton b = new JButton();
|
||||||
|
|
||||||
|
Color c = new Color( 0x020001 );
|
||||||
|
b.setForeground( c );
|
||||||
|
|
||||||
|
testButtonColors( b, b2 -> ((FlatButtonUI)b2.getUI()).getForeground( b2 ),
|
||||||
|
c,
|
||||||
|
UIManager.getColor( "Button.disabledText" ),
|
||||||
|
null,
|
||||||
|
UIManager.getColor( "Button.hoverForeground" ),
|
||||||
|
UIManager.getColor( "Button.pressedForeground" ) );
|
||||||
|
|
||||||
|
// selected
|
||||||
|
b.setSelected( true );
|
||||||
|
testButtonColors( b, b2 -> ((FlatButtonUI)b2.getUI()).getForeground( b2 ),
|
||||||
|
c,
|
||||||
|
FlatUIUtils.getUIColor( "Button.disabledSelectedForeground", "Button.disabledText" ),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
UIManager.getColor( "Button.pressedForeground" ) );
|
||||||
|
b.setSelected( false );
|
||||||
|
|
||||||
|
// default
|
||||||
|
JRootPane rootPane = new JRootPane();
|
||||||
|
rootPane.getContentPane().add( b );
|
||||||
|
rootPane.setDefaultButton( b );
|
||||||
|
testButtonColors( b, b2 -> ((FlatButtonUI)b2.getUI()).getForeground( b2 ),
|
||||||
|
c,
|
||||||
|
UIManager.getColor( "Button.disabledText" ),
|
||||||
|
null,
|
||||||
|
UIManager.getColor( "Button.default.hoverForeground" ),
|
||||||
|
UIManager.getColor( "Button.default.pressedForeground" ) );
|
||||||
|
rootPane.getContentPane().remove( b );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void backgroundStyled() {
|
||||||
|
JButton b = new JButton();
|
||||||
|
|
||||||
|
b.putClientProperty( FlatClientProperties.STYLE,
|
||||||
|
"background: #020001;" +
|
||||||
|
"disabledBackground: #020002;" +
|
||||||
|
"focusedBackground: #020003;" +
|
||||||
|
"hoverBackground: #020004;" +
|
||||||
|
"pressedBackground: #020005;" +
|
||||||
|
"selectedBackground: #020006;" +
|
||||||
|
"disabledSelectedBackground: #020007;" );
|
||||||
|
|
||||||
|
testButtonColors( b, b2 -> ((FlatButtonUI)b2.getUI()).getBackground( b2 ),
|
||||||
|
new Color( 0x020001 ),
|
||||||
|
new Color( 0x020002 ),
|
||||||
|
new Color( 0x020003 ),
|
||||||
|
new Color( 0x020004 ),
|
||||||
|
new Color( 0x020005 ) );
|
||||||
|
|
||||||
|
// selected
|
||||||
|
b.setSelected( true );
|
||||||
|
testButtonColors( b, b2 -> ((FlatButtonUI)b2.getUI()).getBackground( b2 ),
|
||||||
|
new Color( 0x020006 ),
|
||||||
|
new Color( 0x020007 ),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
new Color( 0x020005 ) );
|
||||||
|
b.setSelected( false );
|
||||||
|
|
||||||
|
|
||||||
|
Color c = new Color( 0x0a0001 );
|
||||||
|
b.setBackground( c );
|
||||||
|
testButtonColors( b, b2 -> ((FlatButtonUI)b2.getUI()).getBackground( b2 ),
|
||||||
|
c,
|
||||||
|
new Color( 0x020002 ),
|
||||||
|
c,
|
||||||
|
new Color( 0x020004 ),
|
||||||
|
new Color( 0x020005 ) );
|
||||||
|
b.setSelected( true );
|
||||||
|
testButtonColors( b, b2 -> ((FlatButtonUI)b2.getUI()).getBackground( b2 ),
|
||||||
|
new Color( 0x020006 ),
|
||||||
|
new Color( 0x020007 ),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
new Color( 0x020005 ) );
|
||||||
|
b.setSelected( false );
|
||||||
|
|
||||||
|
|
||||||
|
b = new JButton();
|
||||||
|
b.putClientProperty( FlatClientProperties.STYLE,
|
||||||
|
"default.background: #020101;" +
|
||||||
|
"disabledBackground: #020102;" +
|
||||||
|
"default.focusedBackground: #020103;" +
|
||||||
|
"default.hoverBackground: #020104;" +
|
||||||
|
"default.pressedBackground: #020105;" );
|
||||||
|
|
||||||
|
// default
|
||||||
|
JRootPane rootPane = new JRootPane();
|
||||||
|
rootPane.getContentPane().add( b );
|
||||||
|
rootPane.setDefaultButton( b );
|
||||||
|
testButtonColors( b, b2 -> ((FlatButtonUI)b2.getUI()).getBackground( b2 ),
|
||||||
|
new Color( 0x020101 ),
|
||||||
|
new Color( 0x020102 ),
|
||||||
|
new Color( 0x020103 ),
|
||||||
|
new Color( 0x020104 ),
|
||||||
|
new Color( 0x020105 ) );
|
||||||
|
rootPane.getContentPane().remove( b );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void foregroundStyled() {
|
||||||
|
JButton b = new JButton();
|
||||||
|
|
||||||
|
b.putClientProperty( FlatClientProperties.STYLE,
|
||||||
|
"foreground: #020001;" +
|
||||||
|
"disabledText: #020002;" +
|
||||||
|
"focusedForeground: #020003;" +
|
||||||
|
"hoverForeground: #020004;" +
|
||||||
|
"pressedForeground: #020005;" +
|
||||||
|
"selectedForeground: #020006;" +
|
||||||
|
"disabledSelectedForeground: #020007;" );
|
||||||
|
|
||||||
|
testButtonColors( b, b2 -> ((FlatButtonUI)b2.getUI()).getForeground( b2 ),
|
||||||
|
new Color( 0x020001 ),
|
||||||
|
new Color( 0x020002 ),
|
||||||
|
new Color( 0x020003 ),
|
||||||
|
new Color( 0x020004 ),
|
||||||
|
new Color( 0x020005 ) );
|
||||||
|
|
||||||
|
// selected
|
||||||
|
b.setSelected( true );
|
||||||
|
testButtonColors( b, b2 -> ((FlatButtonUI)b2.getUI()).getForeground( b2 ),
|
||||||
|
new Color( 0x020006 ),
|
||||||
|
new Color( 0x020007 ),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
new Color( 0x020005 ) );
|
||||||
|
b.setSelected( false );
|
||||||
|
|
||||||
|
|
||||||
|
Color c = new Color( 0x0a0001 );
|
||||||
|
b.setForeground( c );
|
||||||
|
testButtonColors( b, b2 -> ((FlatButtonUI)b2.getUI()).getForeground( b2 ),
|
||||||
|
c,
|
||||||
|
new Color( 0x020002 ),
|
||||||
|
c,
|
||||||
|
new Color( 0x020004 ),
|
||||||
|
new Color( 0x020005 ) );
|
||||||
|
b.setSelected( true );
|
||||||
|
testButtonColors( b, b2 -> ((FlatButtonUI)b2.getUI()).getForeground( b2 ),
|
||||||
|
c,
|
||||||
|
new Color( 0x020007 ),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
new Color( 0x020005 ) );
|
||||||
|
b.setSelected( false );
|
||||||
|
|
||||||
|
|
||||||
|
b = new JButton();
|
||||||
|
b.putClientProperty( FlatClientProperties.STYLE,
|
||||||
|
"default.foreground: #020101;" +
|
||||||
|
"disabledText: #020102;" +
|
||||||
|
"default.focusedForeground: #020103;" +
|
||||||
|
"default.hoverForeground: #020104;" +
|
||||||
|
"default.pressedForeground: #020105;" );
|
||||||
|
|
||||||
|
// default
|
||||||
|
JRootPane rootPane = new JRootPane();
|
||||||
|
rootPane.getContentPane().add( b );
|
||||||
|
rootPane.setDefaultButton( b );
|
||||||
|
testButtonColors( b, b2 -> ((FlatButtonUI)b2.getUI()).getForeground( b2 ),
|
||||||
|
new Color( 0x020101 ),
|
||||||
|
new Color( 0x020102 ),
|
||||||
|
new Color( 0x020103 ),
|
||||||
|
new Color( 0x020104 ),
|
||||||
|
new Color( 0x020105 ) );
|
||||||
|
rootPane.getContentPane().remove( b );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testButtonColors( JButton b, Function<JButton, Color> f,
|
||||||
|
Color expectedEnabled, Color expectedDisabled, Color expectedFocused,
|
||||||
|
Color expectedHover, Color expectedPressed
|
||||||
|
)
|
||||||
|
{
|
||||||
|
assertEquals( expectedEnabled, f.apply( b ) );
|
||||||
|
|
||||||
|
// disabled
|
||||||
|
b.setEnabled( false );
|
||||||
|
assertEquals( expectedDisabled, f.apply( b ) );
|
||||||
|
b.setEnabled( true );
|
||||||
|
|
||||||
|
// focused
|
||||||
|
if( expectedFocused != null ) {
|
||||||
|
b.putClientProperty( FlatClientProperties.COMPONENT_FOCUS_OWNER, (Predicate<JComponent>) c -> true );
|
||||||
|
assertEquals( expectedFocused, f.apply( b ) );
|
||||||
|
b.putClientProperty( FlatClientProperties.COMPONENT_FOCUS_OWNER, null );
|
||||||
|
}
|
||||||
|
|
||||||
|
// hover
|
||||||
|
if( expectedHover != null ) {
|
||||||
|
b.getModel().setRollover( true );
|
||||||
|
assertEquals( expectedHover, f.apply( b ) );
|
||||||
|
b.getModel().setRollover( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
// pressed
|
||||||
|
if( expectedPressed != null ) {
|
||||||
|
b.getModel().setPressed( true );
|
||||||
|
assertEquals( expectedPressed, f.apply( b ) );
|
||||||
|
b.getModel().setPressed( false );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.formdev.flatlaf.ui;
|
package com.formdev.flatlaf.ui;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
@@ -73,6 +74,15 @@ public class TestFlatHTML
|
|||||||
testHtmlBaseSize( "<html>${BASE_SIZE}<style type='text/css'>body { color: #f00; }</style><h1>header1</h1>" + body + "</html>", "header1\n" + 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 ) {
|
private void testHtmlBaseSize( String html, String expectedPlain ) {
|
||||||
testHtmlBaseSizeImpl( html, expectedPlain );
|
testHtmlBaseSizeImpl( html, expectedPlain );
|
||||||
testHtmlBaseSizeImpl( html.toUpperCase( Locale.ENGLISH ), expectedPlain.toUpperCase( Locale.ENGLISH ) );
|
testHtmlBaseSizeImpl( html.toUpperCase( Locale.ENGLISH ), expectedPlain.toUpperCase( Locale.ENGLISH ) );
|
||||||
|
|||||||
@@ -30,6 +30,10 @@ import org.junit.jupiter.api.AfterAll;
|
|||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import com.formdev.flatlaf.icons.*;
|
import com.formdev.flatlaf.icons.*;
|
||||||
|
import com.formdev.flatlaf.ui.FlatInternalFrameUI.FlatInternalFrameBorder;
|
||||||
|
import com.formdev.flatlaf.ui.TestFlatStyling.CustomCheckBoxIcon;
|
||||||
|
import com.formdev.flatlaf.ui.TestFlatStyling.CustomIcon;
|
||||||
|
import com.formdev.flatlaf.ui.TestFlatStyling.CustomRadioButtonIcon;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Karl Tauber
|
* @author Karl Tauber
|
||||||
@@ -70,6 +74,8 @@ public class TestFlatStyleableInfo
|
|||||||
//---- FlatHelpButtonIcon ----
|
//---- FlatHelpButtonIcon ----
|
||||||
|
|
||||||
expectedMap( expected,
|
expectedMap( expected,
|
||||||
|
"help.scale", float.class,
|
||||||
|
|
||||||
"help.focusWidth", int.class,
|
"help.focusWidth", int.class,
|
||||||
"help.focusColor", Color.class,
|
"help.focusColor", Color.class,
|
||||||
"help.innerFocusWidth", float.class,
|
"help.innerFocusWidth", float.class,
|
||||||
@@ -144,7 +150,20 @@ public class TestFlatStyleableInfo
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void checkBox() {
|
void checkBox() {
|
||||||
JCheckBox c = new JCheckBox();
|
checkBox( new JCheckBox() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void checkBox2() {
|
||||||
|
checkBox( new JCheckBox( new CustomIcon() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void checkBox3() {
|
||||||
|
checkBox( new JCheckBox( new CustomCheckBoxIcon() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkBox( JCheckBox c ) {
|
||||||
FlatCheckBoxUI ui = (FlatCheckBoxUI) c.getUI();
|
FlatCheckBoxUI ui = (FlatCheckBoxUI) c.getUI();
|
||||||
|
|
||||||
assertTrue( ui.getDefaultIcon() instanceof FlatCheckBoxIcon );
|
assertTrue( ui.getDefaultIcon() instanceof FlatCheckBoxIcon );
|
||||||
@@ -153,6 +172,11 @@ public class TestFlatStyleableInfo
|
|||||||
Map<String, Class<?>> expected = new LinkedHashMap<>();
|
Map<String, Class<?>> expected = new LinkedHashMap<>();
|
||||||
radioButton( expected );
|
radioButton( expected );
|
||||||
|
|
||||||
|
// remove "icon." keys if check box has custom icon
|
||||||
|
Icon icon = c.getIcon();
|
||||||
|
if( icon != null && !(icon instanceof FlatCheckBoxIcon) )
|
||||||
|
expected.keySet().removeIf( key -> key.startsWith( "icon." ) );
|
||||||
|
|
||||||
assertMapEquals( expected, ui.getStyleableInfos( c ) );
|
assertMapEquals( expected, ui.getStyleableInfos( c ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,8 +199,9 @@ public class TestFlatStyleableInfo
|
|||||||
"disabledForeground", Color.class,
|
"disabledForeground", Color.class,
|
||||||
|
|
||||||
"buttonBackground", Color.class,
|
"buttonBackground", Color.class,
|
||||||
"buttonFocusedBackground", Color.class,
|
|
||||||
"buttonEditableBackground", Color.class,
|
"buttonEditableBackground", Color.class,
|
||||||
|
"buttonFocusedBackground", Color.class,
|
||||||
|
"buttonFocusedEditableBackground", Color.class,
|
||||||
"buttonSeparatorWidth", float.class,
|
"buttonSeparatorWidth", float.class,
|
||||||
"buttonSeparatorColor", Color.class,
|
"buttonSeparatorColor", Color.class,
|
||||||
"buttonDisabledSeparatorColor", Color.class,
|
"buttonDisabledSeparatorColor", Color.class,
|
||||||
@@ -270,6 +295,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,
|
||||||
|
|
||||||
@@ -390,6 +416,8 @@ public class TestFlatStyleableInfo
|
|||||||
|
|
||||||
private void menuItem_checkIcon( Map<String, Class<?>> expected ) {
|
private void menuItem_checkIcon( Map<String, Class<?>> expected ) {
|
||||||
expectedMap( expected,
|
expectedMap( expected,
|
||||||
|
"icon.scale", float.class,
|
||||||
|
|
||||||
"icon.checkmarkColor", Color.class,
|
"icon.checkmarkColor", Color.class,
|
||||||
"icon.disabledCheckmarkColor", Color.class,
|
"icon.disabledCheckmarkColor", Color.class,
|
||||||
"selectionForeground", Color.class
|
"selectionForeground", Color.class
|
||||||
@@ -398,6 +426,8 @@ public class TestFlatStyleableInfo
|
|||||||
|
|
||||||
private void menuItem_arrowIcon( Map<String, Class<?>> expected ) {
|
private void menuItem_arrowIcon( Map<String, Class<?>> expected ) {
|
||||||
expectedMap( expected,
|
expectedMap( expected,
|
||||||
|
"icon.scale", float.class,
|
||||||
|
|
||||||
"icon.arrowType", String.class,
|
"icon.arrowType", String.class,
|
||||||
"icon.arrowColor", Color.class,
|
"icon.arrowColor", Color.class,
|
||||||
"icon.disabledArrowColor", Color.class,
|
"icon.disabledArrowColor", Color.class,
|
||||||
@@ -433,7 +463,8 @@ public class TestFlatStyleableInfo
|
|||||||
|
|
||||||
expectedMap( expected,
|
expectedMap( expected,
|
||||||
// capsLockIcon
|
// capsLockIcon
|
||||||
"capsLockIconColor", Color.class
|
"capsLockIconColor", Color.class,
|
||||||
|
"capsLockIconScale", float.class
|
||||||
);
|
);
|
||||||
|
|
||||||
// border
|
// border
|
||||||
@@ -491,7 +522,20 @@ public class TestFlatStyleableInfo
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void radioButton() {
|
void radioButton() {
|
||||||
JRadioButton c = new JRadioButton();
|
radioButton( new JRadioButton() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void radioButton2() {
|
||||||
|
radioButton( new JRadioButton( new CustomIcon() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void radioButton3() {
|
||||||
|
radioButton( new JRadioButton( new CustomRadioButtonIcon() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void radioButton( JRadioButton c ) {
|
||||||
FlatRadioButtonUI ui = (FlatRadioButtonUI) c.getUI();
|
FlatRadioButtonUI ui = (FlatRadioButtonUI) c.getUI();
|
||||||
|
|
||||||
assertTrue( ui.getDefaultIcon() instanceof FlatRadioButtonIcon );
|
assertTrue( ui.getDefaultIcon() instanceof FlatRadioButtonIcon );
|
||||||
@@ -503,6 +547,11 @@ public class TestFlatStyleableInfo
|
|||||||
"icon.centerDiameter", float.class
|
"icon.centerDiameter", float.class
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// remove "icon." keys if radio button has custom icon
|
||||||
|
Icon icon = c.getIcon();
|
||||||
|
if( icon != null && !(icon instanceof FlatRadioButtonIcon) )
|
||||||
|
expected.keySet().removeIf( key -> key.startsWith( "icon." ) );
|
||||||
|
|
||||||
assertMapEquals( expected, ui.getStyleableInfos( c ) );
|
assertMapEquals( expected, ui.getStyleableInfos( c ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -512,11 +561,15 @@ public class TestFlatStyleableInfo
|
|||||||
|
|
||||||
//---- icon ----
|
//---- icon ----
|
||||||
|
|
||||||
|
"icon.scale", float.class,
|
||||||
|
|
||||||
"icon.focusWidth", float.class,
|
"icon.focusWidth", float.class,
|
||||||
"icon.focusColor", Color.class,
|
"icon.focusColor", Color.class,
|
||||||
"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 +578,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 +588,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 +598,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 +608,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
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -773,6 +841,7 @@ public class TestFlatStyleableInfo
|
|||||||
"tabIconPlacement", int.class,
|
"tabIconPlacement", int.class,
|
||||||
|
|
||||||
// FlatTabbedPaneCloseIcon
|
// FlatTabbedPaneCloseIcon
|
||||||
|
"closeScale", float.class,
|
||||||
"closeSize", Dimension.class,
|
"closeSize", Dimension.class,
|
||||||
"closeArc", int.class,
|
"closeArc", int.class,
|
||||||
"closeCrossPlainSize", float.class,
|
"closeCrossPlainSize", float.class,
|
||||||
@@ -965,9 +1034,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 +1131,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,
|
||||||
@@ -1090,6 +1163,16 @@ public class TestFlatStyleableInfo
|
|||||||
assertMapEquals( expected, border.getStyleableInfos() );
|
assertMapEquals( expected, border.getStyleableInfos() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void flatScrollPaneBorder() {
|
||||||
|
FlatScrollPaneBorder border = new FlatScrollPaneBorder();
|
||||||
|
|
||||||
|
Map<String, Class<?>> expected = new LinkedHashMap<>();
|
||||||
|
flatScrollPaneBorder( expected );
|
||||||
|
|
||||||
|
assertMapEquals( expected, border.getStyleableInfos() );
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void flatTextBorder() {
|
void flatTextBorder() {
|
||||||
FlatTextBorder border = new FlatTextBorder();
|
FlatTextBorder border = new FlatTextBorder();
|
||||||
@@ -1110,6 +1193,64 @@ public class TestFlatStyleableInfo
|
|||||||
assertMapEquals( expected, border.getStyleableInfos() );
|
assertMapEquals( expected, border.getStyleableInfos() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void flatDropShadowBorder() {
|
||||||
|
FlatDropShadowBorder border = new FlatDropShadowBorder();
|
||||||
|
|
||||||
|
Map<String, Class<?>> expected = expectedMap(
|
||||||
|
"shadowColor", Color.class,
|
||||||
|
"shadowInsets", Insets.class,
|
||||||
|
"shadowOpacity", float.class
|
||||||
|
);
|
||||||
|
|
||||||
|
assertMapEquals( expected, border.getStyleableInfos() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void flatMenuBarBorder() {
|
||||||
|
FlatMenuBarBorder border = new FlatMenuBarBorder();
|
||||||
|
|
||||||
|
Map<String, Class<?>> expected = expectedMap(
|
||||||
|
"borderColor", Color.class
|
||||||
|
);
|
||||||
|
|
||||||
|
assertMapEquals( expected, border.getStyleableInfos() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void flatPopupMenuBorder() {
|
||||||
|
FlatPopupMenuBorder border = new FlatPopupMenuBorder();
|
||||||
|
|
||||||
|
Map<String, Class<?>> expected = expectedMap(
|
||||||
|
"borderInsets", Insets.class,
|
||||||
|
"borderColor", Color.class
|
||||||
|
);
|
||||||
|
|
||||||
|
assertMapEquals( expected, border.getStyleableInfos() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void flatInternalFrameBorder() {
|
||||||
|
FlatInternalFrameBorder border = new FlatInternalFrameBorder();
|
||||||
|
|
||||||
|
Map<String, Class<?>> expected = expectedMap(
|
||||||
|
"activeBorderColor", Color.class,
|
||||||
|
"inactiveBorderColor", Color.class,
|
||||||
|
"borderLineWidth", int.class,
|
||||||
|
"dropShadowPainted", boolean.class,
|
||||||
|
"borderMargins", Insets.class,
|
||||||
|
|
||||||
|
"activeDropShadowColor", Color.class,
|
||||||
|
"activeDropShadowInsets", Insets.class,
|
||||||
|
"activeDropShadowOpacity", float.class,
|
||||||
|
"inactiveDropShadowColor", Color.class,
|
||||||
|
"inactiveDropShadowInsets", Insets.class,
|
||||||
|
"inactiveDropShadowOpacity", float.class
|
||||||
|
);
|
||||||
|
|
||||||
|
assertMapEquals( expected, border.getStyleableInfos() );
|
||||||
|
}
|
||||||
|
|
||||||
//---- icons --------------------------------------------------------------
|
//---- icons --------------------------------------------------------------
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -1139,11 +1280,15 @@ public class TestFlatStyleableInfo
|
|||||||
|
|
||||||
private void flatCheckBoxIcon( Map<String, Class<?>> expected ) {
|
private void flatCheckBoxIcon( Map<String, Class<?>> expected ) {
|
||||||
expectedMap( expected,
|
expectedMap( expected,
|
||||||
|
"scale", float.class,
|
||||||
|
|
||||||
"focusWidth", float.class,
|
"focusWidth", float.class,
|
||||||
"focusColor", Color.class,
|
"focusColor", Color.class,
|
||||||
"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 +1297,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 +1307,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 +1317,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 +1327,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
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1206,6 +1366,8 @@ public class TestFlatStyleableInfo
|
|||||||
|
|
||||||
private void flatCheckBoxMenuItemIcon( Map<String, Class<?>> expected ) {
|
private void flatCheckBoxMenuItemIcon( Map<String, Class<?>> expected ) {
|
||||||
expectedMap( expected,
|
expectedMap( expected,
|
||||||
|
"scale", float.class,
|
||||||
|
|
||||||
"checkmarkColor", Color.class,
|
"checkmarkColor", Color.class,
|
||||||
"disabledCheckmarkColor", Color.class,
|
"disabledCheckmarkColor", Color.class,
|
||||||
"selectionForeground", Color.class
|
"selectionForeground", Color.class
|
||||||
@@ -1224,6 +1386,8 @@ public class TestFlatStyleableInfo
|
|||||||
|
|
||||||
private void flatMenuArrowIcon( Map<String, Class<?>> expected ) {
|
private void flatMenuArrowIcon( Map<String, Class<?>> expected ) {
|
||||||
expectedMap( expected,
|
expectedMap( expected,
|
||||||
|
"scale", float.class,
|
||||||
|
|
||||||
"arrowType", String.class,
|
"arrowType", String.class,
|
||||||
"arrowColor", Color.class,
|
"arrowColor", Color.class,
|
||||||
"disabledArrowColor", Color.class,
|
"disabledArrowColor", Color.class,
|
||||||
@@ -1236,6 +1400,8 @@ public class TestFlatStyleableInfo
|
|||||||
FlatHelpButtonIcon icon = new FlatHelpButtonIcon();
|
FlatHelpButtonIcon icon = new FlatHelpButtonIcon();
|
||||||
|
|
||||||
Map<String, Class<?>> expected = expectedMap(
|
Map<String, Class<?>> expected = expectedMap(
|
||||||
|
"scale", float.class,
|
||||||
|
|
||||||
"focusWidth", int.class,
|
"focusWidth", int.class,
|
||||||
"focusColor", Color.class,
|
"focusColor", Color.class,
|
||||||
"innerFocusWidth", float.class,
|
"innerFocusWidth", float.class,
|
||||||
@@ -1256,4 +1422,87 @@ public class TestFlatStyleableInfo
|
|||||||
|
|
||||||
assertMapEquals( expected, icon.getStyleableInfos() );
|
assertMapEquals( expected, icon.getStyleableInfos() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void flatClearIcon() {
|
||||||
|
FlatClearIcon icon = new FlatClearIcon();
|
||||||
|
|
||||||
|
Map<String, Class<?>> expected = expectedMap(
|
||||||
|
"clearIconScale", float.class,
|
||||||
|
|
||||||
|
"clearIconColor", Color.class,
|
||||||
|
"clearIconHoverColor", Color.class,
|
||||||
|
"clearIconPressedColor", Color.class
|
||||||
|
);
|
||||||
|
|
||||||
|
assertMapEquals( expected, icon.getStyleableInfos() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void flatSearchIcon() {
|
||||||
|
FlatSearchIcon icon = new FlatSearchIcon();
|
||||||
|
|
||||||
|
Map<String, Class<?>> expected = new LinkedHashMap<>();
|
||||||
|
flatSearchIcon( expected );
|
||||||
|
|
||||||
|
assertMapEquals( expected, icon.getStyleableInfos() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void flatSearchWithHistoryIcon() {
|
||||||
|
FlatSearchWithHistoryIcon icon = new FlatSearchWithHistoryIcon();
|
||||||
|
|
||||||
|
Map<String, Class<?>> expected = new LinkedHashMap<>();
|
||||||
|
flatSearchIcon( expected );
|
||||||
|
|
||||||
|
assertMapEquals( expected, icon.getStyleableInfos() );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void flatSearchIcon( Map<String, Class<?>> expected ) {
|
||||||
|
expectedMap( expected,
|
||||||
|
"searchIconScale", float.class,
|
||||||
|
|
||||||
|
"searchIconColor", Color.class,
|
||||||
|
"searchIconHoverColor", Color.class,
|
||||||
|
"searchIconPressedColor", Color.class
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void flatCapsLockIcon() {
|
||||||
|
FlatCapsLockIcon icon = new FlatCapsLockIcon();
|
||||||
|
|
||||||
|
Map<String, Class<?>> expected = expectedMap(
|
||||||
|
"capsLockIconScale", float.class,
|
||||||
|
|
||||||
|
"capsLockIconColor", Color.class
|
||||||
|
);
|
||||||
|
|
||||||
|
assertMapEquals( expected, icon.getStyleableInfos() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void flatTabbedPaneCloseIcon() {
|
||||||
|
FlatTabbedPaneCloseIcon icon = new FlatTabbedPaneCloseIcon();
|
||||||
|
|
||||||
|
Map<String, Class<?>> expected = expectedMap(
|
||||||
|
//TODO closeScale ?
|
||||||
|
// "scale", float.class,
|
||||||
|
"closeScale", float.class,
|
||||||
|
|
||||||
|
"closeSize", Dimension.class,
|
||||||
|
"closeArc", int.class,
|
||||||
|
"closeCrossPlainSize", float.class,
|
||||||
|
"closeCrossFilledSize", float.class,
|
||||||
|
"closeCrossLineWidth", float.class,
|
||||||
|
"closeBackground", Color.class,
|
||||||
|
"closeForeground", Color.class,
|
||||||
|
"closeHoverBackground", Color.class,
|
||||||
|
"closeHoverForeground", Color.class,
|
||||||
|
"closePressedBackground", Color.class,
|
||||||
|
"closePressedForeground", Color.class
|
||||||
|
);
|
||||||
|
|
||||||
|
assertMapEquals( expected, icon.getStyleableInfos() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -17,9 +17,15 @@
|
|||||||
package com.formdev.flatlaf.ui;
|
package com.formdev.flatlaf.ui;
|
||||||
|
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
import java.util.TreeSet;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
import org.opentest4j.AssertionFailedError;
|
import org.opentest4j.AssertionFailedError;
|
||||||
import com.formdev.flatlaf.FlatIntelliJLaf;
|
import com.formdev.flatlaf.FlatIntelliJLaf;
|
||||||
import com.formdev.flatlaf.FlatLightLaf;
|
import com.formdev.flatlaf.FlatLightLaf;
|
||||||
@@ -57,12 +63,57 @@ public class TestUtils
|
|||||||
|
|
||||||
public static void assertMapEquals( Map<?, ?> expected, Map<?, ?> actual ) {
|
public static void assertMapEquals( Map<?, ?> expected, Map<?, ?> actual ) {
|
||||||
if( !Objects.equals( expected, actual ) ) {
|
if( !Objects.equals( expected, actual ) ) {
|
||||||
String expectedStr = String.valueOf( expected ).replace( ", ", ",\n" );
|
String expectedStr = String.valueOf( new TreeMap<>( expected ) ).replace( ", ", ",\n" );
|
||||||
String actualStr = String.valueOf( actual ).replace( ", ", ",\n" );
|
String actualStr = String.valueOf( new TreeMap<>( actual ) ).replace( ", ", ",\n" );
|
||||||
String msg = String.format( "expected: <%s> but was: <%s>", expectedStr, actualStr );
|
String msg = String.format( "expected: <%s> but was: <%s>", expectedStr, actualStr );
|
||||||
|
|
||||||
// pass expected/actual strings to exception for nice diff in IDE
|
// pass expected/actual strings to exception for nice diff in IDE
|
||||||
throw new AssertionFailedError( msg, expectedStr, actualStr );
|
throw new AssertionFailedError( msg, expectedStr, actualStr );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void assertSetEquals( Set<?> expected, Set<?> actual, String message ) {
|
||||||
|
if( !Objects.equals( expected, actual ) ) {
|
||||||
|
String expectedStr = String.valueOf( new TreeSet<>( expected ) ).replace( ", ", ",\n" );
|
||||||
|
String actualStr = String.valueOf( new TreeSet<>( actual ) ).replace( ", ", ",\n" );
|
||||||
|
String msg = String.format( "expected: <%s> but was: <%s>", expectedStr, actualStr );
|
||||||
|
if( message != null )
|
||||||
|
msg = message + " ==> " + msg;
|
||||||
|
|
||||||
|
// pass expected/actual strings to exception for nice diff in IDE
|
||||||
|
throw new AssertionFailedError( msg, expectedStr, actualStr );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void checkImplementedTests( Set<String> excludes, Class<?> baseClass, Class<?>... classes ) {
|
||||||
|
Set<String> expected = getTestMethods( baseClass );
|
||||||
|
|
||||||
|
for( Class<?> cls : classes ) {
|
||||||
|
Set<String> actual = getTestMethods( cls );
|
||||||
|
|
||||||
|
for( String methodName : expected ) {
|
||||||
|
if( !actual.contains( methodName ) && !excludes.contains( methodName ) ) {
|
||||||
|
throw new AssertionFailedError( "missing " + cls.getSimpleName() + '.' + methodName
|
||||||
|
+ "() for " + baseClass.getSimpleName() + '.' + methodName + "()" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for( String methodName : actual ) {
|
||||||
|
if( !expected.contains( methodName ) && !excludes.contains( methodName ) ) {
|
||||||
|
throw new AssertionFailedError( "missing " + baseClass.getSimpleName() + '.' + methodName
|
||||||
|
+ "() for " + cls.getSimpleName() + '.' + methodName + "()" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Set<String> getTestMethods( Class<?> cls ) {
|
||||||
|
HashSet<String> tests = new HashSet<>();
|
||||||
|
Method[] methods = cls.getDeclaredMethods();
|
||||||
|
for( Method m : methods ) {
|
||||||
|
if( m.isAnnotationPresent( Test.class ) )
|
||||||
|
tests.add( m.getName() );
|
||||||
|
}
|
||||||
|
return tests;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,343 @@
|
|||||||
|
/*
|
||||||
|
* 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.util;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
import javax.swing.UIManager;
|
||||||
|
import javax.swing.UnsupportedLookAndFeelException;
|
||||||
|
import javax.swing.plaf.metal.MetalLookAndFeel;
|
||||||
|
import org.junit.jupiter.api.AfterAll;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import com.formdev.flatlaf.FlatDarkLaf;
|
||||||
|
import com.formdev.flatlaf.FlatLaf;
|
||||||
|
import com.formdev.flatlaf.FlatLightLaf;
|
||||||
|
import com.formdev.flatlaf.FlatSystemProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Karl Tauber
|
||||||
|
*/
|
||||||
|
public class TestUIScale
|
||||||
|
{
|
||||||
|
private static Map<String, String> FONT_EXTRA_DEFAULTS_1x = Collections.singletonMap(
|
||||||
|
"defaultFont", "{instance}java.awt.Font,Dialog,0,12" );
|
||||||
|
private static Map<String, String> FONT_EXTRA_DEFAULTS_1_5x = Collections.singletonMap(
|
||||||
|
"defaultFont", "{instance}java.awt.Font,Dialog,0,18" );
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
static void setup() {
|
||||||
|
UIScale.inUnitTests = true;
|
||||||
|
|
||||||
|
// disable platform specific fonts
|
||||||
|
System.setProperty( "flatlaf.uiScale.fontSizeDivider", "12" );
|
||||||
|
FlatLaf.setGlobalExtraDefaults( FONT_EXTRA_DEFAULTS_1x );
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterAll
|
||||||
|
static void cleanup() throws UnsupportedLookAndFeelException {
|
||||||
|
System.clearProperty( "flatlaf.uiScale.fontSizeDivider" );
|
||||||
|
FlatLaf.setGlobalExtraDefaults( null );
|
||||||
|
|
||||||
|
UIScale.inUnitTests = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
void afterEach() throws UnsupportedLookAndFeelException {
|
||||||
|
UIManager.setLookAndFeel( new MetalLookAndFeel() );
|
||||||
|
UIManager.put( "defaultFont", null );
|
||||||
|
UIManager.put( "Label.font", null );
|
||||||
|
FlatLaf.setGlobalExtraDefaults( FONT_EXTRA_DEFAULTS_1x );
|
||||||
|
|
||||||
|
UIScale.tests_uninitialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testCustomScaleFactor() {
|
||||||
|
System.setProperty( FlatSystemProperties.UI_SCALE, "1.25x" );
|
||||||
|
assertScaleFactor( 1.25f );
|
||||||
|
|
||||||
|
System.setProperty( FlatSystemProperties.UI_SCALE, "2x" );
|
||||||
|
UIScale.tests_uninitialize();
|
||||||
|
assertScaleFactor( 2f );
|
||||||
|
|
||||||
|
System.clearProperty( FlatSystemProperties.UI_SCALE );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testLabelFontScaling() {
|
||||||
|
assertInstanceOf( MetalLookAndFeel.class, UIManager.getLookAndFeel() );
|
||||||
|
|
||||||
|
testLabelFont( 8, 1f );
|
||||||
|
testLabelFont( 9, 1f );
|
||||||
|
testLabelFont( 10, 1f );
|
||||||
|
testLabelFont( 11, 1f );
|
||||||
|
testLabelFont( 12, 1f );
|
||||||
|
testLabelFont( 13, 1f );
|
||||||
|
testLabelFont( 14, 1.25f );
|
||||||
|
testLabelFont( 15, 1.25f );
|
||||||
|
testLabelFont( 16, 1.25f );
|
||||||
|
testLabelFont( 17, 1.5f );
|
||||||
|
testLabelFont( 18, 1.5f );
|
||||||
|
testLabelFont( 19, 1.5f );
|
||||||
|
testLabelFont( 20, 1.75f );
|
||||||
|
testLabelFont( 21, 1.75f );
|
||||||
|
testLabelFont( 22, 1.75f );
|
||||||
|
testLabelFont( 23, 2f );
|
||||||
|
testLabelFont( 24, 2f );
|
||||||
|
testLabelFont( 25, 2f );
|
||||||
|
testLabelFont( 26, 2.25f );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testLabelFont( int fontSize, float expectedScaleFactor ) {
|
||||||
|
UIManager.put( "Label.font", new Font( Font.DIALOG, Font.PLAIN, fontSize ) );
|
||||||
|
assertScaleFactor( expectedScaleFactor );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testDefaultFontScaling() {
|
||||||
|
FlatLightLaf.setup();
|
||||||
|
|
||||||
|
testDefaultFont( 8, 1f );
|
||||||
|
testDefaultFont( 9, 1f );
|
||||||
|
testDefaultFont( 10, 1f );
|
||||||
|
testDefaultFont( 11, 1f );
|
||||||
|
testDefaultFont( 12, 1f );
|
||||||
|
testDefaultFont( 13, 1f );
|
||||||
|
testDefaultFont( 14, 1.25f );
|
||||||
|
testDefaultFont( 15, 1.25f );
|
||||||
|
testDefaultFont( 16, 1.25f );
|
||||||
|
testDefaultFont( 17, 1.5f );
|
||||||
|
testDefaultFont( 18, 1.5f );
|
||||||
|
testDefaultFont( 19, 1.5f );
|
||||||
|
testDefaultFont( 20, 1.75f );
|
||||||
|
testDefaultFont( 21, 1.75f );
|
||||||
|
testDefaultFont( 22, 1.75f );
|
||||||
|
testDefaultFont( 23, 2f );
|
||||||
|
testDefaultFont( 24, 2f );
|
||||||
|
testDefaultFont( 25, 2f );
|
||||||
|
testDefaultFont( 26, 2.25f );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testDefaultFont( int fontSize, float expectedScaleFactor ) {
|
||||||
|
UIManager.put( "defaultFont", new Font( Font.DIALOG, Font.PLAIN, fontSize ) );
|
||||||
|
assertScaleFactor( expectedScaleFactor );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testInitialScaleFactorAndFontSizes() {
|
||||||
|
FlatLightLaf.setup();
|
||||||
|
assertScaleFactorAndFontSizes( 1f, 12, -1 );
|
||||||
|
|
||||||
|
FlatLaf.setGlobalExtraDefaults( FONT_EXTRA_DEFAULTS_1_5x );
|
||||||
|
FlatDarkLaf.setup();
|
||||||
|
assertScaleFactorAndFontSizes( 1.5f, 18, -1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void zoom_Metal() {
|
||||||
|
UIScale.setZoomFactor( 1.1f );
|
||||||
|
assertScaleFactor( 1.1f );
|
||||||
|
|
||||||
|
UIScale.setZoomFactor( 1.3f );
|
||||||
|
assertScaleFactor( 1.3f );
|
||||||
|
|
||||||
|
UIScale.setZoomFactor( 2.3f );
|
||||||
|
assertScaleFactor( 2.3f );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void zoom_1x() {
|
||||||
|
FlatLightLaf.setup();
|
||||||
|
testZoom( 0.7f, 0.7f, 8, -1 );
|
||||||
|
testZoom( 0.75f, 0.75f, 9, -1 );
|
||||||
|
testZoom( 0.8f, 0.8f, 10, -1 );
|
||||||
|
testZoom( 0.9f, 0.9f, 11, -1 );
|
||||||
|
testZoom( 1f, 1f, 12, -1 );
|
||||||
|
testZoom( 1.1f, 1.1f, 13, -1 );
|
||||||
|
testZoom( 1.2f, 1.2f, 14, -1 );
|
||||||
|
testZoom( 1.25f, 1.25f, 15, -1 );
|
||||||
|
testZoom( 1.3f, 1.3f, 16, -1 );
|
||||||
|
testZoom( 1.4f, 1.4f, 17, -1 );
|
||||||
|
testZoom( 1.5f, 1.5f, 18, -1 );
|
||||||
|
testZoom( 1.6f, 1.6f, 19, -1 );
|
||||||
|
testZoom( 1.7f, 1.7f, 20, -1 );
|
||||||
|
testZoom( 1.75f, 1.75f, 21, -1 );
|
||||||
|
testZoom( 1.8f, 1.8f, 22, -1 );
|
||||||
|
testZoom( 1.9f, 1.9f, 23, -1 );
|
||||||
|
testZoom( 2f, 2f, 24, -1 );
|
||||||
|
testZoom( 2.25f, 2.25f, 27, -1 );
|
||||||
|
testZoom( 2.5f, 2.5f, 30, -1 );
|
||||||
|
testZoom( 2.75f, 2.75f, 33, -1 );
|
||||||
|
testZoom( 3f, 3f, 36, -1 );
|
||||||
|
testZoom( 4f, 4f, 48, -1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void zoom_1_5x() {
|
||||||
|
FlatLaf.setGlobalExtraDefaults( FONT_EXTRA_DEFAULTS_1_5x );
|
||||||
|
FlatLightLaf.setup();
|
||||||
|
|
||||||
|
testZoom( 0.7f, 1.05f, 13, -1 );
|
||||||
|
testZoom( 0.75f, 1.13f, 14, -1 );
|
||||||
|
testZoom( 0.8f, 1.2f, 14, -1 );
|
||||||
|
testZoom( 0.9f, 1.35f, 16, -1 );
|
||||||
|
testZoom( 1f, 1.5f, 18, -1 );
|
||||||
|
testZoom( 1.1f, 1.65f, 20, -1 );
|
||||||
|
testZoom( 1.2f, 1.8f, 22, -1 );
|
||||||
|
testZoom( 1.25f, 1.88f, 23, -1 );
|
||||||
|
testZoom( 1.3f, 1.95f, 23, -1 );
|
||||||
|
testZoom( 1.4f, 2.1f, 25, -1 );
|
||||||
|
testZoom( 1.5f, 2.25f, 27, -1 );
|
||||||
|
testZoom( 1.6f, 2.4f, 29, -1 );
|
||||||
|
testZoom( 1.7f, 2.55f, 31, -1 );
|
||||||
|
testZoom( 1.75f, 2.63f, 32, -1 );
|
||||||
|
testZoom( 1.8f, 2.7f, 32, -1 );
|
||||||
|
testZoom( 1.9f, 2.85f, 34, -1 );
|
||||||
|
testZoom( 2f, 3f, 36, -1 );
|
||||||
|
testZoom( 2.25f, 3.38f, 41, -1 );
|
||||||
|
testZoom( 2.5f, 3.75f, 45, -1 );
|
||||||
|
testZoom( 2.75f, 4.13f, 50, -1 );
|
||||||
|
testZoom( 3f, 4.5f, 54, -1 );
|
||||||
|
testZoom( 4f, 6f, 72, -1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void zoomAppFont_1x() {
|
||||||
|
FlatLightLaf.setup();
|
||||||
|
UIManager.put( "defaultFont", new Font( Font.DIALOG, Font.PLAIN, 14 ) );
|
||||||
|
|
||||||
|
testZoom( 1f, 1.25f, 12, 14 );
|
||||||
|
testZoom( 1.1f, 1.38f, 13, 15 );
|
||||||
|
testZoom( 1.25f, 1.56f, 15, 17 );
|
||||||
|
testZoom( 1.5f, 1.88f, 18, 20 );
|
||||||
|
testZoom( 1.75f, 2.19f, 21, 23 );
|
||||||
|
testZoom( 2f, 2.5f, 24, 26 );
|
||||||
|
testZoom( 1f, 1.25f, 12, 13 );
|
||||||
|
testZoom( 2f, 2.5f, 24, 26 );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void zoomWithLafChange() {
|
||||||
|
FlatLightLaf.setup();
|
||||||
|
assertScaleFactorAndFontSizes( 1f, 12, -1 );
|
||||||
|
testZoom( 1.1f, 1.1f, 13, -1 );
|
||||||
|
|
||||||
|
FlatDarkLaf.setup();
|
||||||
|
assertScaleFactorAndFontSizes( 1.1f, 13, -1 );
|
||||||
|
testZoom( 1.2f, 1.2f, 14, -1 );
|
||||||
|
|
||||||
|
FlatLightLaf.setup();
|
||||||
|
assertScaleFactorAndFontSizes( 1.2f, 14, -1 );
|
||||||
|
testZoom( 1.3f, 1.3f, 16, -1 );
|
||||||
|
|
||||||
|
FlatLaf.setGlobalExtraDefaults( FONT_EXTRA_DEFAULTS_1_5x );
|
||||||
|
FlatDarkLaf.setup();
|
||||||
|
assertScaleFactorAndFontSizes( 1.95f, 23, -1 );
|
||||||
|
testZoom( 1.4f, 2.1f, 25, -1 );
|
||||||
|
|
||||||
|
FlatLightLaf.setup();
|
||||||
|
assertScaleFactorAndFontSizes( 2.1f, 25, -1 );
|
||||||
|
testZoom( 1.5f, 2.25f, 27, -1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void zoomWithDefaultFontChange() {
|
||||||
|
FlatLightLaf.setup();
|
||||||
|
assertScaleFactorAndFontSizes( 1f, 12, -1 );
|
||||||
|
|
||||||
|
float zoom1 = 1.4f;
|
||||||
|
testZoom( zoom1, zoom1, 17, -1 );
|
||||||
|
testDefaultFont( 8, z( zoom1, 1f ) );
|
||||||
|
testDefaultFont( 9, z( zoom1, 1f ) );
|
||||||
|
testDefaultFont( 10, z( zoom1, 1f ) );
|
||||||
|
testDefaultFont( 11, z( zoom1, 1f ) );
|
||||||
|
testDefaultFont( 12, z( zoom1, 1f ) );
|
||||||
|
testDefaultFont( 13, z( zoom1, 1f ) );
|
||||||
|
testDefaultFont( 14, z( zoom1, 1.25f ) );
|
||||||
|
testDefaultFont( 15, z( zoom1, 1.25f ) );
|
||||||
|
testDefaultFont( 16, z( zoom1, 1.25f ) );
|
||||||
|
testDefaultFont( 17, z( zoom1, 1.5f ) );
|
||||||
|
testDefaultFont( 18, z( zoom1, 1.5f ) );
|
||||||
|
testDefaultFont( 19, z( zoom1, 1.5f ) );
|
||||||
|
testDefaultFont( 20, z( zoom1, 1.75f ) );
|
||||||
|
testDefaultFont( 21, z( zoom1, 1.75f ) );
|
||||||
|
testDefaultFont( 22, z( zoom1, 1.75f ) );
|
||||||
|
testDefaultFont( 23, z( zoom1, 2f ) );
|
||||||
|
testDefaultFont( 24, z( zoom1, 2f ) );
|
||||||
|
testDefaultFont( 25, z( zoom1, 2f ) );
|
||||||
|
testDefaultFont( 26, z( zoom1, 2.25f ) );
|
||||||
|
|
||||||
|
float zoom2 = 1.8f;
|
||||||
|
testZoom( zoom2, 4.05f, 22, 33 );
|
||||||
|
testDefaultFont( 8, z( zoom2, 1f ) );
|
||||||
|
testDefaultFont( 9, z( zoom2, 1f ) );
|
||||||
|
testDefaultFont( 10, z( zoom2, 1f ) );
|
||||||
|
testDefaultFont( 11, z( zoom2, 1f ) );
|
||||||
|
testDefaultFont( 12, z( zoom2, 1f ) );
|
||||||
|
testDefaultFont( 13, z( zoom2, 1f ) );
|
||||||
|
testDefaultFont( 14, z( zoom2, 1.25f ) );
|
||||||
|
testDefaultFont( 15, z( zoom2, 1.25f ) );
|
||||||
|
testDefaultFont( 16, z( zoom2, 1.25f ) );
|
||||||
|
testDefaultFont( 17, z( zoom2, 1.5f ) );
|
||||||
|
testDefaultFont( 18, z( zoom2, 1.5f ) );
|
||||||
|
testDefaultFont( 19, z( zoom2, 1.5f ) );
|
||||||
|
testDefaultFont( 20, z( zoom2, 1.75f ) );
|
||||||
|
testDefaultFont( 21, z( zoom2, 1.75f ) );
|
||||||
|
testDefaultFont( 22, z( zoom2, 1.75f ) );
|
||||||
|
testDefaultFont( 23, z( zoom2, 2f ) );
|
||||||
|
testDefaultFont( 24, z( zoom2, 2f ) );
|
||||||
|
testDefaultFont( 25, z( zoom2, 2f ) );
|
||||||
|
testDefaultFont( 26, z( zoom2, 2.25f ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float z( float zoom, float scale ) {
|
||||||
|
// round scale factor to 1/100
|
||||||
|
return Math.round( (zoom * scale) * 100f ) / 100f;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testZoom( float zoomFactor, float expectedScaleFactor,
|
||||||
|
int expectedLafFontSize, int expectedAppFontSize )
|
||||||
|
{
|
||||||
|
UIScale.setZoomFactor( zoomFactor );
|
||||||
|
assertScaleFactorAndFontSizes( expectedScaleFactor, expectedLafFontSize, expectedAppFontSize );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertScaleFactorAndFontSizes( float expectedScaleFactor,
|
||||||
|
int expectedLafFontSize, int expectedAppFontSize )
|
||||||
|
{
|
||||||
|
assertScaleFactor( expectedScaleFactor );
|
||||||
|
|
||||||
|
Font lafFont = UIManager.getLookAndFeelDefaults().getFont( "defaultFont" );
|
||||||
|
Font appFont = UIManager.getFont( "defaultFont" );
|
||||||
|
assertEquals( expectedLafFontSize, lafFont.getSize() );
|
||||||
|
if( expectedAppFontSize > 0 ) {
|
||||||
|
assertNotEquals( lafFont, appFont );
|
||||||
|
assertEquals( expectedAppFontSize, appFont.getSize() );
|
||||||
|
} else
|
||||||
|
assertEquals( lafFont, appFont );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertScaleFactor( float expectedScaleFactor ) {
|
||||||
|
assertEquals( expectedScaleFactor, UIScale.getUserScaleFactor() );
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user