mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2026-02-12 06:57:13 -06:00
Compare commits
301 Commits
2.6
...
fonts/inte
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca3b2b4b07 | ||
|
|
722dde63df | ||
|
|
c85baf4dc6 | ||
|
|
96b7770ab2 | ||
|
|
0c00117820 | ||
|
|
eed11d211b | ||
|
|
19f27a8d56 | ||
|
|
cf3fa17666 | ||
|
|
6fdc56f2d3 | ||
|
|
9f17a5b26d | ||
|
|
fa53e90847 | ||
|
|
50c630f403 | ||
|
|
5630c161ea | ||
|
|
7d16ff9e79 | ||
|
|
a9ea9daec3 | ||
|
|
45bdd40dce | ||
|
|
a2bca88eec | ||
|
|
c0dd02ee13 | ||
|
|
97495a6093 | ||
|
|
4ad45088c4 | ||
|
|
d6d1d4b1b7 | ||
|
|
6e453c170f | ||
|
|
beb2deee52 | ||
|
|
9c69043b2c | ||
|
|
4df34b3f9d | ||
|
|
ee01756188 | ||
|
|
0386aaa18b | ||
|
|
92c4230cde | ||
|
|
26165999e0 | ||
|
|
38b2641078 | ||
|
|
4e19169312 | ||
|
|
46de81c1c9 | ||
|
|
9bf4da7acf | ||
|
|
6f32236fb7 | ||
|
|
c25d857e78 | ||
|
|
8cc2925fd0 | ||
|
|
2b87d3c4db | ||
|
|
7f6f366744 | ||
|
|
b1fdbde5cd | ||
|
|
417f0f5f1c | ||
|
|
ec7673790c | ||
|
|
7d0bdf3b9e | ||
|
|
2ef5270095 | ||
|
|
61ba011c3b | ||
|
|
8d8b9f3e98 | ||
|
|
69899ec29f | ||
|
|
5063621c95 | ||
|
|
030177f739 | ||
|
|
808f5a6381 | ||
|
|
9602b191a9 | ||
|
|
34bd2d781c | ||
|
|
cf364c1264 | ||
|
|
a997820bb6 | ||
|
|
b8fabd59c0 | ||
|
|
97d290795e | ||
|
|
2a237ff5fc | ||
|
|
13a418f74e | ||
|
|
5c56dbfed6 | ||
|
|
0d2f37e1da | ||
|
|
0494c2161c | ||
|
|
635a620439 | ||
|
|
0a7c76ec72 | ||
|
|
9ad8fb38e8 | ||
|
|
1dbe968952 | ||
|
|
460b6492cb | ||
|
|
67b0faa9ae | ||
|
|
5553425a1a | ||
|
|
8ff516e43a | ||
|
|
b6207bafde | ||
|
|
b9f43fd560 | ||
|
|
c617d9f569 | ||
|
|
9efb9761c6 | ||
|
|
03f9115fbf | ||
|
|
a2859cedb5 | ||
|
|
0c604b1023 | ||
|
|
cdee0594f8 | ||
|
|
808833d749 | ||
|
|
581c64b601 | ||
|
|
40418607e5 | ||
|
|
5436ea88d8 | ||
|
|
7bec5ec6dc | ||
|
|
c953ff84d0 | ||
|
|
96cd207df3 | ||
|
|
7a75f62a6a | ||
|
|
61e5fe58c2 | ||
|
|
1a3baba702 | ||
|
|
58dc14bb46 | ||
|
|
a5b7e04943 | ||
|
|
22f2aa5475 | ||
|
|
d4e9cb12be | ||
|
|
75da361480 | ||
|
|
7488bcb7b0 | ||
|
|
1b1a9be107 | ||
|
|
db2f94aa53 | ||
|
|
810146b993 | ||
|
|
93091662ab | ||
|
|
d349227fbf | ||
|
|
c9423e3aa8 | ||
|
|
b9737ca4f1 | ||
|
|
4b4990635d | ||
|
|
afaa2c8c78 | ||
|
|
f506ef0d4f | ||
|
|
d30fe66cac | ||
|
|
270e998e86 | ||
|
|
c395386c05 | ||
|
|
4f1207b0db | ||
|
|
dc3878e290 | ||
|
|
be2876149d | ||
|
|
52bae9dfb0 | ||
|
|
bb636bac3f | ||
|
|
502b18fa86 | ||
|
|
e0a5450264 | ||
|
|
5ffb23c37f | ||
|
|
b75f22b7bd | ||
|
|
35fa3197c8 | ||
|
|
f03725ae36 | ||
|
|
2b640e2129 | ||
|
|
2a983f5c03 | ||
|
|
cacc5daa14 | ||
|
|
593502287d | ||
|
|
7a9bdf9be0 | ||
|
|
170c22c5ed | ||
|
|
7e8fa58bd7 | ||
|
|
046200625c | ||
|
|
710ed55152 | ||
|
|
ce527329a6 | ||
|
|
b455dd41ab | ||
|
|
b47ed94f40 | ||
|
|
f1351a2093 | ||
|
|
c1c5e81df0 | ||
|
|
8e3c8ba6c5 | ||
|
|
dfe4404a17 | ||
|
|
b3fb63c9f5 | ||
|
|
9db3dfff26 | ||
|
|
3c9051e7de | ||
|
|
798a6d061c | ||
|
|
19afbe99d9 | ||
|
|
4715d8d16c | ||
|
|
193da2bc4d | ||
|
|
799f8efe22 | ||
|
|
f6062e1ec4 | ||
|
|
c790778a46 | ||
|
|
4344f1b3a0 | ||
|
|
d520b30500 | ||
|
|
11c02e5f50 | ||
|
|
aa4c6ee9da | ||
|
|
98f8557392 | ||
|
|
6f6a860887 | ||
|
|
38695e9e16 | ||
|
|
242c478cb3 | ||
|
|
f003e835bd | ||
|
|
267defb321 | ||
|
|
4392c7627b | ||
|
|
fde65b2730 | ||
|
|
e908362f0a | ||
|
|
a40b837634 | ||
|
|
b391465fbf | ||
|
|
bad0428f5b | ||
|
|
97018df2f9 | ||
|
|
9d84501bc8 | ||
|
|
e9fb2b3fdc | ||
|
|
f60250fd8a | ||
|
|
5fc3cae28a | ||
|
|
e7935be85b | ||
|
|
89363b2ea1 | ||
|
|
e84390ee46 | ||
|
|
65a0f467ae | ||
|
|
4afb150106 | ||
|
|
0f6702217e | ||
|
|
13a0097858 | ||
|
|
01c830ad92 | ||
|
|
dce4f4623c | ||
|
|
d530624362 | ||
|
|
2e878b62d1 | ||
|
|
d27a246dfe | ||
|
|
778def118a | ||
|
|
bc5587477b | ||
|
|
03a775cd31 | ||
|
|
875083a924 | ||
|
|
f6fc925c9e | ||
|
|
74e1972781 | ||
|
|
2f5c54bb49 | ||
|
|
465798ee3d | ||
|
|
425f3acced | ||
|
|
546382e471 | ||
|
|
7e91d78633 | ||
|
|
136e1e4e30 | ||
|
|
f5f6850172 | ||
|
|
28cdde3f17 | ||
|
|
29b801e13d | ||
|
|
1435469ee5 | ||
|
|
4a0bd2c09f | ||
|
|
f8d67f863f | ||
|
|
0291dd5416 | ||
|
|
9014435d4d | ||
|
|
07ad467c73 | ||
|
|
35e23574cf | ||
|
|
9b62b8395f | ||
|
|
45e7022deb | ||
|
|
32dce16363 | ||
|
|
e34b5eafe1 | ||
|
|
4e1e749094 | ||
|
|
ede9293377 | ||
|
|
9101324a1f | ||
|
|
4b844353ee | ||
|
|
2134c19c58 | ||
|
|
c974784ebb | ||
|
|
5eb6961023 | ||
|
|
07cbd8b97b | ||
|
|
09c7f15364 | ||
|
|
b879b393ad | ||
|
|
e4503c2a54 | ||
|
|
7e2d02b997 | ||
|
|
d286550572 | ||
|
|
4e44e25d30 | ||
|
|
9fef2f9d05 | ||
|
|
04f1f5921d | ||
|
|
f9ecffb850 | ||
|
|
c9b5274ccf | ||
|
|
d209d47b9e | ||
|
|
21baaf810c | ||
|
|
95b4366270 | ||
|
|
c3adadfe2f | ||
|
|
adf7753617 | ||
|
|
d491847754 | ||
|
|
6afc747790 | ||
|
|
ff46935448 | ||
|
|
78c2f98f1f | ||
|
|
91be9aa2fe | ||
|
|
13e5da584f | ||
|
|
1762e0b7a6 | ||
|
|
05240abfe0 | ||
|
|
b515e8be04 | ||
|
|
24bc7fb0b5 | ||
|
|
0d2e1e6d18 | ||
|
|
f23c523baf | ||
|
|
76fee29f5b | ||
|
|
ec77746a43 | ||
|
|
92cd6f8f34 | ||
|
|
e7d2b5cbb6 | ||
|
|
4d175da3a0 | ||
|
|
5f047ddda9 | ||
|
|
ccca6fe88e | ||
|
|
a1f18e1ec9 | ||
|
|
afdaf7a0a5 | ||
|
|
62f0ef19f4 | ||
|
|
b736502c27 | ||
|
|
2be2dae3d6 | ||
|
|
aefe104ca4 | ||
|
|
3e6bce9cec | ||
|
|
a6394cac38 | ||
|
|
1e09ddfc93 | ||
|
|
664f5c98e9 | ||
|
|
c7bfd2ea82 | ||
|
|
9ce7ddd088 | ||
|
|
cca8d427d2 | ||
|
|
aa9263a2e7 | ||
|
|
5eaebde437 | ||
|
|
7f15f557a5 | ||
|
|
b459715cb5 | ||
|
|
bfede219d0 | ||
|
|
ef21efecf5 | ||
|
|
2bfbc9dc12 | ||
|
|
c3a1b45546 | ||
|
|
b72508f920 | ||
|
|
22bb80218d | ||
|
|
873a7e8572 | ||
|
|
0c5016fe89 | ||
|
|
607b084697 | ||
|
|
9d8ffec276 | ||
|
|
15f08e9b7c | ||
|
|
08aa6b1894 | ||
|
|
06b02c4f7c | ||
|
|
b56acd271f | ||
|
|
b24e2db59e | ||
|
|
f215356629 | ||
|
|
f7be12df67 | ||
|
|
a1d1e221ae | ||
|
|
0a4dc54fb9 | ||
|
|
b8c7801365 | ||
|
|
a7099c039f | ||
|
|
a4d2d347e3 | ||
|
|
829c537fd3 | ||
|
|
28437f99cf | ||
|
|
c1402d85e1 | ||
|
|
32e071ab89 | ||
|
|
01125e030e | ||
|
|
b43278439a | ||
|
|
7a445aabd7 | ||
|
|
380dae1017 | ||
|
|
fb15cdc546 | ||
|
|
a525fe29db | ||
|
|
bf0685cee2 | ||
|
|
8262793751 | ||
|
|
5ec7848fb0 | ||
|
|
450fc123ff | ||
|
|
3802c64be3 | ||
|
|
7bf1b26812 | ||
|
|
f1792e46c6 | ||
|
|
84e9c36280 | ||
|
|
2ef6a2c3c9 |
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -20,7 +20,9 @@
|
|||||||
*.gif binary
|
*.gif binary
|
||||||
*.jar binary
|
*.jar binary
|
||||||
*.lib binary
|
*.lib binary
|
||||||
|
*.otf binary
|
||||||
*.png binary
|
*.png binary
|
||||||
*.sketch binary
|
*.sketch binary
|
||||||
*.so binary
|
*.so binary
|
||||||
|
*.ttf binary
|
||||||
*.zip binary
|
*.zip binary
|
||||||
|
|||||||
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
custom: https://www.formdev.com/flatlaf/sponsor/
|
||||||
39
.github/workflows/ci.yml
vendored
39
.github/workflows/ci.yml
vendored
@@ -1,4 +1,5 @@
|
|||||||
# https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
|
# 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: CI
|
name: CI
|
||||||
|
|
||||||
@@ -8,9 +9,6 @@ on:
|
|||||||
- '*'
|
- '*'
|
||||||
tags:
|
tags:
|
||||||
- '[0-9]*'
|
- '[0-9]*'
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- '*'
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
@@ -21,7 +19,7 @@ jobs:
|
|||||||
# test against
|
# test against
|
||||||
# - Java 8 (minimum requirement)
|
# - Java 8 (minimum requirement)
|
||||||
# - Java LTS versions (11, 17, ...)
|
# - Java LTS versions (11, 17, ...)
|
||||||
# - lastest Java version(s)
|
# - latest Java version(s)
|
||||||
java:
|
java:
|
||||||
- 8
|
- 8
|
||||||
- 11 # LTS
|
- 11 # LTS
|
||||||
@@ -29,31 +27,36 @@ jobs:
|
|||||||
toolchain: [""]
|
toolchain: [""]
|
||||||
include:
|
include:
|
||||||
- java: 17
|
- java: 17
|
||||||
toolchain: 19 # latest
|
toolchain: 21 # latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- uses: gradle/wrapper-validation-action@v1
|
- uses: gradle/wrapper-validation-action@v1
|
||||||
if: matrix.java == '8'
|
if: matrix.java == '8'
|
||||||
|
|
||||||
- name: Setup Java ${{ matrix.java }}
|
- name: Setup Java ${{ matrix.java }}
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
java-version: ${{ matrix.java }}
|
java-version: ${{ matrix.java }}
|
||||||
distribution: adopt # Java 8 and 11 are pre-installed on ubuntu-latest
|
distribution: temurin # Java 8, 11 and 17 are pre-installed on ubuntu-latest
|
||||||
cache: gradle
|
cache: gradle
|
||||||
|
|
||||||
|
- name: Check with Error Prone
|
||||||
|
if: matrix.java == '11'
|
||||||
|
run: ./gradlew errorprone clean -Dtoolchain=${{ matrix.toolchain }}
|
||||||
|
|
||||||
- name: Build with Gradle
|
- name: Build with Gradle
|
||||||
run: ./gradlew build -Dtoolchain=${{ matrix.toolchain }}
|
run: ./gradlew build -Dtoolchain=${{ matrix.toolchain }}
|
||||||
|
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
if: matrix.java == '11'
|
if: matrix.java == '11'
|
||||||
with:
|
with:
|
||||||
name: FlatLaf-build-artifacts
|
name: FlatLaf-build-artifacts
|
||||||
path: |
|
path: |
|
||||||
flatlaf-*/build/libs
|
flatlaf-*/build/libs
|
||||||
|
flatlaf-*/flatlaf-*/build/libs
|
||||||
!**/*-javadoc.jar
|
!**/*-javadoc.jar
|
||||||
!**/*-sources.jar
|
!**/*-sources.jar
|
||||||
|
|
||||||
@@ -67,17 +70,17 @@ jobs:
|
|||||||
github.repository == 'JFormDesigner/FlatLaf'
|
github.repository == 'JFormDesigner/FlatLaf'
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Java 11
|
- name: Setup Java 11
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
java-version: 11
|
java-version: 11
|
||||||
distribution: adopt # pre-installed on ubuntu-latest
|
distribution: temurin # pre-installed on ubuntu-latest
|
||||||
cache: gradle
|
cache: gradle
|
||||||
|
|
||||||
- name: Publish snapshot to oss.sonatype.org
|
- name: Publish snapshot to oss.sonatype.org
|
||||||
run: ./gradlew publish :flatlaf-theme-editor:build -Dorg.gradle.internal.publish.checksums.insecure=true
|
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 }}
|
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
|
||||||
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
|
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
|
||||||
@@ -103,17 +106,17 @@ jobs:
|
|||||||
github.repository == 'JFormDesigner/FlatLaf'
|
github.repository == 'JFormDesigner/FlatLaf'
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Java 11
|
- name: Setup Java 11
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
java-version: 11
|
java-version: 11
|
||||||
distribution: adopt # pre-installed on ubuntu-latest
|
distribution: temurin # pre-installed on ubuntu-latest
|
||||||
cache: gradle
|
cache: gradle
|
||||||
|
|
||||||
- name: Release a new stable version to Maven Central
|
- name: Release a new stable version to Maven Central
|
||||||
run: ./gradlew publish :flatlaf-demo:build :flatlaf-theme-editor:build -Drelease=true
|
run: ./gradlew publish :flatlaf-demo:build :flatlaf-theme-editor:build -PskipFonts -Prelease -Dorg.gradle.parallel=false
|
||||||
env:
|
env:
|
||||||
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
|
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
|
||||||
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
|
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
|
||||||
|
|||||||
60
.github/workflows/fonts.yml
vendored
Normal file
60
.github/workflows/fonts.yml
vendored
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
# 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: Fonts
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- '*'
|
||||||
|
tags:
|
||||||
|
- 'fonts/*-[0-9]*'
|
||||||
|
paths:
|
||||||
|
- 'flatlaf-fonts/**'
|
||||||
|
- '.github/workflows/fonts.yml'
|
||||||
|
- 'gradle/wrapper/gradle-wrapper.properties'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
Fonts:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
font:
|
||||||
|
- inter
|
||||||
|
- jetbrains-mono
|
||||||
|
- roboto
|
||||||
|
- roboto-mono
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: |
|
||||||
|
github.event_name == 'push' &&
|
||||||
|
github.repository == 'JFormDesigner/FlatLaf'
|
||||||
|
|
||||||
|
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: Build with Gradle
|
||||||
|
run: ./gradlew :flatlaf-fonts-${{ matrix.font }}:build
|
||||||
|
if: startsWith( github.ref, format( 'refs/tags/fonts/{0}-', matrix.font ) ) != true
|
||||||
|
|
||||||
|
- name: Publish snapshot to oss.sonatype.org
|
||||||
|
run: ./gradlew :flatlaf-fonts-${{ matrix.font }}:publish -Dorg.gradle.internal.publish.checksums.insecure=true
|
||||||
|
env:
|
||||||
|
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
|
||||||
|
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
|
||||||
|
if: github.ref == 'refs/heads/main' || startsWith( github.ref, 'refs/heads/develop-' )
|
||||||
|
|
||||||
|
- name: Release a new stable version to Maven Central
|
||||||
|
run: ./gradlew :flatlaf-fonts-${{ matrix.font }}:build :flatlaf-fonts-${{ matrix.font }}:publish -Prelease
|
||||||
|
env:
|
||||||
|
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
|
||||||
|
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
|
||||||
|
SIGNING_KEY: ${{ secrets.SIGNING_KEY }}
|
||||||
|
SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }}
|
||||||
|
if: startsWith( github.ref, format( 'refs/tags/fonts/{0}-', matrix.font ) )
|
||||||
19
.github/workflows/natives.yml
vendored
19
.github/workflows/natives.yml
vendored
@@ -1,4 +1,5 @@
|
|||||||
# https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
|
# 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: Native Libraries
|
name: Native Libraries
|
||||||
|
|
||||||
@@ -12,13 +13,6 @@ on:
|
|||||||
- 'flatlaf-natives/**'
|
- 'flatlaf-natives/**'
|
||||||
- '.github/workflows/natives.yml'
|
- '.github/workflows/natives.yml'
|
||||||
- 'gradle/wrapper/gradle-wrapper.properties'
|
- 'gradle/wrapper/gradle-wrapper.properties'
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- '*'
|
|
||||||
paths:
|
|
||||||
- 'flatlaf-natives/**'
|
|
||||||
- '.github/workflows/natives.yml'
|
|
||||||
- 'gradle/wrapper/gradle-wrapper.properties'
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
Natives:
|
Natives:
|
||||||
@@ -26,20 +20,21 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
os:
|
os:
|
||||||
- windows
|
- windows
|
||||||
|
- macos
|
||||||
- ubuntu
|
- ubuntu
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}-latest
|
runs-on: ${{ matrix.os }}-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- uses: gradle/wrapper-validation-action@v1
|
- uses: gradle/wrapper-validation-action@v1
|
||||||
|
|
||||||
- name: Setup Java 11
|
- name: Setup Java 11
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
java-version: 11
|
java-version: 11
|
||||||
distribution: adopt
|
distribution: temurin
|
||||||
cache: gradle
|
cache: gradle
|
||||||
|
|
||||||
- name: Build with Gradle
|
- name: Build with Gradle
|
||||||
@@ -48,7 +43,7 @@ jobs:
|
|||||||
run: ./gradlew build-natives --no-daemon
|
run: ./gradlew build-natives --no-daemon
|
||||||
|
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: FlatLaf-natives-build-artifacts-${{ matrix.os }}
|
name: FlatLaf-natives-build-artifacts-${{ matrix.os }}
|
||||||
path: |
|
path: |
|
||||||
|
|||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -9,5 +9,7 @@ out/
|
|||||||
*.iml
|
*.iml
|
||||||
*.ipr
|
*.ipr
|
||||||
*.iws
|
*.iws
|
||||||
|
*.xcuserstate
|
||||||
|
*.xcworkspacedata
|
||||||
.vs/
|
.vs/
|
||||||
.vscode/
|
.vscode/
|
||||||
|
|||||||
320
CHANGELOG.md
320
CHANGELOG.md
@@ -1,6 +1,326 @@
|
|||||||
FlatLaf Change Log
|
FlatLaf Change Log
|
||||||
==================
|
==================
|
||||||
|
|
||||||
|
## 3.4-SNAPSHOT
|
||||||
|
|
||||||
|
#### New features and improvements
|
||||||
|
|
||||||
|
- Native libraries: System property `flatlaf.nativeLibraryPath` now supports
|
||||||
|
loading native libraries named the same as on Maven central. Improved log
|
||||||
|
messages for loading fails.
|
||||||
|
- Fonts: Updated **Inter** to
|
||||||
|
[v4.0](https://github.com/rsms/inter/releases/tag/v4.0).
|
||||||
|
|
||||||
|
#### Fixed bugs
|
||||||
|
|
||||||
|
- JIDE CommandMenuBar: Fixed `ClassCastException` when JIDE command bar displays
|
||||||
|
`JideMenu` in popup. (PR #794)
|
||||||
|
|
||||||
|
|
||||||
|
## 3.3
|
||||||
|
|
||||||
|
#### New features and improvements
|
||||||
|
|
||||||
|
- macOS (10.14+): Popups (`JPopupMenu`, `JComboBox`, `JToolTip`, etc.) now use
|
||||||
|
native macOS rounded borders. (PR #772; issue #715)
|
||||||
|
- Native libraries: Added `libflatlaf-macos-arm64.dylib` and
|
||||||
|
`libflatlaf-macos-x86_64.dylib`. See also
|
||||||
|
https://www.formdev.com/flatlaf/native-libraries/.
|
||||||
|
- ScrollPane: Support rounded border. (PR #713)
|
||||||
|
- SplitPane: Support divider hover and pressed background colors. (PR #788)
|
||||||
|
- TabbedPane: Support vertical tabs. (PR #758, issue #633)
|
||||||
|
- TabbedPane: Paint rounded tab area background for rounded cards. (issue #717)
|
||||||
|
- ToolBar: Added styling properties `separatorWidth` and `separatorColor`.
|
||||||
|
|
||||||
|
#### Fixed bugs
|
||||||
|
|
||||||
|
- Button and ToggleButton: Selected buttons did not use explicitly set
|
||||||
|
foreground color. (issue 756)
|
||||||
|
- FileChooser: Catch NPE in Java 21 when getting icon for `.exe` files that use
|
||||||
|
default Windows exe icon. (see
|
||||||
|
[JDK-8320692](https://bugs.openjdk.org/browse/JDK-8320692))
|
||||||
|
- OptionPane: Fixed styling custom panel background in `JOptionPane`. (issue
|
||||||
|
#761)
|
||||||
|
- ScrollPane: Styling ScrollPane border properties did not work if view
|
||||||
|
component is a Table.
|
||||||
|
- Table:
|
||||||
|
- Switching theme looses table grid and intercell spacing. (issues #733 and
|
||||||
|
#750)
|
||||||
|
- Fixed background of `boolean` columns when using alternating row colors.
|
||||||
|
(issue #780)
|
||||||
|
- Fixed border arc of components in complex table cell editors. (issue #786)
|
||||||
|
- TableHeader:
|
||||||
|
- No longer temporary replace header cell renderer while painting. This avoids
|
||||||
|
a `StackOverflowError` in case that custom renderer does this too. (see
|
||||||
|
[NetBeans issue #6835](https://github.com/apache/netbeans/issues/6835)) This
|
||||||
|
also improves compatibility with custom table header implementations.
|
||||||
|
- Header cell renderer background/foreground colors were not restored after
|
||||||
|
hover if renderer uses `null` for background/foreground. (PR #790)
|
||||||
|
- TabbedPane:
|
||||||
|
- Avoid unnecessary repainting whole tabbed pane content area when layouting
|
||||||
|
leading/trailing components.
|
||||||
|
- Avoid unnecessary repainting of selected tab on temporary changes.
|
||||||
|
- Fixed "endless" layouting and repainting when using nested tabbed panes (top
|
||||||
|
and bottom tab placement) and RSyntaxTextArea (with enabled line-wrapping)
|
||||||
|
as tab content. (see
|
||||||
|
[jadx issue #2030](https://github.com/skylot/jadx/issues/2030))
|
||||||
|
- Fixed broken rendering after resizing window to minimum size and then
|
||||||
|
increasing size again. (issue #767)
|
||||||
|
|
||||||
|
#### Incompatibilities
|
||||||
|
|
||||||
|
- Removed support for JetBrains custom decorations, which required
|
||||||
|
[JetBrains Runtime](https://github.com/JetBrains/JetBrainsRuntime/wiki) (JBR)
|
||||||
|
8 or 11. It did not work for JBR 17. System property
|
||||||
|
`flatlaf.useJetBrainsCustomDecorations` is now ignored. **Note**: FlatLaf
|
||||||
|
window decorations continue to work with JBR.
|
||||||
|
|
||||||
|
|
||||||
|
## 3.2.5
|
||||||
|
|
||||||
|
#### Fixed bugs
|
||||||
|
|
||||||
|
- Popup: Fixed NPE if popup invoker is `null` on Windows 10. (issue #753;
|
||||||
|
regression in 3.2.1 in fix for #626)
|
||||||
|
|
||||||
|
|
||||||
|
## 3.2.4
|
||||||
|
|
||||||
|
#### Fixed bugs
|
||||||
|
|
||||||
|
- Popup: Fixed NPE if popup invoker is `null` on Linux with Wayland and Java 21.
|
||||||
|
(issue #752; regression in 3.2.3)
|
||||||
|
|
||||||
|
|
||||||
|
## 3.2.3
|
||||||
|
|
||||||
|
#### Fixed bugs
|
||||||
|
|
||||||
|
- Popup: Popups that request focus were not shown on Linux with Wayland and Java 21.
|
||||||
|
(issue #752)
|
||||||
|
|
||||||
|
|
||||||
|
## 3.2.2
|
||||||
|
|
||||||
|
#### Fixed bugs
|
||||||
|
|
||||||
|
- Button: Fixed painting icon and text at wrong location when using HTML text,
|
||||||
|
left/right vertical alignment and running in Java 19+. (issue #746)
|
||||||
|
- CheckBox and RadioButton: Fixed cut off right side when border is removed and
|
||||||
|
horizontal alignment is set to `right`. (issue #734)
|
||||||
|
- TabbedPane: Fixed NPE when using focusable component as tab component and
|
||||||
|
switching theme. (issue #745)
|
||||||
|
|
||||||
|
|
||||||
|
## 3.2.1
|
||||||
|
|
||||||
|
#### Fixed bugs
|
||||||
|
|
||||||
|
- Fixed memory leak in
|
||||||
|
`MultiResolutionImageSupport.create(int,Dimension[],Function<Dimension,Image>)`,
|
||||||
|
which caches images created by the producer function. Used by
|
||||||
|
`FlatSVGIcon.getImage()` and `FlatSVGUtils.createWindowIconImages()`. If you
|
||||||
|
use one of these methods, it is **strongly recommended** to upgrade to this
|
||||||
|
version, because if the returned image is larger and painted very often it may
|
||||||
|
result in an out-of-memory situation. (issue #726)
|
||||||
|
- FileChooser: Fixed occasional NPE in `FlatShortcutsPanel` on Windows. (issue
|
||||||
|
#718)
|
||||||
|
- TextField: Fixed placeholder text painting, which did not respect horizontal
|
||||||
|
alignment property of `JTextField`. (issue #721)
|
||||||
|
- Popup: Fixed drop shadow if popup overlaps a heavyweight component. (Windows
|
||||||
|
10 only; issue #626)
|
||||||
|
|
||||||
|
|
||||||
|
## 3.2
|
||||||
|
|
||||||
|
#### New features and improvements
|
||||||
|
|
||||||
|
- TabbedPane: Support rounded underline selection and rounded card tabs. (PR
|
||||||
|
#703)
|
||||||
|
- FlatLaf window decorations:
|
||||||
|
- Support for Windows on ARM 64-bit. (issue #443, PR #707)
|
||||||
|
- Support toolbox-style "small" window title bar. (issue #659, PR #702)
|
||||||
|
- Extras: Class `FlatSVGIcon` now uses [JSVG](https://github.com/weisJ/jsvg)
|
||||||
|
library (instead of svgSalamander) for rendering. JSVG provides improved SVG
|
||||||
|
rendering and uses less memory compared to svgSalamander. (PR #684)
|
||||||
|
- ComboBox: Improved location of selected item in popup if list is large and
|
||||||
|
scrollable.
|
||||||
|
- FileChooser: Show localized text for all locales supported by Java's Metal
|
||||||
|
look and feel. (issue #680)
|
||||||
|
- Added system property `flatlaf.useNativeLibrary` to allow disabling loading of
|
||||||
|
FlatLaf native library. (issue #674)
|
||||||
|
- IntelliJ Themes:
|
||||||
|
- Reduced memory footprint by releasing Json data and ignoring IntelliJ UI
|
||||||
|
properties that are not used in FlatLaf.
|
||||||
|
- Updated "Hiberbee Dark" and "Gradianto" themes.
|
||||||
|
|
||||||
|
#### Fixed bugs
|
||||||
|
|
||||||
|
- Styling: Fixed scaling of some styling properties (`rowHeight` for Table and
|
||||||
|
Tree; `iconTextGap` for Button, CheckBox and RadioButton). (issue #682)
|
||||||
|
- Fixed `IllegalComponentStateException` when invoker is not showing in
|
||||||
|
`SubMenuUsabilityHelper`. (issue #692)
|
||||||
|
- macOS themes: Changing `@accentColor` variable in FlatLaf properties files did
|
||||||
|
not change all accent related colors for all components.
|
||||||
|
- IntelliJ Themes:
|
||||||
|
- "Light Owl" theme: Fixed wrong (unreadable) text color in selected menu
|
||||||
|
items, selected text in text components, and selection in ComboBox popup
|
||||||
|
list. (issue #687)
|
||||||
|
- "Gradianto Midnight Blue" theme: Fixed color of ScrollBar track, which was
|
||||||
|
not visible. (issue #686)
|
||||||
|
- "Monocai" theme: Fixed unreadable text color of default buttons. (issue
|
||||||
|
#693)
|
||||||
|
- "Vuesion" theme: Fixed foreground colors of disabled text.
|
||||||
|
- "Material UI Lite" themes: Fixed non-editable ComboBox button background.
|
||||||
|
- CheckBox and RadioButton: Fixed unselected icon colors for themes "Atom One
|
||||||
|
Light", "Cyan Light", "GitHub", "Light Owl", "Material Lighter" and
|
||||||
|
"Solarized Light".
|
||||||
|
- TabbedPane: Fixed focused tab background color for themes "Arc *", "Material
|
||||||
|
Design Dark", "Monocai", "One Dark", "Spacegray" and "Xcode-Dark". (issue
|
||||||
|
#697)
|
||||||
|
- TextComponents, ComboBox and Spinner: Fixed background colors of enabled
|
||||||
|
text components, to distinguish from disabled, for themes "Carbon", "Cobalt
|
||||||
|
2", "Gradianto *", "Gruvbox *", "Monocai", "Spacegray", "Vuesion",
|
||||||
|
"Xcode-Dark", "GitHub", and "Light Owl". (issue #528)
|
||||||
|
- Fixed wrong disabled text colors in "Dark Flat", "Hiberbee Dark", "Light
|
||||||
|
Flat", "Nord", "Solarized Dark" and "Solarized Light" themes.
|
||||||
|
- Fixed colors for selection background/foreground, Separator, Slider track
|
||||||
|
and ProgressBar background in various themes.
|
||||||
|
- Native Windows libraries: Fixed crash when running in Java 8 and newer Java
|
||||||
|
version is installed in `PATH` environment variable and using class
|
||||||
|
`SystemInfo` before AWT initialization. (issue #673)
|
||||||
|
- ComboBox: Fixed search in item list for text with spaces. (issue #691)
|
||||||
|
- FormattedTextField: On Linux, fixed `IllegalArgumentException: Invalid
|
||||||
|
location` if `JFormattedTextField.setDocument()` is invoked in a focus gained
|
||||||
|
listener on that formatted text field. (issue #698)
|
||||||
|
- PopupMenu: Make sure that popup menu does not overlap any operating system
|
||||||
|
task bar. (issue #701)
|
||||||
|
- FileChooser: Use system icons on Windows with Java 17.0.3 (and later) 32-bit.
|
||||||
|
Only Java 17 - 17.0.2 32-bit do not use system icons because of a bug in Java
|
||||||
|
32-bit that crashes the application. (PR #709)
|
||||||
|
- FileChooser: Fixed crash on Windows with Java 17 to 17.0.2 32-bit. Java 17
|
||||||
|
64-bit is not affected. (regression since FlatLaf 2.3; PR #522, see also issue
|
||||||
|
#403)
|
||||||
|
|
||||||
|
#### Incompatibilities
|
||||||
|
|
||||||
|
- Extras: Class `FlatSVGIcon` now uses [JSVG](https://github.com/weisJ/jsvg)
|
||||||
|
library for SVG rendering. You need to replace svgSalamander with JSVG in your
|
||||||
|
build scripts and distribute `jsvg.jar` with your application. Also replace
|
||||||
|
`com.kitfox.svg` with `com.github.weisj.jsvg` in `module-info.java` files.
|
||||||
|
- IntelliJ Themes: Removed all "Contrast" themes from "Material UI Lite".
|
||||||
|
|
||||||
|
|
||||||
|
## 3.1.1
|
||||||
|
|
||||||
|
- IntelliJ Themes:
|
||||||
|
- Fixed too large menu item paddings and too large table/tree row heights (all
|
||||||
|
"Material Theme UI Lite" themes; issue #667; regression in FlatLaf 3.1).
|
||||||
|
- Fixed too large tree row height in "Carbon", "Dark Purple", "Gray",
|
||||||
|
"Material Design Dark", "Monokai Pro", "One Dark" and "Spacegray" themes.
|
||||||
|
- Native libraries: Fixed `IllegalArgumentException: URI scheme is not "file"`
|
||||||
|
when using FlatLaf in WebStart. (issue #668; regression in FlatLaf 3.1)
|
||||||
|
|
||||||
|
|
||||||
|
## 3.1
|
||||||
|
|
||||||
|
#### New features and improvements
|
||||||
|
|
||||||
|
- Windows 11: Popups (`JPopupMenu`, `JComboBox`, `JToolTip`, etc.) now use
|
||||||
|
native Windows 11 rounded borders and drop shadows. (PR #643)
|
||||||
|
- Fonts:
|
||||||
|
- Added **Roboto Mono** (https://fonts.google.com/specimen/Roboto+Mono). (PR
|
||||||
|
#639, issue #638)
|
||||||
|
- Updated **JetBrains Mono** to
|
||||||
|
[v2.304](https://github.com/JetBrains/JetBrainsMono/releases/tag/v2.304).
|
||||||
|
- Theme Editor: Support macOS light and dark themes.
|
||||||
|
- TabbedPane: Support hover and focused tab foreground colors. (issue #627)
|
||||||
|
- TabbedPane: `tabbedPane.getBackgroundAt(tabIndex)` now has higher priority
|
||||||
|
than `TabbedPane.focusColor` and `TabbedPane.selectedBackground`. If
|
||||||
|
`tabbedPane.setBackgroundAt(tabIndex)` is used to set a color for a single
|
||||||
|
tab, then this color is now used even if the tab is focused or selected.
|
||||||
|
- TableHeader: Support column hover and pressed background and foreground
|
||||||
|
colors. (issue #636)
|
||||||
|
- Native libraries: Made it easier to distribute FlatLaf native libraries
|
||||||
|
(Windows `.dll` and Linux `.so`) to avoid problems on operating systems with
|
||||||
|
enabled execution restrictions.
|
||||||
|
See https://www.formdev.com/flatlaf/native-libraries/ for more details. (issue #624)
|
||||||
|
- Published native libraries to Maven Central for easy using them as
|
||||||
|
dependencies in Gradle and Maven.
|
||||||
|
- If available, native libraries are now loaded from same location as
|
||||||
|
`flatlaf.jar`, otherwise they are extract from `flatlaf.jar` to temporary
|
||||||
|
folder and loaded from there.
|
||||||
|
- Windows DLLs are now digitally signed with FormDev Software GmbH
|
||||||
|
certificate.
|
||||||
|
|
||||||
|
#### Fixed bugs
|
||||||
|
|
||||||
|
- FlatLaf window decorations:
|
||||||
|
- Fixed inconsistent size of glass pane depending on whether FlatLaf window
|
||||||
|
decorations are used (e.g. Windows 10/11) or not (e.g. macOS). Now the glass
|
||||||
|
pane no longer overlaps the FlatLaf window title bar. (issue #630)
|
||||||
|
- Linux: Fixed broken window resizing on multi-screen setups. (issue #632)
|
||||||
|
- Linux: Fixed behavior of maximize/restore button when tiling window to left
|
||||||
|
or right half of screen. (issue #647)
|
||||||
|
- IntelliJ Themes:
|
||||||
|
- Fixed default button hover background in "Solarized Light" theme. (issue
|
||||||
|
#628)
|
||||||
|
- Avoid that accent color affect some colors in some IntelliJ themes. (issue
|
||||||
|
#625)
|
||||||
|
- Updated "Hiberbee Dark" and "Material Theme UI Lite" themes.
|
||||||
|
- Styling: Fixed resolving of UI variables in styles that use other variables.
|
||||||
|
- MenuItem: Fixed horizontal alignment of icons. (issue #631)
|
||||||
|
- Table: Fixed potential performance issue with paint cell focus indicator
|
||||||
|
border. (issue #654)
|
||||||
|
- Tree: Fixed missing custom closed/opened/leaf icons of a custom
|
||||||
|
`DefaultTreeCellRenderer`. (issue #653; regression since implementing PR #609
|
||||||
|
in FlatLaf 3.0)
|
||||||
|
- Tree: Fixed truncated node text and too small painted non-wide node background
|
||||||
|
if custom cell renderer sets icon, but not disabled icon, and tree is
|
||||||
|
disabled. (issue #640)
|
||||||
|
- Fixed `HiDPIUtils.paintAtScale1x()`, which painted at wrong location if
|
||||||
|
graphics is rotated, is scaled and `x` or `y` parameters are not zero. (issue
|
||||||
|
#646)
|
||||||
|
|
||||||
|
|
||||||
|
## 3.0
|
||||||
|
|
||||||
|
#### New features and improvements
|
||||||
|
|
||||||
|
- **macOS light and dark themes**: The two new themes `FlatMacLightLaf` and
|
||||||
|
`FlatMacDarkLaf` use macOS colors and look similar to native macOS controls.
|
||||||
|
(PRs #533, #612 and #607)
|
||||||
|
- **Fonts**: Packaged some fonts into JARs and provide an easy way to use them
|
||||||
|
with FlatLaf. (PRs #545, #614 and #615) At the moment there are three fonts:
|
||||||
|
- **Inter** (https://rsms.me/inter/) - a typeface carefully crafted & designed
|
||||||
|
for computer screens
|
||||||
|
- **Roboto** (https://fonts.google.com/specimen/Roboto) - default font on
|
||||||
|
Android and recommended for Material Design
|
||||||
|
- **JetBrains Mono** (https://www.jetbrains.com/mono) - a monospaced typeface
|
||||||
|
- **Rounded selection**: Optionally use rounded selection in:
|
||||||
|
- Menus (PR #536)
|
||||||
|
- ComboBox (PR #548)
|
||||||
|
- List (PR #547)
|
||||||
|
- Tree (PR #546)
|
||||||
|
- Tree: Hide default closed/opened/leaf icons by default. Set UI value
|
||||||
|
`Tree.showDefaultIcons` to `true` to show them.
|
||||||
|
- ToolBar: Hover effect for button groups. (PR #534)
|
||||||
|
- Icons: New modern **rounded outlined icons** for `JFileChooser`,
|
||||||
|
`JOptionPane`, `JPasswordField` and `JTree`. (PR #577)
|
||||||
|
|
||||||
|
#### Fixed bugs
|
||||||
|
|
||||||
|
- FileChooser: Fixed layout of (optional) accessory component and fixed too
|
||||||
|
large right margin. (issue #604; regression since implementing PR #522 in
|
||||||
|
FlatLaf 2.3)
|
||||||
|
- Tree:
|
||||||
|
- Fixed missing tree lines (if enabled) for wide-selected rows. (issue #598)
|
||||||
|
- Fixed scaling of tree lines and fixed alignment to expand/collapse arrows.
|
||||||
|
- Removed support for dashed tree lines. `Tree.lineTypeDashed` is now ignored.
|
||||||
|
- SwingX: Fonts in `JXHeader`, `JXMonthView`, `JXTaskPane` and `JXTitledPanel`
|
||||||
|
were not updated when changing default font.
|
||||||
|
|
||||||
|
|
||||||
## 2.6
|
## 2.6
|
||||||
|
|
||||||
#### New features and improvements
|
#### New features and improvements
|
||||||
|
|||||||
285
README.md
285
README.md
@@ -6,7 +6,7 @@ Swing desktop applications.
|
|||||||
|
|
||||||
It looks almost flat (no shadows or gradients), clean, simple and elegant.
|
It looks almost flat (no shadows or gradients), clean, simple and elegant.
|
||||||
FlatLaf comes with **Light**, **Dark**, **IntelliJ** and **Darcula** themes,
|
FlatLaf comes with **Light**, **Dark**, **IntelliJ** and **Darcula** themes,
|
||||||
scales on **HiDPI** displays and runs on Java 8 or newer.
|
scales on **HiDPI** displays and runs on Java 8 or newer (LTS and latest).
|
||||||
|
|
||||||
The look is heavily inspired by **Darcula** and **IntelliJ** themes from
|
The look is heavily inspired by **Darcula** and **IntelliJ** themes from
|
||||||
IntelliJ IDEA 2019.2+ and uses almost the same colors and icons.
|
IntelliJ IDEA 2019.2+ and uses almost the same colors and icons.
|
||||||
@@ -15,6 +15,11 @@ IntelliJ IDEA 2019.2+ and uses almost the same colors and icons.
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
macOS Themes
|
||||||
|
------------
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
IntelliJ Platform Themes
|
IntelliJ Platform Themes
|
||||||
------------------------
|
------------------------
|
||||||
@@ -25,6 +30,17 @@ FlatLaf can use 3rd party themes created for IntelliJ Platform (see
|
|||||||

|

|
||||||
|
|
||||||
|
|
||||||
|
Sponsors
|
||||||
|
--------
|
||||||
|
|
||||||
|
<a href="https://www.ej-technologies.com/"><img src="https://www.formdev.com/flatlaf/sponsor/ej-technologies.png" width="200" alt="ej-technologies" title="ej-technologies - Java APM, Java Profiler, Java Installer Builder"></a>
|
||||||
|
|
||||||
|
<a href="https://www.dbvis.com/"><img src="https://www.formdev.com/flatlaf/sponsor/dbvisualizer.svg" width="200" alt="DbVisualizer" title="DbVisualizer - SQL Client and Editor"></a>
|
||||||
|
|
||||||
|
<a href="https://www.dscsag.com/"><img src="https://www.formdev.com/flatlaf/sponsor/DSC.png" height="48" alt="DSC Software AG" title="DSC Software AG - Your Companion for Integrative PLM"></a>
|
||||||
|
|
||||||
|
[Become a Sponsor](https://www.formdev.com/flatlaf/sponsor/)
|
||||||
|
|
||||||
Demo
|
Demo
|
||||||
----
|
----
|
||||||
|
|
||||||
@@ -46,10 +62,15 @@ build script:
|
|||||||
artifactId: flatlaf
|
artifactId: flatlaf
|
||||||
version: (see button below)
|
version: (see button below)
|
||||||
|
|
||||||
Otherwise download `flatlaf-<version>.jar` here:
|
Otherwise, download `flatlaf-<version>.jar` here:
|
||||||
|
|
||||||
[](https://maven-badges.herokuapp.com/maven-central/com.formdev/flatlaf)
|
[](https://maven-badges.herokuapp.com/maven-central/com.formdev/flatlaf)
|
||||||
|
|
||||||
|
See also
|
||||||
|
[Native Libraries distribution](https://www.formdev.com/flatlaf/native-libraries/)
|
||||||
|
for instructions on how to redistribute FlatLaf native libraries with your
|
||||||
|
application.
|
||||||
|
|
||||||
|
|
||||||
### Snapshots
|
### Snapshots
|
||||||
|
|
||||||
@@ -74,6 +95,8 @@ Addons
|
|||||||
- [SwingX](flatlaf-swingx) - support for SwingX components
|
- [SwingX](flatlaf-swingx) - support for SwingX components
|
||||||
- [JIDE Common Layer](flatlaf-jide-oss) - support for JIDE Common Layer
|
- [JIDE Common Layer](flatlaf-jide-oss) - support for JIDE Common Layer
|
||||||
components
|
components
|
||||||
|
- [Fonts](flatlaf-fonts) - some font families bundled in easy-to-use and
|
||||||
|
redistributable JARs
|
||||||
|
|
||||||
|
|
||||||
Getting started
|
Getting started
|
||||||
@@ -118,7 +141,7 @@ details and downloads.
|
|||||||
Buzz
|
Buzz
|
||||||
----
|
----
|
||||||
|
|
||||||
- [What others say about FlatLaf on Twitter](https://twitter.com/search?f=live&q=flatlaf)
|
- [FlatLaf 3.1 (and 3.0) announcement on Reddit](https://www.reddit.com/r/java/comments/12xgrsu/flatlaf_31_and_30_swing_look_and_feel/)
|
||||||
- [FlatLaf 1.0 announcement on Reddit](https://www.reddit.com/r/java/comments/lsbcwe/flatlaf_10_swing_look_and_feel/)
|
- [FlatLaf 1.0 announcement on Reddit](https://www.reddit.com/r/java/comments/lsbcwe/flatlaf_10_swing_look_and_feel/)
|
||||||
- [FlatLaf announcement on Reddit](https://www.reddit.com/r/java/comments/dl0hu3/flatlaf_flat_look_and_feel/)
|
- [FlatLaf announcement on Reddit](https://www.reddit.com/r/java/comments/dl0hu3/flatlaf_flat_look_and_feel/)
|
||||||
|
|
||||||
@@ -126,99 +149,193 @@ Buzz
|
|||||||
Applications using FlatLaf
|
Applications using FlatLaf
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
-  [Ultorg](https://www.ultorg.com/) (**commercial**) - a
|
### Featured
|
||||||
visual query system for relational databases
|
|
||||||
-  [MooInfo](https://github.com/rememberber/MooInfo) -
|
-  [JFormDesigner](https://www.formdev.com/)
|
||||||
visual implementation of OSHI, to view information about the system and
|
(**commercial**) - Java/Swing GUI Designer (from the FlatLaf creators)
|
||||||
hardware
|
- 
|
||||||
-  [Jailer](https://github.com/Wisser/Jailer) 11.2 -
|
[JProfiler](https://www.ej-technologies.com/products/jprofiler/overview.html)
|
||||||
database subsetting and relational data browsing tool
|
(**commercial**) - the award-winning all-in-one Java profiler
|
||||||
- [Apache NetBeans](https://netbeans.apache.org/) 11.3 - IDE for Java, PHP, HTML
|
- 
|
||||||
and much more
|
|
||||||
- [jclasslib bytecode viewer](https://github.com/ingokegel/jclasslib) 5.5
|
|
||||||
- [KeyStore Explorer](https://keystore-explorer.org/) 5.4.3
|
|
||||||
- 
|
|
||||||
[install4j](https://www.ej-technologies.com/products/install4j/overview.html)
|
[install4j](https://www.ej-technologies.com/products/install4j/overview.html)
|
||||||
9.0 (**commercial**) - the powerful multi-platform Java installer builder
|
(**commercial**) - the powerful multi-platform Java installer builder
|
||||||
-  [DbVisualizer](https://www.dbvis.com/) 12.0
|
-  [DbVisualizer](https://www.dbvis.com/)
|
||||||
(**commercial**) - the universal database tool for developers, analysts and
|
(**commercial**) - the universal database tool for developers, analysts and
|
||||||
DBAs
|
DBAs
|
||||||
-  [MagicPlot](https://magicplot.com/) 3.0
|
-  [Apache NetBeans](https://netbeans.apache.org/) - IDE
|
||||||
(**commercial**) - Software for nonlinear fitting, plotting and data analysis
|
for Java, PHP, HTML and much more
|
||||||
- 
|
- 
|
||||||
[Thermo-Calc](https://thermocalc.com/products/thermo-calc/) 2021a
|
[Thermo-Calc](https://thermocalc.com/products/thermo-calc/) (**commercial**) -
|
||||||
(**commercial**) - Thermodynamics and Properties Software
|
Thermodynamics and Properties Software
|
||||||
- [OWASP ZAP](https://www.zaproxy.org/) 2.10 - the worlds most widely used web
|
|
||||||
app scanner
|
### Data
|
||||||
|
|
||||||
|
-  [Ultorg](https://www.ultorg.com/) (**commercial**) - a
|
||||||
|
visual query system for relational databases
|
||||||
|
- [Jailer](https://github.com/Wisser/Jailer) - database subsetting and
|
||||||
|
relational data browsing tool
|
||||||
|
-  [MagicPlot](https://magicplot.com/) (**commercial**) -
|
||||||
|
Software for nonlinear fitting, plotting and data analysis
|
||||||
|
-  [Constellation](https://www.constellation-app.com/) -
|
||||||
|
Data Visualization and Analytics (based on NetBeans platform)
|
||||||
- 
|
- 
|
||||||
|
[Kafka Visualizer](https://github.com/kumait/kafkavisualizer) - Kafka GUI
|
||||||
|
client
|
||||||
|
|
||||||
|
### Security
|
||||||
|
|
||||||
|
-  [ZAP](https://www.zaproxy.org/) - the world's most
|
||||||
|
widely used web app scanner
|
||||||
|
- 
|
||||||
[Burp Suite Professional and Community Edition](https://portswigger.net/burp/pro)
|
[Burp Suite Professional and Community Edition](https://portswigger.net/burp/pro)
|
||||||
2020.11.2 (**commercial**) - the leading software for web security testing
|
(**commercial**) - the leading software for web security testing
|
||||||
- 
|
- 
|
||||||
[BurpCustomizer](https://github.com/CoreyD97/BurpCustomizer) - adds more
|
[Ghidra](https://github.com/NationalSecurityAgency/ghidra) - a software
|
||||||
|
reverse engineering (SRE) framework
|
||||||
|
-  [jadx](https://github.com/skylot/jadx) - Dex to Java
|
||||||
|
decompiler
|
||||||
|
- [BurpCustomizer](https://github.com/CoreyD97/BurpCustomizer) - adds more
|
||||||
FlatLaf themes to Burp Suite
|
FlatLaf themes to Burp Suite
|
||||||
- [JOSM](https://josm.openstreetmap.de/) - an extensible editor for
|
- [Total Validator](https://www.totalvalidator.com/) (**commercial**) - checks
|
||||||
[OpenStreetMap](https://www.openstreetmap.org/) (requires FlatLaf JOSM plugin)
|
your website
|
||||||
- [jAlbum](https://jalbum.net/) 21 (**commercial**) - creates photo album
|
- [JPass](https://github.com/gaborbata/jpass) - password manager with strong
|
||||||
websites
|
encryption
|
||||||
-  [PDF Studio](https://www.qoppa.com/pdfstudio/) 2021
|
|
||||||
(**commercial**) - create, review and edit PDF documents
|
### Software Development
|
||||||
- [XMLmind XML Editor](https://www.xmlmind.com/xmleditor/) 9.3 (**commercial**)
|
|
||||||
- [Total Validator](https://www.totalvalidator.com/) 15 (**commercial**) -
|
- [jclasslib bytecode viewer](https://github.com/ingokegel/jclasslib)
|
||||||
checks your website
|
- [KeyStore Explorer](https://keystore-explorer.org/)
|
||||||
- [j-lawyer](https://github.com/jlawyerorg/j-lawyer-org) - Kanzleisoftware
|
- 
|
||||||
- [MegaMek](https://github.com/MegaMek/megamek),
|
[muCommander](https://github.com/mucommander/mucommander) - lightweight
|
||||||
[MegaMekLab](https://github.com/MegaMek/megameklab) and
|
cross-platform file manager
|
||||||
[MekHQ](https://github.com/MegaMek/mekhq) v0.47.5+ - a sci-fi tabletop
|
-  [Guiffy](https://www.guiffy.com/) (**commercial**) -
|
||||||
BattleTech simulator suite handling battles, unit building, and campaigns
|
advanced cross-platform Diff/Merge
|
||||||
- [GUIslice Builder](https://github.com/ImpulseAdventure/GUIslice-Builder)
|
-  [HashGarten](https://github.com/jonelo/HashGarten) -
|
||||||
0.13.b024 - GUI builder for
|
cross-platform Swing GUI for Jacksum
|
||||||
[GUIslice](https://github.com/ImpulseAdventure/GUIslice), a lightweight GUI
|
- [Pseudo Assembler IDE](https://github.com/tomasz-herman/PseudoAssemblerIDE) -
|
||||||
framework for embedded displays
|
IDE for Pseudo-Assembler
|
||||||
- [Rest Suite](https://github.com/supanadit/restsuite) - Rest API testing
|
- [Linotte](https://github.com/cpc6128/LangageLinotte) - French programming
|
||||||
- [ControllerBuddy](https://github.com/bwRavencl/ControllerBuddy) - advanced
|
language created to learn programming
|
||||||
gamepad mapping software
|
- [lsfusion platform](https://github.com/lsfusion/platform) - information
|
||||||
- [SpringRemote](https://github.com/HaleyWang/SpringRemote) - remote Linux SSH
|
systems development platform
|
||||||
connections manager
|
|
||||||
- [jEnTunnel](https://github.com/ggrandes/jentunnel) - manage SSH Tunnels made
|
### Electrical
|
||||||
easy
|
|
||||||
|
- [Antares](https://www.antarescircuit.io/) - a free, powerful platform for
|
||||||
|
designing, simulating and explaining digital circuits
|
||||||
|
- [Logisim-evolution](https://github.com/logisim-evolution/logisim-evolution) -
|
||||||
|
Digital logic design tool and simulator
|
||||||
|
- [Makelangelo Software](https://github.com/MarginallyClever/Makelangelo-software) -
|
||||||
|
for plotters, especially the wall-hanging polargraph
|
||||||
|
- [GUIslice Builder](https://github.com/ImpulseAdventure/GUIslice-Builder) - GUI
|
||||||
|
builder for [GUIslice](https://github.com/ImpulseAdventure/GUIslice), a
|
||||||
|
lightweight GUI framework for embedded displays
|
||||||
|
- [ThunderFocus](https://github.com/marcocipriani01/ThunderFocus) -
|
||||||
|
Arduino-based telescope focuser
|
||||||
|
- [RemoteLight](https://github.com/Drumber/RemoteLight) - multifunctional LED
|
||||||
|
control software
|
||||||
|
|
||||||
|
### Media
|
||||||
|
|
||||||
|
-  [jAlbum](https://jalbum.net/) (**commercial**) -
|
||||||
|
creates photo album websites
|
||||||
|
-  [MediathekView](https://mediathekview.de/) - search in
|
||||||
|
media libraries of various German broadcasters
|
||||||
|
- [Cinecred](https://loadingbyte.com/cinecred/) - create beautiful film credit
|
||||||
|
sequences
|
||||||
|
- [tinyMediaManager](https://www.tinymediamanager.org/) (**commercial**) - a
|
||||||
|
media management tool
|
||||||
|
- [Weasis](https://nroduit.github.io/) - medical DICOM viewer used in healthcare
|
||||||
|
by hospitals, health networks, etc
|
||||||
|
- [Shutter Encoder](https://www.shutterencoder.com/)
|
||||||
|
([source code](https://github.com/paulpacifico/shutter-encoder)) -
|
||||||
|
professional video converter and compression tool
|
||||||
|
- [Sound Analysis](https://github.com/tomasz-herman/SoundAnalysis) - analyze
|
||||||
|
sound files in time or frequency domain
|
||||||
|
- [Novel-Grabber](https://github.com/Flameish/Novel-Grabber) - download novels
|
||||||
|
from any webnovel and lightnovel site
|
||||||
|
- [lectureStudio](https://www.lecturestudio.org/) - digitize your lectures with
|
||||||
|
ease
|
||||||
|
|
||||||
|
### Modelling
|
||||||
|
|
||||||
|
-  [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
|
||||||
|
Application System
|
||||||
|
|
||||||
|
### Documents
|
||||||
|
|
||||||
|
-  [Big Faceless (BFO) PDF Viewer](https://bfo.com/)
|
||||||
|
(**commercial**) - Swing PDF Viewer
|
||||||
|
- [PDF Studio](https://www.qoppa.com/pdfstudio/) (**commercial**) - create,
|
||||||
|
review and edit PDF documents
|
||||||
|
- [XMLmind XML Editor](https://www.xmlmind.com/xmleditor/) (**commercial**)
|
||||||
|
|
||||||
|
### Geo
|
||||||
|
|
||||||
|
-  [JOSM](https://josm.openstreetmap.de/) - an extensible
|
||||||
|
editor for [OpenStreetMap](https://www.openstreetmap.org/) (requires FlatLaf
|
||||||
|
JOSM plugin)
|
||||||
|
- [Mapton](https://mapton.org/)
|
||||||
|
([source code](https://github.com/trixon/mapton)) - some kind of map
|
||||||
|
application (based on NetBeans platform)
|
||||||
|
- [MeteoInfo](https://github.com/meteoinfo/MeteoInfo) - GIS and scientific
|
||||||
|
computation environment for meteorological community
|
||||||
|
|
||||||
|
### Business / Legal
|
||||||
|
|
||||||
|
- 
|
||||||
|
[j-lawyer](https://github.com/jlawyerorg/j-lawyer-org) - Kanzleisoftware
|
||||||
|
-  [Jeyla Studio](https://www.jeylastudio.com/) -
|
||||||
|
Salon Software
|
||||||
|
- [Fanurio](https://www.fanuriotimetracking.com/) (**commercial**) - time
|
||||||
|
tracking and billing for freelancers and teams
|
||||||
|
- [Jes](https://www.jes-eur.de) - Die Java-EÜR
|
||||||
- [mendelson AS2](https://sourceforge.net/projects/mec-as2/),
|
- [mendelson AS2](https://sourceforge.net/projects/mec-as2/),
|
||||||
[AS4](https://sourceforge.net/projects/mendelson-as4/) and
|
[AS4](https://sourceforge.net/projects/mendelson-as4/) and
|
||||||
[OFTP2](https://sourceforge.net/projects/mendelson-oftp2/) (open-source) and
|
[OFTP2](https://sourceforge.net/projects/mendelson-oftp2/) (open-source) and
|
||||||
[mendelson AS2](https://mendelson-e-c.com/as2/),
|
[mendelson AS2](https://mendelson-e-c.com/as2/),
|
||||||
[AS4](https://mendelson-e-c.com/as4/) and
|
[AS4](https://mendelson-e-c.com/as4/) and
|
||||||
[OFTP2](https://mendelson-e-c.com/oftp2) (**commercial**)
|
[OFTP2](https://mendelson-e-c.com/oftp2) (**commercial**)
|
||||||
-  [IGMAS+](https://www.gfz-potsdam.de/igmas) -
|
|
||||||
Interactive Gravity and Magnetic Application System
|
### Messaging
|
||||||
- [MeteoInfo](https://github.com/meteoinfo/MeteoInfo) 2.2 - GIS and scientific
|
|
||||||
computation environment for meteorological community
|
-  [Spark](https://github.com/igniterealtime/Spark) -
|
||||||
- [lsfusion platform](https://github.com/lsfusion/platform) 4 - information
|
cross-platform IM client optimized for businesses and organizations
|
||||||
systems development platform
|
-  [Chatty](https://github.com/chatty/chatty) - Twitch
|
||||||
- [JPass](https://github.com/gaborbata/jpass) - password manager with strong
|
Chat Client
|
||||||
encryption
|
|
||||||
- [Jes - Die Java-EÜR](https://www.jes-eur.de)
|
### Gaming
|
||||||
- [Mapton](https://mapton.org/) 2.0
|
|
||||||
([source code](https://github.com/trixon/mapton)) - some kind of map
|
-  
|
||||||
application (based on NetBeans platform)
|
[BGBlitz](https://www.bgblitz.com/) (**commercial**) - professional Backgammon
|
||||||
- [Pseudo Assembler IDE](https://github.com/tomasz-herman/PseudoAssemblerIDE) -
|
-  [MapTool](https://github.com/RPTools/maptool) - virtual
|
||||||
IDE for Pseudo-Assembler
|
Tabletop for playing role-playing games
|
||||||
- [Linotte](https://github.com/cpc6128/LangageLinotte) 3.1 - French programming
|
- [MegaMek](https://github.com/MegaMek/megamek),
|
||||||
language created to learn programming
|
[MegaMekLab](https://github.com/MegaMek/megameklab) and
|
||||||
- [MEKA](https://github.com/Waikato/meka) 1.9.3 - multi-label classifiers and
|
[MekHQ](https://github.com/MegaMek/mekhq) - a sci-fi tabletop BattleTech
|
||||||
evaluation procedures using the Weka machine learning framework
|
simulator suite handling battles, unit building, and campaigns
|
||||||
- [Shutter Encoder](https://www.shutterencoder.com/) 14.2
|
- [ControllerBuddy](https://github.com/bwRavencl/ControllerBuddy) - advanced
|
||||||
([source code](https://github.com/paulpacifico/shutter-encoder)) -
|
gamepad mapping software
|
||||||
professional video converter and compression tool (screenshots show **old**
|
|
||||||
look)
|
### Utilities
|
||||||
- [Sound Analysis](https://github.com/tomasz-herman/SoundAnalysis) - analyze
|
|
||||||
sound files in time or frequency domain
|
- [MooInfo](https://github.com/rememberber/MooInfo) - visual implementation of
|
||||||
- [RemoteLight](https://github.com/Drumber/RemoteLight) - multifunctional LED
|
OSHI, to view information about the system and hardware
|
||||||
control software
|
- 
|
||||||
- [ThunderFocus](https://github.com/marcocipriani01/ThunderFocus) -
|
[Linux Task Manager (LTM)](https://github.com/ajee10x/LTM-LinuxTaskManager) -
|
||||||
Arduino-based telescope focuser
|
GUI for monitoring and managing various aspects of a Linux system
|
||||||
- [Novel-Grabber](https://github.com/Flameish/Novel-Grabber) - download novels
|
- [Rest Suite](https://github.com/supanadit/restsuite) - Rest API testing
|
||||||
from any webnovel and lightnovel site
|
- [SpringRemote](https://github.com/HaleyWang/SpringRemote) - remote Linux SSH
|
||||||
- [lectureStudio](https://www.lecturestudio.org/) 4.3.1060 - digitize your
|
connections manager
|
||||||
lectures with ease
|
- [jEnTunnel](https://github.com/ggrandes/jentunnel) - manage SSH Tunnels made
|
||||||
|
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
|
||||||
- and more...
|
|
||||||
|
### Miscellaneous
|
||||||
|
|
||||||
|
- [MEKA](https://github.com/Waikato/meka) - multi-label classifiers and
|
||||||
|
evaluation procedures using the Weka machine learning framework
|
||||||
|
|||||||
@@ -14,10 +14,9 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
val releaseVersion = "2.6"
|
import net.ltgt.gradle.errorprone.errorprone
|
||||||
val developmentVersion = "3.0-SNAPSHOT"
|
|
||||||
|
|
||||||
version = if( java.lang.Boolean.getBoolean( "release" ) ) releaseVersion else developmentVersion
|
version = property( if( hasProperty( "release" ) ) "flatlaf.releaseVersion" else "flatlaf.developmentVersion" ) as String
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
version = rootProject.version
|
version = rootProject.version
|
||||||
@@ -43,6 +42,10 @@ if( !toolchainJavaVersion.isNullOrEmpty() )
|
|||||||
println()
|
println()
|
||||||
|
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
alias( libs.plugins.errorprone ) apply false
|
||||||
|
}
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
tasks {
|
tasks {
|
||||||
withType<JavaCompile>().configureEach {
|
withType<JavaCompile>().configureEach {
|
||||||
@@ -81,4 +84,56 @@ allprojects {
|
|||||||
isFailOnError = false
|
isFailOnError = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//---- Error Prone ----
|
||||||
|
|
||||||
|
tasks.register( "errorprone" ) {
|
||||||
|
group = "verification"
|
||||||
|
tasks.withType<JavaCompile>().forEach {
|
||||||
|
dependsOn( it )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val useErrorProne = gradle.startParameter.taskNames.contains( "errorprone" )
|
||||||
|
if( useErrorProne ) {
|
||||||
|
plugins.withType<JavaPlugin> {
|
||||||
|
apply( plugin = libs.plugins.errorprone.get().pluginId )
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
"errorprone"( libs.errorprone )
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType<JavaCompile>().configureEach {
|
||||||
|
options.compilerArgs.add( "-Werror" )
|
||||||
|
options.errorprone {
|
||||||
|
disable(
|
||||||
|
"ReferenceEquality", // reports usage of '==' for objects
|
||||||
|
"StringSplitter", // reports String.split()
|
||||||
|
"JavaTimeDefaultTimeZone", // reports Year.now()
|
||||||
|
"MissingSummary", // reports `/** @since 2 */`
|
||||||
|
"InvalidBlockTag", // reports @uiDefault in javadoc
|
||||||
|
"AlreadyChecked", // reports false positives
|
||||||
|
"InlineMeSuggester", // suggests using Error Prone annotations for deprecated methods
|
||||||
|
"TypeParameterUnusedInFormals",
|
||||||
|
"UnsynchronizedOverridesSynchronized",
|
||||||
|
"NonApiType", // reports ArrayList/HashSet in parameter or return type
|
||||||
|
)
|
||||||
|
when( project.name ) {
|
||||||
|
"flatlaf-intellij-themes" -> disable(
|
||||||
|
"MutablePublicArray", // reports FlatAllIJThemes.INFOS
|
||||||
|
)
|
||||||
|
"flatlaf-theme-editor" -> disable(
|
||||||
|
"CatchAndPrintStackTrace",
|
||||||
|
)
|
||||||
|
"flatlaf-testing" -> disable(
|
||||||
|
"CatchAndPrintStackTrace",
|
||||||
|
"JdkObsolete", // reports Hashtable used for JSlider.setLabelTable()
|
||||||
|
"JavaUtilDate", // reports usage of class Date
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ public class ReorderJarEntries
|
|||||||
// 1st pass: copy .properties files
|
// 1st pass: copy .properties files
|
||||||
copyFiles( zipOutStream, jarFile, name -> name.endsWith( ".properties" ) );
|
copyFiles( zipOutStream, jarFile, name -> name.endsWith( ".properties" ) );
|
||||||
|
|
||||||
// 2st pass: copy other files
|
// 2nd pass: copy other files
|
||||||
copyFiles( zipOutStream, jarFile, name -> !name.endsWith( ".properties" ) );
|
copyFiles( zipOutStream, jarFile, name -> !name.endsWith( ".properties" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ tasks {
|
|||||||
// depend on :flatlaf-core:compileJava because it generates the JNI headers
|
// depend on :flatlaf-core:compileJava because it generates the JNI headers
|
||||||
dependsOn( ":flatlaf-core:compileJava" )
|
dependsOn( ":flatlaf-core:compileJava" )
|
||||||
|
|
||||||
from( project( ":flatlaf-core" ).buildDir.resolve( "generated/jni-headers" ) )
|
from( project( ":flatlaf-core" ).layout.buildDirectory.dir( "generated/jni-headers" ) )
|
||||||
into( "src/main/headers" )
|
into( "src/main/headers" )
|
||||||
include( extension.headers )
|
include( extension.headers )
|
||||||
filter<org.apache.tools.ant.filters.FixCrLfFilter>(
|
filter<org.apache.tools.ant.filters.FixCrLfFilter>(
|
||||||
|
|||||||
@@ -15,10 +15,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
open class NativeArtifact( val fileName: String, val classifier: String, val type: String ) {}
|
||||||
|
|
||||||
open class PublishExtension {
|
open class PublishExtension {
|
||||||
var artifactId: String? = null
|
var artifactId: String? = null
|
||||||
var name: String? = null
|
var name: String? = null
|
||||||
var description: String? = null
|
var description: String? = null
|
||||||
|
var nativeArtifacts: List<NativeArtifact>? = null
|
||||||
}
|
}
|
||||||
|
|
||||||
val extension = project.extensions.create<PublishExtension>( "flatlafPublish" )
|
val extension = project.extensions.create<PublishExtension>( "flatlafPublish" )
|
||||||
@@ -71,6 +74,15 @@ publishing {
|
|||||||
url.set( "https://github.com/JFormDesigner/FlatLaf/issues" )
|
url.set( "https://github.com/JFormDesigner/FlatLaf/issues" )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
afterEvaluate {
|
||||||
|
extension.nativeArtifacts?.forEach {
|
||||||
|
artifact( artifacts.add( "archives", file( it.fileName ) ) {
|
||||||
|
classifier = it.classifier
|
||||||
|
type = it.type
|
||||||
|
} )
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +92,7 @@ publishing {
|
|||||||
|
|
||||||
val releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
|
val releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
|
||||||
val snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots/"
|
val snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots/"
|
||||||
url = uri( if( java.lang.Boolean.getBoolean( "release" ) ) releasesRepoUrl else snapshotsRepoUrl )
|
url = uri( if( rootProject.hasProperty( "release" ) ) releasesRepoUrl else snapshotsRepoUrl )
|
||||||
|
|
||||||
credentials {
|
credentials {
|
||||||
// get from gradle.properties
|
// get from gradle.properties
|
||||||
@@ -108,5 +120,13 @@ signing {
|
|||||||
|
|
||||||
// disable signing of snapshots
|
// disable signing of snapshots
|
||||||
tasks.withType<Sign>().configureEach {
|
tasks.withType<Sign>().configureEach {
|
||||||
onlyIf { java.lang.Boolean.getBoolean( "release" ) }
|
onlyIf { rootProject.hasProperty( "release" ) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// check whether parallel build is enabled
|
||||||
|
tasks.withType<PublishToMavenRepository>().configureEach {
|
||||||
|
doFirst {
|
||||||
|
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'." )
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
2
flatlaf-core/.settings/org.eclipse.core.resources.prefs
Normal file
2
flatlaf-core/.settings/org.eclipse.core.resources.prefs
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
eclipse.preferences.version=1
|
||||||
|
encoding/<project>=ISO-8859-1
|
||||||
@@ -14,6 +14,8 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import Flatlaf_publish_gradle.NativeArtifact
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
`java-library`
|
`java-library`
|
||||||
`flatlaf-toolchain`
|
`flatlaf-toolchain`
|
||||||
@@ -25,12 +27,11 @@ plugins {
|
|||||||
val sigtest = configurations.create( "sigtest" )
|
val sigtest = configurations.create( "sigtest" )
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
testImplementation( "org.junit.jupiter:junit-jupiter-api:5.7.2" )
|
testImplementation( libs.bundles.junit )
|
||||||
testImplementation( "org.junit.jupiter:junit-jupiter-params" )
|
testRuntimeOnly( libs.junit.engine )
|
||||||
testRuntimeOnly( "org.junit.jupiter:junit-jupiter-engine" )
|
|
||||||
|
|
||||||
// https://github.com/jtulach/netbeans-apitest
|
// https://github.com/jtulach/netbeans-apitest
|
||||||
sigtest( "org.netbeans.tools:sigtest-maven-plugin:1.7" )
|
sigtest( libs.sigtest )
|
||||||
}
|
}
|
||||||
|
|
||||||
java {
|
java {
|
||||||
@@ -41,7 +42,7 @@ java {
|
|||||||
tasks {
|
tasks {
|
||||||
compileJava {
|
compileJava {
|
||||||
// generate JNI headers
|
// generate JNI headers
|
||||||
options.headerOutputDirectory.set( buildDir.resolve( "generated/jni-headers" ) )
|
options.headerOutputDirectory.set( layout.buildDirectory.dir( "generated/jni-headers" ) )
|
||||||
}
|
}
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
@@ -87,7 +88,7 @@ tasks {
|
|||||||
"action" to "generate",
|
"action" to "generate",
|
||||||
"fileName" to "${project.name}-sigtest.txt",
|
"fileName" to "${project.name}-sigtest.txt",
|
||||||
"classpath" to jar.get().outputs.files.asPath,
|
"classpath" to jar.get().outputs.files.asPath,
|
||||||
"packages" to "com.formdev.flatlaf,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" )
|
||||||
@@ -123,4 +124,14 @@ flatlafPublish {
|
|||||||
artifactId = "flatlaf"
|
artifactId = "flatlaf"
|
||||||
name = "FlatLaf"
|
name = "FlatLaf"
|
||||||
description = "Flat Look and Feel"
|
description = "Flat Look and Feel"
|
||||||
|
|
||||||
|
val natives = "src/main/resources/com/formdev/flatlaf/natives"
|
||||||
|
nativeArtifacts = listOf(
|
||||||
|
NativeArtifact( "${natives}/flatlaf-windows-x86.dll", "windows-x86", "dll" ),
|
||||||
|
NativeArtifact( "${natives}/flatlaf-windows-x86_64.dll", "windows-x86_64", "dll" ),
|
||||||
|
NativeArtifact( "${natives}/flatlaf-windows-arm64.dll", "windows-arm64", "dll" ),
|
||||||
|
NativeArtifact( "${natives}/libflatlaf-macos-arm64.dylib", "macos-arm64", "dylib" ),
|
||||||
|
NativeArtifact( "${natives}/libflatlaf-macos-x86_64.dylib", "macos-x86_64", "dylib" ),
|
||||||
|
NativeArtifact( "${natives}/libflatlaf-linux-x86_64.so", "linux-x86_64", "so" ),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#Signature file v4.1
|
#Signature file v4.1
|
||||||
#Version 2.5
|
#Version 3.3
|
||||||
|
|
||||||
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"
|
||||||
@@ -12,6 +12,7 @@ fld public final static java.lang.String BUTTON_TYPE_TOOLBAR_BUTTON = "toolBarBu
|
|||||||
fld public final static java.lang.String COMPONENT_FOCUS_OWNER = "JComponent.focusOwner"
|
fld public final static java.lang.String COMPONENT_FOCUS_OWNER = "JComponent.focusOwner"
|
||||||
fld public final static java.lang.String COMPONENT_ROUND_RECT = "JComponent.roundRect"
|
fld public final static java.lang.String COMPONENT_ROUND_RECT = "JComponent.roundRect"
|
||||||
fld public final static java.lang.String COMPONENT_TITLE_BAR_CAPTION = "JComponent.titleBarCaption"
|
fld public final static java.lang.String COMPONENT_TITLE_BAR_CAPTION = "JComponent.titleBarCaption"
|
||||||
|
fld public final static java.lang.String GLASS_PANE_FULL_HEIGHT = "JRootPane.glassPaneFullHeight"
|
||||||
fld public final static java.lang.String MENU_BAR_EMBEDDED = "JRootPane.menuBarEmbedded"
|
fld public final static java.lang.String MENU_BAR_EMBEDDED = "JRootPane.menuBarEmbedded"
|
||||||
fld public final static java.lang.String MINIMUM_HEIGHT = "JComponent.minimumHeight"
|
fld public final static java.lang.String MINIMUM_HEIGHT = "JComponent.minimumHeight"
|
||||||
fld public final static java.lang.String MINIMUM_WIDTH = "JComponent.minimumWidth"
|
fld public final static java.lang.String MINIMUM_WIDTH = "JComponent.minimumWidth"
|
||||||
@@ -19,8 +20,10 @@ 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_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_DROP_SHADOW_PAINTED = "Popup.dropShadowPainted"
|
fld public final static java.lang.String POPUP_DROP_SHADOW_PAINTED = "Popup.dropShadowPainted"
|
||||||
fld public final static java.lang.String POPUP_FORCE_HEAVY_WEIGHT = "Popup.forceHeavyWeight"
|
fld public final static java.lang.String POPUP_FORCE_HEAVY_WEIGHT = "Popup.forceHeavyWeight"
|
||||||
|
fld public final static java.lang.String POPUP_ROUNDED_BORDER_WIDTH = "Popup.roundedBorderWidth"
|
||||||
fld public final static java.lang.String PROGRESS_BAR_LARGE_HEIGHT = "JProgressBar.largeHeight"
|
fld public final static java.lang.String PROGRESS_BAR_LARGE_HEIGHT = "JProgressBar.largeHeight"
|
||||||
fld public final static java.lang.String PROGRESS_BAR_SQUARE = "JProgressBar.square"
|
fld public final static java.lang.String PROGRESS_BAR_SQUARE = "JProgressBar.square"
|
||||||
fld public final static java.lang.String SCROLL_BAR_SHOW_BUTTONS = "JScrollBar.showButtons"
|
fld public final static java.lang.String SCROLL_BAR_SHOW_BUTTONS = "JScrollBar.showButtons"
|
||||||
@@ -65,6 +68,11 @@ fld public final static java.lang.String TABBED_PANE_TAB_CLOSE_TOOLTIPTEXT = "JT
|
|||||||
fld public final static java.lang.String TABBED_PANE_TAB_HEIGHT = "JTabbedPane.tabHeight"
|
fld public final static java.lang.String TABBED_PANE_TAB_HEIGHT = "JTabbedPane.tabHeight"
|
||||||
fld public final static java.lang.String TABBED_PANE_TAB_ICON_PLACEMENT = "JTabbedPane.tabIconPlacement"
|
fld public final static java.lang.String TABBED_PANE_TAB_ICON_PLACEMENT = "JTabbedPane.tabIconPlacement"
|
||||||
fld public final static java.lang.String TABBED_PANE_TAB_INSETS = "JTabbedPane.tabInsets"
|
fld public final static java.lang.String TABBED_PANE_TAB_INSETS = "JTabbedPane.tabInsets"
|
||||||
|
fld public final static java.lang.String TABBED_PANE_TAB_ROTATION = "JTabbedPane.tabRotation"
|
||||||
|
fld public final static java.lang.String TABBED_PANE_TAB_ROTATION_AUTO = "auto"
|
||||||
|
fld public final static java.lang.String TABBED_PANE_TAB_ROTATION_LEFT = "left"
|
||||||
|
fld public final static java.lang.String TABBED_PANE_TAB_ROTATION_NONE = "none"
|
||||||
|
fld public final static java.lang.String TABBED_PANE_TAB_ROTATION_RIGHT = "right"
|
||||||
fld public final static java.lang.String TABBED_PANE_TAB_TYPE = "JTabbedPane.tabType"
|
fld public final static java.lang.String TABBED_PANE_TAB_TYPE = "JTabbedPane.tabType"
|
||||||
fld public final static java.lang.String TABBED_PANE_TAB_TYPE_CARD = "card"
|
fld public final static java.lang.String TABBED_PANE_TAB_TYPE_CARD = "card"
|
||||||
fld public final static java.lang.String TABBED_PANE_TAB_TYPE_UNDERLINED = "underlined"
|
fld public final static java.lang.String TABBED_PANE_TAB_TYPE_UNDERLINED = "underlined"
|
||||||
@@ -86,10 +94,16 @@ fld public final static java.lang.String TEXT_FIELD_TRAILING_COMPONENT = "JTextF
|
|||||||
fld public final static java.lang.String TEXT_FIELD_TRAILING_ICON = "JTextField.trailingIcon"
|
fld public final static java.lang.String TEXT_FIELD_TRAILING_ICON = "JTextField.trailingIcon"
|
||||||
fld public final static java.lang.String TITLE_BAR_BACKGROUND = "JRootPane.titleBarBackground"
|
fld public final static java.lang.String TITLE_BAR_BACKGROUND = "JRootPane.titleBarBackground"
|
||||||
fld public final static java.lang.String TITLE_BAR_FOREGROUND = "JRootPane.titleBarForeground"
|
fld public final static java.lang.String TITLE_BAR_FOREGROUND = "JRootPane.titleBarForeground"
|
||||||
|
fld public final static java.lang.String TITLE_BAR_SHOW_CLOSE = "JRootPane.titleBarShowClose"
|
||||||
fld public final static java.lang.String TITLE_BAR_SHOW_ICON = "JRootPane.titleBarShowIcon"
|
fld public final static java.lang.String TITLE_BAR_SHOW_ICON = "JRootPane.titleBarShowIcon"
|
||||||
|
fld public final static java.lang.String TITLE_BAR_SHOW_ICONIFFY = "JRootPane.titleBarShowIconify"
|
||||||
|
fld public final static java.lang.String TITLE_BAR_SHOW_MAXIMIZE = "JRootPane.titleBarShowMaximize"
|
||||||
|
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_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_SMALL = "small"
|
||||||
meth public static <%0 extends java.lang.Object> {%%0} clientProperty(javax.swing.JComponent,java.lang.String,{%%0},java.lang.Class<{%%0}>)
|
meth public static <%0 extends java.lang.Object> {%%0} clientProperty(javax.swing.JComponent,java.lang.String,{%%0},java.lang.Class<{%%0}>)
|
||||||
meth public static boolean clientPropertyBoolean(javax.swing.JComponent,java.lang.String,boolean)
|
meth public static boolean clientPropertyBoolean(javax.swing.JComponent,java.lang.String,boolean)
|
||||||
meth public static boolean clientPropertyEquals(javax.swing.JComponent,java.lang.String,java.lang.Object)
|
meth public static boolean clientPropertyEquals(javax.swing.JComponent,java.lang.String,java.lang.Object)
|
||||||
@@ -195,8 +209,13 @@ meth public static boolean isUseNativeWindowDecorations()
|
|||||||
meth public static boolean setup(javax.swing.LookAndFeel)
|
meth public static boolean setup(javax.swing.LookAndFeel)
|
||||||
meth public static boolean supportsNativeWindowDecorations()
|
meth public static boolean supportsNativeWindowDecorations()
|
||||||
meth public static java.lang.Object parseDefaultsValue(java.lang.String,java.lang.String,java.lang.Class<?>)
|
meth public static java.lang.Object parseDefaultsValue(java.lang.String,java.lang.String,java.lang.Class<?>)
|
||||||
|
meth public static java.lang.String getPreferredFontFamily()
|
||||||
|
meth public static java.lang.String getPreferredLightFontFamily()
|
||||||
|
meth public static java.lang.String getPreferredMonospacedFontFamily()
|
||||||
|
meth public static java.lang.String getPreferredSemiboldFontFamily()
|
||||||
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.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 hideMnemonics()
|
meth public static void hideMnemonics()
|
||||||
meth public static void initIconColors(javax.swing.UIDefaults,boolean)
|
meth public static void initIconColors(javax.swing.UIDefaults,boolean)
|
||||||
@@ -209,6 +228,11 @@ meth public static void repaintAllFramesAndDialogs()
|
|||||||
meth public static void revalidateAndRepaintAllFramesAndDialogs()
|
meth public static void revalidateAndRepaintAllFramesAndDialogs()
|
||||||
meth public static void runWithUIDefaultsGetter(java.util.function.Function<java.lang.Object,java.lang.Object>,java.lang.Runnable)
|
meth public static void runWithUIDefaultsGetter(java.util.function.Function<java.lang.Object,java.lang.Object>,java.lang.Runnable)
|
||||||
meth public static void setGlobalExtraDefaults(java.util.Map<java.lang.String,java.lang.String>)
|
meth public static void setGlobalExtraDefaults(java.util.Map<java.lang.String,java.lang.String>)
|
||||||
|
meth public static void setPreferredFontFamily(java.lang.String)
|
||||||
|
meth public static void setPreferredLightFontFamily(java.lang.String)
|
||||||
|
meth public static void setPreferredMonospacedFontFamily(java.lang.String)
|
||||||
|
meth public static void setPreferredSemiboldFontFamily(java.lang.String)
|
||||||
|
meth public static void setSystemColorGetter(java.util.function.Function<java.lang.String,java.awt.Color>)
|
||||||
meth public static void setUseNativeWindowDecorations(boolean)
|
meth public static void setUseNativeWindowDecorations(boolean)
|
||||||
meth public static void showMnemonics(java.awt.Component)
|
meth public static void showMnemonics(java.awt.Component)
|
||||||
meth public static void unregisterCustomDefaultsSource(java.io.File)
|
meth public static void unregisterCustomDefaultsSource(java.io.File)
|
||||||
@@ -223,7 +247,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,getUIMethod,getUIMethodInitialized,globalExtraDefaults,mnemonicHandler,oldPopupFactory,postInitialization,subMenuUsabilityHelperInstalled,uiDefaultsGetters,updateUIPending
|
hfds DESKTOPFONTHINTS,aquaLoaded,customDefaultsSources,desktopPropertyListener,desktopPropertyName,desktopPropertyName2,extraDefaults,globalExtraDefaults,mnemonicHandler,oldPopupFactory,postInitialization,preferredFontFamily,preferredLightFontFamily,preferredMonospacedFontFamily,preferredSemiboldFontFamily,subMenuUsabilityHelperInstalled,systemColorGetter,uiDefaultsGetters,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
|
||||||
@@ -264,6 +288,8 @@ fld public final static java.lang.String UI_SCALE_ALLOW_SCALE_DOWN = "flatlaf.ui
|
|||||||
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"
|
||||||
fld public final static java.lang.String UPDATE_UI_ON_SYSTEM_FONT_CHANGE = "flatlaf.updateUIOnSystemFontChange"
|
fld public final static java.lang.String UPDATE_UI_ON_SYSTEM_FONT_CHANGE = "flatlaf.updateUIOnSystemFontChange"
|
||||||
fld public final static java.lang.String USE_JETBRAINS_CUSTOM_DECORATIONS = "flatlaf.useJetBrainsCustomDecorations"
|
fld public final static java.lang.String USE_JETBRAINS_CUSTOM_DECORATIONS = "flatlaf.useJetBrainsCustomDecorations"
|
||||||
|
anno 0 java.lang.Deprecated()
|
||||||
|
fld public final static java.lang.String USE_NATIVE_LIBRARY = "flatlaf.useNativeLibrary"
|
||||||
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"
|
||||||
@@ -282,7 +308,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,uiKeyInverseMapping,uiKeyMapping
|
hfds checkboxDuplicateColors,checkboxKeyMapping,colors,icons,isMaterialUILite,namedColors,ui,uiKeyCopying,uiKeyDoNotOverride,uiKeyExcludes,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
|
||||||
@@ -295,6 +321,26 @@ meth public java.lang.String getName()
|
|||||||
supr com.formdev.flatlaf.FlatLaf
|
supr com.formdev.flatlaf.FlatLaf
|
||||||
hfds theme
|
hfds theme
|
||||||
|
|
||||||
|
CLSS public com.formdev.flatlaf.themes.FlatMacDarkLaf
|
||||||
|
cons public init()
|
||||||
|
fld public final static java.lang.String NAME = "FlatLaf macOS Dark"
|
||||||
|
meth public boolean isDark()
|
||||||
|
meth public java.lang.String getDescription()
|
||||||
|
meth public java.lang.String getName()
|
||||||
|
meth public static boolean setup()
|
||||||
|
meth public static void installLafInfo()
|
||||||
|
supr com.formdev.flatlaf.FlatDarkLaf
|
||||||
|
|
||||||
|
CLSS public com.formdev.flatlaf.themes.FlatMacLightLaf
|
||||||
|
cons public init()
|
||||||
|
fld public final static java.lang.String NAME = "FlatLaf macOS Light"
|
||||||
|
meth public boolean isDark()
|
||||||
|
meth public java.lang.String getDescription()
|
||||||
|
meth public java.lang.String getName()
|
||||||
|
meth public static boolean setup()
|
||||||
|
meth public static void installLafInfo()
|
||||||
|
supr com.formdev.flatlaf.FlatLightLaf
|
||||||
|
|
||||||
CLSS public abstract interface com.formdev.flatlaf.util.AnimatedIcon
|
CLSS public abstract interface com.formdev.flatlaf.util.AnimatedIcon
|
||||||
innr public static AnimationSupport
|
innr public static AnimationSupport
|
||||||
intf javax.swing.Icon
|
intf javax.swing.Icon
|
||||||
@@ -362,6 +408,7 @@ meth public static float clamp(float)
|
|||||||
meth public static float luma(java.awt.Color)
|
meth public static float luma(java.awt.Color)
|
||||||
meth public static java.awt.Color darken(java.awt.Color,float)
|
meth public static java.awt.Color darken(java.awt.Color,float)
|
||||||
meth public static java.awt.Color desaturate(java.awt.Color,float)
|
meth public static java.awt.Color desaturate(java.awt.Color,float)
|
||||||
|
meth public static java.awt.Color fade(java.awt.Color,float)
|
||||||
meth public static java.awt.Color lighten(java.awt.Color,float)
|
meth public static java.awt.Color lighten(java.awt.Color,float)
|
||||||
meth public static java.awt.Color mix(java.awt.Color,java.awt.Color,float)
|
meth public static java.awt.Color mix(java.awt.Color,java.awt.Color,float)
|
||||||
meth public static java.awt.Color saturate(java.awt.Color,float)
|
meth public static java.awt.Color saturate(java.awt.Color,float)
|
||||||
@@ -437,6 +484,17 @@ meth public java.lang.String toString()
|
|||||||
supr javax.swing.plaf.ColorUIResource
|
supr javax.swing.plaf.ColorUIResource
|
||||||
hfds baseOfDefaultColorRGB,functions,hasBaseOfDefaultColor
|
hfds baseOfDefaultColorRGB,functions,hasBaseOfDefaultColor
|
||||||
|
|
||||||
|
CLSS public com.formdev.flatlaf.util.FontUtils
|
||||||
|
cons public init()
|
||||||
|
meth public static boolean installFont(java.net.URL)
|
||||||
|
meth public static java.awt.Font getCompositeFont(java.lang.String,int,int)
|
||||||
|
meth public static java.awt.Font[] getAllFonts()
|
||||||
|
meth public static java.lang.String[] getAvailableFontFamilyNames()
|
||||||
|
meth public static void loadFontFamily(java.lang.String)
|
||||||
|
meth public static void registerFontFamilyLoader(java.lang.String,java.lang.Runnable)
|
||||||
|
supr java.lang.Object
|
||||||
|
hfds loadersMap
|
||||||
|
|
||||||
CLSS public com.formdev.flatlaf.util.Graphics2DProxy
|
CLSS public com.formdev.flatlaf.util.Graphics2DProxy
|
||||||
cons public init(java.awt.Graphics2D)
|
cons public init(java.awt.Graphics2D)
|
||||||
meth public boolean drawImage(java.awt.Image,int,int,int,int,int,int,int,int,java.awt.Color,java.awt.image.ImageObserver)
|
meth public boolean drawImage(java.awt.Image,int,int,int,int,int,int,int,int,java.awt.Color,java.awt.image.ImageObserver)
|
||||||
@@ -573,7 +631,7 @@ meth public static void drawStringWithYCorrection(javax.swing.JComponent,java.aw
|
|||||||
meth public static void paintAtScale1x(java.awt.Graphics2D,int,int,int,int,com.formdev.flatlaf.util.HiDPIUtils$Painter)
|
meth public static void paintAtScale1x(java.awt.Graphics2D,int,int,int,int,com.formdev.flatlaf.util.HiDPIUtils$Painter)
|
||||||
meth public static void paintAtScale1x(java.awt.Graphics2D,javax.swing.JComponent,com.formdev.flatlaf.util.HiDPIUtils$Painter)
|
meth public static void paintAtScale1x(java.awt.Graphics2D,javax.swing.JComponent,com.formdev.flatlaf.util.HiDPIUtils$Painter)
|
||||||
supr java.lang.Object
|
supr java.lang.Object
|
||||||
hfds useTextYCorrection
|
hfds CORRECTION_INTER,CORRECTION_OPEN_SANS,CORRECTION_SEGOE_UI,CORRECTION_TAHOMA,SCALE_FACTORS,useDebugScaleFactor,useTextYCorrection
|
||||||
|
|
||||||
CLSS public abstract interface static com.formdev.flatlaf.util.HiDPIUtils$Painter
|
CLSS public abstract interface static com.formdev.flatlaf.util.HiDPIUtils$Painter
|
||||||
outer com.formdev.flatlaf.util.HiDPIUtils
|
outer com.formdev.flatlaf.util.HiDPIUtils
|
||||||
@@ -604,6 +662,7 @@ supr java.lang.Object
|
|||||||
|
|
||||||
CLSS public com.formdev.flatlaf.util.NativeLibrary
|
CLSS public com.formdev.flatlaf.util.NativeLibrary
|
||||||
cons public init(java.io.File,boolean)
|
cons public init(java.io.File,boolean)
|
||||||
|
cons public init(java.lang.String,boolean)
|
||||||
cons public init(java.lang.String,java.lang.ClassLoader,boolean)
|
cons public init(java.lang.String,java.lang.ClassLoader,boolean)
|
||||||
meth public boolean isLoaded()
|
meth public boolean isLoaded()
|
||||||
supr java.lang.Object
|
supr java.lang.Object
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
package com.formdev.flatlaf;
|
package com.formdev.flatlaf;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
import java.awt.IllegalComponentStateException;
|
||||||
|
import java.awt.Window;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.SwingConstants;
|
import javax.swing.SwingConstants;
|
||||||
@@ -31,7 +33,7 @@ public interface FlatClientProperties
|
|||||||
//---- JButton ------------------------------------------------------------
|
//---- JButton ------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies type of a button.
|
* Specifies type of button.
|
||||||
* <p>
|
* <p>
|
||||||
* <strong>Components</strong> {@link javax.swing.JButton} and {@link javax.swing.JToggleButton}<br>
|
* <strong>Components</strong> {@link javax.swing.JButton} and {@link javax.swing.JToggleButton}<br>
|
||||||
* <strong>Value type</strong> {@link java.lang.String}<br>
|
* <strong>Value type</strong> {@link java.lang.String}<br>
|
||||||
@@ -124,6 +126,7 @@ public interface FlatClientProperties
|
|||||||
*/
|
*/
|
||||||
String SQUARE_SIZE = "JButton.squareSize";
|
String SQUARE_SIZE = "JButton.squareSize";
|
||||||
|
|
||||||
|
|
||||||
//---- JComponent ---------------------------------------------------------
|
//---- JComponent ---------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -266,8 +269,47 @@ public interface FlatClientProperties
|
|||||||
*/
|
*/
|
||||||
String COMPONENT_TITLE_BAR_CAPTION = "JComponent.titleBarCaption";
|
String COMPONENT_TITLE_BAR_CAPTION = "JComponent.titleBarCaption";
|
||||||
|
|
||||||
|
|
||||||
//---- Popup --------------------------------------------------------------
|
//---- Popup --------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the popup border corner radius if the component is shown in a popup
|
||||||
|
* or if the component is the owner of another component that is shown in a popup.
|
||||||
|
* <p>
|
||||||
|
* Note that this is not available on all platforms since it requires special support.
|
||||||
|
* Supported platforms:
|
||||||
|
* <ul>
|
||||||
|
* <li><strong>Windows 11</strong>: Only two corner radiuses are supported
|
||||||
|
* by the OS: {@code DWMWCP_ROUND} is 8px and {@code DWMWCP_ROUNDSMALL} is 4px.
|
||||||
|
* If this value is {@code 1 - 4}, then {@code DWMWCP_ROUNDSMALL} is used.
|
||||||
|
* If it is {@code >= 5}, then {@code DWMWCP_ROUND} is used.
|
||||||
|
* <li><strong>macOS</strong> (10.14 and later): Any corner radius is supported.
|
||||||
|
* </ul>
|
||||||
|
* <strong>Component</strong> {@link javax.swing.JComponent}<br>
|
||||||
|
* <strong>Value type</strong> {@link java.lang.Integer}<br>
|
||||||
|
*
|
||||||
|
* @since 3.1
|
||||||
|
*/
|
||||||
|
String POPUP_BORDER_CORNER_RADIUS = "Popup.borderCornerRadius";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the popup rounded border width if the component is shown in a popup
|
||||||
|
* or if the component is the owner of another component that is shown in a popup.
|
||||||
|
* <p>
|
||||||
|
* Only used if popup uses rounded border.
|
||||||
|
* <p>
|
||||||
|
* Note that this is not available on all platforms since it requires special support.
|
||||||
|
* Supported platforms:
|
||||||
|
* <ul>
|
||||||
|
* <li><strong>macOS</strong> (10.14 and later)
|
||||||
|
* </ul>
|
||||||
|
* <strong>Component</strong> {@link javax.swing.JComponent}<br>
|
||||||
|
* <strong>Value type</strong> {@link java.lang.Integer} or {@link java.lang.Float}<br>
|
||||||
|
*
|
||||||
|
* @since 3.3
|
||||||
|
*/
|
||||||
|
String POPUP_ROUNDED_BORDER_WIDTH = "Popup.roundedBorderWidth";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies whether a drop shadow is painted if the component is shown in a popup
|
* Specifies whether a drop shadow is painted if the component is shown in a popup
|
||||||
* or if the component is the owner of another component that is shown in a popup.
|
* or if the component is the owner of another component that is shown in a popup.
|
||||||
@@ -286,6 +328,7 @@ public interface FlatClientProperties
|
|||||||
*/
|
*/
|
||||||
String POPUP_FORCE_HEAVY_WEIGHT = "Popup.forceHeavyWeight";
|
String POPUP_FORCE_HEAVY_WEIGHT = "Popup.forceHeavyWeight";
|
||||||
|
|
||||||
|
|
||||||
//---- JProgressBar -------------------------------------------------------
|
//---- JProgressBar -------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -304,6 +347,7 @@ public interface FlatClientProperties
|
|||||||
*/
|
*/
|
||||||
String PROGRESS_BAR_SQUARE = "JProgressBar.square";
|
String PROGRESS_BAR_SQUARE = "JProgressBar.square";
|
||||||
|
|
||||||
|
|
||||||
//---- JRootPane ----------------------------------------------------------
|
//---- JRootPane ----------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -346,7 +390,7 @@ public interface FlatClientProperties
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies whether the window icon should be shown in the window title bar
|
* Specifies whether the window icon should be shown in the window title bar
|
||||||
* (requires enabled window decorations).
|
* (requires enabled window decorations). Default is UI property {@code TitlePane.showIcon}.
|
||||||
* <p>
|
* <p>
|
||||||
* Setting this shows/hides the windows icon
|
* Setting this shows/hides the windows icon
|
||||||
* for the {@code JFrame} or {@code JDialog} that contains the root pane.
|
* for the {@code JFrame} or {@code JDialog} that contains the root pane.
|
||||||
@@ -362,6 +406,62 @@ public interface FlatClientProperties
|
|||||||
*/
|
*/
|
||||||
String TITLE_BAR_SHOW_ICON = "JRootPane.titleBarShowIcon";
|
String TITLE_BAR_SHOW_ICON = "JRootPane.titleBarShowIcon";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies whether the window title should be shown in the window title bar
|
||||||
|
* (requires enabled window decorations). Default is {@code true}.
|
||||||
|
* <p>
|
||||||
|
* Setting this shows/hides the windows title
|
||||||
|
* for the {@code JFrame} or {@code JDialog} that contains the root pane.
|
||||||
|
* <p>
|
||||||
|
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||||
|
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||||
|
*
|
||||||
|
* @since 3
|
||||||
|
*/
|
||||||
|
String TITLE_BAR_SHOW_TITLE = "JRootPane.titleBarShowTitle";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies whether the "iconify" button should be shown in the window title bar
|
||||||
|
* (requires enabled window decorations). Default is {@code true}.
|
||||||
|
* <p>
|
||||||
|
* Setting this shows/hides the "iconify" button
|
||||||
|
* for the {@code JFrame} that contains the root pane.
|
||||||
|
* <p>
|
||||||
|
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||||
|
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||||
|
*
|
||||||
|
* @since 3
|
||||||
|
*/
|
||||||
|
String TITLE_BAR_SHOW_ICONIFFY = "JRootPane.titleBarShowIconify";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies whether the "maximize/restore" button should be shown in the window title bar
|
||||||
|
* (requires enabled window decorations). Default is {@code true}.
|
||||||
|
* <p>
|
||||||
|
* Setting this shows/hides the "maximize/restore" button
|
||||||
|
* for the {@code JFrame} that contains the root pane.
|
||||||
|
* <p>
|
||||||
|
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||||
|
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||||
|
*
|
||||||
|
* @since 3
|
||||||
|
*/
|
||||||
|
String TITLE_BAR_SHOW_MAXIMIZE = "JRootPane.titleBarShowMaximize";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies whether the "close" button should be shown in the window title bar
|
||||||
|
* (requires enabled window decorations). Default is {@code true}.
|
||||||
|
* <p>
|
||||||
|
* Setting this shows/hides the "close" button
|
||||||
|
* for the {@code JFrame} or {@code JDialog} that contains the root pane.
|
||||||
|
* <p>
|
||||||
|
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||||
|
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||||
|
*
|
||||||
|
* @since 3
|
||||||
|
*/
|
||||||
|
String TITLE_BAR_SHOW_CLOSE = "JRootPane.titleBarShowClose";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Background color of window title bar (requires enabled window decorations).
|
* Background color of window title bar (requires enabled window decorations).
|
||||||
* <p>
|
* <p>
|
||||||
@@ -386,6 +486,48 @@ public interface FlatClientProperties
|
|||||||
*/
|
*/
|
||||||
String TITLE_BAR_FOREGROUND = "JRootPane.titleBarForeground";
|
String TITLE_BAR_FOREGROUND = "JRootPane.titleBarForeground";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies whether the glass pane should have full height and overlap the title bar,
|
||||||
|
* if FlatLaf window decorations are enabled. Default is {@code false}.
|
||||||
|
* <p>
|
||||||
|
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||||
|
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||||
|
*
|
||||||
|
* @since 3.1
|
||||||
|
*/
|
||||||
|
String GLASS_PANE_FULL_HEIGHT = "JRootPane.glassPaneFullHeight";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the style of the window title bar.
|
||||||
|
* Besides the default title bar style, you can use a Utility-style title bar,
|
||||||
|
* which is smaller than the default title bar.
|
||||||
|
* <p>
|
||||||
|
* On Windows 10/11, this requires FlatLaf window decorations.
|
||||||
|
* On macOS, Java supports this out of the box.
|
||||||
|
* <p>
|
||||||
|
* Note that this client property must be set before the window becomes displayable.
|
||||||
|
* Otherwise, an {@link IllegalComponentStateException} is thrown.
|
||||||
|
* <p>
|
||||||
|
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||||
|
* <strong>Value type</strong> {@link java.lang.String}<br>
|
||||||
|
* <strong>Allowed Values</strong>
|
||||||
|
* {@link #WINDOW_STYLE_SMALL}
|
||||||
|
*
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
String WINDOW_STYLE = "Window.style";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The window has Utility-style title bar, which is smaller than default title bar.
|
||||||
|
* <p>
|
||||||
|
* This is the same as using {@link Window#setType}( {@link Window.Type#UTILITY} ).
|
||||||
|
*
|
||||||
|
* @see #WINDOW_STYLE
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
String WINDOW_STYLE_SMALL = "small";
|
||||||
|
|
||||||
|
|
||||||
//---- JScrollBar / JScrollPane -------------------------------------------
|
//---- JScrollBar / JScrollPane -------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -404,6 +546,7 @@ public interface FlatClientProperties
|
|||||||
*/
|
*/
|
||||||
String SCROLL_PANE_SMOOTH_SCROLLING = "JScrollPane.smoothScrolling";
|
String SCROLL_PANE_SMOOTH_SCROLLING = "JScrollPane.smoothScrolling";
|
||||||
|
|
||||||
|
|
||||||
//---- JSplitPane ---------------------------------------------------------
|
//---- JSplitPane ---------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -438,6 +581,7 @@ public interface FlatClientProperties
|
|||||||
*/
|
*/
|
||||||
String SPLIT_PANE_EXPANDABLE_SIDE_RIGHT = "right";
|
String SPLIT_PANE_EXPANDABLE_SIDE_RIGHT = "right";
|
||||||
|
|
||||||
|
|
||||||
//---- JTabbedPane --------------------------------------------------------
|
//---- JTabbedPane --------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -807,6 +951,59 @@ public interface FlatClientProperties
|
|||||||
*/
|
*/
|
||||||
String TABBED_PANE_TAB_ICON_PLACEMENT = "JTabbedPane.tabIconPlacement";
|
String TABBED_PANE_TAB_ICON_PLACEMENT = "JTabbedPane.tabIconPlacement";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the rotation of the tabs (title, icon, etc.).
|
||||||
|
* <p>
|
||||||
|
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
|
||||||
|
* <strong>Value type</strong> {@link java.lang.Integer} or {@link java.lang.String}<br>
|
||||||
|
* <strong>Allowed Values</strong>
|
||||||
|
* {@link SwingConstants#LEFT},
|
||||||
|
* {@link SwingConstants#RIGHT},
|
||||||
|
* {@link #TABBED_PANE_TAB_ROTATION_NONE}, (default)
|
||||||
|
* {@link #TABBED_PANE_TAB_ROTATION_AUTO},
|
||||||
|
* {@link #TABBED_PANE_TAB_ROTATION_LEFT} or
|
||||||
|
* {@link #TABBED_PANE_TAB_ROTATION_RIGHT}
|
||||||
|
*
|
||||||
|
* @since 3.3
|
||||||
|
*/
|
||||||
|
String TABBED_PANE_TAB_ROTATION = "JTabbedPane.tabRotation";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tabs are not rotated.
|
||||||
|
*
|
||||||
|
* @see #TABBED_PANE_TAB_ROTATION
|
||||||
|
* @since 3.3
|
||||||
|
*/
|
||||||
|
String TABBED_PANE_TAB_ROTATION_NONE = "none";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tabs are rotated depending on tab placement.
|
||||||
|
* <p>
|
||||||
|
* For top and bottom tab placement, the tabs are not rotated.<br>
|
||||||
|
* For left tab placement, the tabs are rotated counter-clockwise.<br>
|
||||||
|
* For right tab placement, the tabs are rotated clockwise.
|
||||||
|
*
|
||||||
|
* @see #TABBED_PANE_TAB_ROTATION
|
||||||
|
* @since 3.3
|
||||||
|
*/
|
||||||
|
String TABBED_PANE_TAB_ROTATION_AUTO = "auto";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tabs are rotated counter-clockwise.
|
||||||
|
*
|
||||||
|
* @see #TABBED_PANE_TAB_ROTATION
|
||||||
|
* @since 3.3
|
||||||
|
*/
|
||||||
|
String TABBED_PANE_TAB_ROTATION_LEFT = "left";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tabs are rotated clockwise.
|
||||||
|
*
|
||||||
|
* @see #TABBED_PANE_TAB_ROTATION
|
||||||
|
* @since 3.3
|
||||||
|
*/
|
||||||
|
String TABBED_PANE_TAB_ROTATION_RIGHT = "right";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies a component that will be placed at the leading edge of the tabs area.
|
* Specifies a component that will be placed at the leading edge of the tabs area.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -833,6 +1030,7 @@ public interface FlatClientProperties
|
|||||||
*/
|
*/
|
||||||
String TABBED_PANE_TRAILING_COMPONENT = "JTabbedPane.trailingComponent";
|
String TABBED_PANE_TRAILING_COMPONENT = "JTabbedPane.trailingComponent";
|
||||||
|
|
||||||
|
|
||||||
//---- JTextField ---------------------------------------------------------
|
//---- JTextField ---------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1002,6 +1200,7 @@ public interface FlatClientProperties
|
|||||||
*/
|
*/
|
||||||
String TEXT_FIELD_CLEAR_CALLBACK = "JTextField.clearCallback";
|
String TEXT_FIELD_CLEAR_CALLBACK = "JTextField.clearCallback";
|
||||||
|
|
||||||
|
|
||||||
//---- JToggleButton ------------------------------------------------------
|
//---- JToggleButton ------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1043,6 +1242,7 @@ public interface FlatClientProperties
|
|||||||
*/
|
*/
|
||||||
String TAB_BUTTON_SELECTED_BACKGROUND = "JToggleButton.tab.selectedBackground";
|
String TAB_BUTTON_SELECTED_BACKGROUND = "JToggleButton.tab.selectedBackground";
|
||||||
|
|
||||||
|
|
||||||
//---- JTree --------------------------------------------------------------
|
//---- JTree --------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1062,6 +1262,7 @@ public interface FlatClientProperties
|
|||||||
*/
|
*/
|
||||||
String TREE_PAINT_SELECTION = "JTree.paintSelection";
|
String TREE_PAINT_SELECTION = "JTree.paintSelection";
|
||||||
|
|
||||||
|
|
||||||
//---- helper methods -----------------------------------------------------
|
//---- helper methods -----------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -50,7 +50,8 @@ class FlatInputMaps
|
|||||||
}
|
}
|
||||||
|
|
||||||
modifyInputMap( defaults, "ComboBox.ancestorInputMap",
|
modifyInputMap( defaults, "ComboBox.ancestorInputMap",
|
||||||
"SPACE", "spacePopup",
|
// Space key still shows popup, but from FlatComboBoxUI.FlatKeySelectionManager
|
||||||
|
// "SPACE", "spacePopup",
|
||||||
|
|
||||||
"UP", mac( "selectPrevious2", "selectPrevious" ),
|
"UP", mac( "selectPrevious2", "selectPrevious" ),
|
||||||
"DOWN", mac( "selectNext2", "selectNext" ),
|
"DOWN", mac( "selectNext2", "selectNext" ),
|
||||||
@@ -70,7 +71,7 @@ class FlatInputMaps
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// join ltr and rtl bindings to fix up/down/etc keys in right-to-left component orientation
|
// join ltr and rtl bindings to fix up/down/etc. keys in right-to-left component orientation
|
||||||
Object[] bindings = (Object[]) defaults.get( "PopupMenu.selectedWindowInputMapBindings" );
|
Object[] bindings = (Object[]) defaults.get( "PopupMenu.selectedWindowInputMapBindings" );
|
||||||
Object[] rtlBindings = (Object[]) defaults.get( "PopupMenu.selectedWindowInputMapBindings.RightToLeft" );
|
Object[] rtlBindings = (Object[]) defaults.get( "PopupMenu.selectedWindowInputMapBindings.RightToLeft" );
|
||||||
if( bindings != null && rtlBindings != null ) {
|
if( bindings != null && rtlBindings != null ) {
|
||||||
|
|||||||
@@ -30,9 +30,6 @@ import java.awt.image.ImageProducer;
|
|||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.lang.invoke.MethodHandle;
|
|
||||||
import java.lang.invoke.MethodHandles;
|
|
||||||
import java.lang.invoke.MethodType;
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -71,13 +68,16 @@ import javax.swing.plaf.FontUIResource;
|
|||||||
import javax.swing.plaf.IconUIResource;
|
import javax.swing.plaf.IconUIResource;
|
||||||
import javax.swing.plaf.UIResource;
|
import javax.swing.plaf.UIResource;
|
||||||
import javax.swing.plaf.basic.BasicLookAndFeel;
|
import javax.swing.plaf.basic.BasicLookAndFeel;
|
||||||
|
import javax.swing.plaf.metal.MetalLookAndFeel;
|
||||||
import javax.swing.text.StyleContext;
|
import javax.swing.text.StyleContext;
|
||||||
import javax.swing.text.html.HTMLEditorKit;
|
import javax.swing.text.html.HTMLEditorKit;
|
||||||
import com.formdev.flatlaf.ui.FlatNativeWindowBorder;
|
import com.formdev.flatlaf.ui.FlatNativeWindowBorder;
|
||||||
import com.formdev.flatlaf.ui.FlatPopupFactory;
|
import com.formdev.flatlaf.ui.FlatPopupFactory;
|
||||||
import com.formdev.flatlaf.ui.FlatRootPaneUI;
|
import com.formdev.flatlaf.ui.FlatRootPaneUI;
|
||||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||||
|
import com.formdev.flatlaf.ui.JavaCompatibility2;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||||
|
import com.formdev.flatlaf.util.FontUtils;
|
||||||
import com.formdev.flatlaf.util.GrayFilter;
|
import com.formdev.flatlaf.util.GrayFilter;
|
||||||
import com.formdev.flatlaf.util.LoggingFacade;
|
import com.formdev.flatlaf.util.LoggingFacade;
|
||||||
import com.formdev.flatlaf.util.MultiResolutionImageSupport;
|
import com.formdev.flatlaf.util.MultiResolutionImageSupport;
|
||||||
@@ -98,6 +98,7 @@ public abstract class FlatLaf
|
|||||||
private static List<Object> customDefaultsSources;
|
private static List<Object> customDefaultsSources;
|
||||||
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 String desktopPropertyName;
|
private String desktopPropertyName;
|
||||||
private String desktopPropertyName2;
|
private String desktopPropertyName2;
|
||||||
@@ -113,6 +114,11 @@ public abstract class FlatLaf
|
|||||||
private Consumer<UIDefaults> postInitialization;
|
private Consumer<UIDefaults> postInitialization;
|
||||||
private List<Function<Object, Object>> uiDefaultsGetters;
|
private List<Function<Object, Object>> uiDefaultsGetters;
|
||||||
|
|
||||||
|
private static String preferredFontFamily;
|
||||||
|
private static String preferredLightFontFamily;
|
||||||
|
private static String preferredSemiboldFontFamily;
|
||||||
|
private static String preferredMonospacedFontFamily;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the application look and feel to the given LaF
|
* Sets the application look and feel to the given LaF
|
||||||
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
|
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
|
||||||
@@ -175,17 +181,11 @@ public abstract class FlatLaf
|
|||||||
* This depends on the operating system and on the used Java runtime.
|
* This depends on the operating system and on the used Java runtime.
|
||||||
* <p>
|
* <p>
|
||||||
* This method returns {@code true} on Windows 10/11 (see exception below)
|
* This method returns {@code true} on Windows 10/11 (see exception below)
|
||||||
* and on Linux, {@code false} otherwise.
|
* and on Linux, otherwise returns {@code false}.
|
||||||
|
* <p>
|
||||||
|
* Returns also {@code false} on Windows 10/11 if
|
||||||
|
* FlatLaf native window border support is available (requires Windows 10/11).
|
||||||
* <p>
|
* <p>
|
||||||
* Returns also {@code false} on Windows 10/11 if:
|
|
||||||
* <ul>
|
|
||||||
* <li>FlatLaf native window border support is available (requires Windows 10/11)</li>
|
|
||||||
* <li>running in
|
|
||||||
* <a href="https://confluence.jetbrains.com/display/JBR/JetBrains+Runtime">JetBrains Runtime 11 (or later)</a>
|
|
||||||
* (<a href="https://github.com/JetBrains/JetBrainsRuntime">source code on github</a>)
|
|
||||||
* and JBR supports custom window decorations
|
|
||||||
* </li>
|
|
||||||
* </ul>
|
|
||||||
* In these cases, custom decorations are enabled by the root pane.
|
* In these cases, custom decorations are enabled by the root pane.
|
||||||
* Usage of {@link JFrame#setDefaultLookAndFeelDecorated(boolean)} or
|
* Usage of {@link JFrame#setDefaultLookAndFeelDecorated(boolean)} or
|
||||||
* {@link JDialog#setDefaultLookAndFeelDecorated(boolean)} is not necessary.
|
* {@link JDialog#setDefaultLookAndFeelDecorated(boolean)} is not necessary.
|
||||||
@@ -384,7 +384,7 @@ public abstract class FlatLaf
|
|||||||
Method m = UIManager.class.getMethod( "createLookAndFeel", String.class );
|
Method m = UIManager.class.getMethod( "createLookAndFeel", String.class );
|
||||||
aquaLaf = (BasicLookAndFeel) m.invoke( null, "Mac OS X" );
|
aquaLaf = (BasicLookAndFeel) m.invoke( null, "Mac OS X" );
|
||||||
} else
|
} else
|
||||||
aquaLaf = (BasicLookAndFeel) Class.forName( aquaLafClassName ).getDeclaredConstructor().newInstance();
|
aquaLaf = Class.forName( aquaLafClassName ).asSubclass( BasicLookAndFeel.class ).getDeclaredConstructor().newInstance();
|
||||||
} catch( Exception ex ) {
|
} catch( Exception ex ) {
|
||||||
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to initialize Aqua look and feel '" + aquaLafClassName + "'.", ex );
|
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to initialize Aqua look and feel '" + aquaLafClassName + "'.", ex );
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
@@ -536,7 +536,7 @@ public abstract class FlatLaf
|
|||||||
// which can happen in applications that use some plugin system
|
// which can happen in applications that use some plugin system
|
||||||
// and load FlatLaf in a plugin that uses its own classloader.
|
// and load FlatLaf in a plugin that uses its own classloader.
|
||||||
// (e.g. Apache NetBeans)
|
// (e.g. Apache NetBeans)
|
||||||
if( defaults.get( "FileChooser.fileNameHeaderText" ) != null )
|
if( defaults.get( "TabbedPane.moreTabsButtonToolTipText" ) != null )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// load FlatLaf resource bundle and add content to defaults
|
// load FlatLaf resource bundle and add content to defaults
|
||||||
@@ -574,10 +574,13 @@ public abstract class FlatLaf
|
|||||||
Object activeFont = new ActiveFont( null, null, -1, 0, 0, 0, 0 );
|
Object activeFont = new ActiveFont( null, null, -1, 0, 0, 0, 0 );
|
||||||
|
|
||||||
// override fonts
|
// override fonts
|
||||||
|
List<String> fontKeys = new ArrayList<>( 50 );
|
||||||
for( Object key : defaults.keySet() ) {
|
for( Object key : defaults.keySet() ) {
|
||||||
if( key instanceof String && (((String)key).endsWith( ".font" ) || ((String)key).endsWith( "Font" )) )
|
if( key instanceof String && (((String)key).endsWith( ".font" ) || ((String)key).endsWith( "Font" )) )
|
||||||
defaults.put( key, activeFont );
|
fontKeys.add( (String) key );
|
||||||
}
|
}
|
||||||
|
for( String key : fontKeys )
|
||||||
|
defaults.put( key, activeFont );
|
||||||
|
|
||||||
// add fonts that are not set in BasicLookAndFeel
|
// add fonts that are not set in BasicLookAndFeel
|
||||||
defaults.put( "RootPane.font", activeFont );
|
defaults.put( "RootPane.font", activeFont );
|
||||||
@@ -630,6 +633,13 @@ public abstract class FlatLaf
|
|||||||
if( uiFont == null )
|
if( uiFont == null )
|
||||||
uiFont = createCompositeFont( Font.SANS_SERIF, Font.PLAIN, 12 );
|
uiFont = createCompositeFont( Font.SANS_SERIF, Font.PLAIN, 12 );
|
||||||
|
|
||||||
|
// use preferred font family (if specified)
|
||||||
|
if( preferredFontFamily != null ) {
|
||||||
|
FontUIResource preferredFont = createCompositeFont( preferredFontFamily, uiFont.getStyle(), uiFont.getSize() );
|
||||||
|
if( !ActiveFont.isFallbackFont( preferredFont ) || ActiveFont.isDialogFamily( preferredFontFamily ) )
|
||||||
|
uiFont = preferredFont;
|
||||||
|
}
|
||||||
|
|
||||||
// get/remove "defaultFont" from defaults if set in properties files
|
// get/remove "defaultFont" from defaults if set in properties files
|
||||||
// (use remove() to avoid that ActiveFont.createValue() gets invoked)
|
// (use remove() to avoid that ActiveFont.createValue() gets invoked)
|
||||||
Object defaultFont = defaults.remove( "defaultFont" );
|
Object defaultFont = defaults.remove( "defaultFont" );
|
||||||
@@ -650,6 +660,9 @@ public abstract class FlatLaf
|
|||||||
}
|
}
|
||||||
|
|
||||||
static FontUIResource createCompositeFont( String family, int style, int size ) {
|
static FontUIResource createCompositeFont( String family, int style, int size ) {
|
||||||
|
// load lazy font family
|
||||||
|
FontUtils.loadFontFamily( family );
|
||||||
|
|
||||||
// using StyleContext.getFont() here because it uses
|
// using StyleContext.getFont() here because it uses
|
||||||
// sun.font.FontUtilities.getCompositeFontUIResource()
|
// sun.font.FontUtilities.getCompositeFontUIResource()
|
||||||
// and creates a composite font that is able to display all Unicode characters
|
// and creates a composite font that is able to display all Unicode characters
|
||||||
@@ -897,14 +910,14 @@ public abstract class FlatLaf
|
|||||||
* E.g. using {@link UIManager#setLookAndFeel(LookAndFeel)} or {@link #setup(LookAndFeel)}.
|
* E.g. using {@link UIManager#setLookAndFeel(LookAndFeel)} or {@link #setup(LookAndFeel)}.
|
||||||
* <p>
|
* <p>
|
||||||
* The global extra defaults are useful for smaller additional defaults that may change.
|
* The global extra defaults are useful for smaller additional defaults that may change.
|
||||||
* E.g. accent color. Otherwise, FlatLaf properties files should be used.
|
* Otherwise, FlatLaf properties files should be used.
|
||||||
* See {@link #registerCustomDefaultsSource(String)}.
|
* See {@link #registerCustomDefaultsSource(String)}.
|
||||||
* <p>
|
* <p>
|
||||||
* The keys and values are strings in same format as in FlatLaf properties files.
|
* The keys and values are strings in same format as in FlatLaf properties files.
|
||||||
* <p>
|
* <p>
|
||||||
* Sample that setups "FlatLaf Light" theme with red accent color:
|
* Sample that setups "FlatLaf Light" theme with white background color:
|
||||||
* <pre>{@code
|
* <pre>{@code
|
||||||
* FlatLaf.setGlobalExtraDefaults( Collections.singletonMap( "@accentColor", "#f00" ) );
|
* FlatLaf.setGlobalExtraDefaults( Collections.singletonMap( "@background", "#fff" ) );
|
||||||
* FlatLightLaf.setup();
|
* FlatLightLaf.setup();
|
||||||
* }</pre>
|
* }</pre>
|
||||||
*
|
*
|
||||||
@@ -929,15 +942,15 @@ public abstract class FlatLaf
|
|||||||
* E.g. using {@link UIManager#setLookAndFeel(LookAndFeel)} or {@link #setup(LookAndFeel)}.
|
* E.g. using {@link UIManager#setLookAndFeel(LookAndFeel)} or {@link #setup(LookAndFeel)}.
|
||||||
* <p>
|
* <p>
|
||||||
* The extra defaults are useful for smaller additional defaults that may change.
|
* The extra defaults are useful for smaller additional defaults that may change.
|
||||||
* E.g. accent color. Otherwise, FlatLaf properties files should be used.
|
* Otherwise, FlatLaf properties files should be used.
|
||||||
* See {@link #registerCustomDefaultsSource(String)}.
|
* See {@link #registerCustomDefaultsSource(String)}.
|
||||||
* <p>
|
* <p>
|
||||||
* The keys and values are strings in same format as in FlatLaf properties files.
|
* The keys and values are strings in same format as in FlatLaf properties files.
|
||||||
* <p>
|
* <p>
|
||||||
* Sample that setups "FlatLaf Light" theme with red accent color:
|
* Sample that setups "FlatLaf Light" theme with white background color:
|
||||||
* <pre>{@code
|
* <pre>{@code
|
||||||
* FlatLaf laf = new FlatLightLaf();
|
* FlatLaf laf = new FlatLightLaf();
|
||||||
* laf.setExtraDefaults( Collections.singletonMap( "@accentColor", "#f00" ) );
|
* laf.setExtraDefaults( Collections.singletonMap( "@background", "#fff" ) );
|
||||||
* FlatLaf.setup( laf );
|
* FlatLaf.setup( laf );
|
||||||
* }</pre>
|
* }</pre>
|
||||||
*
|
*
|
||||||
@@ -979,6 +992,36 @@ public abstract class FlatLaf
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the system color getter function, or {@code null}.
|
||||||
|
*
|
||||||
|
* @since 3
|
||||||
|
*/
|
||||||
|
public static Function<String, Color> getSystemColorGetter() {
|
||||||
|
return systemColorGetter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a system color getter function that is invoked when function
|
||||||
|
* {@code systemColor()} is used in FlatLaf properties files.
|
||||||
|
* <p>
|
||||||
|
* The name of the system color is passed as parameter to the function.
|
||||||
|
* The function should return {@code null} for unknown system colors.
|
||||||
|
* <p>
|
||||||
|
* Can be used to change the accent color:
|
||||||
|
* <pre>{@code
|
||||||
|
* FlatLaf.setSystemColorGetter( name -> {
|
||||||
|
* return name.equals( "accent" ) ? Color.red : null;
|
||||||
|
* } );
|
||||||
|
* FlatLightLaf.setup();
|
||||||
|
* }</pre>
|
||||||
|
*
|
||||||
|
* @since 3
|
||||||
|
*/
|
||||||
|
public static void setSystemColorGetter( Function<String, Color> systemColorGetter ) {
|
||||||
|
FlatLaf.systemColorGetter = systemColorGetter;
|
||||||
|
}
|
||||||
|
|
||||||
private static void reSetLookAndFeel() {
|
private static void reSetLookAndFeel() {
|
||||||
EventQueue.invokeLater( () -> {
|
EventQueue.invokeLater( () -> {
|
||||||
LookAndFeel lookAndFeel = UIManager.getLookAndFeel();
|
LookAndFeel lookAndFeel = UIManager.getLookAndFeel();
|
||||||
@@ -1244,8 +1287,8 @@ public abstract class FlatLaf
|
|||||||
* @since 2.5
|
* @since 2.5
|
||||||
*/
|
*/
|
||||||
public static Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
public static Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||||
StyleableUI ui = getStyleableUI( c );
|
ComponentUI ui = JavaCompatibility2.getUI( c );
|
||||||
return (ui != null) ? ui.getStyleableInfos( c ) : null;
|
return (ui instanceof StyleableUI) ? ((StyleableUI)ui).getStyleableInfos( c ) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1257,66 +1300,129 @@ public abstract class FlatLaf
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings( "unchecked" )
|
@SuppressWarnings( "unchecked" )
|
||||||
public static <T> T getStyleableValue( JComponent c, String key ) {
|
public static <T> T getStyleableValue( JComponent c, String key ) {
|
||||||
StyleableUI ui = getStyleableUI( c );
|
ComponentUI ui = JavaCompatibility2.getUI( c );
|
||||||
return (ui != null) ? (T) ui.getStyleableValue( c, key ) : null;
|
return (ui instanceof StyleableUI) ? (T) ((StyleableUI)ui).getStyleableValue( c, key ) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static StyleableUI getStyleableUI( JComponent c ) {
|
/**
|
||||||
if( !getUIMethodInitialized ) {
|
* Returns the preferred font family to be used for (nearly) all fonts; or {@code null}.
|
||||||
getUIMethodInitialized = true;
|
*
|
||||||
|
* @since 3
|
||||||
if( SystemInfo.isJava_9_orLater ) {
|
*/
|
||||||
try {
|
public static String getPreferredFontFamily() {
|
||||||
// JComponent.getUI() is available since Java 9
|
return preferredFontFamily;
|
||||||
getUIMethod = MethodHandles.lookup().findVirtual( JComponent.class, "getUI",
|
|
||||||
MethodType.methodType( ComponentUI.class ) );
|
|
||||||
} catch( Exception ex ) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
/**
|
||||||
Object ui;
|
* Sets the preferred font family to be used for (nearly) all fonts.
|
||||||
if( getUIMethod != null )
|
* <p>
|
||||||
ui = getUIMethod.invoke( c );
|
* <strong>Note</strong>: This must be invoked <strong>before</strong> setting
|
||||||
else
|
* the application look and feel.
|
||||||
ui = c.getClass().getMethod( "getUI" ).invoke( c );
|
*
|
||||||
return (ui instanceof StyleableUI) ? (StyleableUI) ui : null;
|
* @since 3
|
||||||
} catch( Throwable ex ) {
|
*/
|
||||||
// ignore
|
public static void setPreferredFontFamily( String preferredFontFamily ) {
|
||||||
return null;
|
FlatLaf.preferredFontFamily = preferredFontFamily;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean getUIMethodInitialized;
|
/**
|
||||||
private static MethodHandle getUIMethod;
|
* Returns the preferred font family to be used for "light" fonts; or {@code null}.
|
||||||
|
*
|
||||||
|
* @since 3
|
||||||
|
*/
|
||||||
|
public static String getPreferredLightFontFamily() {
|
||||||
|
return preferredLightFontFamily;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the preferred font family to be used for "light" fonts.
|
||||||
|
* <p>
|
||||||
|
* <strong>Note</strong>: This must be invoked <strong>before</strong> setting
|
||||||
|
* the application look and feel.
|
||||||
|
*
|
||||||
|
* @since 3
|
||||||
|
*/
|
||||||
|
public static void setPreferredLightFontFamily( String preferredLightFontFamily ) {
|
||||||
|
FlatLaf.preferredLightFontFamily = preferredLightFontFamily;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the preferred font family to be used for "semibold" fonts; or {@code null}.
|
||||||
|
*
|
||||||
|
* @since 3
|
||||||
|
*/
|
||||||
|
public static String getPreferredSemiboldFontFamily() {
|
||||||
|
return preferredSemiboldFontFamily;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the preferred font family to be used for "semibold" fonts.
|
||||||
|
* <p>
|
||||||
|
* <strong>Note</strong>: This must be invoked <strong>before</strong> setting
|
||||||
|
* the application look and feel.
|
||||||
|
*
|
||||||
|
* @since 3
|
||||||
|
*/
|
||||||
|
public static void setPreferredSemiboldFontFamily( String preferredSemiboldFontFamily ) {
|
||||||
|
FlatLaf.preferredSemiboldFontFamily = preferredSemiboldFontFamily;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the preferred font family to be used for monospaced fonts; or {@code null}.
|
||||||
|
*
|
||||||
|
* @since 3
|
||||||
|
*/
|
||||||
|
public static String getPreferredMonospacedFontFamily() {
|
||||||
|
return preferredMonospacedFontFamily;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the preferred font family to be used for monospaced fonts.
|
||||||
|
* <p>
|
||||||
|
* <strong>Note</strong>: This must be invoked <strong>before</strong> setting
|
||||||
|
* the application look and feel.
|
||||||
|
*
|
||||||
|
* @since 3
|
||||||
|
*/
|
||||||
|
public static void setPreferredMonospacedFontFamily( String preferredMonospacedFontFamily ) {
|
||||||
|
FlatLaf.preferredMonospacedFontFamily = preferredMonospacedFontFamily;
|
||||||
|
}
|
||||||
|
|
||||||
//---- class FlatUIDefaults -----------------------------------------------
|
//---- class FlatUIDefaults -----------------------------------------------
|
||||||
|
|
||||||
private class FlatUIDefaults
|
private class FlatUIDefaults
|
||||||
extends UIDefaults
|
extends UIDefaults
|
||||||
{
|
{
|
||||||
|
private UIDefaults metalDefaults;
|
||||||
|
|
||||||
FlatUIDefaults( int initialCapacity, float loadFactor ) {
|
FlatUIDefaults( int initialCapacity, float loadFactor ) {
|
||||||
super( initialCapacity, loadFactor );
|
super( initialCapacity, loadFactor );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object get( Object key ) {
|
public Object get( Object key ) {
|
||||||
Object value = getValue( key );
|
return get( key, null );
|
||||||
return (value != null) ? (value != NULL_VALUE ? value : null) : super.get( key );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object get( Object key, Locale l ) {
|
public Object get( Object key, Locale l ) {
|
||||||
Object value = getValue( key );
|
Object value = getFromUIDefaultsGetters( key );
|
||||||
return (value != null) ? (value != NULL_VALUE ? value : null) : super.get( key, l );
|
if( value != null )
|
||||||
|
return (value != NULL_VALUE) ? value : null;
|
||||||
|
|
||||||
|
value = super.get( key, l );
|
||||||
|
if( value != null )
|
||||||
|
return value;
|
||||||
|
|
||||||
|
// get file chooser texts from Metal
|
||||||
|
return (key instanceof String && ((String)key).startsWith( "FileChooser." ))
|
||||||
|
? getFromMetal( (String) key, l )
|
||||||
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object getValue( Object key ) {
|
private Object getFromUIDefaultsGetters( Object key ) {
|
||||||
// use local variable for getters to avoid potential multi-threading issues
|
// use local variable for getters to avoid potential multi-threading issues
|
||||||
List<Function<Object, Object>> uiDefaultsGetters = FlatLaf.this.uiDefaultsGetters;
|
List<Function<Object, Object>> uiDefaultsGetters = FlatLaf.this.uiDefaultsGetters;
|
||||||
|
|
||||||
if( uiDefaultsGetters == null )
|
if( uiDefaultsGetters == null )
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@@ -1328,6 +1434,22 @@ public abstract class FlatLaf
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private synchronized Object getFromMetal( String key, Locale l ) {
|
||||||
|
if( metalDefaults == null ) {
|
||||||
|
metalDefaults = new MetalLookAndFeel() {
|
||||||
|
// avoid unnecessary initialization
|
||||||
|
@Override protected void initClassDefaults( UIDefaults table ) {}
|
||||||
|
@Override protected void initSystemColorDefaults( UIDefaults table ) {}
|
||||||
|
}.getDefaults();
|
||||||
|
|
||||||
|
// empty not needed defaults (to save memory) because we're only interested
|
||||||
|
// in resource bundle strings, which are stored in another internal map
|
||||||
|
metalDefaults.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
return metalDefaults.get( key, l );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//---- class ActiveFont ---------------------------------------------------
|
//---- class ActiveFont ---------------------------------------------------
|
||||||
@@ -1410,7 +1532,7 @@ public abstract class FlatLaf
|
|||||||
int newStyle = (style != -1)
|
int newStyle = (style != -1)
|
||||||
? style
|
? style
|
||||||
: (styleChange != 0)
|
: (styleChange != 0)
|
||||||
? baseStyle & ~((styleChange >> 16) & 0xffff) | (styleChange & 0xffff)
|
? (baseStyle & ~((styleChange >> 16) & 0xffff)) | (styleChange & 0xffff)
|
||||||
: baseStyle;
|
: baseStyle;
|
||||||
|
|
||||||
// new size
|
// new size
|
||||||
@@ -1426,9 +1548,16 @@ public abstract class FlatLaf
|
|||||||
|
|
||||||
// create font for family
|
// create font for family
|
||||||
if( families != null && !families.isEmpty() ) {
|
if( families != null && !families.isEmpty() ) {
|
||||||
|
String preferredFamily = preferredFamily( families );
|
||||||
|
if( preferredFamily != null ) {
|
||||||
|
Font font = createCompositeFont( preferredFamily, newStyle, newSize );
|
||||||
|
if( !isFallbackFont( font ) || isDialogFamily( preferredFamily ) )
|
||||||
|
return toUIResource( font );
|
||||||
|
}
|
||||||
|
|
||||||
for( String family : families ) {
|
for( String family : families ) {
|
||||||
Font font = createCompositeFont( family, newStyle, newSize );
|
Font font = createCompositeFont( family, newStyle, newSize );
|
||||||
if( !isFallbackFont( font ) || family.equalsIgnoreCase( Font.DIALOG ) )
|
if( !isFallbackFont( font ) || isDialogFamily( family ) )
|
||||||
return toUIResource( font );
|
return toUIResource( font );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1457,9 +1586,26 @@ public abstract class FlatLaf
|
|||||||
: new FontUIResource( font );
|
: new FontUIResource( font );
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isFallbackFont( Font font ) {
|
private static boolean isFallbackFont( Font font ) {
|
||||||
return Font.DIALOG.equalsIgnoreCase( font.getFamily() );
|
return Font.DIALOG.equalsIgnoreCase( font.getFamily() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isDialogFamily( String family ) {
|
||||||
|
return family.equalsIgnoreCase( Font.DIALOG );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String preferredFamily( List<String> families ) {
|
||||||
|
for( String family : families ) {
|
||||||
|
family = family.toLowerCase( Locale.ENGLISH );
|
||||||
|
if( family.endsWith( " light" ) || family.endsWith( "-thin" ) )
|
||||||
|
return preferredLightFontFamily;
|
||||||
|
if( family.endsWith( " semibold" ) || family.endsWith( "-medium" ) )
|
||||||
|
return preferredSemiboldFontFamily;
|
||||||
|
if( family.equals( "monospaced" ) )
|
||||||
|
return preferredMonospacedFontFamily;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//---- class ImageIconUIResource ------------------------------------------
|
//---- class ImageIconUIResource ------------------------------------------
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import java.io.FileInputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -96,7 +97,7 @@ public class FlatPropertiesLaf
|
|||||||
protected ArrayList<Class<?>> getLafClassesForDefaultsLoading() {
|
protected ArrayList<Class<?>> getLafClassesForDefaultsLoading() {
|
||||||
ArrayList<Class<?>> lafClasses = new ArrayList<>();
|
ArrayList<Class<?>> lafClasses = new ArrayList<>();
|
||||||
lafClasses.add( FlatLaf.class );
|
lafClasses.add( FlatLaf.class );
|
||||||
switch( baseTheme.toLowerCase() ) {
|
switch( baseTheme.toLowerCase( Locale.ENGLISH ) ) {
|
||||||
default:
|
default:
|
||||||
case "light":
|
case "light":
|
||||||
lafClasses.add( FlatLightLaf.class );
|
lafClasses.add( FlatLightLaf.class );
|
||||||
|
|||||||
@@ -103,7 +103,10 @@ public interface FlatSystemProperties
|
|||||||
* <p>
|
* <p>
|
||||||
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
||||||
* <strong>Default</strong> {@code false} (since v2; was {@code true} in v1)
|
* <strong>Default</strong> {@code false} (since v2; was {@code true} in v1)
|
||||||
|
*
|
||||||
|
* @deprecated No longer used since FlatLaf 3.3. Retained for API compatibility.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
String USE_JETBRAINS_CUSTOM_DECORATIONS = "flatlaf.useJetBrainsCustomDecorations";
|
String USE_JETBRAINS_CUSTOM_DECORATIONS = "flatlaf.useJetBrainsCustomDecorations";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -150,24 +153,52 @@ public interface FlatSystemProperties
|
|||||||
* <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}
|
* <strong>Default</strong> {@code true}
|
||||||
|
*
|
||||||
* @since 2.5
|
* @since 2.5
|
||||||
*/
|
*/
|
||||||
String UPDATE_UI_ON_SYSTEM_FONT_CHANGE = "flatlaf.updateUIOnSystemFontChange";
|
String UPDATE_UI_ON_SYSTEM_FONT_CHANGE = "flatlaf.updateUIOnSystemFontChange";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies a directory in which the native FlatLaf libraries have been extracted.
|
* Specifies whether FlatLaf native library should be used.
|
||||||
|
* <p>
|
||||||
|
* Setting this to {@code false} disables loading native library,
|
||||||
|
* which also disables some features that depend on the native library.
|
||||||
|
* <p>
|
||||||
|
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
||||||
|
* <strong>Default</strong> {@code true}
|
||||||
|
*
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
String USE_NATIVE_LIBRARY = "flatlaf.useNativeLibrary";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies a directory in which the FlatLaf native libraries are searched for.
|
||||||
* The path can be absolute or relative to current application working directory.
|
* The path can be absolute or relative to current application working directory.
|
||||||
* This can be used to avoid extraction of the native libraries to the temporary directory at runtime.
|
* This can be used to avoid extraction of the native libraries to the temporary directory at runtime.
|
||||||
* <p>
|
* <p>
|
||||||
* If the value is {@code "system"}, then {@link System#loadLibrary(String)} is
|
* If the value is {@code "system"} (supported since FlatLaf 2.6),
|
||||||
* used to load the native library.
|
* then {@link System#loadLibrary(String)} is used to load the native library.
|
||||||
* Searches for the native library in classloader of caller
|
* This searches for the native library in classloader of caller
|
||||||
* (using {@link ClassLoader#findLibrary(String)}) and in paths specified
|
* (using {@link ClassLoader#findLibrary(String)}) and in paths specified
|
||||||
* in system properties {@code sun.boot.library.path} and {@code java.library.path}.
|
* in system properties {@code sun.boot.library.path} and {@code java.library.path}.
|
||||||
* (supported since FlatLaf 2.6)
|
|
||||||
* <p>
|
* <p>
|
||||||
* If the native library can not loaded from the given path (or via {@link System#loadLibrary(String)}),
|
* If the native library can not be loaded from the given path (or via {@link System#loadLibrary(String)}),
|
||||||
* then the embedded native library is extracted to the temporary directory and loaded from there.
|
* then the embedded native library is extracted to the temporary directory and loaded from there.
|
||||||
|
* <p>
|
||||||
|
* The file names of the native libraries must be either:
|
||||||
|
* <ul>
|
||||||
|
* <li>the same as in flatlaf.jar in package 'com/formdev/flatlaf/natives' (required for "system") or
|
||||||
|
* <li>when downloaded from Maven central then as described here:
|
||||||
|
* <a href="https://www.formdev.com/flatlaf/native-libraries/">https://www.formdev.com/flatlaf/native-libraries/</a>
|
||||||
|
* (requires FlatLaf 3.4)
|
||||||
|
* </ul>
|
||||||
|
* <p>
|
||||||
|
* <strong>Note</strong>: Since FlatLaf 3.1 it is recommended to download the
|
||||||
|
* FlatLaf native libraries from Maven central and distribute them with your
|
||||||
|
* application in the same directory as flatlaf.jar.
|
||||||
|
* Then it is <strong>not necessary</strong> to set this system property.
|
||||||
|
* See <a href="https://www.formdev.com/flatlaf/native-libraries/">https://www.formdev.com/flatlaf/native-libraries/</a>
|
||||||
|
* for details.
|
||||||
*
|
*
|
||||||
* @since 2
|
* @since 2
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -23,13 +23,17 @@ import java.io.InputStreamReader;
|
|||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
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.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import javax.swing.UIDefaults;
|
import javax.swing.UIDefaults;
|
||||||
import javax.swing.plaf.ColorUIResource;
|
import javax.swing.plaf.ColorUIResource;
|
||||||
import com.formdev.flatlaf.json.Json;
|
import com.formdev.flatlaf.json.Json;
|
||||||
@@ -61,9 +65,9 @@ public class IntelliJTheme
|
|||||||
|
|
||||||
private final boolean isMaterialUILite;
|
private final boolean isMaterialUILite;
|
||||||
|
|
||||||
private final Map<String, String> colors;
|
private Map<String, String> colors;
|
||||||
private final Map<String, Object> ui;
|
private Map<String, Object> ui;
|
||||||
private final Map<String, Object> icons;
|
private Map<String, Object> icons;
|
||||||
|
|
||||||
private Map<String, ColorUIResource> namedColors = Collections.emptyMap();
|
private Map<String, ColorUIResource> namedColors = Collections.emptyMap();
|
||||||
|
|
||||||
@@ -196,8 +200,9 @@ public class IntelliJTheme
|
|||||||
defaults.put( "HelpButton.focusedBackground", defaults.get( "Button.focusedBackground" ) );
|
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
|
||||||
defaults.put( "ComboBox.editableBackground", defaults.get( "TextField.background" ) );
|
Object textFieldBackground = get( defaults, themeSpecificDefaults, "TextField.background" );
|
||||||
defaults.put( "Spinner.background", defaults.get( "TextField.background" ) );
|
defaults.put( "ComboBox.editableBackground", textFieldBackground );
|
||||||
|
defaults.put( "Spinner.background", textFieldBackground );
|
||||||
|
|
||||||
// Spinner arrow button always has same colors as ComboBox arrow button
|
// Spinner arrow button always has same colors as ComboBox arrow button
|
||||||
defaults.put( "Spinner.buttonBackground", defaults.get( "ComboBox.buttonEditableBackground" ) );
|
defaults.put( "Spinner.buttonBackground", defaults.get( "ComboBox.buttonEditableBackground" ) );
|
||||||
@@ -205,22 +210,41 @@ public class IntelliJTheme
|
|||||||
defaults.put( "Spinner.buttonDisabledArrowColor", defaults.get( "ComboBox.buttonDisabledArrowColor" ) );
|
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)
|
// (probably because those components are not used in IntelliJ IDEA)
|
||||||
if( uiKeys.contains( "TextField.background" ) ) {
|
putAll( defaults, textFieldBackground,
|
||||||
Object textFieldBackground = defaults.get( "TextField.background" );
|
"EditorPane.background",
|
||||||
if( !uiKeys.contains( "FormattedTextField.background" ) )
|
"FormattedTextField.background",
|
||||||
defaults.put( "FormattedTextField.background", textFieldBackground );
|
"PasswordField.background",
|
||||||
if( !uiKeys.contains( "PasswordField.background" ) )
|
"TextArea.background",
|
||||||
defaults.put( "PasswordField.background", textFieldBackground );
|
"TextPane.background"
|
||||||
if( !uiKeys.contains( "EditorPane.background" ) )
|
);
|
||||||
defaults.put( "EditorPane.background", textFieldBackground );
|
putAll( defaults, get( defaults, themeSpecificDefaults, "TextField.selectionBackground" ),
|
||||||
if( !uiKeys.contains( "TextArea.background" ) )
|
"EditorPane.selectionBackground",
|
||||||
defaults.put( "TextArea.background", textFieldBackground );
|
"FormattedTextField.selectionBackground",
|
||||||
if( !uiKeys.contains( "TextPane.background" ) )
|
"PasswordField.selectionBackground",
|
||||||
defaults.put( "TextPane.background", textFieldBackground );
|
"TextArea.selectionBackground",
|
||||||
if( !uiKeys.contains( "Spinner.background" ) )
|
"TextPane.selectionBackground"
|
||||||
defaults.put( "Spinner.background", textFieldBackground );
|
);
|
||||||
}
|
putAll( defaults, get( defaults, themeSpecificDefaults, "TextField.selectionForeground" ),
|
||||||
|
"EditorPane.selectionForeground",
|
||||||
|
"FormattedTextField.selectionForeground",
|
||||||
|
"PasswordField.selectionForeground",
|
||||||
|
"TextArea.selectionForeground",
|
||||||
|
"TextPane.selectionForeground"
|
||||||
|
);
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
putAll( defaults, panelBackground,
|
||||||
|
"ComboBox.disabledBackground",
|
||||||
|
"EditorPane.disabledBackground", "EditorPane.inactiveBackground",
|
||||||
|
"FormattedTextField.disabledBackground", "FormattedTextField.inactiveBackground",
|
||||||
|
"PasswordField.disabledBackground", "PasswordField.inactiveBackground",
|
||||||
|
"Spinner.disabledBackground",
|
||||||
|
"TextArea.disabledBackground", "TextArea.inactiveBackground",
|
||||||
|
"TextField.disabledBackground", "TextField.inactiveBackground",
|
||||||
|
"TextPane.disabledBackground", "TextPane.inactiveBackground"
|
||||||
|
);
|
||||||
|
|
||||||
// fix ToggleButton
|
// fix ToggleButton
|
||||||
if( !uiKeys.contains( "ToggleButton.startBackground" ) && !uiKeys.contains( "*.startBackground" ) )
|
if( !uiKeys.contains( "ToggleButton.startBackground" ) && !uiKeys.contains( "*.startBackground" ) )
|
||||||
@@ -247,6 +271,33 @@ public class IntelliJTheme
|
|||||||
if( rowHeight > 22 )
|
if( rowHeight > 22 )
|
||||||
defaults.put( "Tree.rowHeight", 22 );
|
defaults.put( "Tree.rowHeight", 22 );
|
||||||
|
|
||||||
|
// get (and remove) theme specific wildcard replacements, which override all other defaults that end with same suffix
|
||||||
|
HashMap<String, Object> wildcards = new HashMap<>();
|
||||||
|
Iterator<Entry<Object, Object>> it = themeSpecificDefaults.entrySet().iterator();
|
||||||
|
while( it.hasNext() ) {
|
||||||
|
Entry<Object, Object> e = it.next();
|
||||||
|
String key = (String) e.getKey();
|
||||||
|
if( key.startsWith( "*." ) ) {
|
||||||
|
wildcards.put( key.substring( "*.".length() ), e.getValue() );
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// override UI defaults with theme specific wildcard replacements
|
||||||
|
if( !wildcards.isEmpty() ) {
|
||||||
|
for( Object key : defaults.keySet().toArray() ) {
|
||||||
|
int dot;
|
||||||
|
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 UI defaults at the end to allow overwriting
|
||||||
for( Map.Entry<Object, Object> e : themeSpecificDefaults.entrySet() ) {
|
for( Map.Entry<Object, Object> e : themeSpecificDefaults.entrySet() ) {
|
||||||
Object key = e.getKey();
|
Object key = e.getKey();
|
||||||
@@ -261,6 +312,20 @@ public class IntelliJTheme
|
|||||||
|
|
||||||
defaults.put( key, value );
|
defaults.put( key, value );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// let Java release memory
|
||||||
|
colors = null;
|
||||||
|
ui = null;
|
||||||
|
icons = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object get( UIDefaults defaults, Map<Object, Object> themeSpecificDefaults, String key ) {
|
||||||
|
return themeSpecificDefaults.getOrDefault( key, defaults.get( key ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void putAll( UIDefaults defaults, Object value, String... keys ) {
|
||||||
|
for( String key : keys )
|
||||||
|
defaults.put( key, value );
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<Object, Object> removeThemeSpecificDefaults( UIDefaults defaults ) {
|
private Map<Object, Object> removeThemeSpecificDefaults( UIDefaults defaults ) {
|
||||||
@@ -302,7 +367,7 @@ public class IntelliJTheme
|
|||||||
|
|
||||||
for( Map.Entry<String, String> e : colors.entrySet() ) {
|
for( Map.Entry<String, String> e : colors.entrySet() ) {
|
||||||
String value = e.getValue();
|
String value = e.getValue();
|
||||||
ColorUIResource color = UIDefaultsLoader.parseColor( value );
|
ColorUIResource color = parseColor( value );
|
||||||
if( color != null ) {
|
if( color != null ) {
|
||||||
String key = e.getKey();
|
String key = e.getKey();
|
||||||
namedColors.put( key, color );
|
namedColors.put( key, color );
|
||||||
@@ -334,10 +399,13 @@ public class IntelliJTheme
|
|||||||
if( "".equals( value ) )
|
if( "".equals( value ) )
|
||||||
return; // ignore empty value
|
return; // ignore empty value
|
||||||
|
|
||||||
uiKeys.add( key );
|
// ignore some properties that affect sizes
|
||||||
|
if( key.endsWith( ".border" ) ||
|
||||||
// fix ComboBox size and Spinner border in all Material UI Lite themes
|
key.endsWith( ".rowHeight" ) ||
|
||||||
if( isMaterialUILite && (key.equals( "ComboBox.padding" ) || key.equals( "Spinner.border" )) )
|
key.equals( "ComboBox.padding" ) ||
|
||||||
|
key.equals( "Spinner.padding" ) ||
|
||||||
|
key.equals( "Tree.leftChildIndent" ) ||
|
||||||
|
key.equals( "Tree.rightChildIndent" ) )
|
||||||
return; // ignore
|
return; // ignore
|
||||||
|
|
||||||
// map keys
|
// map keys
|
||||||
@@ -345,6 +413,16 @@ public class IntelliJTheme
|
|||||||
if( key.isEmpty() )
|
if( key.isEmpty() )
|
||||||
return; // ignore key
|
return; // ignore key
|
||||||
|
|
||||||
|
// exclude properties
|
||||||
|
int dot = key.indexOf( '.' );
|
||||||
|
if( dot > 0 && uiKeyExcludes.contains( key.substring( 0, dot + 1 ) ) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( uiKeyDoNotOverride.contains( key ) && uiKeys.contains( key ) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
uiKeys.add( key );
|
||||||
|
|
||||||
String valueStr = value.toString();
|
String valueStr = value.toString();
|
||||||
|
|
||||||
// map named colors
|
// map named colors
|
||||||
@@ -390,7 +468,8 @@ public class IntelliJTheme
|
|||||||
// replace all values in UI defaults that match the wildcard key
|
// replace all values in UI defaults that match the wildcard key
|
||||||
for( Object k : defaultsKeysCache ) {
|
for( Object k : defaultsKeysCache ) {
|
||||||
if( k.equals( "Desktop.background" ) ||
|
if( k.equals( "Desktop.background" ) ||
|
||||||
k.equals( "DesktopIcon.background" ) )
|
k.equals( "DesktopIcon.background" ) ||
|
||||||
|
k.equals( "TabbedPane.focusColor" ) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if( k instanceof String ) {
|
if( k instanceof String ) {
|
||||||
@@ -448,12 +527,20 @@ public class IntelliJTheme
|
|||||||
ColorUIResource color = namedColors.get( value );
|
ColorUIResource color = namedColors.get( value );
|
||||||
|
|
||||||
// parse color
|
// parse color
|
||||||
return (color != null) ? color : UIDefaultsLoader.parseColor( value );
|
return (color != null) ? color : parseColor( value );
|
||||||
|
}
|
||||||
|
|
||||||
|
private ColorUIResource parseColor( String value ) {
|
||||||
|
try {
|
||||||
|
return UIDefaultsLoader.parseColor( value );
|
||||||
|
} catch( IllegalArgumentException ex ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
* this 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 UI defaults.
|
||||||
*/
|
*/
|
||||||
private void applyCheckBoxColors( UIDefaults defaults ) {
|
private void applyCheckBoxColors( UIDefaults defaults ) {
|
||||||
@@ -473,18 +560,6 @@ public class IntelliJTheme
|
|||||||
if( !key.startsWith( "Checkbox." ) || !(value instanceof String) )
|
if( !key.startsWith( "Checkbox." ) || !(value instanceof String) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if( key.equals( "Checkbox.Background.Default" ) ||
|
|
||||||
key.equals( "Checkbox.Foreground.Selected" ) )
|
|
||||||
{
|
|
||||||
// This two keys do not work correctly in IDEA because they
|
|
||||||
// map SVG color "#ffffff" to another color, but checkBox.svg and
|
|
||||||
// radio.svg (in package com.intellij.ide.ui.laf.icons.intellij)
|
|
||||||
// use "#fff". So use white to get same appearance as in IDEA.
|
|
||||||
value = "#ffffff";
|
|
||||||
}
|
|
||||||
|
|
||||||
String key2 = checkboxDuplicateColors.get( key );
|
|
||||||
|
|
||||||
if( dark )
|
if( dark )
|
||||||
key = StringUtils.removeTrailing( key, ".Dark" );
|
key = StringUtils.removeTrailing( key, ".Dark" );
|
||||||
|
|
||||||
@@ -498,6 +573,7 @@ public class IntelliJTheme
|
|||||||
if( color != null ) {
|
if( color != null ) {
|
||||||
defaults.put( newKey, color );
|
defaults.put( newKey, color );
|
||||||
|
|
||||||
|
String key2 = checkboxDuplicateColors.get( key + ".Dark");
|
||||||
if( key2 != null ) {
|
if( key2 != null ) {
|
||||||
// When IDEA replaces colors in SVGs it uses color values and not the keys
|
// When IDEA replaces colors in SVGs it uses color values and not the keys
|
||||||
// from com.intellij.ide.ui.UITheme.colorPalette, but there are some keys that
|
// from com.intellij.ide.ui.UITheme.colorPalette, but there are some keys that
|
||||||
@@ -540,7 +616,7 @@ public class IntelliJTheme
|
|||||||
// radioFocused.svg and radioSelectedFocused.svg
|
// radioFocused.svg and radioSelectedFocused.svg
|
||||||
// use opacity=".65" for the border
|
// use opacity=".65" for the border
|
||||||
// --> add alpha to focused border colors
|
// --> add alpha to focused border colors
|
||||||
String[] focusedBorderColorKeys = new String[] {
|
String[] focusedBorderColorKeys = {
|
||||||
"CheckBox.icon.focusedBorderColor",
|
"CheckBox.icon.focusedBorderColor",
|
||||||
"CheckBox.icon.focusedSelectedBorderColor",
|
"CheckBox.icon.focusedSelectedBorderColor",
|
||||||
"CheckBox.icon[filled].focusedBorderColor",
|
"CheckBox.icon[filled].focusedBorderColor",
|
||||||
@@ -562,17 +638,59 @@ public class IntelliJTheme
|
|||||||
defaults.put( destKey, defaults.get( srcKey ) );
|
defaults.put( destKey, defaults.get( srcKey ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final Set<String> uiKeyExcludes;
|
||||||
|
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<>();
|
||||||
/** Copy UI default keys (value --> key). */
|
/** Copy UI default keys (value --> key). */
|
||||||
private static final Map<String, String> uiKeyCopying = new HashMap<>();
|
private static final Map<String, String> uiKeyCopying = new LinkedHashMap<>();
|
||||||
private static final Map<String, String> uiKeyInverseMapping = new HashMap<>();
|
private static final Map<String, String> uiKeyInverseMapping = new HashMap<>();
|
||||||
private static final Map<String, String> checkboxKeyMapping = new HashMap<>();
|
private static final Map<String, String> checkboxKeyMapping = new HashMap<>();
|
||||||
private static final Map<String, String> checkboxDuplicateColors = new HashMap<>();
|
private static final Map<String, String> checkboxDuplicateColors = new HashMap<>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
// IntelliJ UI properties that are not used in FlatLaf
|
||||||
|
uiKeyExcludes = new HashSet<>( Arrays.asList(
|
||||||
|
"ActionButton.", "ActionToolbar.", "ActionsList.", "AppInspector.", "AssignedMnemonic.", "Autocomplete.",
|
||||||
|
"AvailableMnemonic.",
|
||||||
|
"BigSpinner.", "Bookmark.", "BookmarkIcon.", "BookmarkMnemonicAssigned.", "BookmarkMnemonicAvailable.",
|
||||||
|
"BookmarkMnemonicCurrent.", "BookmarkMnemonicIcon.", "Borders.", "Breakpoint.",
|
||||||
|
"Canvas.", "CodeWithMe.", "ComboBoxButton.", "CompletionPopup.", "ComplexPopup.", "Content.",
|
||||||
|
"CurrentMnemonic.", "Counter.",
|
||||||
|
"Debugger.", "DebuggerPopup.", "DebuggerTabs.", "DefaultTabs.", "Dialog.", "DialogWrapper.", "DragAndDrop.",
|
||||||
|
"Editor.", "EditorGroupsTabs.", "EditorTabs.",
|
||||||
|
"FileColor.", "FlameGraph.", "Focus.",
|
||||||
|
"Git.", "Github.", "GotItTooltip.", "Group.", "Gutter.", "GutterTooltip.",
|
||||||
|
"HeaderColor.", "HelpTooltip.", "Hg.",
|
||||||
|
"IconBadge.", "InformationHint.", "InplaceRefactoringPopup.",
|
||||||
|
"Lesson.", "Link.", "LiveIndicator.",
|
||||||
|
"MainMenu.", "MainToolbar.", "MemoryIndicator.", "MlModelBinding.", "MnemonicIcon.",
|
||||||
|
"NavBar.", "NewClass.", "NewPSD.", "Notification.", "Notifications.", "NotificationsToolwindow.",
|
||||||
|
"OnePixelDivider.", "OptionButton.", "Outline.",
|
||||||
|
"ParameterInfo.", "Plugins.", "ProgressIcon.", "PsiViewer.",
|
||||||
|
"ReviewList.", "RunWidget.",
|
||||||
|
"ScreenView.", "SearchEverywhere.", "SearchFieldWithExtension.", "SearchMatch.", "SearchOption.",
|
||||||
|
"SearchResults.", "SegmentedButton.", "Settings.", "SidePanel.", "Space.", "SpeedSearch.", "StateWidget.",
|
||||||
|
"StatusBar.",
|
||||||
|
"Tag.", "TipOfTheDay.", "ToolbarComboWidget.", "ToolWindow.",
|
||||||
|
"UIDesigner.", "UnattendedHostStatus.",
|
||||||
|
"ValidationTooltip.", "VersionControl.",
|
||||||
|
"WelcomeScreen.",
|
||||||
|
|
||||||
|
// lower case
|
||||||
|
"darcula.", "dropArea.", "icons.", "intellijlaf.", "macOSWindow.", "material.", "tooltips.",
|
||||||
|
|
||||||
|
// possible typos in .theme.json files
|
||||||
|
"Checkbox.", "Toolbar.", "Tooltip.", "UiDesigner.", "link."
|
||||||
|
) );
|
||||||
|
|
||||||
|
uiKeyDoNotOverride = new HashSet<>( Arrays.asList(
|
||||||
|
"TabbedPane.selectedForeground"
|
||||||
|
) );
|
||||||
|
|
||||||
// ComboBox
|
// ComboBox
|
||||||
uiKeyMapping.put( "ComboBox.background", "" ); // ignore
|
uiKeyMapping.put( "ComboBox.background", "" ); // ignore
|
||||||
|
uiKeyMapping.put( "ComboBox.buttonBackground", "" ); // ignore
|
||||||
uiKeyMapping.put( "ComboBox.nonEditableBackground", "ComboBox.background" );
|
uiKeyMapping.put( "ComboBox.nonEditableBackground", "ComboBox.background" );
|
||||||
uiKeyMapping.put( "ComboBox.ArrowButton.background", "ComboBox.buttonEditableBackground" );
|
uiKeyMapping.put( "ComboBox.ArrowButton.background", "ComboBox.buttonEditableBackground" );
|
||||||
uiKeyMapping.put( "ComboBox.ArrowButton.disabledIconColor", "ComboBox.buttonDisabledArrowColor" );
|
uiKeyMapping.put( "ComboBox.ArrowButton.disabledIconColor", "ComboBox.buttonDisabledArrowColor" );
|
||||||
@@ -630,9 +748,9 @@ public class IntelliJTheme
|
|||||||
uiKeyCopying.put( "Spinner.buttonDisabledSeparatorColor", "Component.disabledBorderColor" );
|
uiKeyCopying.put( "Spinner.buttonDisabledSeparatorColor", "Component.disabledBorderColor" );
|
||||||
|
|
||||||
// TabbedPane
|
// TabbedPane
|
||||||
uiKeyCopying.put( "TabbedPane.selectedBackground", "DefaultTabs.underlinedTabBackground" );
|
uiKeyMapping.put( "DefaultTabs.underlinedTabBackground", "TabbedPane.selectedBackground" );
|
||||||
uiKeyCopying.put( "TabbedPane.selectedForeground", "DefaultTabs.underlinedTabForeground" );
|
uiKeyMapping.put( "DefaultTabs.underlinedTabForeground", "TabbedPane.selectedForeground" );
|
||||||
uiKeyCopying.put( "TabbedPane.inactiveUnderlineColor", "DefaultTabs.inactiveUnderlineColor" );
|
uiKeyMapping.put( "DefaultTabs.inactiveUnderlineColor", "TabbedPane.inactiveUnderlineColor" );
|
||||||
|
|
||||||
// TitlePane
|
// TitlePane
|
||||||
uiKeyCopying.put( "TitlePane.inactiveBackground", "TitlePane.background" );
|
uiKeyCopying.put( "TitlePane.inactiveBackground", "TitlePane.background" );
|
||||||
|
|||||||
@@ -23,11 +23,14 @@ import java.awt.GraphicsEnvironment;
|
|||||||
import java.awt.Toolkit;
|
import java.awt.Toolkit;
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileReader;
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import javax.swing.text.StyleContext;
|
import javax.swing.text.StyleContext;
|
||||||
import com.formdev.flatlaf.util.LoggingFacade;
|
import com.formdev.flatlaf.util.LoggingFacade;
|
||||||
@@ -68,7 +71,7 @@ class LinuxFontPolicy
|
|||||||
if( word.endsWith( "," ) )
|
if( word.endsWith( "," ) )
|
||||||
word = word.substring( 0, word.length() - 1 ).trim();
|
word = word.substring( 0, word.length() - 1 ).trim();
|
||||||
|
|
||||||
String lword = word.toLowerCase();
|
String lword = word.toLowerCase( Locale.ENGLISH );
|
||||||
if( lword.equals( "italic" ) || lword.equals( "oblique" ) )
|
if( lword.equals( "italic" ) || lword.equals( "oblique" ) )
|
||||||
style |= Font.ITALIC;
|
style |= Font.ITALIC;
|
||||||
else if( lword.equals( "bold" ) )
|
else if( lword.equals( "bold" ) )
|
||||||
@@ -104,7 +107,7 @@ class LinuxFontPolicy
|
|||||||
size = 1;
|
size = 1;
|
||||||
|
|
||||||
// handle logical font names
|
// handle logical font names
|
||||||
String logicalFamily = mapFcName( family.toLowerCase() );
|
String logicalFamily = mapFcName( family.toLowerCase( Locale.ENGLISH ) );
|
||||||
if( logicalFamily != null )
|
if( logicalFamily != null )
|
||||||
family = logicalFamily;
|
family = logicalFamily;
|
||||||
|
|
||||||
@@ -143,7 +146,7 @@ class LinuxFontPolicy
|
|||||||
return createFont( Font.DIALOG, style, size, dsize );
|
return createFont( Font.DIALOG, style, size, dsize );
|
||||||
|
|
||||||
// check whether last work contains some font weight (e.g. Ultra-Bold or Heavy)
|
// check whether last work contains some font weight (e.g. Ultra-Bold or Heavy)
|
||||||
String lastWord = family.substring( index + 1 ).toLowerCase();
|
String lastWord = family.substring( index + 1 ).toLowerCase( Locale.ENGLISH );
|
||||||
if( lastWord.contains( "bold" ) || lastWord.contains( "heavy" ) || lastWord.contains( "black" ) )
|
if( lastWord.contains( "bold" ) || lastWord.contains( "heavy" ) || lastWord.contains( "black" ) )
|
||||||
style |= Font.BOLD;
|
style |= Font.BOLD;
|
||||||
|
|
||||||
@@ -200,7 +203,7 @@ class LinuxFontPolicy
|
|||||||
* Gets the default font for KDE from KDE configuration files.
|
* Gets the default font for KDE from KDE configuration files.
|
||||||
*
|
*
|
||||||
* The Swing fonts are not updated when the user changes system font size
|
* The Swing fonts are not updated when the user changes system font size
|
||||||
* (System Settings > Fonts > Force Font DPI). A application restart is necessary.
|
* (System Settings > Fonts > Force Font DPI). An application restart is necessary.
|
||||||
* This is the same behavior as in native KDE applications.
|
* This is the same behavior as in native KDE applications.
|
||||||
*
|
*
|
||||||
* The "display scale factor" (kdeglobals: [KScreen] > ScaleFactor) is not used
|
* The "display scale factor" (kdeglobals: [KScreen] > ScaleFactor) is not used
|
||||||
@@ -257,6 +260,7 @@ class LinuxFontPolicy
|
|||||||
return createFont( family, style, size, dsize );
|
return createFont( family, style, size, dsize );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings( "MixedMutabilityReturnType" ) // Error Prone
|
||||||
private static List<String> readConfig( String filename ) {
|
private static List<String> readConfig( String filename ) {
|
||||||
File userHome = new File( System.getProperty( "user.home" ) );
|
File userHome = new File( System.getProperty( "user.home" ) );
|
||||||
|
|
||||||
@@ -277,7 +281,9 @@ class LinuxFontPolicy
|
|||||||
|
|
||||||
// read config file
|
// read config file
|
||||||
ArrayList<String> lines = new ArrayList<>( 200 );
|
ArrayList<String> lines = new ArrayList<>( 200 );
|
||||||
try( BufferedReader reader = new BufferedReader( new FileReader( file ) ) ) {
|
try( BufferedReader reader = new BufferedReader( new InputStreamReader(
|
||||||
|
new FileInputStream( file ), StandardCharsets.US_ASCII ) ) )
|
||||||
|
{
|
||||||
String line;
|
String line;
|
||||||
while( (line = reader.readLine()) != null )
|
while( (line = reader.readLine()) != null )
|
||||||
lines.add( line );
|
lines.add( line );
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ debug*/
|
|||||||
|
|
||||||
// get invoker screen bounds
|
// get invoker screen bounds
|
||||||
Component invoker = popup.getInvoker();
|
Component invoker = popup.getInvoker();
|
||||||
invokerBounds = (invoker != null)
|
invokerBounds = (invoker != null && invoker.isShowing())
|
||||||
? new Rectangle( invoker.getLocationOnScreen(), invoker.getSize() )
|
? new Rectangle( invoker.getLocationOnScreen(), invoker.getSize() )
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
@@ -172,7 +172,7 @@ debug*/
|
|||||||
targetTopY = popupLocation.y;
|
targetTopY = popupLocation.y;
|
||||||
targetBottomY = popupLocation.y + popupSize.height;
|
targetBottomY = popupLocation.y + popupSize.height;
|
||||||
|
|
||||||
// install own event queue to supress mouse events when mouse is moved within safe triangle
|
// install own event queue to suppress mouse events when mouse is moved within safe triangle
|
||||||
if( subMenuEventQueue == null )
|
if( subMenuEventQueue == null )
|
||||||
subMenuEventQueue = new SubMenuEventQueue();
|
subMenuEventQueue = new SubMenuEventQueue();
|
||||||
|
|
||||||
|
|||||||
@@ -27,8 +27,12 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
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.Executable;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
@@ -84,6 +88,7 @@ class UIDefaultsLoader
|
|||||||
|
|
||||||
private static int parseColorDepth;
|
private static int parseColorDepth;
|
||||||
|
|
||||||
|
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 void loadDefaultsFromProperties( Class<?> lookAndFeelClass, List<FlatDefaultsAddon> addons,
|
||||||
@@ -105,6 +110,10 @@ class UIDefaultsLoader
|
|||||||
Properties additionalDefaults, boolean dark, UIDefaults defaults )
|
Properties additionalDefaults, boolean dark, UIDefaults defaults )
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
// temporary cache system colors while loading defaults,
|
||||||
|
// which avoids that system color getter is invoked multiple times
|
||||||
|
systemColorCache = (FlatLaf.getSystemColorGetter() != null) ? new HashMap<>() : null;
|
||||||
|
|
||||||
// load core properties files
|
// load core properties files
|
||||||
Properties properties = new Properties();
|
Properties properties = new Properties();
|
||||||
for( Class<?> lafClass : lafClasses ) {
|
for( Class<?> lafClass : lafClasses ) {
|
||||||
@@ -266,8 +275,9 @@ class UIDefaultsLoader
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
String value = resolveValue( (String) e.getValue(), propertiesGetter );
|
String value = (String) e.getValue();
|
||||||
try {
|
try {
|
||||||
|
value = resolveValue( value, propertiesGetter );
|
||||||
defaults.put( key, parseValue( key, value, null, null, resolver, addonClassLoaders ) );
|
defaults.put( key, parseValue( key, value, null, null, resolver, addonClassLoaders ) );
|
||||||
} catch( RuntimeException ex ) {
|
} catch( RuntimeException ex ) {
|
||||||
logParseError( key, value, ex, true );
|
logParseError( key, value, ex, true );
|
||||||
@@ -276,6 +286,9 @@ 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 );
|
||||||
|
|
||||||
|
// clear/disable system color cache
|
||||||
|
systemColorCache = null;
|
||||||
} catch( IOException ex ) {
|
} catch( IOException ex ) {
|
||||||
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to load properties files.", ex );
|
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to load properties files.", ex );
|
||||||
}
|
}
|
||||||
@@ -289,7 +302,9 @@ class UIDefaultsLoader
|
|||||||
LoggingFacade.INSTANCE.logConfig( message, ex );
|
LoggingFacade.INSTANCE.logConfig( message, ex );
|
||||||
}
|
}
|
||||||
|
|
||||||
static String resolveValue( String value, Function<String, String> propertiesGetter ) {
|
static String resolveValue( String value, Function<String, String> propertiesGetter )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
value = value.trim();
|
value = value.trim();
|
||||||
String value0 = value;
|
String value0 = value;
|
||||||
|
|
||||||
@@ -318,7 +333,9 @@ class UIDefaultsLoader
|
|||||||
return resolveValue( newValue, propertiesGetter );
|
return resolveValue( newValue, propertiesGetter );
|
||||||
}
|
}
|
||||||
|
|
||||||
static String resolveValueFromUIManager( String value ) {
|
static String resolveValueFromUIManager( String value )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
if( value.startsWith( VARIABLE_PREFIX ) ) {
|
if( value.startsWith( VARIABLE_PREFIX ) ) {
|
||||||
@SuppressWarnings( "unchecked" )
|
@SuppressWarnings( "unchecked" )
|
||||||
Map<String, String> variables = (Map<String, String>) UIManager.get( KEY_VARIABLES );
|
Map<String, String> variables = (Map<String, String>) UIManager.get( KEY_VARIABLES );
|
||||||
@@ -326,7 +343,7 @@ class UIDefaultsLoader
|
|||||||
if( newValue == null )
|
if( newValue == null )
|
||||||
throw new IllegalArgumentException( "variable '" + value + "' not found" );
|
throw new IllegalArgumentException( "variable '" + value + "' not found" );
|
||||||
|
|
||||||
return newValue;
|
return resolveValueFromUIManager( newValue );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !value.startsWith( PROPERTY_PREFIX ) )
|
if( !value.startsWith( PROPERTY_PREFIX ) )
|
||||||
@@ -340,8 +357,11 @@ class UIDefaultsLoader
|
|||||||
// convert binary color to string
|
// convert binary color to string
|
||||||
if( newValue instanceof Color ) {
|
if( newValue instanceof Color ) {
|
||||||
Color color = (Color) newValue;
|
Color color = (Color) newValue;
|
||||||
|
int rgb = color.getRGB() & 0xffffff;
|
||||||
int alpha = color.getAlpha();
|
int alpha = color.getAlpha();
|
||||||
return String.format( (alpha != 255) ? "#%06x%02x" : "#%06x", color.getRGB() & 0xffffff, alpha );
|
return (alpha != 255)
|
||||||
|
? String.format( "#%06x%02x", rgb, alpha )
|
||||||
|
: String.format( "#%06x", rgb );
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new IllegalArgumentException( "property value type '" + newValue.getClass().getName() + "' not supported in references" );
|
throw new IllegalArgumentException( "property value type '" + newValue.getClass().getName() + "' not supported in references" );
|
||||||
@@ -354,12 +374,15 @@ class UIDefaultsLoader
|
|||||||
private static Map<Class<?>, ValueType> javaValueTypes;
|
private static Map<Class<?>, ValueType> javaValueTypes;
|
||||||
private static Map<String, ValueType> knownValueTypes;
|
private static Map<String, ValueType> knownValueTypes;
|
||||||
|
|
||||||
static Object parseValue( String key, String value, Class<?> valueType ) {
|
static Object parseValue( String key, String value, Class<?> valueType )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
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, ValueType[] resultValueType,
|
||||||
Function<String, String> resolver, List<ClassLoader> addonClassLoaders )
|
Function<String, String> resolver, List<ClassLoader> addonClassLoaders )
|
||||||
|
throws IllegalArgumentException
|
||||||
{
|
{
|
||||||
if( resultValueType == null )
|
if( resultValueType == null )
|
||||||
resultValueType = tempResultValueType;
|
resultValueType = tempResultValueType;
|
||||||
@@ -389,7 +412,7 @@ class UIDefaultsLoader
|
|||||||
if( value.startsWith( "if(" ) && value.endsWith( ")" ) ) {
|
if( value.startsWith( "if(" ) && value.endsWith( ")" ) ) {
|
||||||
List<String> params = splitFunctionParams( value.substring( 3, value.length() - 1 ), ',' );
|
List<String> params = splitFunctionParams( value.substring( 3, value.length() - 1 ), ',' );
|
||||||
if( params.size() != 3 )
|
if( params.size() != 3 )
|
||||||
throwMissingParametersException( value );
|
throw newMissingParametersException( value );
|
||||||
|
|
||||||
boolean ifCondition = parseCondition( params.get( 0 ), resolver, addonClassLoaders );
|
boolean ifCondition = parseCondition( params.get( 0 ), resolver, addonClassLoaders );
|
||||||
String ifValue = params.get( ifCondition ? 1 : 2 );
|
String ifValue = params.get( ifCondition ? 1 : 2 );
|
||||||
@@ -525,20 +548,20 @@ class UIDefaultsLoader
|
|||||||
case STRING: return value;
|
case STRING: return value;
|
||||||
case BOOLEAN: return parseBoolean( value );
|
case BOOLEAN: return parseBoolean( value );
|
||||||
case CHARACTER: return parseCharacter( value );
|
case CHARACTER: return parseCharacter( value );
|
||||||
case INTEGER: return parseInteger( value, true );
|
case INTEGER: return parseInteger( value );
|
||||||
case INTEGERORFLOAT:return parseIntegerOrFloat( value, true );
|
case INTEGERORFLOAT:return parseIntegerOrFloat( value );
|
||||||
case FLOAT: return parseFloat( value, true );
|
case FLOAT: return parseFloat( value );
|
||||||
case BORDER: return parseBorder( value, resolver, addonClassLoaders );
|
case BORDER: return parseBorder( value, resolver, addonClassLoaders );
|
||||||
case ICON: return parseInstance( value, addonClassLoaders );
|
case ICON: return parseInstance( value, resolver, addonClassLoaders );
|
||||||
case INSETS: return parseInsets( value );
|
case INSETS: return parseInsets( value );
|
||||||
case DIMENSION: return parseDimension( value );
|
case DIMENSION: return parseDimension( value );
|
||||||
case COLOR: return parseColorOrFunction( value, resolver, true );
|
case COLOR: return parseColorOrFunction( value, resolver );
|
||||||
case FONT: return parseFont( value );
|
case FONT: return parseFont( value );
|
||||||
case SCALEDINTEGER: return parseScaledInteger( value );
|
case SCALEDINTEGER: return parseScaledInteger( value );
|
||||||
case SCALEDFLOAT: return parseScaledFloat( value );
|
case SCALEDFLOAT: return parseScaledFloat( value );
|
||||||
case SCALEDINSETS: return parseScaledInsets( value );
|
case SCALEDINSETS: return parseScaledInsets( value );
|
||||||
case SCALEDDIMENSION:return parseScaledDimension( value );
|
case SCALEDDIMENSION:return parseScaledDimension( value );
|
||||||
case INSTANCE: return parseInstance( value, addonClassLoaders );
|
case INSTANCE: return parseInstance( value, resolver, addonClassLoaders );
|
||||||
case CLASS: return parseClass( value, addonClassLoaders );
|
case CLASS: return parseClass( value, addonClassLoaders );
|
||||||
case GRAYFILTER: return parseGrayFilter( value );
|
case GRAYFILTER: return parseGrayFilter( value );
|
||||||
case UNKNOWN:
|
case UNKNOWN:
|
||||||
@@ -550,24 +573,34 @@ class UIDefaultsLoader
|
|||||||
}
|
}
|
||||||
|
|
||||||
// colors
|
// colors
|
||||||
Object color = parseColorOrFunction( value, resolver, false );
|
if( value.startsWith( "#" ) || value.endsWith( ")" ) ) {
|
||||||
if( color != null ) {
|
Object color = parseColorOrFunction( value, resolver );
|
||||||
resultValueType[0] = ValueType.COLOR;
|
resultValueType[0] = (color != null) ? ValueType.COLOR : ValueType.NULL;
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// integer or float
|
||||||
|
char firstChar = value.charAt( 0 );
|
||||||
|
if( (firstChar >= '0' && firstChar <= '9') ||
|
||||||
|
firstChar == '-' || firstChar == '+' || firstChar == '.' )
|
||||||
|
{
|
||||||
// integer
|
// integer
|
||||||
Integer integer = parseInteger( value, false );
|
try {
|
||||||
if( integer != null ) {
|
Integer integer = parseInteger( value );
|
||||||
resultValueType[0] = ValueType.INTEGER;
|
resultValueType[0] = ValueType.INTEGER;
|
||||||
return integer;
|
return integer;
|
||||||
|
} catch( NumberFormatException ex ) {
|
||||||
|
// ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
// float
|
// float
|
||||||
Float f = parseFloat( value, false );
|
try {
|
||||||
if( f != null ) {
|
Float f = parseFloat( value );
|
||||||
resultValueType[0] = ValueType.FLOAT;
|
resultValueType[0] = ValueType.FLOAT;
|
||||||
return f;
|
return f;
|
||||||
|
} catch( NumberFormatException ex ) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// string
|
// string
|
||||||
@@ -590,16 +623,18 @@ class UIDefaultsLoader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object parseBorder( String value, Function<String, String> resolver, List<ClassLoader> addonClassLoaders ) {
|
private static Object parseBorder( String value, Function<String, String> resolver, List<ClassLoader> addonClassLoaders )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
if( value.indexOf( ',' ) >= 0 ) {
|
if( value.indexOf( ',' ) >= 0 ) {
|
||||||
// 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, ',' );
|
||||||
Insets insets = parseInsets( value );
|
Insets insets = parseInsets( value );
|
||||||
ColorUIResource lineColor = (parts.size() >= 5)
|
ColorUIResource lineColor = (parts.size() >= 5)
|
||||||
? (ColorUIResource) parseColorOrFunction( resolver.apply( parts.get( 4 ) ), resolver, true )
|
? (ColorUIResource) parseColorOrFunction( resolver.apply( parts.get( 4 ) ), resolver )
|
||||||
: null;
|
: null;
|
||||||
float lineThickness = (parts.size() >= 6 && !parts.get( 5 ).isEmpty()) ? parseFloat( parts.get( 5 ), true ) : 1f;
|
float lineThickness = (parts.size() >= 6 && !parts.get( 5 ).isEmpty()) ? parseFloat( parts.get( 5 ) ) : 1f;
|
||||||
int arc = (parts.size() >= 7) ? parseInteger( parts.get( 6 ), true ) : 0;
|
int arc = (parts.size() >= 7) ? parseInteger( parts.get( 6 ) ) : 0;
|
||||||
|
|
||||||
return (LazyValue) t -> {
|
return (LazyValue) t -> {
|
||||||
return (lineColor != null)
|
return (lineColor != null)
|
||||||
@@ -607,12 +642,28 @@ class UIDefaultsLoader
|
|||||||
: new FlatEmptyBorder( insets );
|
: new FlatEmptyBorder( insets );
|
||||||
};
|
};
|
||||||
} else
|
} else
|
||||||
return parseInstance( value, addonClassLoaders );
|
return parseInstance( value, resolver, addonClassLoaders );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object parseInstance( String value, List<ClassLoader> addonClassLoaders ) {
|
private static Object parseInstance( String value, Function<String, String> resolver, List<ClassLoader> addonClassLoaders ) {
|
||||||
return (LazyValue) t -> {
|
return (LazyValue) t -> {
|
||||||
try {
|
try {
|
||||||
|
if( value.indexOf( ',' ) >= 0 ) {
|
||||||
|
// Syntax: className,param1,param2,...
|
||||||
|
List<String> parts = splitFunctionParams( value, ',' );
|
||||||
|
String className = parts.get( 0 );
|
||||||
|
Class<?> cls = findClass( className, addonClassLoaders );
|
||||||
|
|
||||||
|
Constructor<?>[] constructors = cls.getDeclaredConstructors();
|
||||||
|
Object result = invokeConstructorOrStaticMethod( constructors, parts, resolver );
|
||||||
|
if( result != null )
|
||||||
|
return result;
|
||||||
|
|
||||||
|
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to instantiate '" + className
|
||||||
|
+ "': no constructor found for parameters '"
|
||||||
|
+ value.substring( value.indexOf( ',' + 1 ) ) + "'.", null );
|
||||||
|
return null;
|
||||||
|
} else
|
||||||
return findClass( value, addonClassLoaders ).getDeclaredConstructor().newInstance();
|
return findClass( value, addonClassLoaders ).getDeclaredConstructor().newInstance();
|
||||||
} catch( Exception ex ) {
|
} catch( Exception ex ) {
|
||||||
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to instantiate '" + value + "'.", ex );
|
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to instantiate '" + value + "'.", ex );
|
||||||
@@ -650,7 +701,9 @@ class UIDefaultsLoader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Insets parseInsets( String value ) {
|
private static Insets parseInsets( String value )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
List<String> numbers = StringUtils.split( value, ',', true, false );
|
List<String> numbers = StringUtils.split( value, ',', true, false );
|
||||||
try {
|
try {
|
||||||
return new InsetsUIResource(
|
return new InsetsUIResource(
|
||||||
@@ -663,7 +716,9 @@ class UIDefaultsLoader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Dimension parseDimension( String value ) {
|
private static Dimension parseDimension( String value )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
List<String> numbers = StringUtils.split( value, ',', true, false );
|
List<String> numbers = StringUtils.split( value, ',', true, false );
|
||||||
try {
|
try {
|
||||||
return new DimensionUIResource(
|
return new DimensionUIResource(
|
||||||
@@ -674,43 +729,39 @@ class UIDefaultsLoader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object parseColorOrFunction( String value, Function<String, String> resolver, boolean reportError ) {
|
private static Object parseColorOrFunction( String value, Function<String, String> resolver )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
if( value.endsWith( ")" ) )
|
if( value.endsWith( ")" ) )
|
||||||
return parseColorFunctions( value, resolver, reportError );
|
return parseColorFunctions( value, resolver );
|
||||||
|
|
||||||
return parseColor( value, reportError );
|
return parseColor( value );
|
||||||
}
|
}
|
||||||
|
|
||||||
static ColorUIResource parseColor( String value ) {
|
/**
|
||||||
return parseColor( value, false );
|
* Parses a hex color in {@code #RGB}, {@code #RGBA}, {@code #RRGGBB} or {@code #RRGGBBAA}
|
||||||
}
|
* format and returns it as color object.
|
||||||
|
*/
|
||||||
private static ColorUIResource parseColor( String value, boolean reportError ) {
|
static ColorUIResource parseColor( String value )
|
||||||
try {
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
int rgba = parseColorRGBA( value );
|
int rgba = parseColorRGBA( value );
|
||||||
return ((rgba & 0xff000000) == 0xff000000)
|
return ((rgba & 0xff000000) == 0xff000000)
|
||||||
? new ColorUIResource( rgba )
|
? new ColorUIResource( rgba )
|
||||||
: new ColorUIResource( new Color( rgba, true ) );
|
: new ColorUIResource( new Color( rgba, true ) );
|
||||||
} catch( IllegalArgumentException ex ) {
|
|
||||||
if( reportError )
|
|
||||||
throw new IllegalArgumentException( "invalid color '" + value + "'" );
|
|
||||||
|
|
||||||
// not a color --> ignore
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a hex color in {@code #RGB}, {@code #RGBA}, {@code #RRGGBB} or {@code #RRGGBBAA}
|
* Parses a hex color in {@code #RGB}, {@code #RGBA}, {@code #RRGGBB} or {@code #RRGGBBAA}
|
||||||
* format and returns it as {@code rgba} integer suitable for {@link java.awt.Color},
|
* format and returns it as {@code rgba} integer suitable for {@link java.awt.Color},
|
||||||
* which includes alpha component in bits 24-31.
|
* which includes alpha component in bits 24-31.
|
||||||
*
|
|
||||||
* @throws IllegalArgumentException
|
|
||||||
*/
|
*/
|
||||||
static int parseColorRGBA( String value ) {
|
static int parseColorRGBA( String value )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
int len = value.length();
|
int len = value.length();
|
||||||
if( (len != 4 && len != 5 && len != 7 && len != 9) || value.charAt( 0 ) != '#' )
|
if( (len != 4 && len != 5 && len != 7 && len != 9) || value.charAt( 0 ) != '#' )
|
||||||
throw new IllegalArgumentException();
|
throw newInvalidColorException( value );
|
||||||
|
|
||||||
// parse hex
|
// parse hex
|
||||||
int n = 0;
|
int n = 0;
|
||||||
@@ -725,7 +776,7 @@ class UIDefaultsLoader
|
|||||||
else if( ch >= 'A' && ch <= 'F' )
|
else if( ch >= 'A' && ch <= 'F' )
|
||||||
digit = ch - 'A' + 10;
|
digit = ch - 'A' + 10;
|
||||||
else
|
else
|
||||||
throw new IllegalArgumentException();
|
throw newInvalidColorException( value );
|
||||||
|
|
||||||
n = (n << 4) | digit;
|
n = (n << 4) | digit;
|
||||||
}
|
}
|
||||||
@@ -744,18 +795,21 @@ class UIDefaultsLoader
|
|||||||
: (((n >> 8) & 0xffffff) | ((n & 0xff) << 24)); // move alpha from lowest to highest byte
|
: (((n >> 8) & 0xffffff) | ((n & 0xff) << 24)); // move alpha from lowest to highest byte
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object parseColorFunctions( String value, Function<String, String> resolver, boolean reportError ) {
|
private static IllegalArgumentException newInvalidColorException( String value ) {
|
||||||
int paramsStart = value.indexOf( '(' );
|
return new IllegalArgumentException( "invalid color '" + value + "'" );
|
||||||
if( paramsStart < 0 ) {
|
|
||||||
if( reportError )
|
|
||||||
throw new IllegalArgumentException( "missing opening parenthesis in function '" + value + "'" );
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Object parseColorFunctions( String value, Function<String, String> resolver )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
|
int paramsStart = value.indexOf( '(' );
|
||||||
|
if( paramsStart < 0 )
|
||||||
|
throw new IllegalArgumentException( "missing opening parenthesis in function '" + value + "'" );
|
||||||
|
|
||||||
String function = StringUtils.substringTrimmed( value, 0, paramsStart );
|
String function = StringUtils.substringTrimmed( value, 0, paramsStart );
|
||||||
List<String> params = splitFunctionParams( value.substring( paramsStart + 1, value.length() - 1 ), ',' );
|
List<String> params = splitFunctionParams( value.substring( paramsStart + 1, value.length() - 1 ), ',' );
|
||||||
if( params.isEmpty() )
|
if( params.isEmpty() )
|
||||||
throwMissingParametersException( value );
|
throw newMissingParametersException( value );
|
||||||
|
|
||||||
if( parseColorDepth > 100 )
|
if( parseColorDepth > 100 )
|
||||||
throw new IllegalArgumentException( "endless recursion in color function '" + value + "'" );
|
throw new IllegalArgumentException( "endless recursion in color function '" + value + "'" );
|
||||||
@@ -763,28 +817,29 @@ class UIDefaultsLoader
|
|||||||
parseColorDepth++;
|
parseColorDepth++;
|
||||||
try {
|
try {
|
||||||
switch( function ) {
|
switch( function ) {
|
||||||
case "if": return parseColorIf( value, params, resolver, reportError );
|
case "if": return parseColorIf( value, params, resolver );
|
||||||
case "rgb": return parseColorRgbOrRgba( false, params, resolver, reportError );
|
case "systemColor": return parseColorSystemColor( value, params, resolver );
|
||||||
case "rgba": return parseColorRgbOrRgba( true, params, resolver, reportError );
|
case "rgb": return parseColorRgbOrRgba( false, params, resolver );
|
||||||
|
case "rgba": return parseColorRgbOrRgba( true, params, resolver );
|
||||||
case "hsl": return parseColorHslOrHsla( false, params );
|
case "hsl": return parseColorHslOrHsla( false, params );
|
||||||
case "hsla": return parseColorHslOrHsla( true, params );
|
case "hsla": return parseColorHslOrHsla( true, params );
|
||||||
case "lighten": return parseColorHSLIncreaseDecrease( 2, true, params, resolver, reportError );
|
case "lighten": return parseColorHSLIncreaseDecrease( 2, true, params, resolver );
|
||||||
case "darken": return parseColorHSLIncreaseDecrease( 2, false, params, resolver, reportError );
|
case "darken": return parseColorHSLIncreaseDecrease( 2, false, params, resolver );
|
||||||
case "saturate": return parseColorHSLIncreaseDecrease( 1, true, params, resolver, reportError );
|
case "saturate": return parseColorHSLIncreaseDecrease( 1, true, params, resolver );
|
||||||
case "desaturate": return parseColorHSLIncreaseDecrease( 1, false, params, resolver, reportError );
|
case "desaturate": return parseColorHSLIncreaseDecrease( 1, false, params, resolver );
|
||||||
case "fadein": return parseColorHSLIncreaseDecrease( 3, true, params, resolver, reportError );
|
case "fadein": return parseColorHSLIncreaseDecrease( 3, true, params, resolver );
|
||||||
case "fadeout": return parseColorHSLIncreaseDecrease( 3, false, params, resolver, reportError );
|
case "fadeout": return parseColorHSLIncreaseDecrease( 3, false, params, resolver );
|
||||||
case "fade": return parseColorFade( params, resolver, reportError );
|
case "fade": return parseColorFade( params, resolver );
|
||||||
case "spin": return parseColorSpin( params, resolver, reportError );
|
case "spin": return parseColorSpin( params, resolver );
|
||||||
case "changeHue": return parseColorChange( 0, params, resolver, reportError );
|
case "changeHue": return parseColorChange( 0, params, resolver );
|
||||||
case "changeSaturation":return parseColorChange( 1, params, resolver, reportError );
|
case "changeSaturation":return parseColorChange( 1, params, resolver );
|
||||||
case "changeLightness": return parseColorChange( 2, params, resolver, reportError );
|
case "changeLightness": return parseColorChange( 2, params, resolver );
|
||||||
case "changeAlpha": return parseColorChange( 3, params, resolver, reportError );
|
case "changeAlpha": return parseColorChange( 3, params, resolver );
|
||||||
case "mix": return parseColorMix( null, params, resolver, reportError );
|
case "mix": return parseColorMix( null, params, resolver );
|
||||||
case "tint": return parseColorMix( "#fff", params, resolver, reportError );
|
case "tint": return parseColorMix( "#fff", params, resolver );
|
||||||
case "shade": return parseColorMix( "#000", params, resolver, reportError );
|
case "shade": return parseColorMix( "#000", params, resolver );
|
||||||
case "contrast": return parseColorContrast( params, resolver, reportError );
|
case "contrast": return parseColorContrast( params, resolver );
|
||||||
case "over": return parseColorOver( params, resolver, reportError );
|
case "over": return parseColorOver( params, resolver );
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
parseColorDepth--;
|
parseColorDepth--;
|
||||||
@@ -799,13 +854,55 @@ class UIDefaultsLoader
|
|||||||
* This "if" function is only used if the "if" is passed as parameter to another
|
* This "if" function is only used if the "if" is passed as parameter to another
|
||||||
* color function. Otherwise, the general "if" function is used.
|
* color function. Otherwise, the general "if" function is used.
|
||||||
*/
|
*/
|
||||||
private static Object parseColorIf( String value, List<String> params, Function<String, String> resolver, boolean reportError ) {
|
private static Object parseColorIf( String value, List<String> params, Function<String, String> resolver )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
if( params.size() != 3 )
|
if( params.size() != 3 )
|
||||||
throwMissingParametersException( value );
|
throw newMissingParametersException( value );
|
||||||
|
|
||||||
boolean ifCondition = parseCondition( params.get( 0 ), resolver, Collections.emptyList() );
|
boolean ifCondition = parseCondition( params.get( 0 ), resolver, Collections.emptyList() );
|
||||||
String ifValue = params.get( ifCondition ? 1 : 2 );
|
String ifValue = params.get( ifCondition ? 1 : 2 );
|
||||||
return parseColorOrFunction( resolver.apply( ifValue ), resolver, reportError );
|
return parseColorOrFunction( resolver.apply( ifValue ), resolver );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Syntax: systemColor(name[,defaultValue])
|
||||||
|
* - name: system color name
|
||||||
|
* - defaultValue: default color value used if system color is not available
|
||||||
|
*/
|
||||||
|
private static Object parseColorSystemColor( String value, List<String> params, Function<String, String> resolver )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
|
if( params.size() < 1 )
|
||||||
|
throw newMissingParametersException( value );
|
||||||
|
|
||||||
|
ColorUIResource systemColor = getSystemColor( params.get( 0 ) );
|
||||||
|
if( systemColor != null )
|
||||||
|
return systemColor;
|
||||||
|
|
||||||
|
String defaultValue = (params.size() > 1) ? params.get( 1 ) : "";
|
||||||
|
if( defaultValue.equals( "null" ) || defaultValue.isEmpty() )
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return parseColorOrFunction( resolver.apply( defaultValue ), resolver );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ColorUIResource getSystemColor( String name ) {
|
||||||
|
Function<String, Color> systemColorGetter = FlatLaf.getSystemColorGetter();
|
||||||
|
if( systemColorGetter == null )
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// use containsKey() because value may be null
|
||||||
|
if( systemColorCache != null && systemColorCache.containsKey( name ) )
|
||||||
|
return systemColorCache.get( name );
|
||||||
|
|
||||||
|
Color color = systemColorGetter.apply( name );
|
||||||
|
ColorUIResource uiColor = (color != null) ? new ColorUIResource( color ) : null;
|
||||||
|
|
||||||
|
if( systemColorCache != null )
|
||||||
|
systemColorCache.put( name, uiColor );
|
||||||
|
|
||||||
|
return uiColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -816,7 +913,8 @@ class UIDefaultsLoader
|
|||||||
* - alpha: an integer 0-255 or a percentage 0-100%
|
* - alpha: an integer 0-255 or a percentage 0-100%
|
||||||
*/
|
*/
|
||||||
private static ColorUIResource parseColorRgbOrRgba( boolean hasAlpha, List<String> params,
|
private static ColorUIResource parseColorRgbOrRgba( boolean hasAlpha, List<String> params,
|
||||||
Function<String, String> resolver, boolean reportError )
|
Function<String, String> resolver )
|
||||||
|
throws IllegalArgumentException
|
||||||
{
|
{
|
||||||
if( hasAlpha && params.size() == 2 ) {
|
if( hasAlpha && params.size() == 2 ) {
|
||||||
// syntax rgba(color,alpha), which allows adding alpha to any color
|
// syntax rgba(color,alpha), which allows adding alpha to any color
|
||||||
@@ -825,7 +923,7 @@ class UIDefaultsLoader
|
|||||||
String colorStr = params.get( 0 );
|
String colorStr = params.get( 0 );
|
||||||
int alpha = parseInteger( params.get( 1 ), 0, 255, true );
|
int alpha = parseInteger( params.get( 1 ), 0, 255, true );
|
||||||
|
|
||||||
ColorUIResource color = (ColorUIResource) parseColorOrFunction( resolver.apply( colorStr ), resolver, reportError );
|
ColorUIResource color = (ColorUIResource) parseColorOrFunction( resolver.apply( colorStr ), resolver );
|
||||||
return new ColorUIResource( new Color( ((alpha & 0xff) << 24) | (color.getRGB() & 0xffffff), true ) );
|
return new ColorUIResource( new Color( ((alpha & 0xff) << 24) | (color.getRGB() & 0xffffff), true ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -846,7 +944,9 @@ class UIDefaultsLoader
|
|||||||
* - lightness: a percentage 0-100%
|
* - lightness: a percentage 0-100%
|
||||||
* - alpha: a percentage 0-100%
|
* - alpha: a percentage 0-100%
|
||||||
*/
|
*/
|
||||||
private static ColorUIResource parseColorHslOrHsla( boolean hasAlpha, List<String> params ) {
|
private static ColorUIResource parseColorHslOrHsla( boolean hasAlpha, List<String> params )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
int hue = parseInteger( params.get( 0 ), 0, 360, false );
|
int hue = parseInteger( params.get( 0 ), 0, 360, false );
|
||||||
int saturation = parsePercentage( params.get( 1 ) );
|
int saturation = parsePercentage( params.get( 1 ) );
|
||||||
int lightness = parsePercentage( params.get( 2 ) );
|
int lightness = parsePercentage( params.get( 2 ) );
|
||||||
@@ -865,7 +965,8 @@ class UIDefaultsLoader
|
|||||||
* - options: [relative] [autoInverse] [noAutoInverse] [lazy] [derived]
|
* - options: [relative] [autoInverse] [noAutoInverse] [lazy] [derived]
|
||||||
*/
|
*/
|
||||||
private static Object parseColorHSLIncreaseDecrease( int hslIndex, boolean increase,
|
private static Object parseColorHSLIncreaseDecrease( int hslIndex, boolean increase,
|
||||||
List<String> params, Function<String, String> resolver, boolean reportError )
|
List<String> params, Function<String, String> resolver )
|
||||||
|
throws IllegalArgumentException
|
||||||
{
|
{
|
||||||
String colorStr = params.get( 0 );
|
String colorStr = params.get( 0 );
|
||||||
int amount = parsePercentage( params.get( 1 ) );
|
int amount = parsePercentage( params.get( 1 ) );
|
||||||
@@ -900,7 +1001,7 @@ class UIDefaultsLoader
|
|||||||
}
|
}
|
||||||
|
|
||||||
// parse base color, apply function and create derived color
|
// parse base color, apply function and create derived color
|
||||||
return parseFunctionBaseColor( colorStr, function, derived, resolver, reportError );
|
return parseFunctionBaseColor( colorStr, function, derived, resolver );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -909,7 +1010,9 @@ class UIDefaultsLoader
|
|||||||
* - amount: percentage 0-100%
|
* - amount: percentage 0-100%
|
||||||
* - options: [derived] [lazy]
|
* - options: [derived] [lazy]
|
||||||
*/
|
*/
|
||||||
private static Object parseColorFade( List<String> params, Function<String, String> resolver, boolean reportError ) {
|
private static Object parseColorFade( List<String> params, Function<String, String> resolver )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
String colorStr = params.get( 0 );
|
String colorStr = params.get( 0 );
|
||||||
int amount = parsePercentage( params.get( 1 ) );
|
int amount = parsePercentage( params.get( 1 ) );
|
||||||
boolean derived = false;
|
boolean derived = false;
|
||||||
@@ -934,7 +1037,7 @@ class UIDefaultsLoader
|
|||||||
}
|
}
|
||||||
|
|
||||||
// parse base color, apply function and create derived color
|
// parse base color, apply function and create derived color
|
||||||
return parseFunctionBaseColor( colorStr, function, derived, resolver, reportError );
|
return parseFunctionBaseColor( colorStr, function, derived, resolver );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -943,9 +1046,11 @@ class UIDefaultsLoader
|
|||||||
* - angle: number of degrees to rotate
|
* - angle: number of degrees to rotate
|
||||||
* - options: [derived]
|
* - options: [derived]
|
||||||
*/
|
*/
|
||||||
private static Object parseColorSpin( List<String> params, Function<String, String> resolver, boolean reportError ) {
|
private static Object parseColorSpin( List<String> params, Function<String, String> resolver )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
String colorStr = params.get( 0 );
|
String colorStr = params.get( 0 );
|
||||||
int amount = parseInteger( params.get( 1 ), true );
|
int amount = parseInteger( params.get( 1 ) );
|
||||||
boolean derived = false;
|
boolean derived = false;
|
||||||
|
|
||||||
if( params.size() > 2 ) {
|
if( params.size() > 2 ) {
|
||||||
@@ -957,7 +1062,7 @@ class UIDefaultsLoader
|
|||||||
ColorFunction function = new ColorFunctions.HSLIncreaseDecrease( 0, true, amount, false, false );
|
ColorFunction function = new ColorFunctions.HSLIncreaseDecrease( 0, true, amount, false, false );
|
||||||
|
|
||||||
// parse base color, apply function and create derived color
|
// parse base color, apply function and create derived color
|
||||||
return parseFunctionBaseColor( colorStr, function, derived, resolver, reportError );
|
return parseFunctionBaseColor( colorStr, function, derived, resolver );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -970,11 +1075,12 @@ class UIDefaultsLoader
|
|||||||
* - options: [derived]
|
* - options: [derived]
|
||||||
*/
|
*/
|
||||||
private static Object parseColorChange( int hslIndex,
|
private static Object parseColorChange( int hslIndex,
|
||||||
List<String> params, Function<String, String> resolver, boolean reportError )
|
List<String> params, Function<String, String> resolver )
|
||||||
|
throws IllegalArgumentException
|
||||||
{
|
{
|
||||||
String colorStr = params.get( 0 );
|
String colorStr = params.get( 0 );
|
||||||
int value = (hslIndex == 0)
|
int value = (hslIndex == 0)
|
||||||
? parseInteger( params.get( 1 ), true )
|
? parseInteger( params.get( 1 ) )
|
||||||
: parsePercentage( params.get( 1 ) );
|
: parsePercentage( params.get( 1 ) );
|
||||||
boolean derived = false;
|
boolean derived = false;
|
||||||
|
|
||||||
@@ -987,7 +1093,7 @@ class UIDefaultsLoader
|
|||||||
ColorFunction function = new ColorFunctions.HSLChange( hslIndex, value );
|
ColorFunction function = new ColorFunctions.HSLChange( hslIndex, value );
|
||||||
|
|
||||||
// parse base color, apply function and create derived color
|
// parse base color, apply function and create derived color
|
||||||
return parseFunctionBaseColor( colorStr, function, derived, resolver, reportError );
|
return parseFunctionBaseColor( colorStr, function, derived, resolver );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -999,7 +1105,9 @@ class UIDefaultsLoader
|
|||||||
* - 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
|
||||||
*/
|
*/
|
||||||
private static Object parseColorMix( String color1Str, List<String> params, Function<String, String> resolver, boolean reportError ) {
|
private static Object parseColorMix( String color1Str, List<String> params, Function<String, String> resolver )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
if( color1Str == null )
|
if( color1Str == null )
|
||||||
color1Str = params.get( i++ );
|
color1Str = params.get( i++ );
|
||||||
@@ -1007,7 +1115,7 @@ class UIDefaultsLoader
|
|||||||
int weight = (params.size() > i) ? parsePercentage( params.get( i ) ) : 50;
|
int weight = (params.size() > i) ? parsePercentage( params.get( i ) ) : 50;
|
||||||
|
|
||||||
// parse second color
|
// parse second color
|
||||||
ColorUIResource color2 = (ColorUIResource) parseColorOrFunction( resolver.apply( color2Str ), resolver, reportError );
|
ColorUIResource color2 = (ColorUIResource) parseColorOrFunction( resolver.apply( color2Str ), resolver );
|
||||||
if( color2 == null )
|
if( color2 == null )
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@@ -1015,7 +1123,7 @@ class UIDefaultsLoader
|
|||||||
ColorFunction function = new ColorFunctions.Mix( color2, weight );
|
ColorFunction function = new ColorFunctions.Mix( color2, weight );
|
||||||
|
|
||||||
// parse first color, apply function and create mixed color
|
// parse first color, apply function and create mixed color
|
||||||
return parseFunctionBaseColor( color1Str, function, false, resolver, reportError );
|
return parseFunctionBaseColor( color1Str, function, false, resolver );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1026,14 +1134,16 @@ class UIDefaultsLoader
|
|||||||
* - threshold: the threshold (in range 0-100%) to specify where the transition
|
* - threshold: the threshold (in range 0-100%) to specify where the transition
|
||||||
* from "dark" to "light" is (default is 43%)
|
* from "dark" to "light" is (default is 43%)
|
||||||
*/
|
*/
|
||||||
private static Object parseColorContrast( List<String> params, Function<String, String> resolver, boolean reportError ) {
|
private static Object parseColorContrast( List<String> params, Function<String, String> resolver )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
String colorStr = params.get( 0 );
|
String colorStr = params.get( 0 );
|
||||||
String darkStr = params.get( 1 );
|
String darkStr = params.get( 1 );
|
||||||
String lightStr = params.get( 2 );
|
String lightStr = params.get( 2 );
|
||||||
int threshold = (params.size() > 3) ? parsePercentage( params.get( 3 ) ) : 43;
|
int threshold = (params.size() > 3) ? parsePercentage( params.get( 3 ) ) : 43;
|
||||||
|
|
||||||
// parse color to compare against
|
// parse color to compare against
|
||||||
ColorUIResource color = (ColorUIResource) parseColorOrFunction( resolver.apply( colorStr ), resolver, reportError );
|
ColorUIResource color = (ColorUIResource) parseColorOrFunction( resolver.apply( colorStr ), resolver );
|
||||||
if( color == null )
|
if( color == null )
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@@ -1043,7 +1153,7 @@ class UIDefaultsLoader
|
|||||||
: darkStr;
|
: darkStr;
|
||||||
|
|
||||||
// parse dark or light color
|
// parse dark or light color
|
||||||
return parseColorOrFunction( resolver.apply( darkOrLightColor ), resolver, reportError );
|
return parseColorOrFunction( resolver.apply( darkOrLightColor ), resolver );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1052,12 +1162,14 @@ class UIDefaultsLoader
|
|||||||
* the alpha of this color is used as weight to mix the two colors
|
* the alpha of this color is used as weight to mix the two colors
|
||||||
* - background: a background color (e.g. #f00) or a color function
|
* - background: a background color (e.g. #f00) or a color function
|
||||||
*/
|
*/
|
||||||
private static ColorUIResource parseColorOver( List<String> params, Function<String, String> resolver, boolean reportError ) {
|
private static ColorUIResource parseColorOver( List<String> params, Function<String, String> resolver )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
String foregroundStr = params.get( 0 );
|
String foregroundStr = params.get( 0 );
|
||||||
String backgroundStr = params.get( 1 );
|
String backgroundStr = params.get( 1 );
|
||||||
|
|
||||||
// parse foreground color
|
// parse foreground color
|
||||||
ColorUIResource foreground = (ColorUIResource) parseColorOrFunction( resolver.apply( foregroundStr ), resolver, reportError );
|
ColorUIResource foreground = (ColorUIResource) parseColorOrFunction( resolver.apply( foregroundStr ), resolver );
|
||||||
if( foreground == null || foreground.getAlpha() == 255 )
|
if( foreground == null || foreground.getAlpha() == 255 )
|
||||||
return foreground;
|
return foreground;
|
||||||
|
|
||||||
@@ -1065,7 +1177,7 @@ class UIDefaultsLoader
|
|||||||
ColorUIResource foreground2 = new ColorUIResource( foreground.getRGB() );
|
ColorUIResource foreground2 = new ColorUIResource( foreground.getRGB() );
|
||||||
|
|
||||||
// parse background color
|
// parse background color
|
||||||
ColorUIResource background = (ColorUIResource) parseColorOrFunction( resolver.apply( backgroundStr ), resolver, reportError );
|
ColorUIResource background = (ColorUIResource) parseColorOrFunction( resolver.apply( backgroundStr ), resolver );
|
||||||
if( background == null )
|
if( background == null )
|
||||||
return foreground2;
|
return foreground2;
|
||||||
|
|
||||||
@@ -1075,11 +1187,12 @@ class UIDefaultsLoader
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static Object parseFunctionBaseColor( String colorStr, ColorFunction function,
|
private static Object parseFunctionBaseColor( String colorStr, ColorFunction function,
|
||||||
boolean derived, Function<String, String> resolver, boolean reportError )
|
boolean derived, Function<String, String> resolver )
|
||||||
|
throws IllegalArgumentException
|
||||||
{
|
{
|
||||||
// parse base color
|
// parse base color
|
||||||
String resolvedColorStr = resolver.apply( colorStr );
|
String resolvedColorStr = resolver.apply( colorStr );
|
||||||
ColorUIResource baseColor = (ColorUIResource) parseColorOrFunction( resolvedColorStr, resolver, reportError );
|
ColorUIResource baseColor = (ColorUIResource) parseColorOrFunction( resolvedColorStr, resolver );
|
||||||
if( baseColor == null )
|
if( baseColor == null )
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@@ -1107,7 +1220,9 @@ class UIDefaultsLoader
|
|||||||
/**
|
/**
|
||||||
* 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]
|
||||||
*/
|
*/
|
||||||
private static Object parseFont( String value ) {
|
private static Object parseFont( String value )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
Object font = fontCache.get( value );
|
Object font = fontCache.get( value );
|
||||||
if( font != null )
|
if( font != null )
|
||||||
return font;
|
return font;
|
||||||
@@ -1163,11 +1278,11 @@ class UIDefaultsLoader
|
|||||||
throw new IllegalArgumentException( "size specified more than once in '" + value + "'" );
|
throw new IllegalArgumentException( "size specified more than once in '" + value + "'" );
|
||||||
|
|
||||||
if( firstChar == '+' || firstChar == '-' )
|
if( firstChar == '+' || firstChar == '-' )
|
||||||
relativeSize = parseInteger( param, true );
|
relativeSize = parseInteger( param );
|
||||||
else if( param.endsWith( "%" ) )
|
else if( param.endsWith( "%" ) )
|
||||||
scaleSize = parseInteger( param.substring( 0, param.length() - 1 ), true ) / 100f;
|
scaleSize = parseInteger( param.substring( 0, param.length() - 1 ) ) / 100f;
|
||||||
else
|
else
|
||||||
absoluteSize = parseInteger( param, true );
|
absoluteSize = parseInteger( param );
|
||||||
} else if( firstChar == '$' ) {
|
} else if( firstChar == '$' ) {
|
||||||
// reference to base font
|
// reference to base font
|
||||||
if( baseFontKey != null )
|
if( baseFontKey != null )
|
||||||
@@ -1205,7 +1320,9 @@ class UIDefaultsLoader
|
|||||||
return font;
|
return font;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int parsePercentage( String value ) {
|
private static int parsePercentage( String value )
|
||||||
|
throws IllegalArgumentException, NumberFormatException
|
||||||
|
{
|
||||||
if( !value.endsWith( "%" ) )
|
if( !value.endsWith( "%" ) )
|
||||||
throw new NumberFormatException( "invalid percentage '" + value + "'" );
|
throw new NumberFormatException( "invalid percentage '" + value + "'" );
|
||||||
|
|
||||||
@@ -1221,7 +1338,9 @@ class UIDefaultsLoader
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Boolean parseBoolean( String value ) {
|
private static Boolean parseBoolean( String value )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
switch( value ) {
|
switch( value ) {
|
||||||
case "false": return false;
|
case "false": return false;
|
||||||
case "true": return true;
|
case "true": return true;
|
||||||
@@ -1229,87 +1348,101 @@ class UIDefaultsLoader
|
|||||||
throw new IllegalArgumentException( "invalid boolean '" + value + "'" );
|
throw new IllegalArgumentException( "invalid boolean '" + value + "'" );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Character parseCharacter( String value ) {
|
private static Character parseCharacter( String value )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
if( value.length() != 1 )
|
if( value.length() != 1 )
|
||||||
throw new IllegalArgumentException( "invalid character '" + value + "'" );
|
throw new IllegalArgumentException( "invalid character '" + value + "'" );
|
||||||
return value.charAt( 0 );
|
return value.charAt( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Integer parseInteger( String value, int min, int max, boolean allowPercentage ) {
|
private static Integer parseInteger( String value, int min, int max, boolean allowPercentage )
|
||||||
|
throws IllegalArgumentException, NumberFormatException
|
||||||
|
{
|
||||||
if( allowPercentage && value.endsWith( "%" ) ) {
|
if( allowPercentage && value.endsWith( "%" ) ) {
|
||||||
int percent = parsePercentage( value );
|
int percent = parsePercentage( value );
|
||||||
return (max * percent) / 100;
|
return (max * percent) / 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
Integer integer = parseInteger( value, true );
|
Integer integer = parseInteger( value );
|
||||||
if( integer < min || integer > max )
|
if( integer < min || integer > max )
|
||||||
throw new NumberFormatException( "integer '" + value + "' out of range (" + min + '-' + max + ')' );
|
throw new NumberFormatException( "integer '" + value + "' out of range (" + min + '-' + max + ')' );
|
||||||
return integer;
|
return integer;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Integer parseInteger( String value, boolean reportError ) {
|
private static Integer parseInteger( String value )
|
||||||
|
throws NumberFormatException
|
||||||
|
{
|
||||||
try {
|
try {
|
||||||
return Integer.parseInt( value );
|
return Integer.parseInt( value );
|
||||||
} catch( NumberFormatException ex ) {
|
} catch( NumberFormatException ex ) {
|
||||||
if( reportError )
|
|
||||||
throw new NumberFormatException( "invalid integer '" + value + "'" );
|
throw new NumberFormatException( "invalid integer '" + value + "'" );
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Number parseIntegerOrFloat( String value, boolean reportError ) {
|
private static Number parseIntegerOrFloat( String value )
|
||||||
|
throws NumberFormatException
|
||||||
|
{
|
||||||
try {
|
try {
|
||||||
return Integer.parseInt( value );
|
return Integer.parseInt( value );
|
||||||
} catch( NumberFormatException ex ) {
|
} catch( NumberFormatException ex ) {
|
||||||
try {
|
try {
|
||||||
return Float.parseFloat( value );
|
return Float.parseFloat( value );
|
||||||
} catch( NumberFormatException ex2 ) {
|
} catch( NumberFormatException ex2 ) {
|
||||||
if( reportError )
|
|
||||||
throw new NumberFormatException( "invalid integer or float '" + value + "'" );
|
throw new NumberFormatException( "invalid integer or float '" + value + "'" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Float parseFloat( String value, boolean reportError ) {
|
private static Float parseFloat( String value )
|
||||||
|
throws NumberFormatException
|
||||||
|
{
|
||||||
try {
|
try {
|
||||||
return Float.parseFloat( value );
|
return Float.parseFloat( value );
|
||||||
} catch( NumberFormatException ex ) {
|
} catch( NumberFormatException ex ) {
|
||||||
if( reportError )
|
|
||||||
throw new NumberFormatException( "invalid float '" + value + "'" );
|
throw new NumberFormatException( "invalid float '" + value + "'" );
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ActiveValue parseScaledInteger( String value ) {
|
private static ActiveValue parseScaledInteger( String value )
|
||||||
int val = parseInteger( value, true );
|
throws NumberFormatException
|
||||||
|
{
|
||||||
|
int val = parseInteger( value );
|
||||||
return t -> {
|
return t -> {
|
||||||
return UIScale.scale( val );
|
return UIScale.scale( val );
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ActiveValue parseScaledFloat( String value ) {
|
private static ActiveValue parseScaledFloat( String value )
|
||||||
float val = parseFloat( value, true );
|
throws NumberFormatException
|
||||||
|
{
|
||||||
|
float val = parseFloat( value );
|
||||||
return t -> {
|
return t -> {
|
||||||
return UIScale.scale( val );
|
return UIScale.scale( val );
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ActiveValue parseScaledInsets( String value ) {
|
private static ActiveValue parseScaledInsets( String value )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
Insets insets = parseInsets( value );
|
Insets insets = parseInsets( value );
|
||||||
return t -> {
|
return t -> {
|
||||||
return UIScale.scale( insets );
|
return UIScale.scale( insets );
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ActiveValue parseScaledDimension( String value ) {
|
private static ActiveValue parseScaledDimension( String value )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
Dimension dimension = parseDimension( value );
|
Dimension dimension = parseDimension( value );
|
||||||
return t -> {
|
return t -> {
|
||||||
return UIScale.scale( dimension );
|
return UIScale.scale( dimension );
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object parseGrayFilter( String value ) {
|
private static Object parseGrayFilter( String value )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
List<String> numbers = StringUtils.split( value, ',', true, false );
|
List<String> numbers = StringUtils.split( value, ',', true, false );
|
||||||
try {
|
try {
|
||||||
int brightness = Integer.parseInt( numbers.get( 0 ) );
|
int brightness = Integer.parseInt( numbers.get( 0 ) );
|
||||||
@@ -1344,11 +1477,95 @@ class UIDefaultsLoader
|
|||||||
start = i + 1;
|
start = i + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
strs.add( StringUtils.substringTrimmed( str, start ) );
|
|
||||||
|
// last param
|
||||||
|
String s = StringUtils.substringTrimmed( str, start );
|
||||||
|
if( !s.isEmpty() || !strs.isEmpty() )
|
||||||
|
strs.add( s );
|
||||||
|
|
||||||
return strs;
|
return strs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Object invokeConstructorOrStaticMethod( Executable[] constructorsOrMethods,
|
||||||
|
List<String> parts, Function<String, String> resolver )
|
||||||
|
throws Exception
|
||||||
|
{
|
||||||
|
// order constructors/methods by parameter types:
|
||||||
|
// - String parameters to the end
|
||||||
|
// - int before float parameters
|
||||||
|
constructorsOrMethods = constructorsOrMethods.clone();
|
||||||
|
Arrays.sort( constructorsOrMethods, (c1, c2) -> {
|
||||||
|
Class<?>[] ptypes1 = c1.getParameterTypes();
|
||||||
|
Class<?>[] ptypes2 = c2.getParameterTypes();
|
||||||
|
if( ptypes1.length != ptypes2.length )
|
||||||
|
return ptypes1.length - ptypes2.length;
|
||||||
|
|
||||||
|
for( int i = 0; i < ptypes1.length; i++ ) {
|
||||||
|
Class<?> pt1 = ptypes1[i];
|
||||||
|
Class<?> pt2 = ptypes2[i];
|
||||||
|
|
||||||
|
if( pt1 == pt2 )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// order methods with String parameters to the end
|
||||||
|
if( pt1 == String.class )
|
||||||
|
return 2;
|
||||||
|
if( pt2 == String.class )
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
// order int before float
|
||||||
|
if( pt1 == int.class )
|
||||||
|
return -1;
|
||||||
|
if( pt2 == int.class )
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
} );
|
||||||
|
|
||||||
|
// search for best constructor/method for given parameter values
|
||||||
|
for( Executable cm : constructorsOrMethods ) {
|
||||||
|
if( cm.getParameterCount() != parts.size() - 1 )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Object[] params = parseMethodParams( cm.getParameterTypes(), parts, resolver );
|
||||||
|
if( params == null )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// invoke constructor or static method
|
||||||
|
if( cm instanceof Constructor )
|
||||||
|
return ((Constructor<?>)cm).newInstance( params );
|
||||||
|
else
|
||||||
|
return ((Method)cm).invoke( null, params );
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Object[] parseMethodParams( Class<?>[] paramTypes, List<String> parts, Function<String, String> resolver ) {
|
||||||
|
Object[] params = new Object[paramTypes.length];
|
||||||
|
try {
|
||||||
|
for( int i = 0; i < params.length; i++ ) {
|
||||||
|
Class<?> paramType = paramTypes[i];
|
||||||
|
String paramValue = parts.get( i + 1 );
|
||||||
|
if( paramType == String.class )
|
||||||
|
params[i] = paramValue;
|
||||||
|
else if( paramType == boolean.class )
|
||||||
|
params[i] = parseBoolean( paramValue );
|
||||||
|
else if( paramType == int.class )
|
||||||
|
params[i] = parseInteger( paramValue );
|
||||||
|
else if( paramType == float.class )
|
||||||
|
params[i] = parseFloat( paramValue );
|
||||||
|
else if( paramType == Color.class )
|
||||||
|
params[i] = parseColorOrFunction( resolver.apply( paramValue ), resolver );
|
||||||
|
else
|
||||||
|
return null; // unsupported parameter type
|
||||||
|
}
|
||||||
|
} catch( IllegalArgumentException ex ) {
|
||||||
|
return null; // failed to parse parameter for expected parameter type
|
||||||
|
}
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For use in LazyValue to get value for given key from UIManager and report error
|
* For use in LazyValue to get value for given key from UIManager and report error
|
||||||
* if not found. If key is prefixed by '?', then no error is reported.
|
* if not found. If key is prefixed by '?', then no error is reported.
|
||||||
@@ -1366,7 +1583,7 @@ class UIDefaultsLoader
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void throwMissingParametersException( String value ) {
|
private static IllegalArgumentException newMissingParametersException( String value ) {
|
||||||
throw new IllegalArgumentException( "missing parameters in function '" + value + "'" );
|
return new IllegalArgumentException( "missing parameters in function '" + value + "'" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,9 +16,12 @@
|
|||||||
|
|
||||||
package com.formdev.flatlaf.icons;
|
package com.formdev.flatlaf.icons;
|
||||||
|
|
||||||
|
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.RenderingHints;
|
||||||
|
import java.awt.geom.Area;
|
||||||
import java.awt.geom.Path2D;
|
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;
|
||||||
@@ -36,6 +39,8 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
|||||||
public class FlatCapsLockIcon
|
public class FlatCapsLockIcon
|
||||||
extends FlatAbstractIcon
|
extends FlatAbstractIcon
|
||||||
{
|
{
|
||||||
|
private Path2D path;
|
||||||
|
|
||||||
public FlatCapsLockIcon() {
|
public FlatCapsLockIcon() {
|
||||||
super( 16, 16, UIManager.getColor( "PasswordField.capsLockIconColor" ) );
|
super( 16, 16, UIManager.getColor( "PasswordField.capsLockIconColor" ) );
|
||||||
}
|
}
|
||||||
@@ -63,16 +68,22 @@ public class FlatCapsLockIcon
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||||
<g fill="none" fill-rule="evenodd">
|
<g fill="none" fill-rule="evenodd">
|
||||||
<rect width="16" height="16" fill="#6E6E6E" rx="3"/>
|
<rect width="16" height="16" fill="#6E6E6E" rx="3"/>
|
||||||
<rect width="6" height="2" x="5" y="11.5" fill="#FFF"/>
|
<rect width="5" height="2" x="5.5" y="11.5" stroke="#FFF" stroke-linejoin="round"/>
|
||||||
<path fill="#FFF" d="M2,8 L8,2 L14,8 L11,8 L11,10 L5,10 L5,8 L2,8 Z"/>
|
<path stroke="#FFF" stroke-linejoin="round" d="M2.5,7.5 L8,2 L13.5,7.5 L10.5,7.5 L10.5,9.5 L5.5,9.5 L5.5,7.5 L2.5,7.5 Z"/>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE );
|
||||||
|
BasicStroke stroke = new BasicStroke( 1, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND );
|
||||||
|
|
||||||
|
if( path == null ) {
|
||||||
|
path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
||||||
path.append( new RoundRectangle2D.Float( 0, 0, 16, 16, 6, 6 ), false );
|
path.append( new RoundRectangle2D.Float( 0, 0, 16, 16, 6, 6 ), false );
|
||||||
path.append( new Rectangle2D.Float( 5, 11.5f, 6, 2 ), false );
|
path.append( new Area( stroke.createStrokedShape( new Rectangle2D.Float( 5.5f, 11.5f, 5, 2 ) ) ), false );
|
||||||
path.append( FlatUIUtils.createPath( 2,8, 8,2, 14,8, 11,8, 11,10, 5,10, 5,8 ), false );
|
path.append( new Area( stroke.createStrokedShape( FlatUIUtils.createPath(
|
||||||
|
2.5,7.5, 8,2, 13.5,7.5, 10.5,7.5, 10.5,9.5, 5.5,9.5, 5.5,7.5, 2.5,7.5 ) ) ), false );
|
||||||
|
}
|
||||||
g.fill( path );
|
g.fill( path );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -242,7 +242,7 @@ public class FlatCheckBoxIcon
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void paintCheckmark( Component c, Graphics2D g ) {
|
protected void paintCheckmark( Component c, Graphics2D g ) {
|
||||||
Path2D.Float path = new Path2D.Float();
|
Path2D.Float path = new Path2D.Float( Path2D.WIND_NON_ZERO, 3 );
|
||||||
path.moveTo( 4.5f, 7.5f );
|
path.moveTo( 4.5f, 7.5f );
|
||||||
path.lineTo( 6.6f, 10f );
|
path.lineTo( 6.6f, 10f );
|
||||||
path.lineTo( 11.25f, 3.5f );
|
path.lineTo( 11.25f, 3.5f );
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ public class FlatCheckBoxMenuItemIcon
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void paintCheckmark( Graphics2D g2 ) {
|
protected void paintCheckmark( Graphics2D g2 ) {
|
||||||
Path2D.Float path = new Path2D.Float();
|
Path2D.Float path = new Path2D.Float( Path2D.WIND_NON_ZERO, 3 );
|
||||||
path.moveTo( 4.5f, 7.5f );
|
path.moveTo( 4.5f, 7.5f );
|
||||||
path.lineTo( 6.6f, 10f );
|
path.lineTo( 6.6f, 10f );
|
||||||
path.lineTo( 11.25f, 3.5f );
|
path.lineTo( 11.25f, 3.5f );
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import java.awt.Color;
|
|||||||
import java.awt.Component;
|
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.Line2D;
|
|
||||||
import java.awt.geom.Path2D;
|
import java.awt.geom.Path2D;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.swing.AbstractButton;
|
import javax.swing.AbstractButton;
|
||||||
@@ -103,9 +102,11 @@ public class FlatClearIcon
|
|||||||
|
|
||||||
// paint cross
|
// paint cross
|
||||||
g.setColor( clearIconColor );
|
g.setColor( clearIconColor );
|
||||||
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD, 4 );
|
||||||
path.append( new Line2D.Float( 5,5, 11,11 ), false );
|
path.moveTo( 5, 5 );
|
||||||
path.append( new Line2D.Float( 5,11, 11,5 ), false );
|
path.lineTo( 11, 11 );
|
||||||
|
path.moveTo( 5, 11 );
|
||||||
|
path.lineTo( 11, 5 );
|
||||||
g.draw( path );
|
g.draw( path );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,21 +39,25 @@ public class FlatFileChooserDetailsViewIcon
|
|||||||
/*
|
/*
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||||
<g fill="none" fill-rule="evenodd">
|
<g fill="none" fill-rule="evenodd">
|
||||||
<rect width="2" height="2" x="2" y="3" fill="#6E6E6E"/>
|
<rect width="2" height="1" x="2" y="3" fill="#6E6E6E" rx=".5"/>
|
||||||
<rect width="2" height="2" x="2" y="7" fill="#6E6E6E"/>
|
<rect width="2" height="1" x="2" y="6" fill="#6E6E6E" rx=".5"/>
|
||||||
<rect width="2" height="2" x="2" y="11" fill="#6E6E6E"/>
|
<rect width="2" height="1" x="2" y="9" fill="#6E6E6E" rx=".5"/>
|
||||||
<rect width="8" height="2" x="6" y="3" fill="#6E6E6E"/>
|
<rect width="2" height="1" x="2" y="12" fill="#6E6E6E" rx=".5"/>
|
||||||
<rect width="8" height="2" x="6" y="7" fill="#6E6E6E"/>
|
<rect width="8" height="1" x="6" y="3" fill="#6E6E6E" rx=".5"/>
|
||||||
<rect width="8" height="2" x="6" y="11" fill="#6E6E6E"/>
|
<rect width="8" height="1" x="6" y="6" fill="#6E6E6E" rx=".5"/>
|
||||||
|
<rect width="8" height="1" x="6" y="9" fill="#6E6E6E" rx=".5"/>
|
||||||
|
<rect width="8" height="1" x="6" y="12" fill="#6E6E6E" rx=".5"/>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
g.fillRect( 2, 3, 2, 2 );
|
g.fillRoundRect( 2, 3, 2, 1, 1, 1 );
|
||||||
g.fillRect( 2, 7, 2, 2 );
|
g.fillRoundRect( 2, 6, 2, 1, 1, 1 );
|
||||||
g.fillRect( 2, 11, 2, 2 );
|
g.fillRoundRect( 2, 9, 2, 1, 1, 1 );
|
||||||
g.fillRect( 6, 3, 8, 2 );
|
g.fillRoundRect( 2, 12, 2, 1, 1, 1 );
|
||||||
g.fillRect( 6, 7, 8, 2 );
|
g.fillRoundRect( 6, 3, 8, 1, 1, 1 );
|
||||||
g.fillRect( 6, 11, 8, 2 );
|
g.fillRoundRect( 6, 6, 8, 1, 1, 1 );
|
||||||
|
g.fillRoundRect( 6, 9, 8, 1, 1, 1 );
|
||||||
|
g.fillRoundRect( 6, 12, 8, 1, 1, 1 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,10 @@
|
|||||||
|
|
||||||
package com.formdev.flatlaf.icons;
|
package com.formdev.flatlaf.icons;
|
||||||
|
|
||||||
|
import java.awt.BasicStroke;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.RenderingHints;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||||
|
|
||||||
@@ -39,10 +41,22 @@ public class FlatFileChooserHomeFolderIcon
|
|||||||
protected void paintIcon( Component c, Graphics2D g ) {
|
protected void paintIcon( Component c, Graphics2D g ) {
|
||||||
/*
|
/*
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||||
<polygon fill="#6E6E6E" fill-rule="evenodd" points="2 8 8 2 14 8 12 8 12 13 9 13 9 10 7 10 7 13 4 13 4 8"/>
|
<g fill="none" fill-rule="evenodd">
|
||||||
|
<polyline stroke="#6E6E6E" stroke-linejoin="round" points="6.5 13 6.5 9.5 9.5 9.5 9.5 13"/>
|
||||||
|
<path stroke="#6E6E6E" d="M3.5,6.5 L3.5,12.5 C3.5,13.0522847 3.94771525,13.5 4.5,13.5 L11.5,13.5 C12.0522847,13.5 12.5,13.0522847 12.5,12.5 L12.5,6.5 L12.5,6.5"/>
|
||||||
|
<polyline stroke="#6E6E6E" stroke-linecap="round" stroke-linejoin="round" points="1.5 8.5 8 2 14.5 8.5"/>
|
||||||
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
g.fill( FlatUIUtils.createPath( 2,8, 8,2, 14,8, 12,8, 12,13, 9,13, 9,10, 7,10, 7,13, 4,13, 4,8 ) );
|
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE );
|
||||||
|
g.setStroke( new BasicStroke( 1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) );
|
||||||
|
|
||||||
|
g.draw( FlatUIUtils.createPath( false, 6.5,13, 6.5,9.5, 9.5,9.5, 9.5,13 ) );
|
||||||
|
g.draw( FlatUIUtils.createPath( false, 3.5,6.5,
|
||||||
|
3.5,12.5, FlatUIUtils.QUAD_TO, 3.5,13.5, 4.5,13.5,
|
||||||
|
11.5,13.5, FlatUIUtils.QUAD_TO, 12.5,13.5, 12.5,12.5,
|
||||||
|
12.5,6.5 ) );
|
||||||
|
g.draw( FlatUIUtils.createPath( false, 1.5,8.5, 8,2, 14.5,8.5 ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,11 @@
|
|||||||
|
|
||||||
package com.formdev.flatlaf.icons;
|
package com.formdev.flatlaf.icons;
|
||||||
|
|
||||||
|
import java.awt.BasicStroke;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.RenderingHints;
|
||||||
|
import java.awt.geom.RoundRectangle2D;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -39,17 +42,20 @@ public class FlatFileChooserListViewIcon
|
|||||||
/*
|
/*
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||||
<g fill="none" fill-rule="evenodd">
|
<g fill="none" fill-rule="evenodd">
|
||||||
<rect width="4" height="4" x="3" y="3" fill="#6E6E6E"/>
|
<rect width="4" height="4" x="2.5" y="2.5" stroke="#6E6E6E" rx="1.5"/>
|
||||||
<rect width="4" height="4" x="3" y="9" fill="#6E6E6E"/>
|
<rect width="4" height="4" x="2.5" y="9.5" stroke="#6E6E6E" rx="1.5"/>
|
||||||
<rect width="4" height="4" x="9" y="9" fill="#6E6E6E"/>
|
<rect width="4" height="4" x="9.5" y="9.5" stroke="#6E6E6E" rx="1.5"/>
|
||||||
<rect width="4" height="4" x="9" y="3" fill="#6E6E6E"/>
|
<rect width="4" height="4" x="9.5" y="2.5" stroke="#6E6E6E" rx="1.5"/>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
g.fillRect( 3, 3, 4, 4 );
|
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE );
|
||||||
g.fillRect( 3, 9, 4, 4 );
|
g.setStroke( new BasicStroke( 1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) );
|
||||||
g.fillRect( 9, 9, 4, 4 );
|
|
||||||
g.fillRect( 9, 3, 4, 4 );
|
g.draw( new RoundRectangle2D.Float( 2.5f, 2.5f, 4, 4, 2, 2 ) );
|
||||||
|
g.draw( new RoundRectangle2D.Float( 2.5f, 9.5f, 4, 4, 2, 2 ) );
|
||||||
|
g.draw( new RoundRectangle2D.Float( 9.5f, 9.5f, 4, 4, 2, 2 ) );
|
||||||
|
g.draw( new RoundRectangle2D.Float( 9.5f, 2.5f, 4, 4, 2, 2 ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,10 +16,13 @@
|
|||||||
|
|
||||||
package com.formdev.flatlaf.icons;
|
package com.formdev.flatlaf.icons;
|
||||||
|
|
||||||
|
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.geom.Line2D;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* "new folder" icon for {@link javax.swing.JFileChooser}.
|
* "new folder" icon for {@link javax.swing.JFileChooser}.
|
||||||
@@ -31,6 +34,8 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
|||||||
public class FlatFileChooserNewFolderIcon
|
public class FlatFileChooserNewFolderIcon
|
||||||
extends FlatAbstractIcon
|
extends FlatAbstractIcon
|
||||||
{
|
{
|
||||||
|
private final Color greenColor = UIManager.getColor( "Actions.Green" );
|
||||||
|
|
||||||
public FlatFileChooserNewFolderIcon() {
|
public FlatFileChooserNewFolderIcon() {
|
||||||
super( 16, 16, UIManager.getColor( "Actions.Grey" ) );
|
super( 16, 16, UIManager.getColor( "Actions.Grey" ) );
|
||||||
}
|
}
|
||||||
@@ -40,13 +45,20 @@ public class FlatFileChooserNewFolderIcon
|
|||||||
/*
|
/*
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||||
<g fill="none" fill-rule="evenodd">
|
<g fill="none" fill-rule="evenodd">
|
||||||
<polygon fill="#6E6E6E" points="2 3 5.5 3 7 5 14 5 14 8 11 8 11 10 9 10 9 13 2 13"/>
|
<path stroke="#6E6E6E" d="M13,13.5 L3,13.5 C2.17157288,13.5 1.5,12.8284271 1.5,12 L1.5,4 C1.5,3.17157288 2.17157288,2.5 3,2.5 L6.29289322,2.5 C6.42550146,2.5 6.55267842,2.55267842 6.64644661,2.64644661 L8.5,4.5 L8.5,4.5 L13,4.5 C13.8284271,4.5 14.5,5.17157288 14.5,6 L14.5,12 C14.5,12.8284271 13.8284271,13.5 13,13.5 Z"/>
|
||||||
<path fill="#59A869" d="M14,11 L16,11 L16,13 L14,13 L14,15 L12,15 L12,13 L10,13 L10,11 L12,11 L12,9 L14,9 L14,11 Z"/>
|
<line x1="5.5" x2="10.5" y1="9" y2="9" stroke="#59A869" stroke-linecap="round"/>
|
||||||
|
<line x1="8" x2="8" y1="6.5" y2="11.5" stroke="#59A869" stroke-linecap="round"/>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
g.fill( FlatUIUtils.createPath( 2,3, 5.5,3, 7,5, 14,5, 14,8, 11,8, 11,10, 9,10, 9,13, 2,13 ) );
|
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE );
|
||||||
g.fill( FlatUIUtils.createPath( 14,11, 16,11, 16,13, 14,13, 14,15, 12,15, 12,13, 10,13, 10,11, 12,11, 12,9, 14,9, 14,11 ) );
|
g.setStroke( new BasicStroke( 1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) );
|
||||||
|
|
||||||
|
g.draw( FlatFileViewDirectoryIcon.createFolderPath() );
|
||||||
|
|
||||||
|
g.setColor( greenColor );
|
||||||
|
g.draw( new Line2D.Float( 5.5f, 9, 10.5f, 9 ) );
|
||||||
|
g.draw( new Line2D.Float( 8, 6.5f, 8, 11.5f ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,9 +16,12 @@
|
|||||||
|
|
||||||
package com.formdev.flatlaf.icons;
|
package com.formdev.flatlaf.icons;
|
||||||
|
|
||||||
|
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.RenderingHints;
|
||||||
|
import java.awt.geom.Line2D;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||||
|
|
||||||
@@ -44,15 +47,20 @@ public class FlatFileChooserUpFolderIcon
|
|||||||
/*
|
/*
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||||
<g fill="none" fill-rule="evenodd">
|
<g fill="none" fill-rule="evenodd">
|
||||||
<polygon fill="#6E6E6E" points="2 3 5.5 3 7 5 9 5 9 9 13 9 13 5 14 5 14 13 2 13"/>
|
<path stroke="#6E6E6E" d="M13,13.5 L3,13.5 C2.17157288,13.5 1.5,12.8284271 1.5,12 L1.5,4 C1.5,3.17157288 2.17157288,2.5 3,2.5 L6.29289322,2.5 C6.42550146,2.5 6.55267842,2.55267842 6.64644661,2.64644661 L8.5,4.5 L8.5,4.5 L13,4.5 C13.8284271,4.5 14.5,5.17157288 14.5,6 L14.5,12 C14.5,12.8284271 13.8284271,13.5 13,13.5 Z"/>
|
||||||
<path fill="#389FD6" d="M12,4 L12,8 L10,8 L10,4 L8,4 L11,1 L14,4 L12,4 Z"/>
|
<line x1="8" x2="8" y1="6.5" y2="11.5" stroke="#389FD6" stroke-linecap="round"/>
|
||||||
|
<polyline stroke="#389FD6" stroke-linecap="round" stroke-linejoin="round" points="5.5 9 8 6.5 10.5 9"/>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
g.fill( FlatUIUtils.createPath( 2,3, 5.5,3, 7,5, 9,5, 9,9, 13,9, 13,5, 14,5, 14,13, 2,13 ) );
|
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE );
|
||||||
|
g.setStroke( new BasicStroke( 1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) );
|
||||||
|
|
||||||
|
g.draw( FlatFileViewDirectoryIcon.createFolderPath() );
|
||||||
|
|
||||||
g.setColor( blueColor );
|
g.setColor( blueColor );
|
||||||
g.fill( FlatUIUtils.createPath( 12,4, 12,8, 10,8, 10,4, 8,4, 11,1, 14,4, 12,4 ) );
|
g.draw( new Line2D.Float( 8, 6.5f, 8, 11.5f ) );
|
||||||
|
g.draw( FlatUIUtils.createPath( false, 5.5,9, 8,6.5, 10.5,9 ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,10 +16,12 @@
|
|||||||
|
|
||||||
package com.formdev.flatlaf.icons;
|
package com.formdev.flatlaf.icons;
|
||||||
|
|
||||||
|
import java.awt.BasicStroke;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.geom.Path2D;
|
import java.awt.RenderingHints;
|
||||||
import java.awt.geom.Rectangle2D;
|
import java.awt.geom.Line2D;
|
||||||
|
import java.awt.geom.RoundRectangle2D;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -41,17 +43,18 @@ public class FlatFileViewComputerIcon
|
|||||||
/*
|
/*
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||||
<g fill="none" fill-rule="evenodd">
|
<g fill="none" fill-rule="evenodd">
|
||||||
<path fill="#6E6E6E" d="M2,3 L14,3 L14,11 L2,11 L2,3 Z M4,5 L4,9 L12,9 L12,5 L4,5 Z"/>
|
<rect width="11" height="7" x="2.5" y="3.5" stroke="#6E6E6E" rx="1"/>
|
||||||
<rect width="12" height="2" x="2" y="12" fill="#6E6E6E"/>
|
<line x1="8" x2="8" y1="11" y2="12" stroke="#6E6E6E"/>
|
||||||
|
<line x1="4.5" x2="11.5" y1="12.5" y2="12.5" stroke="#6E6E6E" stroke-linecap="round"/>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE );
|
||||||
path.append( new Rectangle2D.Float( 2, 3, 12, 8 ), false );
|
g.setStroke( new BasicStroke( 1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) );
|
||||||
path.append( new Rectangle2D.Float( 4, 5, 8, 4 ), false );
|
|
||||||
g.fill( path );
|
|
||||||
|
|
||||||
g.fillRect( 2, 12, 12, 2 );
|
g.draw( new RoundRectangle2D.Float( 2.5f, 3.5f, 11, 7, 2, 2 ) );
|
||||||
|
g.drawLine( 8, 11, 8, 12 );
|
||||||
|
g.draw( new Line2D.Float( 4.5f, 12.5f, 11.5f, 12.5f ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ package com.formdev.flatlaf.icons;
|
|||||||
|
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.RenderingHints;
|
||||||
|
import java.awt.geom.Path2D;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||||
|
|
||||||
@@ -31,6 +33,8 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
|||||||
public class FlatFileViewDirectoryIcon
|
public class FlatFileViewDirectoryIcon
|
||||||
extends FlatAbstractIcon
|
extends FlatAbstractIcon
|
||||||
{
|
{
|
||||||
|
private Path2D path;
|
||||||
|
|
||||||
public FlatFileViewDirectoryIcon() {
|
public FlatFileViewDirectoryIcon() {
|
||||||
super( 16, 16, UIManager.getColor( "Objects.Grey" ) );
|
super( 16, 16, UIManager.getColor( "Objects.Grey" ) );
|
||||||
}
|
}
|
||||||
@@ -39,10 +43,32 @@ public class FlatFileViewDirectoryIcon
|
|||||||
protected void paintIcon( Component c, Graphics2D g ) {
|
protected void paintIcon( Component c, Graphics2D g ) {
|
||||||
/*
|
/*
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||||
<polygon fill="#6E6E6E" fill-rule="evenodd" points="1 2 6 2 8 4 15 4 15 13 1 13"/>
|
<path fill="none" stroke="#6E6E6E" d="M13,13.5 L3,13.5 C2.17157288,13.5 1.5,12.8284271 1.5,12 L1.5,4 C1.5,3.17157288 2.17157288,2.5 3,2.5 L6.29289322,2.5 C6.42550146,2.5 6.55267842,2.55267842 6.64644661,2.64644661 L8.5,4.5 L8.5,4.5 L13,4.5 C13.8284271,4.5 14.5,5.17157288 14.5,6 L14.5,12 C14.5,12.8284271 13.8284271,13.5 13,13.5 Z"/>
|
||||||
</svg>
|
</svg>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
g.fill( FlatUIUtils.createPath( 1,2, 6,2, 8,4, 15,4, 15,13, 1,13 ) );
|
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE );
|
||||||
|
|
||||||
|
if( path == null )
|
||||||
|
path = createFolderPath();
|
||||||
|
g.draw( path );
|
||||||
|
}
|
||||||
|
|
||||||
|
static Path2D createFolderPath() {
|
||||||
|
double arc = 1.5;
|
||||||
|
double arc2 = 0.5;
|
||||||
|
return FlatUIUtils.createPath(
|
||||||
|
// bottom-right
|
||||||
|
14.5,13.5-arc, FlatUIUtils.QUAD_TO, 14.5,13.5, 14.5-arc,13.5,
|
||||||
|
// bottom-left
|
||||||
|
1.5+arc,13.5, FlatUIUtils.QUAD_TO, 1.5,13.5, 1.5,13.5-arc,
|
||||||
|
// top-left
|
||||||
|
1.5,2.5+arc, FlatUIUtils.QUAD_TO, 1.5,2.5, 1.5+arc,2.5,
|
||||||
|
// top-mid-left
|
||||||
|
6.5-arc2,2.5, FlatUIUtils.QUAD_TO, 6.5,2.5, 6.5+arc2,2.5+arc2,
|
||||||
|
// top-mid-right
|
||||||
|
8.5,4.5,
|
||||||
|
// top-right
|
||||||
|
14.5-arc,4.5, FlatUIUtils.QUAD_TO, 14.5,4.5, 14.5,4.5+arc );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,11 @@
|
|||||||
|
|
||||||
package com.formdev.flatlaf.icons;
|
package com.formdev.flatlaf.icons;
|
||||||
|
|
||||||
|
import java.awt.BasicStroke;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.RenderingHints;
|
||||||
|
import java.awt.geom.Path2D;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||||
|
|
||||||
@@ -31,6 +34,8 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
|||||||
public class FlatFileViewFileIcon
|
public class FlatFileViewFileIcon
|
||||||
extends FlatAbstractIcon
|
extends FlatAbstractIcon
|
||||||
{
|
{
|
||||||
|
private Path2D path;
|
||||||
|
|
||||||
public FlatFileViewFileIcon() {
|
public FlatFileViewFileIcon() {
|
||||||
super( 16, 16, UIManager.getColor( "Objects.Grey" ) );
|
super( 16, 16, UIManager.getColor( "Objects.Grey" ) );
|
||||||
}
|
}
|
||||||
@@ -39,14 +44,33 @@ public class FlatFileViewFileIcon
|
|||||||
protected void paintIcon( Component c, Graphics2D g ) {
|
protected void paintIcon( Component c, Graphics2D g ) {
|
||||||
/*
|
/*
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||||
<g fill="none" fill-rule="evenodd">
|
<g fill="none" fill-rule="evenodd" stroke-linejoin="round">
|
||||||
<polygon fill="#6E6E6E" points="8 6 8 1 13 1 13 15 3 15 3 6"/>
|
<path stroke="#6E6E6E" d="M4,1.5 L8.8,1.5 L8.8,1.5 L13.5,6.2 L13.5,13 C13.5,13.8284271 12.8284271,14.5 12,14.5 L4,14.5 C3.17157288,14.5 2.5,13.8284271 2.5,13 L2.5,3 C2.5,2.17157288 3.17157288,1.5 4,1.5 Z"/>
|
||||||
<polygon fill="#6E6E6E" points="3 5 7 5 7 1"/>
|
<path stroke="#6E6E6E" d="M8.5,2 L8.5,5 C8.5,5.82842712 9.17157288,6.5 10,6.5 L13,6.5 L13,6.5"/>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
g.fill( FlatUIUtils.createPath( 8,6, 8,1, 13,1, 13,15, 3,15, 3,6 ) );
|
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE );
|
||||||
g.fill( FlatUIUtils.createPath( 3,5, 7,5, 7,1 ) );
|
g.setStroke( new BasicStroke( 1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) );
|
||||||
|
|
||||||
|
if( path == null ) {
|
||||||
|
double arc = 1.5;
|
||||||
|
path = FlatUIUtils.createPath( false,
|
||||||
|
// top-left
|
||||||
|
2.5,1.5+arc, FlatUIUtils.QUAD_TO, 2.5,1.5, 2.5+arc,1.5,
|
||||||
|
// top-right
|
||||||
|
8.8,1.5, 13.5,6.2,
|
||||||
|
// bottom-right
|
||||||
|
13.5,14.5-arc, FlatUIUtils.QUAD_TO, 13.5,14.5, 13.5-arc,14.5,
|
||||||
|
// bottom-left
|
||||||
|
2.5+arc,14.5, FlatUIUtils.QUAD_TO, 2.5,14.5, 2.5,14.5-arc,
|
||||||
|
FlatUIUtils.CLOSE_PATH,
|
||||||
|
|
||||||
|
FlatUIUtils.MOVE_TO, 8.5,2,
|
||||||
|
8.5,6.5-arc, FlatUIUtils.QUAD_TO, 8.5,6.5, 8.5+arc,6.5,
|
||||||
|
13,6.5 );
|
||||||
|
}
|
||||||
|
g.draw( path );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,9 +16,10 @@
|
|||||||
|
|
||||||
package com.formdev.flatlaf.icons;
|
package com.formdev.flatlaf.icons;
|
||||||
|
|
||||||
|
import java.awt.BasicStroke;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.geom.Path2D;
|
import java.awt.RenderingHints;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||||
|
|
||||||
@@ -40,18 +41,22 @@ public class FlatFileViewFloppyDriveIcon
|
|||||||
protected void paintIcon( Component c, Graphics2D g ) {
|
protected void paintIcon( Component c, Graphics2D g ) {
|
||||||
/*
|
/*
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||||
<g fill="none" fill-rule="evenodd">
|
<g fill="none" fill-rule="evenodd" stroke-linejoin="round">
|
||||||
<path fill="#6E6E6E" d="M11,14 L11,11 L5,11 L5,14 L2,14 L2,2 L14,2 L14,14 L11,14 Z M4,4 L4,8 L12,8 L12,4 L4,4 Z"/>
|
<path stroke="#6E6E6E" d="M3.5,2.5 L11.5,2.5 L11.5,2.5 L13.5,4.5 L13.5,12.5 C13.5,13.0522847 13.0522847,13.5 12.5,13.5 L3.5,13.5 C2.94771525,13.5 2.5,13.0522847 2.5,12.5 L2.5,3.5 C2.5,2.94771525 2.94771525,2.5 3.5,2.5 Z"/>
|
||||||
<rect width="4" height="2" x="6" y="12" fill="#6E6E6E"/>
|
<polyline stroke="#6E6E6E" points="4.5 13 4.5 9.5 11.5 9.5 11.5 13"/>
|
||||||
|
<polyline stroke="#6E6E6E" points="5.5 3 5.5 5.5 10.5 5.5 10.5 3"/>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE );
|
||||||
path.append( FlatUIUtils.createPath( 11,14, 11,11, 5,11, 5,14, 2,14, 2,2, 14,2, 14,14, 11,14 ), false );
|
g.setStroke( new BasicStroke( 1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) );
|
||||||
path.append( FlatUIUtils.createPath( 4,4, 4,8, 12,8, 12,4, 4,4 ), false );
|
|
||||||
g.fill( path );
|
|
||||||
|
|
||||||
g.fillRect( 6, 12, 4, 2 );
|
g.draw( FlatUIUtils.createPath( 3.5,2.5, 11.5,2.5, 11.5,2.5, 13.5,4.5,
|
||||||
|
13.5,12.5, FlatUIUtils.QUAD_TO, 13.5,13.5, 12.5,13.5,
|
||||||
|
3.5,13.5, FlatUIUtils.QUAD_TO, 2.5,13.5, 2.5,12.5,
|
||||||
|
2.5,3.5, FlatUIUtils.QUAD_TO, 2.5,2.5, 3.5,2.5 ) );
|
||||||
|
g.draw( FlatUIUtils.createPath( false, 4.5,13, 4.5,9.5, 11.5,9.5, 11.5,13 ) );
|
||||||
|
g.draw( FlatUIUtils.createPath( false, 5.5,3, 5.5,5.5, 10.5,5.5, 10.5,3 ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,10 +16,12 @@
|
|||||||
|
|
||||||
package com.formdev.flatlaf.icons;
|
package com.formdev.flatlaf.icons;
|
||||||
|
|
||||||
|
import java.awt.BasicStroke;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.geom.Path2D;
|
import java.awt.RenderingHints;
|
||||||
import java.awt.geom.Rectangle2D;
|
import java.awt.geom.Ellipse2D;
|
||||||
|
import java.awt.geom.RoundRectangle2D;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -40,14 +42,19 @@ public class FlatFileViewHardDriveIcon
|
|||||||
protected void paintIcon( Component c, Graphics2D g ) {
|
protected void paintIcon( Component c, Graphics2D g ) {
|
||||||
/*
|
/*
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||||
<path fill="#6E6E6E" fill-rule="evenodd" d="M2,6 L14,6 L14,10 L2,10 L2,6 Z M12,8 L12,9 L13,9 L13,8 L12,8 Z M10,8 L10,9 L11,9 L11,8 L10,8 Z"/>
|
<g fill="none" fill-rule="evenodd">
|
||||||
|
<rect width="11" height="5" x="2.5" y="5.5" stroke="#6E6E6E" rx="1"/>
|
||||||
|
<circle cx="11.5" cy="8.5" r="1" fill="#6E6E6E"/>
|
||||||
|
<circle cx="9.5" cy="8.5" r="1" fill="#6E6E6E"/>
|
||||||
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE );
|
||||||
path.append( new Rectangle2D.Float( 2, 6, 12, 4 ), false );
|
g.setStroke( new BasicStroke( 1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) );
|
||||||
path.append( new Rectangle2D.Float( 12, 8, 1, 1 ), false );
|
|
||||||
path.append( new Rectangle2D.Float( 10, 8, 1, 1 ), false );
|
g.draw( new RoundRectangle2D.Float( 2.5f, 5.5f, 11, 5, 2, 2 ) );
|
||||||
g.fill( path );
|
g.fill( new Ellipse2D.Float( 10.8f, 7.8f, 1.4f, 1.4f ) );
|
||||||
|
g.fill( new Ellipse2D.Float( 8.8f, 7.8f, 1.4f, 1.4f ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,9 +17,11 @@
|
|||||||
package com.formdev.flatlaf.icons;
|
package com.formdev.flatlaf.icons;
|
||||||
|
|
||||||
import static com.formdev.flatlaf.util.UIScale.*;
|
import static com.formdev.flatlaf.util.UIScale.*;
|
||||||
|
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.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 java.util.Map;
|
||||||
@@ -96,7 +98,8 @@ public class FlatHelpButtonIcon
|
|||||||
<g fill="none" fill-rule="evenodd">
|
<g fill="none" fill-rule="evenodd">
|
||||||
<circle cx="11" cy="11" r="10.5" fill="#6E6E6E"/>
|
<circle cx="11" cy="11" r="10.5" fill="#6E6E6E"/>
|
||||||
<circle cx="11" cy="11" r="9.5" fill="#FFF"/>
|
<circle cx="11" cy="11" r="9.5" fill="#FFF"/>
|
||||||
<path fill="#6E6E6E" d="M10,17 L12,17 L12,15 L10,15 L10,17 Z M11,5 C8.8,5 7,6.8 7,9 L9,9 C9,7.9 9.9,7 11,7 C12.1,7 13,7.9 13,9 C13,11 10,10.75 10,14 L12,14 C12,11.75 15,11.5 15,9 C15,6.8 13.2,5 11,5 Z"/>
|
<path stroke="#6E6E6E" stroke-linecap="round" stroke-width="2" d="M8,8.5 C8.25,7 9.66585007,6 11,6 C12.5,6 14,7 14,8.5 C14,10.5 11,11 11,13"/>
|
||||||
|
<circle cx="11" cy="16" r="1.2" fill="#6E6E6E"/>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
*/
|
*/
|
||||||
@@ -147,22 +150,19 @@ public class FlatHelpButtonIcon
|
|||||||
g2.fill( new Ellipse2D.Float( xy, xy, wh, wh ) );
|
g2.fill( new Ellipse2D.Float( xy, xy, wh, wh ) );
|
||||||
|
|
||||||
// paint question mark
|
// paint question mark
|
||||||
Path2D q = new Path2D.Float();
|
Path2D q = new Path2D.Float( Path2D.WIND_NON_ZERO, 10 );
|
||||||
q.moveTo( 11, 5 );
|
q.moveTo( 8,8.5 );
|
||||||
q.curveTo( 8.8,5, 7,6.8, 7,9 );
|
q.curveTo( 8.25,7, 9.66585007,6, 11,6 );
|
||||||
q.lineTo( 9, 9 );
|
q.curveTo( 12.5,6, 14,7, 14,8.5 );
|
||||||
q.curveTo( 9,7.9, 9.9,7, 11,7 );
|
q.curveTo( 14,10.5, 11,11, 11,13 );
|
||||||
q.curveTo( 12.1,7, 13,7.9, 13,9 );
|
|
||||||
q.curveTo( 13,11, 10,10.75, 10,14 );
|
g2.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE );
|
||||||
q.lineTo( 12, 14 );
|
g2.setStroke( new BasicStroke( 2, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) );
|
||||||
q.curveTo( 12,11.75, 15,11.5, 15,9 );
|
|
||||||
q.curveTo( 15,6.8, 13.2,5, 11,5 );
|
|
||||||
q.closePath();
|
|
||||||
|
|
||||||
g2.translate( focusWidth, focusWidth );
|
g2.translate( focusWidth, focusWidth );
|
||||||
g2.setColor( enabled ? questionMarkColor : disabledQuestionMarkColor );
|
g2.setColor( enabled ? questionMarkColor : disabledQuestionMarkColor );
|
||||||
g2.fill( q );
|
g2.draw( q );
|
||||||
g2.fillRect( 10, 15, 2, 2 );
|
g2.fill( new Ellipse2D.Float( 9.8f, 14.8f, 2.4f, 2.4f ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ 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.Line2D;
|
|
||||||
import java.awt.geom.Path2D;
|
import java.awt.geom.Path2D;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import com.formdev.flatlaf.ui.FlatButtonUI;
|
import com.formdev.flatlaf.ui.FlatButtonUI;
|
||||||
@@ -54,13 +53,15 @@ public class FlatInternalFrameCloseIcon
|
|||||||
|
|
||||||
g.setColor( FlatButtonUI.buttonStateColor( c, c.getForeground(), null, null, hoverForeground, pressedForeground ) );
|
g.setColor( FlatButtonUI.buttonStateColor( c, c.getForeground(), null, null, hoverForeground, pressedForeground ) );
|
||||||
|
|
||||||
float mx = width / 2;
|
float mx = width / 2f;
|
||||||
float my = height / 2;
|
float my = height / 2f;
|
||||||
float r = 3.25f;
|
float r = 3.25f;
|
||||||
|
|
||||||
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD, 4 );
|
||||||
path.append( new Line2D.Float( mx - r, my - r, mx + r, my + r ), false );
|
path.moveTo( mx - r, my - r );
|
||||||
path.append( new Line2D.Float( mx - r, my + r, mx + r, my - r ), false );
|
path.lineTo( mx + r, my + r );
|
||||||
|
path.moveTo( mx - r, my + r );
|
||||||
|
path.lineTo( mx + r, my - r );
|
||||||
g.setStroke( new BasicStroke( 1f ) );
|
g.setStroke( new BasicStroke( 1f ) );
|
||||||
g.draw( path );
|
g.draw( path );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ package com.formdev.flatlaf.icons;
|
|||||||
import java.awt.Shape;
|
import java.awt.Shape;
|
||||||
import java.awt.geom.Ellipse2D;
|
import java.awt.geom.Ellipse2D;
|
||||||
import java.awt.geom.Path2D;
|
import java.awt.geom.Path2D;
|
||||||
import java.awt.geom.Rectangle2D;
|
import java.awt.geom.RoundRectangle2D;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* "Error" icon for {@link javax.swing.JOptionPane}.
|
* "Error" icon for {@link javax.swing.JOptionPane}.
|
||||||
@@ -40,8 +40,8 @@ public class FlatOptionPaneErrorIcon
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||||
<g fill="none" fill-rule="evenodd">
|
<g fill="none" fill-rule="evenodd">
|
||||||
<circle cx="16" cy="16" r="14" fill="#DB5860"/>
|
<circle cx="16" cy="16" r="14" fill="#DB5860"/>
|
||||||
<rect width="4" height="11" x="14" y="7" fill="#FFF"/>
|
<rect width="4" height="12" x="14" y="7" fill="#FFF" rx="2"/>
|
||||||
<rect width="4" height="4" x="14" y="21" fill="#FFF"/>
|
<circle cx="16" cy="23" r="2" fill="#FFF"/>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
*/
|
*/
|
||||||
@@ -54,8 +54,8 @@ public class FlatOptionPaneErrorIcon
|
|||||||
@Override
|
@Override
|
||||||
protected Shape createInside() {
|
protected Shape createInside() {
|
||||||
Path2D inside = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
Path2D inside = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
||||||
inside.append( new Rectangle2D.Float( 14, 7, 4, 11 ), false );
|
inside.append( new RoundRectangle2D.Float( 14, 7, 4, 12, 4, 4 ), false );
|
||||||
inside.append( new Rectangle2D.Float( 14, 21, 4, 4 ), false );
|
inside.append( new Ellipse2D.Float( 14, 21, 4, 4 ), false );
|
||||||
return inside;
|
return inside;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ package com.formdev.flatlaf.icons;
|
|||||||
import java.awt.Shape;
|
import java.awt.Shape;
|
||||||
import java.awt.geom.Ellipse2D;
|
import java.awt.geom.Ellipse2D;
|
||||||
import java.awt.geom.Path2D;
|
import java.awt.geom.Path2D;
|
||||||
import java.awt.geom.Rectangle2D;
|
import java.awt.geom.RoundRectangle2D;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* "Information" icon for {@link javax.swing.JOptionPane}.
|
* "Information" icon for {@link javax.swing.JOptionPane}.
|
||||||
@@ -40,8 +40,8 @@ public class FlatOptionPaneInformationIcon
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||||
<g fill="none" fill-rule="evenodd">
|
<g fill="none" fill-rule="evenodd">
|
||||||
<circle cx="16" cy="16" r="14" fill="#389FD6"/>
|
<circle cx="16" cy="16" r="14" fill="#389FD6"/>
|
||||||
<rect width="4" height="11" x="14" y="14" fill="#FFF"/>
|
<rect width="4" height="12" x="14" y="13" fill="#FFF" rx="2"/>
|
||||||
<rect width="4" height="4" x="14" y="7" fill="#FFF"/>
|
<circle cx="16" cy="9" r="2" fill="#FFF"/>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
*/
|
*/
|
||||||
@@ -54,8 +54,8 @@ public class FlatOptionPaneInformationIcon
|
|||||||
@Override
|
@Override
|
||||||
protected Shape createInside() {
|
protected Shape createInside() {
|
||||||
Path2D inside = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
Path2D inside = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
||||||
inside.append( new Rectangle2D.Float( 14, 14, 4, 11 ), false );
|
inside.append( new RoundRectangle2D.Float( 14, 13, 4, 12, 4, 4 ), false );
|
||||||
inside.append( new Rectangle2D.Float( 14, 7, 4, 4 ), false );
|
inside.append( new Ellipse2D.Float( 14, 7, 4, 4 ), false );
|
||||||
return inside;
|
return inside;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,10 +16,10 @@
|
|||||||
|
|
||||||
package com.formdev.flatlaf.icons;
|
package com.formdev.flatlaf.icons;
|
||||||
|
|
||||||
|
import java.awt.BasicStroke;
|
||||||
import java.awt.Shape;
|
import java.awt.Shape;
|
||||||
import java.awt.geom.Ellipse2D;
|
import java.awt.geom.Ellipse2D;
|
||||||
import java.awt.geom.Path2D;
|
import java.awt.geom.Path2D;
|
||||||
import java.awt.geom.Rectangle2D;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* "Question" icon for {@link javax.swing.JOptionPane}.
|
* "Question" icon for {@link javax.swing.JOptionPane}.
|
||||||
@@ -40,8 +40,8 @@ public class FlatOptionPaneQuestionIcon
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||||
<g fill="none" fill-rule="evenodd">
|
<g fill="none" fill-rule="evenodd">
|
||||||
<circle cx="16" cy="16" r="14" fill="#389FD6"/>
|
<circle cx="16" cy="16" r="14" fill="#389FD6"/>
|
||||||
<rect width="4" height="4" x="14" y="22" fill="#FFF"/>
|
<circle cx="16" cy="24" r="1.7" fill="#FFF"/>
|
||||||
<path fill="#FFF" d="M14,20 C14,20 18,20 18,20 C18,16 23,16 23,12 C23,8 20,6 16,6 C12,6 9,8 9,12 C9,12 13,12 13,12 C13,10 14,9 16,9 C18,9 19,10 19,12 C19,15 14,15 14,20 Z"/>
|
<path stroke="#FFF" stroke-linecap="round" stroke-width="3" d="M11.5,11.75 C11.75,9.5 13.75,8 16,8 C18.25,8 20.5,9.5 20.5,11.75 C20.5,14.75 16,15.5 16,19"/>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
*/
|
*/
|
||||||
@@ -53,21 +53,17 @@ public class FlatOptionPaneQuestionIcon
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Shape createInside() {
|
protected Shape createInside() {
|
||||||
Path2D q = new Path2D.Float();
|
Path2D q = new Path2D.Float( Path2D.WIND_NON_ZERO, 10 );
|
||||||
q.moveTo( 14, 20 );
|
q.moveTo( 11.5,11.75 );
|
||||||
q.lineTo( 18, 20 );
|
q.curveTo( 11.75,9.5, 13.75,8, 16,8 );
|
||||||
q.curveTo( 18, 16, 23, 16, 23, 12 );
|
q.curveTo( 18.25,8, 20.5,9.5, 20.5,11.75 );
|
||||||
q.curveTo( 23, 8, 20, 6, 16, 6 );
|
q.curveTo( 20.5,14.75, 16,15.5, 16,19 );
|
||||||
q.curveTo( 12, 6, 9, 8, 9, 12 );
|
|
||||||
q.curveTo( 9, 12, 13, 12, 13, 12 );
|
BasicStroke stroke = new BasicStroke( 3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER );
|
||||||
q.curveTo( 13, 10, 14, 9, 16, 9 );
|
|
||||||
q.curveTo( 18, 9, 19, 10, 19, 12 );
|
|
||||||
q.curveTo( 19, 15, 14, 15, 14, 20 );
|
|
||||||
q.closePath();
|
|
||||||
|
|
||||||
Path2D inside = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
Path2D inside = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
||||||
inside.append( new Rectangle2D.Float( 14, 22, 4, 4 ), false );
|
inside.append( new Ellipse2D.Float( 14.3f, 22.3f, 3.4f, 3.4f ), false );
|
||||||
inside.append( q, false );
|
inside.append( stroke.createStrokedShape( q ), false );
|
||||||
return inside;
|
return inside;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,9 @@
|
|||||||
package com.formdev.flatlaf.icons;
|
package com.formdev.flatlaf.icons;
|
||||||
|
|
||||||
import java.awt.Shape;
|
import java.awt.Shape;
|
||||||
|
import java.awt.geom.Ellipse2D;
|
||||||
import java.awt.geom.Path2D;
|
import java.awt.geom.Path2D;
|
||||||
import java.awt.geom.Rectangle2D;
|
import java.awt.geom.RoundRectangle2D;
|
||||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -39,23 +40,24 @@ public class FlatOptionPaneWarningIcon
|
|||||||
/*
|
/*
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||||
<g fill="none" fill-rule="evenodd">
|
<g fill="none" fill-rule="evenodd">
|
||||||
<polygon fill="#EDA200" points="16 2 31 28 1 28"/>
|
<path fill="#EDA200" d="M17.7364863,3.038851 L30.2901269,25.0077221 C30.8381469,25.966757 30.5049534,27.1884663 29.5459185,27.7364863 C29.2437231,27.9091694 28.9016945,28 28.5536406,28 L3.44635936,28 C2.34178986,28 1.44635936,27.1045695 1.44635936,26 C1.44635936,25.6519461 1.53718999,25.3099175 1.70987307,25.0077221 L14.2635137,3.038851 C14.8115337,2.0798161 16.033243,1.74662265 16.9922779,2.29464259 C17.3023404,2.47182119 17.5593077,2.72878844 17.7364863,3.038851 Z"/>
|
||||||
<rect width="4" height="8" x="14" y="10" fill="#FFF"/>
|
<rect width="4" height="11" x="14" y="8" fill="#FFF" rx="2"/>
|
||||||
<rect width="4" height="4" x="14" y="21" fill="#FFF"/>
|
<circle cx="16" cy="23" r="2" fill="#FFF"/>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Shape createOutside() {
|
protected Shape createOutside() {
|
||||||
return FlatUIUtils.createPath( 16,2, 31,28, 1,28 );
|
return FlatUIUtils.createRoundTrianglePath( 16,0, 32,28, 0,28, 4 );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Shape createInside() {
|
protected Shape createInside() {
|
||||||
Path2D inside = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
Path2D inside = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
||||||
inside.append( new Rectangle2D.Float( 14, 10, 4, 8 ), false );
|
inside.append( new RoundRectangle2D.Float( 14, 8, 4, 11, 4, 4 ), false );
|
||||||
inside.append( new Rectangle2D.Float( 14, 21, 4, 4 ), false );
|
inside.append( new Ellipse2D.Float( 14, 21, 4, 4 ), false );
|
||||||
return inside;
|
return inside;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ public class FlatSearchIcon
|
|||||||
@Styleable protected Color searchIconPressedColor = UIManager.getColor( "SearchField.searchIconPressedColor" );
|
@Styleable protected Color searchIconPressedColor = UIManager.getColor( "SearchField.searchIconPressedColor" );
|
||||||
|
|
||||||
private final boolean ignoreButtonState;
|
private final boolean ignoreButtonState;
|
||||||
|
private Area area;
|
||||||
|
|
||||||
public FlatSearchIcon() {
|
public FlatSearchIcon() {
|
||||||
this( false );
|
this( false );
|
||||||
@@ -89,9 +90,11 @@ public class FlatSearchIcon
|
|||||||
null, searchIconHoverColor, searchIconPressedColor ) );
|
null, searchIconHoverColor, searchIconPressedColor ) );
|
||||||
|
|
||||||
// paint magnifier
|
// paint magnifier
|
||||||
Area area = new Area( new Ellipse2D.Float( 2, 2, 10, 10 ) );
|
if( area == null ) {
|
||||||
|
area = new Area( new Ellipse2D.Float( 2, 2, 10, 10 ) );
|
||||||
area.subtract( new Area( new Ellipse2D.Float( 3, 3, 8, 8 ) ) );
|
area.subtract( new Area( new Ellipse2D.Float( 3, 3, 8, 8 ) ) );
|
||||||
area.add( new Area( FlatUIUtils.createPath( 10.813,9.75, 14,12.938, 12.938,14, 9.75,10.813 ) ) );
|
area.add( new Area( FlatUIUtils.createPath( 10.813,9.75, 14,12.938, 12.938,14, 9.75,10.813 ) ) );
|
||||||
|
}
|
||||||
g.fill( area );
|
g.fill( area );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import java.awt.Color;
|
|||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.geom.Line2D;
|
|
||||||
import java.awt.geom.Path2D;
|
import java.awt.geom.Path2D;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
@@ -91,18 +90,20 @@ public class FlatTabbedPaneCloseIcon
|
|||||||
closeSize.width, closeSize.height, closeArc, closeArc );
|
closeSize.width, closeSize.height, closeArc, closeArc );
|
||||||
}
|
}
|
||||||
|
|
||||||
// set cross color
|
// set color of cross
|
||||||
Color fg = FlatButtonUI.buttonStateColor( c, closeForeground, null, null, closeHoverForeground, closePressedForeground );
|
Color fg = FlatButtonUI.buttonStateColor( c, closeForeground, null, null, closeHoverForeground, closePressedForeground );
|
||||||
g.setColor( FlatUIUtils.deriveColor( fg, c.getForeground() ) );
|
g.setColor( FlatUIUtils.deriveColor( fg, c.getForeground() ) );
|
||||||
|
|
||||||
float mx = width / 2;
|
float mx = width / 2f;
|
||||||
float my = height / 2;
|
float my = height / 2f;
|
||||||
float r = ((bg != null) ? closeCrossFilledSize : closeCrossPlainSize) / 2;
|
float r = ((bg != null) ? closeCrossFilledSize : closeCrossPlainSize) / 2;
|
||||||
|
|
||||||
// paint cross
|
// paint cross
|
||||||
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD, 4 );
|
||||||
path.append( new Line2D.Float( mx - r, my - r, mx + r, my + r ), false );
|
path.moveTo( mx - r, my - r );
|
||||||
path.append( new Line2D.Float( mx - r, my + r, mx + r, my - r ), false );
|
path.lineTo( mx + r, my + r );
|
||||||
|
path.moveTo( mx - r, my + r );
|
||||||
|
path.lineTo( mx + r, my - r );
|
||||||
g.setStroke( new BasicStroke( closeCrossLineWidth ) );
|
g.setStroke( new BasicStroke( closeCrossLineWidth ) );
|
||||||
g.draw( path );
|
g.draw( path );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,8 +18,9 @@ package com.formdev.flatlaf.icons;
|
|||||||
|
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.RenderingHints;
|
||||||
|
import java.awt.geom.Path2D;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* "closed" icon for {@link javax.swing.JTree} used by {@link javax.swing.tree.DefaultTreeCellRenderer}.
|
* "closed" icon for {@link javax.swing.JTree} used by {@link javax.swing.tree.DefaultTreeCellRenderer}.
|
||||||
@@ -31,6 +32,8 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
|||||||
public class FlatTreeClosedIcon
|
public class FlatTreeClosedIcon
|
||||||
extends FlatAbstractIcon
|
extends FlatAbstractIcon
|
||||||
{
|
{
|
||||||
|
private Path2D path;
|
||||||
|
|
||||||
public FlatTreeClosedIcon() {
|
public FlatTreeClosedIcon() {
|
||||||
super( 16, 16, UIManager.getColor( "Tree.icon.closedColor" ) );
|
super( 16, 16, UIManager.getColor( "Tree.icon.closedColor" ) );
|
||||||
}
|
}
|
||||||
@@ -41,10 +44,14 @@ public class FlatTreeClosedIcon
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||||
<polygon fill="#6E6E6E" fill-rule="evenodd" points="1 2 6 2 8 4 15 4 15 13 1 13"/>
|
<path fill="none" stroke="#6E6E6E" d="M13,13.5 L3,13.5 C2.17157288,13.5 1.5,12.8284271 1.5,12 L1.5,4 C1.5,3.17157288 2.17157288,2.5 3,2.5 L6.29289322,2.5 C6.42550146,2.5 6.55267842,2.55267842 6.64644661,2.64644661 L8.5,4.5 L8.5,4.5 L13,4.5 C13.8284271,4.5 14.5,5.17157288 14.5,6 L14.5,12 C14.5,12.8284271 13.8284271,13.5 13,13.5 Z"/>
|
||||||
</svg>
|
</svg>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
g.fill( FlatUIUtils.createPath( 1,2, 6,2, 8,4, 15,4, 15,13, 1,13 ) );
|
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE );
|
||||||
|
|
||||||
|
if( path == null )
|
||||||
|
path = FlatFileViewDirectoryIcon.createFolderPath();
|
||||||
|
g.draw( path );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,9 +16,11 @@
|
|||||||
|
|
||||||
package com.formdev.flatlaf.icons;
|
package com.formdev.flatlaf.icons;
|
||||||
|
|
||||||
|
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.util.function.Function;
|
import java.util.function.Function;
|
||||||
import javax.swing.JTree;
|
import javax.swing.JTree;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
@@ -39,6 +41,7 @@ public class FlatTreeCollapsedIcon
|
|||||||
extends FlatAbstractIcon
|
extends FlatAbstractIcon
|
||||||
{
|
{
|
||||||
private final boolean chevron;
|
private final boolean chevron;
|
||||||
|
private Path2D path;
|
||||||
|
|
||||||
public FlatTreeCollapsedIcon() {
|
public FlatTreeCollapsedIcon() {
|
||||||
this( UIManager.getColor( "Tree.icon.collapsedColor" ) );
|
this( UIManager.getColor( "Tree.icon.collapsedColor" ) );
|
||||||
@@ -59,10 +62,15 @@ public class FlatTreeCollapsedIcon
|
|||||||
|
|
||||||
if( chevron ) {
|
if( chevron ) {
|
||||||
// chevron arrow
|
// chevron arrow
|
||||||
g.fill( FlatUIUtils.createPath( 3,1, 3,2.5, 6,5.5, 3,8.5, 3,10, 4.5,10, 9,5.5, 4.5,1 ) );
|
g.setStroke( new BasicStroke( 1f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER ) );
|
||||||
|
if( path == null )
|
||||||
|
path = FlatUIUtils.createPath( false, 3.5,1.5, 7.5,5.5, 3.5,9.5 );
|
||||||
|
g.draw( path );
|
||||||
} else {
|
} else {
|
||||||
// triangle arrow
|
// triangle arrow
|
||||||
g.fill( FlatUIUtils.createPath( 2,1, 2,10, 10,5.5 ) );
|
if( path == null )
|
||||||
|
path = FlatUIUtils.createPath( 2,1, 2,10, 10,5.5 );
|
||||||
|
g.fill( path );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,10 +16,14 @@
|
|||||||
|
|
||||||
package com.formdev.flatlaf.icons;
|
package com.formdev.flatlaf.icons;
|
||||||
|
|
||||||
|
import java.awt.BasicStroke;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.RenderingHints;
|
||||||
|
import java.awt.geom.Line2D;
|
||||||
|
import java.awt.geom.RoundRectangle2D;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
import com.formdev.flatlaf.util.ColorFunctions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* "leaf" icon for {@link javax.swing.JTree} used by {@link javax.swing.tree.DefaultTreeCellRenderer}.
|
* "leaf" icon for {@link javax.swing.JTree} used by {@link javax.swing.tree.DefaultTreeCellRenderer}.
|
||||||
@@ -42,13 +46,22 @@ public class FlatTreeLeafIcon
|
|||||||
/*
|
/*
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||||
<g fill="none" fill-rule="evenodd">
|
<g fill="none" fill-rule="evenodd">
|
||||||
<polygon fill="#6E6E6E" points="8 6 8 1 13 1 13 15 3 15 3 6"/>
|
<rect width="11" height="13" x="2.5" y="1.5" stroke="#6E6E6E" rx="1.5"/>
|
||||||
<polygon fill="#6E6E6E" points="3 5 7 5 7 1"/>
|
<line x1="5.5" x2="10.5" y1="5.5" y2="5.5" stroke="#6E6E6E" stroke-linecap="round" stroke-opacity=".6"/>
|
||||||
|
<line x1="5.5" x2="10.5" y1="8" y2="8" stroke="#6E6E6E" stroke-linecap="round" stroke-opacity=".6"/>
|
||||||
|
<line x1="5.5" x2="10.5" y1="10.5" y2="10.5" stroke="#6E6E6E" stroke-linecap="round" stroke-opacity=".6"/>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
g.fill( FlatUIUtils.createPath( 8,6, 8,1, 13,1, 13,15, 3,15, 3,6 ) );
|
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE );
|
||||||
g.fill( FlatUIUtils.createPath( 3,5, 7,5, 7,1 ) );
|
g.setStroke( new BasicStroke( 1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) );
|
||||||
|
|
||||||
|
g.draw( new RoundRectangle2D.Float( 2.5f, 1.5f, 11, 13, 3, 3 ) );
|
||||||
|
|
||||||
|
g.setColor( ColorFunctions.fade( g.getColor(), 0.6f ) );
|
||||||
|
g.draw( new Line2D.Float( 5.5f, 5.5f, 10.5f, 5.5f ) );
|
||||||
|
g.draw( new Line2D.Float( 5.5f, 8, 10.5f, 8 ) );
|
||||||
|
g.draw( new Line2D.Float( 5.5f, 10.5f, 10.5f, 10.5f ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,11 @@
|
|||||||
|
|
||||||
package com.formdev.flatlaf.icons;
|
package com.formdev.flatlaf.icons;
|
||||||
|
|
||||||
|
import java.awt.BasicStroke;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.RenderingHints;
|
||||||
|
import java.awt.geom.Path2D;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||||
|
|
||||||
@@ -31,6 +34,8 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
|||||||
public class FlatTreeOpenIcon
|
public class FlatTreeOpenIcon
|
||||||
extends FlatAbstractIcon
|
extends FlatAbstractIcon
|
||||||
{
|
{
|
||||||
|
private Path2D path;
|
||||||
|
|
||||||
public FlatTreeOpenIcon() {
|
public FlatTreeOpenIcon() {
|
||||||
super( 16, 16, UIManager.getColor( "Tree.icon.openColor" ) );
|
super( 16, 16, UIManager.getColor( "Tree.icon.openColor" ) );
|
||||||
}
|
}
|
||||||
@@ -41,14 +46,38 @@ public class FlatTreeOpenIcon
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||||
<g fill="none" fill-rule="evenodd">
|
<path fill="none" stroke="#6E6E6E" d="M2,13.5 L4.11538462,8.42307692 C4.34828895,7.86410651 4.89444872,7.5 5.5,7.5 L14.75,7.5 C15.0261424,7.5 15.25,7.72385763 15.25,8 C15.25,8.06601301 15.2369281,8.13137261 15.2115385,8.19230769 L13.3846154,12.5769231 C13.151711,13.1358935 12.6055513,13.5 12,13.5 L3,13.5 C2.17157288,13.5 1.5,12.8284271 1.5,12 L1.5,4 C1.5,3.17157288 2.17157288,2.5 3,2.5 L6.29289322,2.5 C6.42550146,2.5 6.55267842,2.55267842 6.64644661,2.64644661 L8.5,4.5 L8.5,4.5 L12,4.5 C12.8284271,4.5 13.5,5.17157288 13.5,6 L13.5,6.5 L13.5,6.5"/>
|
||||||
<polygon fill="#6E6E6E" points="1 2 6 2 8 4 14 4 14 6 3.5 6 1 11"/>
|
|
||||||
<polygon fill="#6E6E6E" points="4 7 16 7 13 13 1 13"/>
|
|
||||||
</g>
|
|
||||||
</svg>
|
</svg>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
g.fill( FlatUIUtils.createPath( 1,2, 6,2, 8,4, 14,4, 14,6, 3.5,6, 1,11 ) );
|
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE );
|
||||||
g.fill( FlatUIUtils.createPath( 4,7, 16,7, 13,13, 1,13 ) );
|
g.setStroke( new BasicStroke( 1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER ) );
|
||||||
|
|
||||||
|
if( path == null ) {
|
||||||
|
double arc = 1.5;
|
||||||
|
double arc2 = 0.5;
|
||||||
|
path = FlatUIUtils.createPath( false,
|
||||||
|
// bottom-left of opened part
|
||||||
|
2,13.5,
|
||||||
|
// top-left of opened part
|
||||||
|
FlatUIUtils.ROUNDED, 4.5,7.5, arc,
|
||||||
|
// top-right of opened part
|
||||||
|
FlatUIUtils.ROUNDED, 15.5,7.5, arc2,
|
||||||
|
|
||||||
|
// bottom-right
|
||||||
|
FlatUIUtils.ROUNDED, 13,13.5, arc,
|
||||||
|
// bottom-left
|
||||||
|
1.5+arc,13.5, FlatUIUtils.QUAD_TO, 1.5,13.5, 1.5,13.5-arc,
|
||||||
|
// top-left
|
||||||
|
1.5,2.5+arc, FlatUIUtils.QUAD_TO, 1.5,2.5, 1.5+arc,2.5,
|
||||||
|
// top-mid-left
|
||||||
|
6.5-arc2,2.5, FlatUIUtils.QUAD_TO, 6.5,2.5, 6.5+arc2,2.5+arc2,
|
||||||
|
// top-mid-right
|
||||||
|
8.5,4.5,
|
||||||
|
// top-right
|
||||||
|
13.5-arc,4.5, FlatUIUtils.QUAD_TO, 13.5,4.5, 13.5,4.5+arc,
|
||||||
|
13.5,6.5 );
|
||||||
|
}
|
||||||
|
g.draw( path );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import java.awt.Component;
|
|||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.RenderingHints;
|
import java.awt.RenderingHints;
|
||||||
import javax.swing.UIManager;
|
|
||||||
import com.formdev.flatlaf.ui.FlatButtonUI;
|
import com.formdev.flatlaf.ui.FlatButtonUI;
|
||||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||||
@@ -30,6 +29,7 @@ import com.formdev.flatlaf.util.HiDPIUtils;
|
|||||||
* Base class for window icons.
|
* Base class for window icons.
|
||||||
*
|
*
|
||||||
* @uiDefault TitlePane.buttonSize Dimension
|
* @uiDefault TitlePane.buttonSize Dimension
|
||||||
|
* @uiDefault TitlePane.buttonSymbolHeight int
|
||||||
* @uiDefault TitlePane.buttonHoverBackground Color
|
* @uiDefault TitlePane.buttonHoverBackground Color
|
||||||
* @uiDefault TitlePane.buttonPressedBackground Color
|
* @uiDefault TitlePane.buttonPressedBackground Color
|
||||||
*
|
*
|
||||||
@@ -38,17 +38,22 @@ import com.formdev.flatlaf.util.HiDPIUtils;
|
|||||||
public abstract class FlatWindowAbstractIcon
|
public abstract class FlatWindowAbstractIcon
|
||||||
extends FlatAbstractIcon
|
extends FlatAbstractIcon
|
||||||
{
|
{
|
||||||
|
private final int symbolHeight;
|
||||||
private final Color hoverBackground;
|
private final Color hoverBackground;
|
||||||
private final Color pressedBackground;
|
private final Color pressedBackground;
|
||||||
|
|
||||||
public FlatWindowAbstractIcon() {
|
/** @since 3.2 */
|
||||||
this( UIManager.getDimension( "TitlePane.buttonSize" ),
|
protected FlatWindowAbstractIcon( String windowStyle ) {
|
||||||
UIManager.getColor( "TitlePane.buttonHoverBackground" ),
|
this( FlatUIUtils.getSubUIDimension( "TitlePane.buttonSize", windowStyle ),
|
||||||
UIManager.getColor( "TitlePane.buttonPressedBackground" ) );
|
FlatUIUtils.getSubUIInt( "TitlePane.buttonSymbolHeight", windowStyle, 10 ),
|
||||||
|
FlatUIUtils.getSubUIColor( "TitlePane.buttonHoverBackground", windowStyle ),
|
||||||
|
FlatUIUtils.getSubUIColor( "TitlePane.buttonPressedBackground", windowStyle ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public FlatWindowAbstractIcon( Dimension size, Color hoverBackground, Color pressedBackground ) {
|
/** @since 3.2 */
|
||||||
|
protected FlatWindowAbstractIcon( Dimension size, int symbolHeight, Color hoverBackground, Color pressedBackground ) {
|
||||||
super( size.width, size.height, null );
|
super( size.width, size.height, null );
|
||||||
|
this.symbolHeight = symbolHeight;
|
||||||
this.hoverBackground = hoverBackground;
|
this.hoverBackground = hoverBackground;
|
||||||
this.pressedBackground = pressedBackground;
|
this.pressedBackground = pressedBackground;
|
||||||
}
|
}
|
||||||
@@ -66,7 +71,7 @@ public abstract class FlatWindowAbstractIcon
|
|||||||
protected void paintBackground( Component c, Graphics2D g ) {
|
protected void paintBackground( Component c, Graphics2D g ) {
|
||||||
Color background = FlatButtonUI.buttonStateColor( c, null, null, null, hoverBackground, pressedBackground );
|
Color background = FlatButtonUI.buttonStateColor( c, null, null, null, hoverBackground, pressedBackground );
|
||||||
if( background != null ) {
|
if( background != null ) {
|
||||||
// disable antialiasing for background rectangle painting to avoid blury edges when scaled (e.g. at 125% or 175%)
|
// disable antialiasing for background rectangle painting to avoid blurry edges when scaled (e.g. at 125% or 175%)
|
||||||
Object oldHint = g.getRenderingHint( RenderingHints.KEY_ANTIALIASING );
|
Object oldHint = g.getRenderingHint( RenderingHints.KEY_ANTIALIASING );
|
||||||
g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF );
|
g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF );
|
||||||
|
|
||||||
@@ -80,4 +85,9 @@ public abstract class FlatWindowAbstractIcon
|
|||||||
protected Color getForeground( Component c ) {
|
protected Color getForeground( Component c ) {
|
||||||
return c.getForeground();
|
return c.getForeground();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @since 3.2 */
|
||||||
|
protected int getSymbolHeight() {
|
||||||
|
return symbolHeight;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,10 +20,9 @@ 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.Line2D;
|
|
||||||
import java.awt.geom.Path2D;
|
import java.awt.geom.Path2D;
|
||||||
import javax.swing.UIManager;
|
|
||||||
import com.formdev.flatlaf.ui.FlatButtonUI;
|
import com.formdev.flatlaf.ui.FlatButtonUI;
|
||||||
|
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||||
import com.formdev.flatlaf.util.SystemInfo;
|
import com.formdev.flatlaf.util.SystemInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -39,27 +38,38 @@ import com.formdev.flatlaf.util.SystemInfo;
|
|||||||
public class FlatWindowCloseIcon
|
public class FlatWindowCloseIcon
|
||||||
extends FlatWindowAbstractIcon
|
extends FlatWindowAbstractIcon
|
||||||
{
|
{
|
||||||
private final Color hoverForeground = UIManager.getColor( "TitlePane.closeHoverForeground" );
|
private final Color hoverForeground;
|
||||||
private final Color pressedForeground = UIManager.getColor( "TitlePane.closePressedForeground" );
|
private final Color pressedForeground;
|
||||||
|
|
||||||
public FlatWindowCloseIcon() {
|
public FlatWindowCloseIcon() {
|
||||||
super( UIManager.getDimension( "TitlePane.buttonSize" ),
|
this( null );
|
||||||
UIManager.getColor( "TitlePane.closeHoverBackground" ),
|
}
|
||||||
UIManager.getColor( "TitlePane.closePressedBackground" ) );
|
|
||||||
|
/** @since 3.2 */
|
||||||
|
public FlatWindowCloseIcon( String windowStyle ) {
|
||||||
|
super( FlatUIUtils.getSubUIDimension( "TitlePane.buttonSize", windowStyle ),
|
||||||
|
FlatUIUtils.getSubUIInt( "TitlePane.buttonSymbolHeight", windowStyle, 10 ),
|
||||||
|
FlatUIUtils.getSubUIColor( "TitlePane.closeHoverBackground", windowStyle ),
|
||||||
|
FlatUIUtils.getSubUIColor( "TitlePane.closePressedBackground", windowStyle ) );
|
||||||
|
|
||||||
|
hoverForeground = FlatUIUtils.getSubUIColor( "TitlePane.closeHoverForeground", 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) (10 * scaleFactor);
|
int iwh = (int) (getSymbolHeight() * scaleFactor);
|
||||||
int ix = x + ((width - iwh) / 2);
|
int ix = x + ((width - iwh) / 2);
|
||||||
int iy = y + ((height - iwh) / 2);
|
int iy = y + ((height - iwh) / 2);
|
||||||
int ix2 = ix + iwh - 1;
|
int ix2 = ix + iwh - 1;
|
||||||
int iy2 = iy + iwh - 1;
|
int iy2 = iy + iwh - 1;
|
||||||
float thickness = SystemInfo.isWindows_11_orLater ? (float) scaleFactor : (int) scaleFactor;
|
float thickness = SystemInfo.isWindows_11_orLater ? (float) scaleFactor : (int) scaleFactor;
|
||||||
|
|
||||||
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD, 4 );
|
||||||
path.append( new Line2D.Float( ix, iy, ix2, iy2 ), false );
|
path.moveTo( ix, iy );
|
||||||
path.append( new Line2D.Float( ix, iy2, ix2, iy ), false );
|
path.lineTo( ix2, iy2 );
|
||||||
|
path.moveTo( ix, iy2 );
|
||||||
|
path.lineTo( ix2, iy );
|
||||||
g.setStroke( new BasicStroke( thickness ) );
|
g.setStroke( new BasicStroke( thickness ) );
|
||||||
g.draw( path );
|
g.draw( path );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,11 +27,17 @@ public class FlatWindowIconifyIcon
|
|||||||
extends FlatWindowAbstractIcon
|
extends FlatWindowAbstractIcon
|
||||||
{
|
{
|
||||||
public FlatWindowIconifyIcon() {
|
public FlatWindowIconifyIcon() {
|
||||||
|
this( null );
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @since 3.2 */
|
||||||
|
public FlatWindowIconifyIcon( String windowStyle ) {
|
||||||
|
super( 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 iw = (int) (10 * scaleFactor);
|
int iw = (int) (getSymbolHeight() * scaleFactor);
|
||||||
int ih = (int) scaleFactor;
|
int ih = (int) scaleFactor;
|
||||||
int ix = x + ((width - iw) / 2);
|
int ix = x + ((width - iw) / 2);
|
||||||
int iy = y + ((height - ih) / 2);
|
int iy = y + ((height - ih) / 2);
|
||||||
|
|||||||
@@ -29,11 +29,17 @@ public class FlatWindowMaximizeIcon
|
|||||||
extends FlatWindowAbstractIcon
|
extends FlatWindowAbstractIcon
|
||||||
{
|
{
|
||||||
public FlatWindowMaximizeIcon() {
|
public FlatWindowMaximizeIcon() {
|
||||||
|
this( null );
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @since 3.2 */
|
||||||
|
public FlatWindowMaximizeIcon( String windowStyle ) {
|
||||||
|
super( 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) (10 * scaleFactor);
|
int iwh = (int) (getSymbolHeight() * scaleFactor);
|
||||||
int ix = x + ((width - iwh) / 2);
|
int ix = x + ((width - iwh) / 2);
|
||||||
int iy = y + ((height - iwh) / 2);
|
int iy = y + ((height - iwh) / 2);
|
||||||
float thickness = SystemInfo.isWindows_11_orLater ? (float) scaleFactor : (int) scaleFactor;
|
float thickness = SystemInfo.isWindows_11_orLater ? (float) scaleFactor : (int) scaleFactor;
|
||||||
|
|||||||
@@ -32,18 +32,24 @@ public class FlatWindowRestoreIcon
|
|||||||
extends FlatWindowAbstractIcon
|
extends FlatWindowAbstractIcon
|
||||||
{
|
{
|
||||||
public FlatWindowRestoreIcon() {
|
public FlatWindowRestoreIcon() {
|
||||||
|
this( null );
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @since 3.2 */
|
||||||
|
public FlatWindowRestoreIcon( String windowStyle ) {
|
||||||
|
super( 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) (10 * scaleFactor);
|
int iwh = (int) (getSymbolHeight() * scaleFactor);
|
||||||
int ix = x + ((width - iwh) / 2);
|
int ix = x + ((width - iwh) / 2);
|
||||||
int iy = y + ((height - iwh) / 2);
|
int iy = y + ((height - iwh) / 2);
|
||||||
float thickness = SystemInfo.isWindows_11_orLater ? (float) scaleFactor : (int) scaleFactor;
|
float thickness = SystemInfo.isWindows_11_orLater ? (float) scaleFactor : (int) scaleFactor;
|
||||||
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) (8 * scaleFactor);
|
int rwh = (int) ((getSymbolHeight() - 2) * scaleFactor);
|
||||||
int ro2 = iwh - rwh;
|
int ro2 = iwh - rwh;
|
||||||
|
|
||||||
// upper-right rectangle
|
// upper-right rectangle
|
||||||
|
|||||||
@@ -502,9 +502,9 @@ class JsonParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean isHexDigit() {
|
private boolean isHexDigit() {
|
||||||
return current >= '0' && current <= '9'
|
return (current >= '0' && current <= '9')
|
||||||
|| current >= 'a' && current <= 'f'
|
|| (current >= 'a' && current <= 'f')
|
||||||
|| current >= 'A' && current <= 'F';
|
|| (current >= 'A' && current <= 'F');
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isEndOfText() {
|
private boolean isEndOfText() {
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ public class Location {
|
|||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (getClass() != obj.getClass()) {
|
if (!(obj instanceof Location)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Location other = (Location)obj;
|
Location other = (Location)obj;
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022 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.themes;
|
||||||
|
|
||||||
|
import javax.swing.UIManager;
|
||||||
|
import com.formdev.flatlaf.FlatDarkLaf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Flat LaF that imitates macOS dark look.
|
||||||
|
* <p>
|
||||||
|
* The UI defaults are loaded from {@code FlatMacDarkLaf.properties},
|
||||||
|
* {@code FlatDarkLaf.properties} and {@code FlatLaf.properties}.
|
||||||
|
*
|
||||||
|
* @author Karl Tauber
|
||||||
|
* @since 3
|
||||||
|
*/
|
||||||
|
public class FlatMacDarkLaf
|
||||||
|
extends FlatDarkLaf
|
||||||
|
{
|
||||||
|
public static final String NAME = "FlatLaf macOS Dark";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the application look and feel to this LaF
|
||||||
|
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
|
||||||
|
*/
|
||||||
|
public static boolean setup() {
|
||||||
|
return setup( new FlatMacDarkLaf() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds this look and feel to the set of available look and feels.
|
||||||
|
* <p>
|
||||||
|
* Useful if your application uses {@link UIManager#getInstalledLookAndFeels()}
|
||||||
|
* to query available LaFs and display them to the user in a combobox.
|
||||||
|
*/
|
||||||
|
public static void installLafInfo() {
|
||||||
|
installLafInfo( NAME, FlatMacDarkLaf.class );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "FlatLaf macOS Dark Look and Feel";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDark() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022 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.themes;
|
||||||
|
|
||||||
|
import javax.swing.UIManager;
|
||||||
|
import com.formdev.flatlaf.FlatLightLaf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Flat LaF that imitates macOS light look.
|
||||||
|
* <p>
|
||||||
|
* The UI defaults are loaded from {@code FlatMacLightLaf.properties},
|
||||||
|
* {@code FlatLightLaf.properties} and {@code FlatLaf.properties}.
|
||||||
|
*
|
||||||
|
* @author Karl Tauber
|
||||||
|
* @since 3
|
||||||
|
*/
|
||||||
|
public class FlatMacLightLaf
|
||||||
|
extends FlatLightLaf
|
||||||
|
{
|
||||||
|
public static final String NAME = "FlatLaf macOS Light";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the application look and feel to this LaF
|
||||||
|
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
|
||||||
|
*/
|
||||||
|
public static boolean setup() {
|
||||||
|
return setup( new FlatMacLightLaf() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds this look and feel to the set of available look and feels.
|
||||||
|
* <p>
|
||||||
|
* Useful if your application uses {@link UIManager#getInstalledLookAndFeels()}
|
||||||
|
* to query available LaFs and display them to the user in a combobox.
|
||||||
|
*/
|
||||||
|
public static void installLafInfo() {
|
||||||
|
installLafInfo( NAME, FlatMacLightLaf.class );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "FlatLaf macOS Light Look and Feel";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDark() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -49,8 +49,10 @@ public class FlatArrowButton
|
|||||||
protected Color pressedBackground;
|
protected Color pressedBackground;
|
||||||
|
|
||||||
private int arrowWidth = DEFAULT_ARROW_WIDTH;
|
private int arrowWidth = DEFAULT_ARROW_WIDTH;
|
||||||
|
private float arrowThickness = 1;
|
||||||
private float xOffset = 0;
|
private float xOffset = 0;
|
||||||
private float yOffset = 0;
|
private float yOffset = 0;
|
||||||
|
private boolean roundBorderAutoXOffset = true;
|
||||||
|
|
||||||
private boolean hover;
|
private boolean hover;
|
||||||
private boolean pressed;
|
private boolean pressed;
|
||||||
@@ -121,6 +123,16 @@ public class FlatArrowButton
|
|||||||
this.arrowWidth = arrowWidth;
|
this.arrowWidth = arrowWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @since 3 */
|
||||||
|
public float getArrowThickness() {
|
||||||
|
return arrowThickness;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @since 3 */
|
||||||
|
public void setArrowThickness( float arrowThickness ) {
|
||||||
|
this.arrowThickness = arrowThickness;
|
||||||
|
}
|
||||||
|
|
||||||
protected boolean isHover() {
|
protected boolean isHover() {
|
||||||
return hover;
|
return hover;
|
||||||
}
|
}
|
||||||
@@ -145,6 +157,16 @@ public class FlatArrowButton
|
|||||||
this.yOffset = yOffset;
|
this.yOffset = yOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @since 3 */
|
||||||
|
public boolean isRoundBorderAutoXOffset() {
|
||||||
|
return roundBorderAutoXOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @since 3 */
|
||||||
|
public void setRoundBorderAutoXOffset( boolean roundBorderAutoXOffset ) {
|
||||||
|
this.roundBorderAutoXOffset = roundBorderAutoXOffset;
|
||||||
|
}
|
||||||
|
|
||||||
protected Color deriveBackground( Color background ) {
|
protected Color deriveBackground( Color background ) {
|
||||||
return background;
|
return background;
|
||||||
}
|
}
|
||||||
@@ -208,14 +230,17 @@ public class FlatArrowButton
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void paintArrow( Graphics2D g ) {
|
protected void paintArrow( Graphics2D g ) {
|
||||||
boolean vert = (direction == NORTH || direction == SOUTH);
|
|
||||||
int x = 0;
|
int x = 0;
|
||||||
|
|
||||||
// move arrow for round borders
|
// move arrow for round borders
|
||||||
|
if( isRoundBorderAutoXOffset() ) {
|
||||||
Container parent = getParent();
|
Container parent = getParent();
|
||||||
|
boolean vert = (direction == NORTH || direction == SOUTH);
|
||||||
if( vert && parent instanceof JComponent && FlatUIUtils.hasRoundBorder( (JComponent) parent ) )
|
if( vert && parent instanceof JComponent && FlatUIUtils.hasRoundBorder( (JComponent) parent ) )
|
||||||
x -= scale( parent.getComponentOrientation().isLeftToRight() ? 1 : -1 );
|
x -= scale( parent.getComponentOrientation().isLeftToRight() ? 1 : -1 );
|
||||||
|
}
|
||||||
|
|
||||||
FlatUIUtils.paintArrow( g, x, 0, getWidth(), getHeight(), getDirection(), chevron, getArrowWidth(), getXOffset(), getYOffset() );
|
FlatUIUtils.paintArrow( g, x, 0, getWidth(), getHeight(), getDirection(), chevron,
|
||||||
|
getArrowWidth(), getArrowThickness(), getXOffset(), getYOffset() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import javax.swing.JComboBox;
|
|||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JScrollPane;
|
import javax.swing.JScrollPane;
|
||||||
import javax.swing.JSpinner;
|
import javax.swing.JSpinner;
|
||||||
import javax.swing.JViewport;
|
|
||||||
import javax.swing.UIManager;
|
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;
|
||||||
@@ -195,8 +194,7 @@ public class FlatBorder
|
|||||||
protected boolean isEnabled( Component c ) {
|
protected boolean isEnabled( Component c ) {
|
||||||
if( c instanceof JScrollPane ) {
|
if( c instanceof JScrollPane ) {
|
||||||
// check whether view component is disabled
|
// check whether view component is disabled
|
||||||
JViewport viewport = ((JScrollPane)c).getViewport();
|
Component view = FlatScrollPaneUI.getView( (JScrollPane) c );
|
||||||
Component view = (viewport != null) ? viewport.getView() : null;
|
|
||||||
if( view != null && !isEnabled( view ) )
|
if( view != null && !isEnabled( view ) )
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import static com.formdev.flatlaf.FlatClientProperties.*;
|
|||||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||||
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.Font;
|
import java.awt.Font;
|
||||||
import java.awt.FontMetrics;
|
import java.awt.FontMetrics;
|
||||||
@@ -45,11 +46,15 @@ import javax.swing.LookAndFeel;
|
|||||||
import javax.swing.SwingConstants;
|
import javax.swing.SwingConstants;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
|
import javax.swing.event.ChangeEvent;
|
||||||
import javax.swing.plaf.ButtonUI;
|
import javax.swing.plaf.ButtonUI;
|
||||||
import javax.swing.plaf.ComponentUI;
|
import javax.swing.plaf.ComponentUI;
|
||||||
|
import javax.swing.plaf.ToolBarUI;
|
||||||
import javax.swing.plaf.UIResource;
|
import javax.swing.plaf.UIResource;
|
||||||
import javax.swing.plaf.basic.BasicButtonListener;
|
import javax.swing.plaf.basic.BasicButtonListener;
|
||||||
import javax.swing.plaf.basic.BasicButtonUI;
|
import javax.swing.plaf.basic.BasicButtonUI;
|
||||||
|
import javax.swing.plaf.basic.BasicHTML;
|
||||||
|
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.icons.FlatHelpButtonIcon;
|
||||||
@@ -359,6 +364,9 @@ public class FlatButtonUI
|
|||||||
return ((FlatHelpButtonIcon)helpButtonIcon).applyStyleProperty( key, value );
|
return ((FlatHelpButtonIcon)helpButtonIcon).applyStyleProperty( key, value );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( "iconTextGap".equals( key ) && value instanceof Integer )
|
||||||
|
value = UIScale.scale( (Integer) value );
|
||||||
|
|
||||||
if( borderShared == null )
|
if( borderShared == null )
|
||||||
borderShared = new AtomicBoolean( true );
|
borderShared = new AtomicBoolean( true );
|
||||||
return FlatStylingSupport.applyToAnnotatedObjectOrBorder( this, key, value, b, borderShared );
|
return FlatStylingSupport.applyToAnnotatedObjectOrBorder( this, key, value, b, borderShared );
|
||||||
@@ -545,9 +553,45 @@ public class FlatButtonUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Similar to BasicButtonUI.paint(), but does not use zero insets for HTML text,
|
||||||
|
* which is done in BasicButtonUI.layout() since Java 19.
|
||||||
|
* See https://github.com/openjdk/jdk/pull/8407
|
||||||
|
* and https://github.com/openjdk/jdk/pull/8407#issuecomment-1761583430
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void paint( Graphics g, JComponent c ) {
|
public void paint( Graphics g, JComponent c ) {
|
||||||
super.paint( FlatLabelUI.createGraphicsHTMLTextYCorrection( g, c ), c );
|
g = FlatLabelUI.createGraphicsHTMLTextYCorrection( g, c );
|
||||||
|
|
||||||
|
AbstractButton b = (AbstractButton) c;
|
||||||
|
|
||||||
|
// layout
|
||||||
|
String clippedText = layout( b, b.getFontMetrics( b.getFont() ), b.getWidth(), b.getHeight() );
|
||||||
|
|
||||||
|
// not used in FlatLaf, but invoked for compatibility with BasicButtonUI.paint()
|
||||||
|
clearTextShiftOffset();
|
||||||
|
|
||||||
|
// not used in FlatLaf, but invoked for compatibility with BasicButtonUI.paint()
|
||||||
|
ButtonModel model = b.getModel();
|
||||||
|
if( model.isArmed() && model.isPressed() )
|
||||||
|
paintButtonPressed( g, b );
|
||||||
|
|
||||||
|
// paint icon
|
||||||
|
if( b.getIcon() != null )
|
||||||
|
paintIcon( g, b, iconR );
|
||||||
|
|
||||||
|
// paint text
|
||||||
|
if( clippedText != null && !clippedText.isEmpty() ) {
|
||||||
|
View view = (View) b.getClientProperty( BasicHTML.propertyKey );
|
||||||
|
if( view != null )
|
||||||
|
view.paint( g, textR ); // HTML text
|
||||||
|
else
|
||||||
|
paintText( g, b, textR, clippedText );
|
||||||
|
}
|
||||||
|
|
||||||
|
// not used in FlatLaf, but invoked for compatibility with BasicButtonUI.paint()
|
||||||
|
if( b.isFocusPainted() && b.hasFocus() )
|
||||||
|
paintFocus( g, b, viewR, textR, iconR );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -677,14 +721,15 @@ public class FlatButtonUI
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected Color getForeground( JComponent c ) {
|
protected Color getForeground( JComponent c ) {
|
||||||
|
Color fg = c.getForeground();
|
||||||
boolean toolBarButton = isToolBarButton( c ) || isBorderlessButton( c );
|
boolean toolBarButton = isToolBarButton( c ) || isBorderlessButton( c );
|
||||||
|
|
||||||
// selected state
|
// selected state
|
||||||
if( ((AbstractButton)c).isSelected() ) {
|
if( ((AbstractButton)c).isSelected() ) {
|
||||||
return buttonStateColor( c,
|
return buttonStateColor( c,
|
||||||
toolBarButton
|
toolBarButton
|
||||||
? (toolbarSelectedForeground != null ? toolbarSelectedForeground : c.getForeground())
|
? (toolbarSelectedForeground != null ? toolbarSelectedForeground : fg)
|
||||||
: selectedForeground,
|
: (isCustomForeground( fg ) ? fg : selectedForeground),
|
||||||
toolBarButton
|
toolBarButton
|
||||||
? (toolbarDisabledSelectedForeground != null ? toolbarDisabledSelectedForeground : disabledText)
|
? (toolbarDisabledSelectedForeground != null ? toolbarDisabledSelectedForeground : disabledText)
|
||||||
: (disabledSelectedForeground != null ? disabledSelectedForeground : disabledText),
|
: (disabledSelectedForeground != null ? disabledSelectedForeground : disabledText),
|
||||||
@@ -696,7 +741,7 @@ public class FlatButtonUI
|
|||||||
// toolbar button
|
// toolbar button
|
||||||
if( toolBarButton ) {
|
if( toolBarButton ) {
|
||||||
return buttonStateColor( c,
|
return buttonStateColor( c,
|
||||||
c.getForeground(),
|
fg,
|
||||||
disabledText,
|
disabledText,
|
||||||
null,
|
null,
|
||||||
toolbarHoverForeground,
|
toolbarHoverForeground,
|
||||||
@@ -707,7 +752,7 @@ public class FlatButtonUI
|
|||||||
return buttonStateColor( c,
|
return buttonStateColor( c,
|
||||||
getForegroundBase( c, def ),
|
getForegroundBase( c, def ),
|
||||||
disabledText,
|
disabledText,
|
||||||
isCustomForeground( c.getForeground() ) ? null : (def ? defaultFocusedForeground : focusedForeground),
|
isCustomForeground( fg ) ? null : (def ? defaultFocusedForeground : focusedForeground),
|
||||||
def ? defaultHoverForeground : hoverForeground,
|
def ? defaultHoverForeground : hoverForeground,
|
||||||
def ? defaultPressedForeground : pressedForeground );
|
def ? defaultPressedForeground : pressedForeground );
|
||||||
}
|
}
|
||||||
@@ -780,6 +825,67 @@ public class FlatButtonUI
|
|||||||
return margin instanceof UIResource && Objects.equals( margin, defaultMargin );
|
return margin instanceof UIResource && Objects.equals( margin, defaultMargin );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBaseline( JComponent c, int width, int height ) {
|
||||||
|
return getBaselineImpl( c, width, height );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Similar to BasicButtonUI.getBaseline(), but does not use zero insets for HTML text,
|
||||||
|
* which is done in BasicButtonUI.layout() since Java 19.
|
||||||
|
* See https://github.com/openjdk/jdk/pull/8407
|
||||||
|
* and https://github.com/openjdk/jdk/pull/8407#issuecomment-1761583430
|
||||||
|
*/
|
||||||
|
static int getBaselineImpl( JComponent c, int width, int height ) {
|
||||||
|
if( width < 0 || height < 0 )
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
|
||||||
|
AbstractButton b = (AbstractButton) c;
|
||||||
|
String text = b.getText();
|
||||||
|
if( text == null || text.isEmpty() )
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
FontMetrics fm = b.getFontMetrics( b.getFont() );
|
||||||
|
layout( b, fm, width, height );
|
||||||
|
|
||||||
|
View view = (View) b.getClientProperty( BasicHTML.propertyKey );
|
||||||
|
if( view != null ) {
|
||||||
|
// HTML text
|
||||||
|
int baseline = BasicHTML.getHTMLBaseline( view, textR.width, textR.height );
|
||||||
|
return (baseline >= 0) ? textR.y + baseline : baseline;
|
||||||
|
} else
|
||||||
|
return textR.y + fm.getAscent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Similar to BasicButtonUI.layout(), but does not use zero insets for HTML text,
|
||||||
|
* which is done in BasicButtonUI.layout() since Java 19.
|
||||||
|
* See https://github.com/openjdk/jdk/pull/8407
|
||||||
|
* and https://github.com/openjdk/jdk/pull/8407#issuecomment-1761583430
|
||||||
|
*/
|
||||||
|
private static String layout( AbstractButton b, FontMetrics fm, int width, int height ) {
|
||||||
|
// compute view rectangle
|
||||||
|
Insets insets = b.getInsets();
|
||||||
|
viewR.setBounds( insets.left, insets.top,
|
||||||
|
width - insets.left - insets.right,
|
||||||
|
height - insets.top - insets.bottom );
|
||||||
|
|
||||||
|
// reset rectangles
|
||||||
|
textR.setBounds( 0, 0, 0, 0 );
|
||||||
|
iconR.setBounds( 0, 0, 0, 0 );
|
||||||
|
|
||||||
|
String text = b.getText();
|
||||||
|
return SwingUtilities.layoutCompoundLabel( b, fm, text, b.getIcon(),
|
||||||
|
b.getVerticalAlignment(), b.getHorizontalAlignment(),
|
||||||
|
b.getVerticalTextPosition(), b.getHorizontalTextPosition(),
|
||||||
|
viewR, iconR, textR,
|
||||||
|
(text != null) ? b.getIconTextGap() : 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Rectangle viewR = new Rectangle();
|
||||||
|
private static Rectangle textR = new Rectangle();
|
||||||
|
private static Rectangle iconR = new Rectangle();
|
||||||
|
|
||||||
//---- class FlatButtonListener -------------------------------------------
|
//---- class FlatButtonListener -------------------------------------------
|
||||||
|
|
||||||
protected class FlatButtonListener
|
protected class FlatButtonListener
|
||||||
@@ -797,5 +903,20 @@ public class FlatButtonUI
|
|||||||
super.propertyChange( e );
|
super.propertyChange( e );
|
||||||
FlatButtonUI.this.propertyChange( b, e );
|
FlatButtonUI.this.propertyChange( b, e );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stateChanged( ChangeEvent e ) {
|
||||||
|
super.stateChanged( e );
|
||||||
|
|
||||||
|
// if button is in toolbar, repaint button groups
|
||||||
|
AbstractButton b = (AbstractButton) e.getSource();
|
||||||
|
Container parent = b.getParent();
|
||||||
|
if( parent instanceof JToolBar ) {
|
||||||
|
JToolBar toolBar = (JToolBar) parent;
|
||||||
|
ToolBarUI ui = toolBar.getUI();
|
||||||
|
if( ui instanceof FlatToolBarUI )
|
||||||
|
((FlatToolBarUI)ui).repaintButtonGroup( b );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,10 +256,14 @@ public class FlatCaret
|
|||||||
// select all
|
// select all
|
||||||
if( c instanceof JFormattedTextField ) {
|
if( c instanceof JFormattedTextField ) {
|
||||||
EventQueue.invokeLater( () -> {
|
EventQueue.invokeLater( () -> {
|
||||||
if( getComponent() == null )
|
// Warning: do not use variables from outside of this runnable
|
||||||
|
// because they may be out-of-date when this runnable is executed
|
||||||
|
|
||||||
|
JTextComponent c2 = getComponent();
|
||||||
|
if( c2 == null )
|
||||||
return; // was deinstalled
|
return; // was deinstalled
|
||||||
|
|
||||||
select( 0, doc.getLength() );
|
select( 0, c2.getDocument().getLength() );
|
||||||
} );
|
} );
|
||||||
} else {
|
} else {
|
||||||
select( 0, doc.getLength() );
|
select( 0, doc.getLength() );
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import java.awt.Component;
|
|||||||
import java.awt.ComponentOrientation;
|
import java.awt.ComponentOrientation;
|
||||||
import java.awt.Container;
|
import java.awt.Container;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
|
import java.awt.EventQueue;
|
||||||
import java.awt.FontMetrics;
|
import java.awt.FontMetrics;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
@@ -48,10 +49,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
import javax.swing.AbstractAction;
|
import javax.swing.AbstractAction;
|
||||||
import javax.swing.BorderFactory;
|
import javax.swing.BorderFactory;
|
||||||
import javax.swing.CellRendererPane;
|
import javax.swing.CellRendererPane;
|
||||||
|
import javax.swing.ComboBoxModel;
|
||||||
import javax.swing.DefaultListCellRenderer;
|
import javax.swing.DefaultListCellRenderer;
|
||||||
import javax.swing.InputMap;
|
import javax.swing.InputMap;
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
import javax.swing.JComboBox;
|
import javax.swing.JComboBox;
|
||||||
|
import javax.swing.JComboBox.KeySelectionManager;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JList;
|
import javax.swing.JList;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
@@ -70,6 +73,7 @@ import javax.swing.plaf.basic.BasicComboBoxUI;
|
|||||||
import javax.swing.plaf.basic.BasicComboPopup;
|
import javax.swing.plaf.basic.BasicComboPopup;
|
||||||
import javax.swing.plaf.basic.ComboPopup;
|
import javax.swing.plaf.basic.ComboPopup;
|
||||||
import javax.swing.text.JTextComponent;
|
import javax.swing.text.JTextComponent;
|
||||||
|
import com.formdev.flatlaf.icons.FlatCheckBoxMenuItemIcon;
|
||||||
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.StyleableField;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableLookupProvider;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableLookupProvider;
|
||||||
@@ -99,9 +103,8 @@ import com.formdev.flatlaf.util.SystemInfo;
|
|||||||
* @uiDefault ComboBox.minimumWidth int
|
* @uiDefault ComboBox.minimumWidth int
|
||||||
* @uiDefault ComboBox.editorColumns int
|
* @uiDefault ComboBox.editorColumns int
|
||||||
* @uiDefault ComboBox.maximumRowCount int
|
* @uiDefault ComboBox.maximumRowCount int
|
||||||
* @uiDefault ComboBox.buttonStyle String auto (default), button or none
|
* @uiDefault ComboBox.buttonStyle String auto (default), button, mac or none
|
||||||
* @uiDefault Component.arrowType String chevron (default) or triangle
|
* @uiDefault Component.arrowType String chevron (default) or triangle
|
||||||
* @uiDefault Component.isIntelliJTheme boolean
|
|
||||||
* @uiDefault ComboBox.editableBackground Color optional; defaults to ComboBox.background
|
* @uiDefault ComboBox.editableBackground Color optional; defaults to ComboBox.background
|
||||||
* @uiDefault ComboBox.focusedBackground Color optional
|
* @uiDefault ComboBox.focusedBackground Color optional
|
||||||
* @uiDefault ComboBox.disabledBackground Color
|
* @uiDefault ComboBox.disabledBackground Color
|
||||||
@@ -117,6 +120,9 @@ import com.formdev.flatlaf.util.SystemInfo;
|
|||||||
* @uiDefault ComboBox.buttonHoverArrowColor Color
|
* @uiDefault ComboBox.buttonHoverArrowColor Color
|
||||||
* @uiDefault ComboBox.buttonPressedArrowColor Color
|
* @uiDefault ComboBox.buttonPressedArrowColor Color
|
||||||
* @uiDefault ComboBox.popupBackground Color optional
|
* @uiDefault ComboBox.popupBackground Color optional
|
||||||
|
* @uiDefault ComboBox.popupInsets Insets
|
||||||
|
* @uiDefault ComboBox.selectionInsets Insets
|
||||||
|
* @uiDefault ComboBox.selectionArc int
|
||||||
*
|
*
|
||||||
* @author Karl Tauber
|
* @author Karl Tauber
|
||||||
*/
|
*/
|
||||||
@@ -130,7 +136,6 @@ public class FlatComboBoxUI
|
|||||||
@Styleable protected int editorColumns;
|
@Styleable protected int editorColumns;
|
||||||
@Styleable protected String buttonStyle;
|
@Styleable protected String buttonStyle;
|
||||||
@Styleable protected String arrowType;
|
@Styleable protected String arrowType;
|
||||||
protected boolean isIntelliJTheme;
|
|
||||||
|
|
||||||
private Color background;
|
private Color background;
|
||||||
@Styleable protected Color editableBackground;
|
@Styleable protected Color editableBackground;
|
||||||
@@ -150,6 +155,9 @@ public class FlatComboBoxUI
|
|||||||
@Styleable protected Color buttonPressedArrowColor;
|
@Styleable protected Color buttonPressedArrowColor;
|
||||||
|
|
||||||
@Styleable protected Color popupBackground;
|
@Styleable protected Color popupBackground;
|
||||||
|
/** @since 3 */ @Styleable protected Insets popupInsets;
|
||||||
|
/** @since 3 */ @Styleable protected Insets selectionInsets;
|
||||||
|
/** @since 3 */ @Styleable protected int selectionArc;
|
||||||
|
|
||||||
private MouseListener hoverListener;
|
private MouseListener hoverListener;
|
||||||
protected boolean hover;
|
protected boolean hover;
|
||||||
@@ -175,6 +183,9 @@ public class FlatComboBoxUI
|
|||||||
private void installUIImpl( JComponent c ) {
|
private void installUIImpl( JComponent c ) {
|
||||||
super.installUI( c );
|
super.installUI( c );
|
||||||
|
|
||||||
|
// install key selection manager that shows popup when Space key is pressed
|
||||||
|
comboBox.setKeySelectionManager( new FlatKeySelectionManager( comboBox.getKeySelectionManager() ) );
|
||||||
|
|
||||||
installStyle();
|
installStyle();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,7 +244,6 @@ public class FlatComboBoxUI
|
|||||||
editorColumns = UIManager.getInt( "ComboBox.editorColumns" );
|
editorColumns = UIManager.getInt( "ComboBox.editorColumns" );
|
||||||
buttonStyle = UIManager.getString( "ComboBox.buttonStyle" );
|
buttonStyle = UIManager.getString( "ComboBox.buttonStyle" );
|
||||||
arrowType = UIManager.getString( "Component.arrowType" );
|
arrowType = UIManager.getString( "Component.arrowType" );
|
||||||
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
|
||||||
|
|
||||||
background = UIManager.getColor( "ComboBox.background" );
|
background = UIManager.getColor( "ComboBox.background" );
|
||||||
editableBackground = UIManager.getColor( "ComboBox.editableBackground" );
|
editableBackground = UIManager.getColor( "ComboBox.editableBackground" );
|
||||||
@@ -253,6 +263,9 @@ public class FlatComboBoxUI
|
|||||||
buttonPressedArrowColor = UIManager.getColor( "ComboBox.buttonPressedArrowColor" );
|
buttonPressedArrowColor = UIManager.getColor( "ComboBox.buttonPressedArrowColor" );
|
||||||
|
|
||||||
popupBackground = UIManager.getColor( "ComboBox.popupBackground" );
|
popupBackground = UIManager.getColor( "ComboBox.popupBackground" );
|
||||||
|
popupInsets = UIManager.getInsets( "ComboBox.popupInsets" );
|
||||||
|
selectionInsets = UIManager.getInsets( "ComboBox.selectionInsets" );
|
||||||
|
selectionArc = UIManager.getInt( "ComboBox.selectionArc" );
|
||||||
|
|
||||||
// set maximumRowCount
|
// set maximumRowCount
|
||||||
int maximumRowCount = UIManager.getInt( "ComboBox.maximumRowCount" );
|
int maximumRowCount = UIManager.getInt( "ComboBox.maximumRowCount" );
|
||||||
@@ -559,7 +572,9 @@ public class FlatComboBoxUI
|
|||||||
int height = c.getHeight();
|
int height = c.getHeight();
|
||||||
int arrowX = arrowButton.getX();
|
int arrowX = arrowButton.getX();
|
||||||
int arrowWidth = arrowButton.getWidth();
|
int arrowWidth = arrowButton.getWidth();
|
||||||
boolean paintButton = (comboBox.isEditable() || "button".equals( buttonStyle )) && !"none".equals( buttonStyle );
|
boolean paintButton = (comboBox.isEditable() || "button".equals( buttonStyle )) &&
|
||||||
|
!"none".equals( buttonStyle ) &&
|
||||||
|
!isMacStyle();
|
||||||
boolean enabled = comboBox.isEnabled();
|
boolean enabled = comboBox.isEnabled();
|
||||||
boolean isLeftToRight = comboBox.getComponentOrientation().isLeftToRight();
|
boolean isLeftToRight = comboBox.getComponentOrientation().isLeftToRight();
|
||||||
|
|
||||||
@@ -577,6 +592,13 @@ public class FlatComboBoxUI
|
|||||||
: buttonBackground;
|
: buttonBackground;
|
||||||
if( buttonColor != null ) {
|
if( buttonColor != null ) {
|
||||||
g2.setColor( buttonColor );
|
g2.setColor( buttonColor );
|
||||||
|
if( isMacStyle() ) {
|
||||||
|
Insets insets = comboBox.getInsets();
|
||||||
|
int gap = scale( 2 );
|
||||||
|
FlatUIUtils.paintComponentBackground( g2, arrowX + gap, insets.top + gap,
|
||||||
|
arrowWidth - (gap * 2), height - insets.top - insets.bottom - (gap * 2),
|
||||||
|
0, arc - focusWidth );
|
||||||
|
} else {
|
||||||
Shape oldClip = g2.getClip();
|
Shape oldClip = g2.getClip();
|
||||||
if( isLeftToRight )
|
if( isLeftToRight )
|
||||||
g2.clipRect( arrowX, 0, width - arrowX, height );
|
g2.clipRect( arrowX, 0, width - arrowX, height );
|
||||||
@@ -586,6 +608,7 @@ public class FlatComboBoxUI
|
|||||||
g2.setClip( oldClip );
|
g2.setClip( oldClip );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// paint vertical line between value and arrow button
|
// paint vertical line between value and arrow button
|
||||||
if( paintButton ) {
|
if( paintButton ) {
|
||||||
@@ -659,7 +682,7 @@ public class FlatComboBoxUI
|
|||||||
|
|
||||||
return (editableBackground != null && comboBox.isEditable()) ? editableBackground : background;
|
return (editableBackground != null && comboBox.isEditable()) ? editableBackground : background;
|
||||||
} else
|
} else
|
||||||
return isIntelliJTheme ? FlatUIUtils.getParentBackground( comboBox ) : disabledBackground;
|
return disabledBackground;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Color getForeground( boolean enabled ) {
|
protected Color getForeground( boolean enabled ) {
|
||||||
@@ -722,6 +745,10 @@ public class FlatComboBoxUI
|
|||||||
return parentParent != null && !comboBox.getBackground().equals( parentParent.getBackground() );
|
return parentParent != null && !comboBox.getBackground().equals( parentParent.getBackground() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isMacStyle() {
|
||||||
|
return "mac".equals( buttonStyle );
|
||||||
|
}
|
||||||
|
|
||||||
/** @since 1.3 */
|
/** @since 1.3 */
|
||||||
public static boolean isPermanentFocusOwner( JComboBox<?> comboBox ) {
|
public static boolean isPermanentFocusOwner( JComboBox<?> comboBox ) {
|
||||||
if( comboBox.isEditable() ) {
|
if( comboBox.isEditable() ) {
|
||||||
@@ -756,6 +783,21 @@ public class FlatComboBoxUI
|
|||||||
buttonHoverArrowColor, null, buttonPressedArrowColor, null );
|
buttonHoverArrowColor, null, buttonPressedArrowColor, null );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getArrowWidth() {
|
||||||
|
return isMacStyle() ? (getWidth() % 2 == 0 ? 6 : 7) : super.getArrowWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getArrowThickness() {
|
||||||
|
return isMacStyle() ? 1.5f : super.getArrowThickness();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRoundBorderAutoXOffset() {
|
||||||
|
return isMacStyle() ? false : super.isRoundBorderAutoXOffset();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean isHover() {
|
protected boolean isHover() {
|
||||||
return super.isHover() || (!comboBox.isEditable() ? hover : false);
|
return super.isHover() || (!comboBox.isEditable() ? hover : false);
|
||||||
@@ -773,6 +815,20 @@ public class FlatComboBoxUI
|
|||||||
|
|
||||||
return super.getArrowColor();
|
return super.getArrowColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void paintArrow( Graphics2D g ) {
|
||||||
|
if( isMacStyle() && !comboBox.isEditable() ) {
|
||||||
|
// for style "mac", paint up and down arrows if combobox is not editable
|
||||||
|
int height = getHeight();
|
||||||
|
int h = Math.round( height / 2f );
|
||||||
|
FlatUIUtils.paintArrow( g, 0, 0, getWidth(), h, SwingConstants.NORTH, chevron,
|
||||||
|
getArrowWidth(), getArrowThickness(), getXOffset(), getYOffset() + 1.25f );
|
||||||
|
FlatUIUtils.paintArrow( g, 0, height - h, getWidth(), h, SwingConstants.SOUTH, chevron,
|
||||||
|
getArrowWidth(), getArrowThickness(), getXOffset(), getYOffset() - 1.25f );
|
||||||
|
} else
|
||||||
|
super.paintArrow( g );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//---- class FlatComboPopup -----------------------------------------------
|
//---- class FlatComboPopup -----------------------------------------------
|
||||||
@@ -807,12 +863,19 @@ public class FlatComboBoxUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for style "mac", add width of "checked item" icon
|
||||||
|
boolean isPopupOverComboBox = isPopupOverComboBox();
|
||||||
|
int selectedIndex = -1;
|
||||||
|
if( isPopupOverComboBox && (selectedIndex = comboBox.getSelectedIndex()) >= 0 )
|
||||||
|
displayWidth += MacCheckedItemIcon.INSTANCE.getIconWidth() + scale( CellPaddingBorder.MAC_STYLE_GAP );
|
||||||
|
|
||||||
// add width of vertical scroll bar
|
// add width of vertical scroll bar
|
||||||
JScrollBar verticalScrollBar = scroller.getVerticalScrollBar();
|
JScrollBar verticalScrollBar = scroller.getVerticalScrollBar();
|
||||||
if( verticalScrollBar != null )
|
if( verticalScrollBar != null )
|
||||||
displayWidth += verticalScrollBar.getPreferredSize().width;
|
displayWidth += verticalScrollBar.getPreferredSize().width;
|
||||||
|
|
||||||
// make popup wider if necessary
|
// make popup wider if necessary
|
||||||
|
int pw0 = pw;
|
||||||
if( displayWidth > pw ) {
|
if( displayWidth > pw ) {
|
||||||
// limit popup width to screen width
|
// limit popup width to screen width
|
||||||
GraphicsConfiguration gc = comboBox.getGraphicsConfiguration();
|
GraphicsConfiguration gc = comboBox.getGraphicsConfiguration();
|
||||||
@@ -832,6 +895,30 @@ public class FlatComboBoxUI
|
|||||||
px -= diff;
|
px -= diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for style "mac", place popup over combobox
|
||||||
|
Rectangle cellBounds;
|
||||||
|
if( isPopupOverComboBox && selectedIndex >= 0 &&
|
||||||
|
(cellBounds = list.getCellBounds( 0, 0 )) != null )
|
||||||
|
{
|
||||||
|
Insets comboBoxInsets = comboBox.getInsets();
|
||||||
|
Insets listInsets = list.getInsets();
|
||||||
|
Insets popupInsets = getInsets();
|
||||||
|
|
||||||
|
// position popup so that selected item is at same Y position as combobox
|
||||||
|
py -= (cellBounds.height * (selectedIndex + 1)) + comboBoxInsets.top + listInsets.top + popupInsets.top;
|
||||||
|
|
||||||
|
// position popup slightly to the left so that a small part of the right side of the combobox stays visible
|
||||||
|
int offset = Math.min( pw - pw0, MacCheckedItemIcon.INSTANCE.getIconWidth() ) + scale( 4 );
|
||||||
|
if( comboBox.getComponentOrientation().isLeftToRight() )
|
||||||
|
px -= offset + comboBoxInsets.right + listInsets.right;
|
||||||
|
else
|
||||||
|
px += offset + comboBoxInsets.left + listInsets.left;
|
||||||
|
|
||||||
|
// not invoking super.computePopupBounds() here to let
|
||||||
|
// JPopupMenu.adjustPopupLocationToFitScreen() fix the location if necessary
|
||||||
|
return new Rectangle( px, py, pw, ph );
|
||||||
|
}
|
||||||
|
|
||||||
return super.computePopupBounds( px, py, pw, ph );
|
return super.computePopupBounds( px, py, pw, ph );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -839,7 +926,7 @@ public class FlatComboBoxUI
|
|||||||
protected void configurePopup() {
|
protected void configurePopup() {
|
||||||
super.configurePopup();
|
super.configurePopup();
|
||||||
|
|
||||||
// make opaque to avoid that background shines thru border (e.g. at 150% scaling)
|
// make opaque to avoid that background shines through border (e.g. at 150% scaling)
|
||||||
setOpaque( true );
|
setOpaque( true );
|
||||||
|
|
||||||
// set popup border
|
// set popup border
|
||||||
@@ -848,11 +935,6 @@ public class FlatComboBoxUI
|
|||||||
Border border = UIManager.getBorder( "PopupMenu.border" );
|
Border border = UIManager.getBorder( "PopupMenu.border" );
|
||||||
if( border != null )
|
if( border != null )
|
||||||
setBorder( FlatUIUtils.nonUIResource( border ) );
|
setBorder( FlatUIUtils.nonUIResource( border ) );
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void configureList() {
|
|
||||||
super.configureList();
|
|
||||||
|
|
||||||
list.setCellRenderer( new PopupListCellRenderer() );
|
list.setCellRenderer( new PopupListCellRenderer() );
|
||||||
updateStyle();
|
updateStyle();
|
||||||
@@ -862,10 +944,19 @@ public class FlatComboBoxUI
|
|||||||
if( popupBackground != null )
|
if( popupBackground != null )
|
||||||
list.setBackground( popupBackground );
|
list.setBackground( popupBackground );
|
||||||
|
|
||||||
// set popup background because it may shine thru when scaled (e.g. at 150%)
|
// set popup background because it may shine through when scaled (e.g. at 150%)
|
||||||
// use non-UIResource to avoid that it is overwritten when making
|
// use non-UIResource to avoid that it is overwritten when making
|
||||||
// popup visible (see JPopupMenu.setInvoker()) in theme editor preview
|
// popup visible (see JPopupMenu.setInvoker()) in theme editor preview
|
||||||
setBackground( FlatUIUtils.nonUIResource( list.getBackground() ) );
|
setBackground( FlatUIUtils.nonUIResource( list.getBackground() ) );
|
||||||
|
|
||||||
|
scroller.setViewportBorder( (popupInsets != null) ? new FlatEmptyBorder( popupInsets ) : null );
|
||||||
|
scroller.setOpaque( false );
|
||||||
|
|
||||||
|
if( list.getUI() instanceof FlatListUI ) {
|
||||||
|
FlatListUI ui = (FlatListUI) list.getUI();
|
||||||
|
ui.selectionInsets = selectionInsets;
|
||||||
|
ui.selectionArc = selectionArc;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -898,6 +989,29 @@ public class FlatComboBoxUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// improve location of selected item in popup if list is large and scrollable
|
||||||
|
if( list.getHeight() == 0 ) {
|
||||||
|
// If popup is shown for the first time (or after a laf switch) and is scrollable,
|
||||||
|
// then BasicComboPopup scrolls the selected item to the top of the visible area.
|
||||||
|
// But for usability it would be better to have selected item somewhere
|
||||||
|
// in the middle of the visible area so that the user can see items above
|
||||||
|
// the selected item, which are usually more "important".
|
||||||
|
|
||||||
|
int selectedIndex = list.getSelectedIndex();
|
||||||
|
if( selectedIndex >= 1 ) {
|
||||||
|
int maximumRowCount = comboBox.getMaximumRowCount();
|
||||||
|
if( selectedIndex < maximumRowCount ) {
|
||||||
|
// selected item is in the first visible items --> scroll to top
|
||||||
|
list.scrollRectToVisible( new Rectangle() );
|
||||||
|
} else {
|
||||||
|
// scroll the selected item to the middle of the visible area
|
||||||
|
int firstVisibleIndex = Math.max( selectedIndex - (maximumRowCount / 2), 0 );
|
||||||
|
if( firstVisibleIndex > 0 )
|
||||||
|
list.ensureIndexIsVisible( firstVisibleIndex );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
super.show( invoker, x, y );
|
super.show( invoker, x, y );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -907,6 +1021,15 @@ public class FlatComboBoxUI
|
|||||||
paddingBorder.uninstall();
|
paddingBorder.uninstall();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isPopupOverComboBox() {
|
||||||
|
return isMacStyle() &&
|
||||||
|
!comboBox.isEditable() &&
|
||||||
|
comboBox.getItemCount() > 0 &&
|
||||||
|
comboBox.getItemCount() <= comboBox.getMaximumRowCount() &&
|
||||||
|
// for compatibility with Aqua Laf
|
||||||
|
!clientPropertyBoolean( comboBox, "JComboBox.isPopDown", false );
|
||||||
|
}
|
||||||
|
|
||||||
//---- class PopupListCellRenderer -----
|
//---- class PopupListCellRenderer -----
|
||||||
|
|
||||||
private class PopupListCellRenderer
|
private class PopupListCellRenderer
|
||||||
@@ -924,6 +1047,13 @@ public class FlatComboBoxUI
|
|||||||
Component c = renderer.getListCellRendererComponent( list, value, index, isSelected, cellHasFocus );
|
Component c = renderer.getListCellRendererComponent( list, value, index, isSelected, cellHasFocus );
|
||||||
c.applyComponentOrientation( comboBox.getComponentOrientation() );
|
c.applyComponentOrientation( comboBox.getComponentOrientation() );
|
||||||
|
|
||||||
|
// style "mac"
|
||||||
|
if( isPopupOverComboBox() && c instanceof JComponent ) {
|
||||||
|
int selectedIndex = comboBox.getSelectedIndex();
|
||||||
|
((JComponent)c).putClientProperty( CellPaddingBorder.KEY_MAC_STYLE_HINT,
|
||||||
|
(selectedIndex >= 0) ? (index == selectedIndex) : null );
|
||||||
|
}
|
||||||
|
|
||||||
paddingBorder.install( c, Math.round( FlatUIUtils.getBorderFocusWidth( comboBox ) ) );
|
paddingBorder.install( c, Math.round( FlatUIUtils.getBorderFocusWidth( comboBox ) ) );
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
@@ -940,10 +1070,16 @@ public class FlatComboBoxUI
|
|||||||
* which vertically aligns text in popup list with text in combobox.
|
* which vertically aligns text in popup list with text in combobox.
|
||||||
* <p>
|
* <p>
|
||||||
* The renderer border is painted on the outer side of this border.
|
* The renderer border is painted on the outer side of this border.
|
||||||
|
* <p>
|
||||||
|
* For button style "mac", also used to increase insets on left side for
|
||||||
|
* "checked item" icon and to paint "checked item" icon for selected combobox item.
|
||||||
*/
|
*/
|
||||||
private static class CellPaddingBorder
|
private static class CellPaddingBorder
|
||||||
extends AbstractBorder
|
extends AbstractBorder
|
||||||
{
|
{
|
||||||
|
static final String KEY_MAC_STYLE_HINT = "FlatLaf.internal.FlatComboBoxUI.macStyleHint";
|
||||||
|
static final int MAC_STYLE_GAP = 4;
|
||||||
|
|
||||||
private Insets padding;
|
private Insets padding;
|
||||||
private JComponent rendererComponent;
|
private JComponent rendererComponent;
|
||||||
private Border rendererBorder;
|
private Border rendererBorder;
|
||||||
@@ -954,7 +1090,7 @@ public class FlatComboBoxUI
|
|||||||
}
|
}
|
||||||
|
|
||||||
// using synchronized to avoid problems with code that modifies combo box
|
// using synchronized to avoid problems with code that modifies combo box
|
||||||
// (model, selection, etc) not on AWT thread (which should be not done)
|
// (model, selection, etc.) not on AWT thread (which should be not done)
|
||||||
synchronized void install( Component c, int focusWidth ) {
|
synchronized void install( Component c, int focusWidth ) {
|
||||||
if( !(c instanceof JComponent) )
|
if( !(c instanceof JComponent) )
|
||||||
return;
|
return;
|
||||||
@@ -993,6 +1129,8 @@ public class FlatComboBoxUI
|
|||||||
if( rendererComponent == null )
|
if( rendererComponent == null )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
rendererComponent.putClientProperty( KEY_MAC_STYLE_HINT, null );
|
||||||
|
|
||||||
if( rendererComponent.getBorder() == this )
|
if( rendererComponent.getBorder() == this )
|
||||||
rendererComponent.setBorder( rendererBorder );
|
rendererComponent.setBorder( rendererBorder );
|
||||||
rendererComponent = null;
|
rendererComponent = null;
|
||||||
@@ -1020,6 +1158,18 @@ public class FlatComboBoxUI
|
|||||||
insets.left += focusWidth;
|
insets.left += focusWidth;
|
||||||
insets.right += focusWidth;
|
insets.right += focusWidth;
|
||||||
|
|
||||||
|
// style "mac"
|
||||||
|
if( c instanceof JComponent ) {
|
||||||
|
Boolean macStyleHint = clientPropertyBooleanStrict( (JComponent) c, KEY_MAC_STYLE_HINT, null );
|
||||||
|
if( macStyleHint != null ) {
|
||||||
|
int indent = MacCheckedItemIcon.INSTANCE.getIconWidth() + scale( MAC_STYLE_GAP );
|
||||||
|
if( c.getComponentOrientation().isLeftToRight() )
|
||||||
|
insets.left += indent;
|
||||||
|
else
|
||||||
|
insets.right += indent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return insets;
|
return insets;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1027,6 +1177,35 @@ public class FlatComboBoxUI
|
|||||||
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( rendererBorder != null )
|
if( rendererBorder != null )
|
||||||
rendererBorder.paintBorder( c, g, x, y, width, height );
|
rendererBorder.paintBorder( c, g, x, y, width, height );
|
||||||
|
|
||||||
|
// style "mac"
|
||||||
|
if( c instanceof JComponent ) {
|
||||||
|
Boolean macStyleHint = clientPropertyBooleanStrict( (JComponent) c, KEY_MAC_STYLE_HINT, null );
|
||||||
|
if( macStyleHint == Boolean.TRUE ) {
|
||||||
|
// paint "checked item" icon
|
||||||
|
int ix = c.getComponentOrientation().isLeftToRight()
|
||||||
|
? x + scale( padding.left )
|
||||||
|
: x + width - scale( padding.right ) - MacCheckedItemIcon.INSTANCE.getIconWidth();
|
||||||
|
MacCheckedItemIcon.INSTANCE.paintIcon( c, g, ix, y + ((height - MacCheckedItemIcon.INSTANCE.getIconHeight()) / 2) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---- class MacCheckedItemIcon -------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use for style "mac" to mark checked item.
|
||||||
|
*/
|
||||||
|
private static class MacCheckedItemIcon
|
||||||
|
extends FlatCheckBoxMenuItemIcon
|
||||||
|
{
|
||||||
|
static MacCheckedItemIcon INSTANCE = new MacCheckedItemIcon();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void paintIcon( Component c, Graphics2D g2 ) {
|
||||||
|
g2.setColor( c.getForeground() );
|
||||||
|
paintCheckmark( g2 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1056,4 +1235,46 @@ public class FlatComboBoxUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---- class FlatKeySelectionManager --------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key selection manager that delegates to the default manager.
|
||||||
|
* Shows the popup if Space key is pressed and "typed characters" buffer is empty.
|
||||||
|
* If items contain spaces (e.g. "a b") it is still possible to select them
|
||||||
|
* by pressing keys 'a', 'Space' and 'b'.
|
||||||
|
*/
|
||||||
|
private class FlatKeySelectionManager
|
||||||
|
implements JComboBox.KeySelectionManager, UIResource
|
||||||
|
{
|
||||||
|
private final KeySelectionManager delegate;
|
||||||
|
private final long timeFactor;
|
||||||
|
private long lastTime;
|
||||||
|
|
||||||
|
FlatKeySelectionManager( JComboBox.KeySelectionManager delegate ) {
|
||||||
|
this.delegate = delegate;
|
||||||
|
|
||||||
|
Long value = (Long) UIManager.get( "ComboBox.timeFactor" );
|
||||||
|
timeFactor = (value != null) ? value : 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings( "rawtypes" )
|
||||||
|
@Override
|
||||||
|
public int selectionForKey( char aKey, ComboBoxModel aModel ) {
|
||||||
|
long time = EventQueue.getMostRecentEventTime();
|
||||||
|
long oldLastTime = lastTime;
|
||||||
|
lastTime = time;
|
||||||
|
|
||||||
|
// SPACE key shows popup if not yet visible
|
||||||
|
if( aKey == ' ' &&
|
||||||
|
time - oldLastTime >= timeFactor &&
|
||||||
|
!comboBox.isPopupVisible() )
|
||||||
|
{
|
||||||
|
comboBox.setPopupVisible( true );
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return delegate.selectionForKey( aKey, aModel );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,6 @@ import com.formdev.flatlaf.util.LoggingFacade;
|
|||||||
* <!-- FlatEditorPaneUI -->
|
* <!-- FlatEditorPaneUI -->
|
||||||
*
|
*
|
||||||
* @uiDefault Component.minimumWidth int
|
* @uiDefault Component.minimumWidth int
|
||||||
* @uiDefault Component.isIntelliJTheme boolean
|
|
||||||
* @uiDefault EditorPane.focusedBackground Color optional
|
* @uiDefault EditorPane.focusedBackground Color optional
|
||||||
*
|
*
|
||||||
* @author Karl Tauber
|
* @author Karl Tauber
|
||||||
@@ -69,7 +68,6 @@ public class FlatEditorPaneUI
|
|||||||
implements StyleableUI
|
implements StyleableUI
|
||||||
{
|
{
|
||||||
@Styleable protected int minimumWidth;
|
@Styleable protected int minimumWidth;
|
||||||
protected boolean isIntelliJTheme;
|
|
||||||
private Color background;
|
private Color background;
|
||||||
@Styleable protected Color disabledBackground;
|
@Styleable protected Color disabledBackground;
|
||||||
@Styleable protected Color inactiveBackground;
|
@Styleable protected Color inactiveBackground;
|
||||||
@@ -101,7 +99,6 @@ public class FlatEditorPaneUI
|
|||||||
|
|
||||||
String prefix = getPropertyPrefix();
|
String prefix = getPropertyPrefix();
|
||||||
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
||||||
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
|
||||||
background = UIManager.getColor( prefix + ".background" );
|
background = UIManager.getColor( prefix + ".background" );
|
||||||
disabledBackground = UIManager.getColor( prefix + ".disabledBackground" );
|
disabledBackground = UIManager.getColor( prefix + ".disabledBackground" );
|
||||||
inactiveBackground = UIManager.getColor( prefix + ".inactiveBackground" );
|
inactiveBackground = UIManager.getColor( prefix + ".inactiveBackground" );
|
||||||
@@ -252,11 +249,11 @@ public class FlatEditorPaneUI
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void paintBackground( Graphics g ) {
|
protected void paintBackground( Graphics g ) {
|
||||||
paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground );
|
paintBackground( g, getComponent(), focusedBackground );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void paintBackground( Graphics g, JTextComponent c, boolean isIntelliJTheme, Color focusedBackground ) {
|
static void paintBackground( Graphics g, JTextComponent c, Color focusedBackground ) {
|
||||||
g.setColor( FlatTextFieldUI.getBackground( c, isIntelliJTheme, focusedBackground ) );
|
g.setColor( FlatTextFieldUI.getBackground( c, focusedBackground ) );
|
||||||
g.fillRect( 0, 0, c.getWidth(), c.getHeight() );
|
g.fillRect( 0, 0, c.getWidth(), c.getHeight() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import java.beans.PropertyChangeEvent;
|
|||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import javax.swing.AbstractButton;
|
import javax.swing.AbstractButton;
|
||||||
import javax.swing.Box;
|
import javax.swing.Box;
|
||||||
@@ -53,6 +54,7 @@ import javax.swing.plaf.ComponentUI;
|
|||||||
import javax.swing.plaf.metal.MetalFileChooserUI;
|
import javax.swing.plaf.metal.MetalFileChooserUI;
|
||||||
import javax.swing.table.TableCellRenderer;
|
import javax.swing.table.TableCellRenderer;
|
||||||
import com.formdev.flatlaf.FlatClientProperties;
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
|
import com.formdev.flatlaf.icons.FlatFileViewDirectoryIcon;
|
||||||
import com.formdev.flatlaf.util.LoggingFacade;
|
import com.formdev.flatlaf.util.LoggingFacade;
|
||||||
import com.formdev.flatlaf.util.ScaledImageIcon;
|
import com.formdev.flatlaf.util.ScaledImageIcon;
|
||||||
import com.formdev.flatlaf.util.SystemInfo;
|
import com.formdev.flatlaf.util.SystemInfo;
|
||||||
@@ -243,11 +245,13 @@ public class FlatFileChooserUI
|
|||||||
borderLayout.setHgap( 8 );
|
borderLayout.setHgap( 8 );
|
||||||
|
|
||||||
Component north = borderLayout.getLayoutComponent( BorderLayout.NORTH );
|
Component north = borderLayout.getLayoutComponent( BorderLayout.NORTH );
|
||||||
|
Component lineEnd = borderLayout.getLayoutComponent( BorderLayout.LINE_END );
|
||||||
Component center = borderLayout.getLayoutComponent( BorderLayout.CENTER );
|
Component center = borderLayout.getLayoutComponent( BorderLayout.CENTER );
|
||||||
Component south = borderLayout.getLayoutComponent( BorderLayout.SOUTH );
|
Component south = borderLayout.getLayoutComponent( BorderLayout.SOUTH );
|
||||||
if( north != null && center != null && south != null ) {
|
if( north != null && lineEnd != null && center != null && south != null ) {
|
||||||
JPanel p = new JPanel( new BorderLayout( 0, 11 ) );
|
JPanel p = new JPanel( new BorderLayout( 0, 11 ) );
|
||||||
p.add( north, BorderLayout.NORTH );
|
p.add( north, BorderLayout.NORTH );
|
||||||
|
p.add( lineEnd, BorderLayout.LINE_END );
|
||||||
p.add( center, BorderLayout.CENTER );
|
p.add( center, BorderLayout.CENTER );
|
||||||
p.add( south, BorderLayout.SOUTH );
|
p.add( south, BorderLayout.SOUTH );
|
||||||
fc.add( p, BorderLayout.CENTER );
|
fc.add( p, BorderLayout.CENTER );
|
||||||
@@ -344,12 +348,12 @@ public class FlatFileChooserUI
|
|||||||
fileView.clearIconCache();
|
fileView.clearIconCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean doNotUseSystemIcons() {
|
private static boolean doNotUseSystemIcons() {
|
||||||
// Java 17 32bit craches on Windows when using system icons
|
// Java 17 32bit craches on Windows when using system icons
|
||||||
// fixed in Java 18+ (see https://bugs.openjdk.java.net/browse/JDK-8277299)
|
// fixed in Java 18+, fix backported in Java 17.0.3+ (see https://bugs.openjdk.java.net/browse/JDK-8277299)
|
||||||
return SystemInfo.isWindows &&
|
return SystemInfo.isWindows &&
|
||||||
SystemInfo.isX86 &&
|
SystemInfo.isX86 &&
|
||||||
(SystemInfo.isJava_17_orLater && !SystemInfo.isJava_18_orLater);
|
(SystemInfo.isJava_17_orLater && SystemInfo.javaVersion < SystemInfo.toVersion( 17, 0, 3, 0 ));
|
||||||
}
|
}
|
||||||
|
|
||||||
//---- class FlatFileView -------------------------------------------------
|
//---- class FlatFileView -------------------------------------------------
|
||||||
@@ -366,7 +370,11 @@ public class FlatFileChooserUI
|
|||||||
|
|
||||||
// get system icon
|
// get system icon
|
||||||
if( f != null ) {
|
if( f != null ) {
|
||||||
|
try {
|
||||||
icon = getFileChooser().getFileSystemView().getSystemIcon( f );
|
icon = getFileChooser().getFileSystemView().getSystemIcon( f );
|
||||||
|
} catch( NullPointerException ex ) {
|
||||||
|
// Java 21 may throw a NPE for exe files that use default Windows exe icon
|
||||||
|
}
|
||||||
|
|
||||||
if( icon != null ) {
|
if( icon != null ) {
|
||||||
if( icon instanceof ImageIcon )
|
if( icon instanceof ImageIcon )
|
||||||
@@ -405,7 +413,7 @@ public class FlatFileChooserUI
|
|||||||
|
|
||||||
protected final File[] files;
|
protected final File[] files;
|
||||||
protected final JToggleButton[] buttons;
|
protected final JToggleButton[] buttons;
|
||||||
protected final ButtonGroup buttonGroup;
|
protected final ButtonGroup buttonGroup = new ButtonGroup();
|
||||||
|
|
||||||
@SuppressWarnings( "unchecked" )
|
@SuppressWarnings( "unchecked" )
|
||||||
public FlatShortcutsPanel( JFileChooser fc ) {
|
public FlatShortcutsPanel( JFileChooser fc ) {
|
||||||
@@ -424,19 +432,22 @@ public class FlatFileChooserUI
|
|||||||
File[] files = getChooserShortcutPanelFiles( fsv );
|
File[] files = getChooserShortcutPanelFiles( fsv );
|
||||||
if( filesFunction != null )
|
if( filesFunction != null )
|
||||||
files = filesFunction.apply( files );
|
files = filesFunction.apply( files );
|
||||||
this.files = files;
|
|
||||||
|
|
||||||
// create toolbar buttons
|
// create toolbar buttons
|
||||||
buttons = new JToggleButton[files.length];
|
ArrayList<File> filesList = new ArrayList<>();
|
||||||
buttonGroup = new ButtonGroup();
|
ArrayList<JToggleButton> buttonsList = new ArrayList<>();
|
||||||
for( int i = 0; i < files.length; i++ ) {
|
for( File file : files ) {
|
||||||
// wrap drive path
|
if( file == null )
|
||||||
if( fsv.isFileSystemRoot( files[i] ) )
|
continue;
|
||||||
files[i] = fsv.createFileObject( files[i].getAbsolutePath() );
|
|
||||||
|
// wrap drive path
|
||||||
|
if( fsv.isFileSystemRoot( file ) )
|
||||||
|
file = fsv.createFileObject( file.getAbsolutePath() );
|
||||||
|
|
||||||
File file = files[i];
|
|
||||||
String name = getDisplayName( fsv, file );
|
String name = getDisplayName( fsv, file );
|
||||||
Icon icon = getIcon( fsv, file );
|
Icon icon = getIcon( fsv, file );
|
||||||
|
if( name == null )
|
||||||
|
continue;
|
||||||
|
|
||||||
// remove path from name
|
// remove path from name
|
||||||
int lastSepIndex = name.lastIndexOf( File.separatorChar );
|
int lastSepIndex = name.lastIndexOf( File.separatorChar );
|
||||||
@@ -451,15 +462,21 @@ public class FlatFileChooserUI
|
|||||||
|
|
||||||
// create button
|
// create button
|
||||||
JToggleButton button = createButton( name, icon );
|
JToggleButton button = createButton( name, icon );
|
||||||
|
File f = file;
|
||||||
button.addActionListener( e -> {
|
button.addActionListener( e -> {
|
||||||
fc.setCurrentDirectory( file );
|
fc.setCurrentDirectory( f );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
add( button );
|
add( button );
|
||||||
buttonGroup.add( button );
|
buttonGroup.add( button );
|
||||||
buttons[i] = button;
|
|
||||||
|
filesList.add( file );
|
||||||
|
buttonsList.add( button );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.files = filesList.toArray( new File[filesList.size()] );
|
||||||
|
this.buttons = buttonsList.toArray( new JToggleButton[buttonsList.size()] );
|
||||||
|
|
||||||
directoryChanged( fc.getCurrentDirectory() );
|
directoryChanged( fc.getCurrentDirectory() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -524,6 +541,10 @@ public class FlatFileChooserUI
|
|||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( doNotUseSystemIcons() )
|
||||||
|
return new FlatFileViewDirectoryIcon();
|
||||||
|
|
||||||
|
try {
|
||||||
// Java 17+ supports getting larger system icons
|
// Java 17+ supports getting larger system icons
|
||||||
try {
|
try {
|
||||||
if( SystemInfo.isJava_17_orLater ) {
|
if( SystemInfo.isJava_17_orLater ) {
|
||||||
@@ -539,14 +560,20 @@ public class FlatFileChooserUI
|
|||||||
return new ImageIcon( image );
|
return new ImageIcon( image );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch( IllegalAccessException ex ) {
|
|
||||||
// do not log because access may be denied via VM option '--illegal-access=deny'
|
|
||||||
} catch( Exception ex ) {
|
} catch( Exception ex ) {
|
||||||
|
// do not log InaccessibleObjectException because access
|
||||||
|
// may be denied via VM option '--illegal-access=deny' (default in Java 16)
|
||||||
|
// (not catching InaccessibleObjectException here because it is new in Java 9, but FlatLaf also runs on Java 8)
|
||||||
|
if( !"java.lang.reflect.InaccessibleObjectException".equals( ex.getClass().getName() ) )
|
||||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||||
}
|
}
|
||||||
|
|
||||||
// get system icon in default size 16x16
|
// get system icon in default size 16x16
|
||||||
return fsv.getSystemIcon( file );
|
return fsv.getSystemIcon( file );
|
||||||
|
} catch( NullPointerException ex ) {
|
||||||
|
// Java 21 may throw a NPE for exe files that use default Windows exe icon
|
||||||
|
return new FlatFileViewDirectoryIcon();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void directoryChanged( File file ) {
|
protected void directoryChanged( File file ) {
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ import javax.swing.plaf.ComponentUI;
|
|||||||
* <!-- FlatTextFieldUI -->
|
* <!-- FlatTextFieldUI -->
|
||||||
*
|
*
|
||||||
* @uiDefault Component.minimumWidth int
|
* @uiDefault Component.minimumWidth int
|
||||||
* @uiDefault Component.isIntelliJTheme boolean
|
|
||||||
* @uiDefault FormattedTextField.placeholderForeground Color
|
* @uiDefault FormattedTextField.placeholderForeground Color
|
||||||
* @uiDefault FormattedTextField.focusedBackground Color optional
|
* @uiDefault FormattedTextField.focusedBackground Color optional
|
||||||
* @uiDefault FormattedTextField.iconTextGap int optional, default is 4
|
* @uiDefault FormattedTextField.iconTextGap int optional, default is 4
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import java.awt.Rectangle;
|
|||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import javax.swing.Icon;
|
import javax.swing.Icon;
|
||||||
@@ -179,7 +180,7 @@ public class FlatLabelUI
|
|||||||
// 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 " + c.getFont().getSize() + "</style>";
|
||||||
|
|
||||||
String lowerText = text.toLowerCase();
|
String lowerText = text.toLowerCase( Locale.ENGLISH );
|
||||||
int headIndex;
|
int headIndex;
|
||||||
int styleIndex;
|
int styleIndex;
|
||||||
|
|
||||||
@@ -228,7 +229,7 @@ public class FlatLabelUI
|
|||||||
int tagBegin = i + 1;
|
int tagBegin = i + 1;
|
||||||
for( i += 2; i < textLength; i++ ) {
|
for( i += 2; i < textLength; i++ ) {
|
||||||
if( !Character.isLetterOrDigit( text.charAt( i ) ) ) {
|
if( !Character.isLetterOrDigit( text.charAt( i ) ) ) {
|
||||||
String tag = text.substring( tagBegin, i ).toLowerCase();
|
String tag = text.substring( tagBegin, i ).toLowerCase( Locale.ENGLISH );
|
||||||
if( tagsUseFontSizeSet.contains( tag ) )
|
if( tagsUseFontSizeSet.contains( tag ) )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import java.awt.Component;
|
|||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.Insets;
|
import java.awt.Insets;
|
||||||
|
import javax.swing.JComponent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Line border for various components.
|
* Line border for various components.
|
||||||
@@ -66,6 +67,9 @@ public class FlatLineBorder
|
|||||||
|
|
||||||
@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( c instanceof JComponent && ((JComponent)c).getClientProperty( FlatPopupFactory.KEY_POPUP_USES_NATIVE_BORDER ) != null )
|
||||||
|
return;
|
||||||
|
|
||||||
Graphics2D g2 = (Graphics2D) g.create();
|
Graphics2D g2 = (Graphics2D) g.create();
|
||||||
try {
|
try {
|
||||||
FlatUIUtils.setRenderingHints( g2 );
|
FlatUIUtils.setRenderingHints( g2 );
|
||||||
|
|||||||
@@ -17,20 +17,34 @@
|
|||||||
package com.formdev.flatlaf.ui;
|
package com.formdev.flatlaf.ui;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
import java.awt.Component;
|
||||||
import java.awt.EventQueue;
|
import java.awt.EventQueue;
|
||||||
|
import java.awt.Graphics;
|
||||||
|
import java.awt.Graphics2D;
|
||||||
import java.awt.Insets;
|
import java.awt.Insets;
|
||||||
|
import java.awt.Point;
|
||||||
|
import java.awt.Rectangle;
|
||||||
import java.awt.event.FocusEvent;
|
import java.awt.event.FocusEvent;
|
||||||
import java.awt.event.FocusListener;
|
import java.awt.event.FocusListener;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import javax.swing.DefaultListCellRenderer;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
|
import javax.swing.JList;
|
||||||
|
import javax.swing.ListCellRenderer;
|
||||||
|
import javax.swing.ListModel;
|
||||||
|
import javax.swing.ListSelectionModel;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
|
import javax.swing.event.ListSelectionListener;
|
||||||
import javax.swing.plaf.ComponentUI;
|
import javax.swing.plaf.ComponentUI;
|
||||||
|
import javax.swing.plaf.basic.BasicComboBoxRenderer;
|
||||||
import javax.swing.plaf.basic.BasicListUI;
|
import javax.swing.plaf.basic.BasicListUI;
|
||||||
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.util.Graphics2DProxy;
|
||||||
import com.formdev.flatlaf.util.LoggingFacade;
|
import com.formdev.flatlaf.util.LoggingFacade;
|
||||||
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JList}.
|
* Provides the Flat LaF UI delegate for {@link javax.swing.JList}.
|
||||||
@@ -59,6 +73,8 @@ import com.formdev.flatlaf.util.LoggingFacade;
|
|||||||
*
|
*
|
||||||
* @uiDefault List.selectionInactiveBackground Color
|
* @uiDefault List.selectionInactiveBackground Color
|
||||||
* @uiDefault List.selectionInactiveForeground Color
|
* @uiDefault List.selectionInactiveForeground Color
|
||||||
|
* @uiDefault List.selectionInsets Insets
|
||||||
|
* @uiDefault List.selectionArc int
|
||||||
*
|
*
|
||||||
* <!-- FlatListCellBorder -->
|
* <!-- FlatListCellBorder -->
|
||||||
*
|
*
|
||||||
@@ -76,6 +92,8 @@ 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 */ @Styleable protected Insets selectionInsets;
|
||||||
|
/** @since 3 */ @Styleable protected int selectionArc;
|
||||||
|
|
||||||
// for FlatListCellBorder
|
// for FlatListCellBorder
|
||||||
/** @since 2 */ @Styleable protected Insets cellMargins;
|
/** @since 2 */ @Styleable protected Insets cellMargins;
|
||||||
@@ -110,6 +128,8 @@ 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" );
|
||||||
|
selectionInsets = UIManager.getInsets( "List.selectionInsets" );
|
||||||
|
selectionArc = UIManager.getInt( "List.selectionArc" );
|
||||||
|
|
||||||
toggleSelectionColors();
|
toggleSelectionColors();
|
||||||
}
|
}
|
||||||
@@ -168,6 +188,29 @@ public class FlatListUI
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ListSelectionListener createListSelectionListener() {
|
||||||
|
ListSelectionListener superListener = super.createListSelectionListener();
|
||||||
|
return e -> {
|
||||||
|
superListener.valueChanged( e );
|
||||||
|
|
||||||
|
// for united rounded selection, repaint parts of the rows/columns that adjoin to the changed rows/columns
|
||||||
|
if( useUnitedRoundedSelection( true, true ) &&
|
||||||
|
!list.isSelectionEmpty() &&
|
||||||
|
(list.getMaxSelectionIndex() - list.getMinSelectionIndex()) >= 1 )
|
||||||
|
{
|
||||||
|
int size = list.getModel().getSize();
|
||||||
|
int firstIndex = Math.min( Math.max( e.getFirstIndex(), 0 ), size - 1 );
|
||||||
|
int lastIndex = Math.min( Math.max( e.getLastIndex(), 0 ), size - 1 );
|
||||||
|
Rectangle r = getCellBounds( list, firstIndex, lastIndex );
|
||||||
|
if( r != null ) {
|
||||||
|
int arc = (int) Math.ceil( UIScale.scale( selectionArc / 2f ) );
|
||||||
|
list.repaint( r.x - arc, r.y - arc, r.width + (arc * 2), r.height + (arc * 2) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/** @since 2 */
|
/** @since 2 */
|
||||||
protected void installStyle() {
|
protected void installStyle() {
|
||||||
try {
|
try {
|
||||||
@@ -247,4 +290,165 @@ public class FlatListUI
|
|||||||
list.setSelectionForeground( selectionInactiveForeground );
|
list.setSelectionForeground( selectionInactiveForeground );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings( "rawtypes" )
|
||||||
|
@Override
|
||||||
|
protected void paintCell( Graphics g, int row, Rectangle rowBounds, ListCellRenderer cellRenderer,
|
||||||
|
ListModel dataModel, ListSelectionModel selModel, int leadIndex )
|
||||||
|
{
|
||||||
|
boolean isSelected = selModel.isSelectedIndex( row );
|
||||||
|
|
||||||
|
// get renderer component
|
||||||
|
@SuppressWarnings( "unchecked" )
|
||||||
|
Component rendererComponent = cellRenderer.getListCellRendererComponent( list,
|
||||||
|
dataModel.getElementAt( row ), row, isSelected,
|
||||||
|
FlatUIUtils.isPermanentFocusOwner( list ) && (row == leadIndex) );
|
||||||
|
|
||||||
|
//
|
||||||
|
boolean isFileList = Boolean.TRUE.equals( list.getClientProperty( "List.isFileList" ) );
|
||||||
|
int cx, cw;
|
||||||
|
if( isFileList ) {
|
||||||
|
// see BasicListUI.paintCell()
|
||||||
|
cw = Math.min( rowBounds.width, rendererComponent.getPreferredSize().width + 4 );
|
||||||
|
cx = list.getComponentOrientation().isLeftToRight()
|
||||||
|
? rowBounds.x
|
||||||
|
: rowBounds.x + (rowBounds.width - cw);
|
||||||
|
} else {
|
||||||
|
cx = rowBounds.x;
|
||||||
|
cw = rowBounds.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
// rounded selection or selection insets
|
||||||
|
if( isSelected &&
|
||||||
|
!isFileList && // rounded selection is not supported for file list
|
||||||
|
(rendererComponent instanceof DefaultListCellRenderer ||
|
||||||
|
rendererComponent instanceof BasicComboBoxRenderer) &&
|
||||||
|
(selectionArc > 0 ||
|
||||||
|
(selectionInsets != null &&
|
||||||
|
(selectionInsets.top != 0 || selectionInsets.left != 0 || selectionInsets.bottom != 0 || selectionInsets.right != 0))) )
|
||||||
|
{
|
||||||
|
// Because selection painting is done in the cell renderer, it would be
|
||||||
|
// necessary to require a FlatLaf specific renderer to implement rounded selection.
|
||||||
|
// Using a LaF specific renderer was avoided because often a custom renderer is
|
||||||
|
// already used in applications. Then either the rounded selection is not used,
|
||||||
|
// or the application has to be changed to extend a FlatLaf renderer.
|
||||||
|
//
|
||||||
|
// To solve this, a graphics proxy is used that paints rounded selection
|
||||||
|
// if row is selected and the renderer wants to fill the background.
|
||||||
|
class RoundedSelectionGraphics extends Graphics2DProxy {
|
||||||
|
// used to avoid endless loop in case that paintCellSelection() invokes
|
||||||
|
// g.fillRect() with full bounds (selectionInsets is 0,0,0,0)
|
||||||
|
private boolean inPaintSelection;
|
||||||
|
|
||||||
|
RoundedSelectionGraphics( Graphics delegate ) {
|
||||||
|
super( (Graphics2D) delegate );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Graphics create() {
|
||||||
|
return new RoundedSelectionGraphics( super.create() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Graphics create( int x, int y, int width, int height ) {
|
||||||
|
return new RoundedSelectionGraphics( super.create( x, y, width, height ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fillRect( int x, int y, int width, int height ) {
|
||||||
|
if( !inPaintSelection &&
|
||||||
|
x == 0 && y == 0 && width == rowBounds.width && height == rowBounds.height &&
|
||||||
|
this.getColor() == rendererComponent.getBackground() )
|
||||||
|
{
|
||||||
|
inPaintSelection = true;
|
||||||
|
paintCellSelection( this, row, x, y, width, height );
|
||||||
|
inPaintSelection = false;
|
||||||
|
} else
|
||||||
|
super.fillRect( x, y, width, height );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g = new RoundedSelectionGraphics( g );
|
||||||
|
}
|
||||||
|
|
||||||
|
// paint renderer
|
||||||
|
rendererPane.paintComponent( g, rendererComponent, list, cx, rowBounds.y, cw, rowBounds.height, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @since 3 */
|
||||||
|
protected void paintCellSelection( Graphics g, int row, int x, int y, int width, int height ) {
|
||||||
|
float arcTopLeft, arcTopRight, arcBottomLeft, arcBottomRight;
|
||||||
|
arcTopLeft = arcTopRight = arcBottomLeft = arcBottomRight = UIScale.scale( selectionArc / 2f );
|
||||||
|
|
||||||
|
if( list.getLayoutOrientation() == JList.VERTICAL ) {
|
||||||
|
// layout orientation: VERTICAL
|
||||||
|
if( useUnitedRoundedSelection( true, false ) ) {
|
||||||
|
if( row > 0 && list.isSelectedIndex( row - 1 ) )
|
||||||
|
arcTopLeft = arcTopRight = 0;
|
||||||
|
if( row < list.getModel().getSize() - 1 && list.isSelectedIndex( row + 1 ) )
|
||||||
|
arcBottomLeft = arcBottomRight = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// layout orientation: VERTICAL_WRAP or HORIZONTAL_WRAP
|
||||||
|
Rectangle r = null;
|
||||||
|
if( useUnitedRoundedSelection( true, false ) ) {
|
||||||
|
// vertical: check whether cells above or below are selected
|
||||||
|
r = getCellBounds( list, row, row );
|
||||||
|
|
||||||
|
int topIndex = locationToIndex( list, new Point( r.x, r.y - 1 ) );
|
||||||
|
int bottomIndex = locationToIndex( list, new Point( r.x, r.y + r.height ) );
|
||||||
|
|
||||||
|
if( topIndex >= 0 && topIndex != row && list.isSelectedIndex( topIndex ) )
|
||||||
|
arcTopLeft = arcTopRight = 0;
|
||||||
|
if( bottomIndex >= 0 && bottomIndex != row && list.isSelectedIndex( bottomIndex ) )
|
||||||
|
arcBottomLeft = arcBottomRight = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( useUnitedRoundedSelection( false, true ) ) {
|
||||||
|
// horizontal: check whether cells left or right are selected
|
||||||
|
if( r == null )
|
||||||
|
r = getCellBounds( list, row, row );
|
||||||
|
|
||||||
|
int leftIndex = locationToIndex( list, new Point( r.x - 1, r.y ) );
|
||||||
|
int rightIndex = locationToIndex( list, new Point( r.x + r.width, r.y ) );
|
||||||
|
|
||||||
|
// special handling for the case that last column contains fewer cells than the other columns
|
||||||
|
boolean ltr = list.getComponentOrientation().isLeftToRight();
|
||||||
|
if( !ltr && leftIndex >= 0 && leftIndex != row && leftIndex == locationToIndex( list, new Point( r.x - 1, r.y - 1 ) ) )
|
||||||
|
leftIndex = -1;
|
||||||
|
if( ltr && rightIndex >= 0 && rightIndex != row && rightIndex == locationToIndex( list, new Point( r.x + r.width, r.y - 1 ) ) )
|
||||||
|
rightIndex = -1;
|
||||||
|
|
||||||
|
if( leftIndex >= 0 && leftIndex != row && list.isSelectedIndex( leftIndex ) )
|
||||||
|
arcTopLeft = arcBottomLeft = 0;
|
||||||
|
if( rightIndex >= 0 && rightIndex != row && list.isSelectedIndex( rightIndex ) )
|
||||||
|
arcTopRight = arcBottomRight = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FlatUIUtils.paintSelection( (Graphics2D) g, x, y, width, height,
|
||||||
|
UIScale.scale( selectionInsets ), arcTopLeft, arcTopRight, arcBottomLeft, arcBottomRight, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean useUnitedRoundedSelection( boolean vertical, boolean horizontal ) {
|
||||||
|
return selectionArc > 0 &&
|
||||||
|
(selectionInsets == null ||
|
||||||
|
(vertical && selectionInsets.top == 0 && selectionInsets.bottom == 0) ||
|
||||||
|
(horizontal && selectionInsets.left == 0 && selectionInsets.right == 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Paints a cell selection at the given coordinates.
|
||||||
|
* The selection color must be set on the graphics context.
|
||||||
|
* <p>
|
||||||
|
* This method is intended for use in custom cell renderers.
|
||||||
|
*
|
||||||
|
* @since 3
|
||||||
|
*/
|
||||||
|
public static void paintCellSelection( JList<?> list, Graphics g, int row, int x, int y, int width, int height ) {
|
||||||
|
if( !(list.getUI() instanceof FlatListUI) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
FlatListUI ui = (FlatListUI) list.getUI();
|
||||||
|
ui.paintCellSelection( g, row, x, y, width, height );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,6 +75,9 @@ public class FlatMenuBarUI
|
|||||||
/** @since 2 */ @Styleable protected Insets itemMargins;
|
/** @since 2 */ @Styleable protected Insets itemMargins;
|
||||||
|
|
||||||
// used in FlatMenuUI
|
// used in FlatMenuUI
|
||||||
|
/** @since 3 */ @Styleable protected Insets selectionInsets;
|
||||||
|
/** @since 3 */ @Styleable protected Insets selectionEmbeddedInsets;
|
||||||
|
/** @since 3 */ @Styleable protected int selectionArc = -1;
|
||||||
/** @since 2 */ @Styleable protected Color hoverBackground;
|
/** @since 2 */ @Styleable protected Color hoverBackground;
|
||||||
/** @since 2.5 */ @Styleable protected Color selectionBackground;
|
/** @since 2.5 */ @Styleable protected Color selectionBackground;
|
||||||
/** @since 2.5 */ @Styleable protected Color selectionForeground;
|
/** @since 2.5 */ @Styleable protected Color selectionForeground;
|
||||||
|
|||||||
@@ -63,6 +63,8 @@ import com.formdev.flatlaf.util.SystemInfo;
|
|||||||
* @uiDefault MenuItem.acceleratorArrowGap int
|
* @uiDefault MenuItem.acceleratorArrowGap int
|
||||||
* @uiDefault MenuItem.checkBackground Color
|
* @uiDefault MenuItem.checkBackground Color
|
||||||
* @uiDefault MenuItem.checkMargins Insets
|
* @uiDefault MenuItem.checkMargins Insets
|
||||||
|
* @uiDefault MenuItem.selectionInsets Insets
|
||||||
|
* @uiDefault MenuItem.selectionArc int
|
||||||
* @uiDefault MenuItem.selectionType String null (default) or underline
|
* @uiDefault MenuItem.selectionType String null (default) or underline
|
||||||
* @uiDefault MenuItem.underlineSelectionBackground Color
|
* @uiDefault MenuItem.underlineSelectionBackground Color
|
||||||
* @uiDefault MenuItem.underlineSelectionCheckBackground Color
|
* @uiDefault MenuItem.underlineSelectionCheckBackground Color
|
||||||
@@ -91,6 +93,9 @@ public class FlatMenuItemRenderer
|
|||||||
@Styleable protected Color checkBackground = UIManager.getColor( "MenuItem.checkBackground" );
|
@Styleable protected Color checkBackground = UIManager.getColor( "MenuItem.checkBackground" );
|
||||||
@Styleable protected Insets checkMargins = UIManager.getInsets( "MenuItem.checkMargins" );
|
@Styleable protected Insets checkMargins = UIManager.getInsets( "MenuItem.checkMargins" );
|
||||||
|
|
||||||
|
/** @since 3 */ @Styleable protected Insets selectionInsets = UIManager.getInsets( "MenuItem.selectionInsets" );
|
||||||
|
/** @since 3 */ @Styleable protected int selectionArc = UIManager.getInt( "MenuItem.selectionArc" );
|
||||||
|
|
||||||
@Styleable protected Color underlineSelectionBackground = UIManager.getColor( "MenuItem.underlineSelectionBackground" );
|
@Styleable protected Color underlineSelectionBackground = UIManager.getColor( "MenuItem.underlineSelectionBackground" );
|
||||||
@Styleable protected Color underlineSelectionCheckBackground = UIManager.getColor( "MenuItem.underlineSelectionCheckBackground" );
|
@Styleable protected Color underlineSelectionCheckBackground = UIManager.getColor( "MenuItem.underlineSelectionCheckBackground" );
|
||||||
@Styleable protected Color underlineSelectionColor = UIManager.getColor( "MenuItem.underlineSelectionColor" );
|
@Styleable protected Color underlineSelectionColor = UIManager.getColor( "MenuItem.underlineSelectionColor" );
|
||||||
@@ -337,10 +342,16 @@ public class FlatMenuItemRenderer
|
|||||||
g.setColor( Color.orange ); g.drawRect( arrowRect.x, arrowRect.y, arrowRect.width - 1, arrowRect.height - 1 );
|
g.setColor( Color.orange ); g.drawRect( arrowRect.x, arrowRect.y, arrowRect.width - 1, arrowRect.height - 1 );
|
||||||
debug*/
|
debug*/
|
||||||
|
|
||||||
|
boolean armedOrSelected = isArmedOrSelected( menuItem );
|
||||||
boolean underlineSelection = isUnderlineSelection();
|
boolean underlineSelection = isUnderlineSelection();
|
||||||
paintBackground( g, underlineSelection ? underlineSelectionBackground : selectionBackground );
|
|
||||||
if( underlineSelection && isArmedOrSelected( menuItem ) )
|
paintBackground( g );
|
||||||
paintUnderlineSelection( g, underlineSelectionColor, underlineSelectionHeight );
|
if( armedOrSelected ) {
|
||||||
|
if( underlineSelection )
|
||||||
|
paintUnderlineSelection( g, underlineSelectionBackground, underlineSelectionColor, underlineSelectionHeight );
|
||||||
|
else
|
||||||
|
paintSelection( g, selectionBackground, selectionInsets, selectionArc );
|
||||||
|
}
|
||||||
paintIcon( g, iconRect, getIconForPainting(), underlineSelection ? underlineSelectionCheckBackground : checkBackground, selectionBackground );
|
paintIcon( g, iconRect, getIconForPainting(), underlineSelection ? underlineSelectionCheckBackground : checkBackground, selectionBackground );
|
||||||
paintText( g, textRect, menuItem.getText(), selectionForeground, disabledForeground );
|
paintText( g, textRect, menuItem.getText(), selectionForeground, disabledForeground );
|
||||||
paintAccelerator( g, accelRect, getAcceleratorText(), acceleratorForeground, acceleratorSelectionForeground, disabledForeground );
|
paintAccelerator( g, accelRect, getAcceleratorText(), acceleratorForeground, acceleratorSelectionForeground, disabledForeground );
|
||||||
@@ -348,21 +359,35 @@ debug*/
|
|||||||
paintArrowIcon( g, arrowRect, arrowIcon );
|
paintArrowIcon( g, arrowRect, arrowIcon );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void paintBackground( Graphics g, Color selectionBackground ) {
|
/** @since 3 */
|
||||||
boolean armedOrSelected = isArmedOrSelected( menuItem );
|
protected void paintBackground( Graphics g ) {
|
||||||
if( menuItem.isOpaque() || armedOrSelected ) {
|
if( menuItem.isOpaque() ) {
|
||||||
// paint background
|
g.setColor( menuItem.getBackground() );
|
||||||
g.setColor( armedOrSelected
|
|
||||||
? deriveBackground( selectionBackground )
|
|
||||||
: menuItem.getBackground() );
|
|
||||||
g.fillRect( 0, 0, menuItem.getWidth(), menuItem.getHeight() );
|
g.fillRect( 0, 0, menuItem.getWidth(), menuItem.getHeight() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void paintUnderlineSelection( Graphics g, Color underlineSelectionColor, int underlineSelectionHeight ) {
|
/** @since 3 */
|
||||||
|
protected void paintSelection( Graphics g, Color selectionBackground, Insets selectionInsets, int selectionArc ) {
|
||||||
|
float arc = scale( selectionArc / 2f );
|
||||||
|
|
||||||
|
g.setColor( deriveBackground( selectionBackground ) );
|
||||||
|
FlatUIUtils.paintSelection( (Graphics2D) g, 0, 0, menuItem.getWidth(), menuItem.getHeight(),
|
||||||
|
scale( selectionInsets ), arc, arc, arc, arc, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @since 3 */
|
||||||
|
protected void paintUnderlineSelection( Graphics g, Color underlineSelectionBackground,
|
||||||
|
Color underlineSelectionColor, int underlineSelectionHeight )
|
||||||
|
{
|
||||||
int width = menuItem.getWidth();
|
int width = menuItem.getWidth();
|
||||||
int height = menuItem.getHeight();
|
int height = menuItem.getHeight();
|
||||||
|
|
||||||
|
// paint background
|
||||||
|
g.setColor( deriveBackground( underlineSelectionBackground ) );
|
||||||
|
g.fillRect( 0, 0, width, height );
|
||||||
|
|
||||||
|
// paint underline
|
||||||
int underlineHeight = scale( underlineSelectionHeight );
|
int underlineHeight = scale( underlineSelectionHeight );
|
||||||
g.setColor( underlineSelectionColor );
|
g.setColor( underlineSelectionColor );
|
||||||
if( isTopLevelMenu( menuItem ) ) {
|
if( isTopLevelMenu( menuItem ) ) {
|
||||||
@@ -431,10 +456,11 @@ debug*/
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// center because the real icon may be smaller than dimension in iconRect
|
// center because the real icon may be smaller than dimension in iconRect
|
||||||
|
int x = iconRect.x + centerOffset( iconRect.width, icon.getIconWidth() );
|
||||||
int y = iconRect.y + centerOffset( iconRect.height, icon.getIconHeight() );
|
int y = iconRect.y + centerOffset( iconRect.height, icon.getIconHeight() );
|
||||||
|
|
||||||
// paint
|
// paint
|
||||||
icon.paintIcon( menuItem, g, iconRect.x, y );
|
icon.paintIcon( menuItem, g, x, y );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static void paintText( Graphics g, JMenuItem menuItem,
|
protected static void paintText( Graphics g, JMenuItem menuItem,
|
||||||
|
|||||||
@@ -17,10 +17,13 @@
|
|||||||
package com.formdev.flatlaf.ui;
|
package com.formdev.flatlaf.ui;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
import java.awt.Container;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
|
import java.awt.Insets;
|
||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
|
import java.awt.Window;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
@@ -32,7 +35,9 @@ import javax.swing.JComponent;
|
|||||||
import javax.swing.JMenu;
|
import javax.swing.JMenu;
|
||||||
import javax.swing.JMenuBar;
|
import javax.swing.JMenuBar;
|
||||||
import javax.swing.JMenuItem;
|
import javax.swing.JMenuItem;
|
||||||
|
import javax.swing.JRootPane;
|
||||||
import javax.swing.LookAndFeel;
|
import javax.swing.LookAndFeel;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.event.MouseInputListener;
|
import javax.swing.event.MouseInputListener;
|
||||||
import javax.swing.plaf.ComponentUI;
|
import javax.swing.plaf.ComponentUI;
|
||||||
@@ -75,9 +80,12 @@ import com.formdev.flatlaf.util.LoggingFacade;
|
|||||||
*
|
*
|
||||||
* <!-- FlatMenuRenderer -->
|
* <!-- FlatMenuRenderer -->
|
||||||
*
|
*
|
||||||
|
* @uiDefault MenuBar.selectionInsets Insets
|
||||||
|
* @uiDefault MenuBar.selectionEmbeddedInsets Insets
|
||||||
|
* @uiDefault MenuBar.selectionArc int
|
||||||
* @uiDefault MenuBar.hoverBackground Color
|
* @uiDefault MenuBar.hoverBackground Color
|
||||||
* @uiDefault MenuBar.selectionBackground Color
|
* @uiDefault MenuBar.selectionBackground Color optional; defaults to Menu.selectionBackground
|
||||||
* @uiDefault MenuBar.selectionForeground Color
|
* @uiDefault MenuBar.selectionForeground Color optional; defaults to Menu.selectionForeground
|
||||||
* @uiDefault MenuBar.underlineSelectionBackground Color
|
* @uiDefault MenuBar.underlineSelectionBackground Color
|
||||||
* @uiDefault MenuBar.underlineSelectionColor Color
|
* @uiDefault MenuBar.underlineSelectionColor Color
|
||||||
* @uiDefault MenuBar.underlineSelectionHeight int
|
* @uiDefault MenuBar.underlineSelectionHeight int
|
||||||
@@ -225,12 +233,15 @@ public class FlatMenuUI
|
|||||||
protected class FlatMenuRenderer
|
protected class FlatMenuRenderer
|
||||||
extends FlatMenuItemRenderer
|
extends FlatMenuItemRenderer
|
||||||
{
|
{
|
||||||
|
/** @since 3 */ protected Insets menuBarSelectionInsets = UIManager.getInsets( "MenuBar.selectionInsets" );
|
||||||
|
/** @since 3 */ protected Insets menuBarSelectionEmbeddedInsets = UIManager.getInsets( "MenuBar.selectionEmbeddedInsets" );
|
||||||
|
/** @since 3 */ protected int menuBarSelectionArc = UIManager.getInt( "MenuBar.selectionArc" );
|
||||||
protected Color hoverBackground = UIManager.getColor( "MenuBar.hoverBackground" );
|
protected Color hoverBackground = UIManager.getColor( "MenuBar.hoverBackground" );
|
||||||
protected Color menuBarSelectionBackground = UIManager.getColor( "MenuBar.selectionBackground" );
|
/** @since 2.5 */ protected Color menuBarSelectionBackground = UIManager.getColor( "MenuBar.selectionBackground" );
|
||||||
protected Color menuBarSelectionForeground = UIManager.getColor( "MenuBar.selectionForeground" );
|
/** @since 2.5 */ protected Color menuBarSelectionForeground = UIManager.getColor( "MenuBar.selectionForeground" );
|
||||||
protected Color menuBarUnderlineSelectionBackground = FlatUIUtils.getUIColor( "MenuBar.underlineSelectionBackground", underlineSelectionBackground );
|
protected Color menuBarUnderlineSelectionBackground = UIManager.getColor( "MenuBar.underlineSelectionBackground" );
|
||||||
protected Color menuBarUnderlineSelectionColor = FlatUIUtils.getUIColor( "MenuBar.underlineSelectionColor", underlineSelectionColor );
|
protected Color menuBarUnderlineSelectionColor = UIManager.getColor( "MenuBar.underlineSelectionColor" );
|
||||||
protected int menuBarUnderlineSelectionHeight = FlatUIUtils.getUIInt( "MenuBar.underlineSelectionHeight", underlineSelectionHeight );
|
protected int menuBarUnderlineSelectionHeight = FlatUIUtils.getUIInt( "MenuBar.underlineSelectionHeight", -1 );
|
||||||
|
|
||||||
protected FlatMenuRenderer( JMenuItem menuItem, Icon checkIcon, Icon arrowIcon,
|
protected FlatMenuRenderer( JMenuItem menuItem, Icon checkIcon, Icon arrowIcon,
|
||||||
Font acceleratorFont, String acceleratorDelimiter )
|
Font acceleratorFont, String acceleratorDelimiter )
|
||||||
@@ -238,55 +249,90 @@ public class FlatMenuUI
|
|||||||
super( menuItem, checkIcon, arrowIcon, acceleratorFont, acceleratorDelimiter );
|
super( menuItem, checkIcon, arrowIcon, acceleratorFont, acceleratorDelimiter );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @since 3 */
|
||||||
@Override
|
@Override
|
||||||
protected void paintBackground( Graphics g, Color selectionBackground ) {
|
protected void paintBackground( Graphics g ) {
|
||||||
if( ((JMenu)menuItem).isTopLevelMenu() ) {
|
super.paintBackground( g );
|
||||||
if( isUnderlineSelection() )
|
|
||||||
selectionBackground = getStyleFromMenuBarUI( ui -> ui.underlineSelectionBackground, menuBarUnderlineSelectionBackground );
|
|
||||||
else {
|
|
||||||
selectionBackground = getStyleFromMenuBarUI( ui -> ui.selectionBackground,
|
|
||||||
menuBarSelectionBackground != null ? menuBarSelectionBackground : selectionBackground );
|
|
||||||
}
|
|
||||||
|
|
||||||
ButtonModel model = menuItem.getModel();
|
if( ((JMenu)menuItem).isTopLevelMenu() && isHover() ) {
|
||||||
if( model.isRollover() && !model.isArmed() && !model.isSelected() && model.isEnabled() ) {
|
// paint hover background
|
||||||
g.setColor( deriveBackground( getStyleFromMenuBarUI( ui -> ui.hoverBackground, hoverBackground ) ) );
|
Color color = deriveBackground( getStyleFromMenuBarUI( ui -> ui.hoverBackground, hoverBackground ) );
|
||||||
|
if( isUnderlineSelection() ) {
|
||||||
|
g.setColor( color );
|
||||||
g.fillRect( 0, 0, menuItem.getWidth(), menuItem.getHeight() );
|
g.fillRect( 0, 0, menuItem.getWidth(), menuItem.getHeight() );
|
||||||
return;
|
} else
|
||||||
|
paintSelection( g, color, selectionInsets, selectionArc );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
super.paintBackground( g, selectionBackground );
|
/** @since 3 */
|
||||||
|
@Override
|
||||||
|
protected void paintSelection( Graphics g, Color selectionBackground, Insets selectionInsets, int selectionArc ) {
|
||||||
|
if( ((JMenu)menuItem).isTopLevelMenu() ) {
|
||||||
|
if( !isHover() )
|
||||||
|
selectionBackground = getStyleFromMenuBarUI( ui -> ui.selectionBackground, menuBarSelectionBackground, selectionBackground );
|
||||||
|
|
||||||
|
Container menuBar = menuItem.getParent();
|
||||||
|
JRootPane rootPane = SwingUtilities.getRootPane( menuBar );
|
||||||
|
if( rootPane != null && rootPane.getParent() instanceof Window &&
|
||||||
|
rootPane.getJMenuBar() == menuBar &&
|
||||||
|
FlatRootPaneUI.isMenuBarEmbedded( rootPane ) )
|
||||||
|
{
|
||||||
|
selectionInsets = getStyleFromMenuBarUI( ui -> ui.selectionEmbeddedInsets, menuBarSelectionEmbeddedInsets );
|
||||||
|
} else
|
||||||
|
selectionInsets = getStyleFromMenuBarUI( ui -> ui.selectionInsets, menuBarSelectionInsets );
|
||||||
|
|
||||||
|
selectionArc = getStyleFromMenuBarUI( ui -> (ui.selectionArc != -1)
|
||||||
|
? ui.selectionArc : null, menuBarSelectionArc );
|
||||||
|
}
|
||||||
|
|
||||||
|
super.paintSelection( g, selectionBackground, selectionInsets, selectionArc );
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @since 3 */
|
||||||
|
@Override
|
||||||
|
protected void paintUnderlineSelection( Graphics g, Color underlineSelectionBackground,
|
||||||
|
Color underlineSelectionColor, int underlineSelectionHeight )
|
||||||
|
{
|
||||||
|
if( ((JMenu)menuItem).isTopLevelMenu() ) {
|
||||||
|
underlineSelectionBackground = getStyleFromMenuBarUI( ui -> ui.underlineSelectionBackground, menuBarUnderlineSelectionBackground, underlineSelectionBackground );
|
||||||
|
underlineSelectionColor = getStyleFromMenuBarUI( ui -> ui.underlineSelectionColor, menuBarUnderlineSelectionColor, underlineSelectionColor );
|
||||||
|
underlineSelectionHeight = getStyleFromMenuBarUI( ui -> (ui.underlineSelectionHeight != -1) ? ui.underlineSelectionHeight : null,
|
||||||
|
(menuBarUnderlineSelectionHeight != -1) ? menuBarUnderlineSelectionHeight : underlineSelectionHeight );
|
||||||
|
}
|
||||||
|
|
||||||
|
super.paintUnderlineSelection( g, underlineSelectionBackground, underlineSelectionColor, underlineSelectionHeight );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void paintText( Graphics g, Rectangle textRect, String text, Color selectionForeground, Color disabledForeground ) {
|
protected void paintText( Graphics g, Rectangle textRect, String text, Color selectionForeground, Color disabledForeground ) {
|
||||||
if( ((JMenu)menuItem).isTopLevelMenu() && !isUnderlineSelection() ) {
|
if( ((JMenu)menuItem).isTopLevelMenu() && !isUnderlineSelection() )
|
||||||
selectionForeground = getStyleFromMenuBarUI( ui -> ui.selectionForeground,
|
selectionForeground = getStyleFromMenuBarUI( ui -> ui.selectionForeground, menuBarSelectionForeground, selectionForeground );
|
||||||
menuBarSelectionForeground != null ? menuBarSelectionForeground : selectionForeground );
|
|
||||||
}
|
|
||||||
|
|
||||||
super.paintText( g, textRect, text, selectionForeground, disabledForeground );
|
super.paintText( g, textRect, text, selectionForeground, disabledForeground );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private boolean isHover() {
|
||||||
protected void paintUnderlineSelection( Graphics g, Color underlineSelectionColor, int underlineSelectionHeight ) {
|
ButtonModel model = menuItem.getModel();
|
||||||
if( ((JMenu)menuItem).isTopLevelMenu() ) {
|
return model.isRollover() && !model.isArmed() && !model.isSelected() && model.isEnabled();
|
||||||
underlineSelectionColor = getStyleFromMenuBarUI( ui -> ui.underlineSelectionColor, menuBarUnderlineSelectionColor );
|
|
||||||
underlineSelectionHeight = getStyleFromMenuBarUI( ui -> (ui.underlineSelectionHeight != -1)
|
|
||||||
? ui.underlineSelectionHeight : null, menuBarUnderlineSelectionHeight );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
super.paintUnderlineSelection( g, underlineSelectionColor, underlineSelectionHeight );
|
private <T> T getStyleFromMenuBarUI( Function<FlatMenuBarUI, T> f, T defaultValue, T defaultValue2 ) {
|
||||||
|
return getStyleFromMenuBarUI( f, (defaultValue != null) ? defaultValue : defaultValue2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T> T getStyleFromMenuBarUI( Function<FlatMenuBarUI, T> f, T defaultValue ) {
|
private <T> T getStyleFromMenuBarUI( Function<FlatMenuBarUI, T> f, T defaultValue ) {
|
||||||
MenuBarUI ui = ((JMenuBar)menuItem.getParent()).getUI();
|
Container menuItemParent = menuItem.getParent();
|
||||||
if( !(ui instanceof FlatMenuBarUI) )
|
if( menuItemParent instanceof JMenuBar ) {
|
||||||
return defaultValue;
|
MenuBarUI ui = ((JMenuBar) menuItemParent).getUI();
|
||||||
|
if( ui instanceof FlatMenuBarUI ) {
|
||||||
T value = f.apply( (FlatMenuBarUI) ui );
|
T value = f.apply( (FlatMenuBarUI) ui );
|
||||||
return (value != null) ? value : defaultValue;
|
if( value != null ) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return defaultValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
package com.formdev.flatlaf.ui;
|
package com.formdev.flatlaf.ui;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.security.CodeSource;
|
||||||
import com.formdev.flatlaf.FlatSystemProperties;
|
import com.formdev.flatlaf.FlatSystemProperties;
|
||||||
import com.formdev.flatlaf.util.LoggingFacade;
|
import com.formdev.flatlaf.util.LoggingFacade;
|
||||||
import com.formdev.flatlaf.util.NativeLibrary;
|
import com.formdev.flatlaf.util.NativeLibrary;
|
||||||
@@ -31,6 +33,7 @@ import com.formdev.flatlaf.util.SystemInfo;
|
|||||||
*/
|
*/
|
||||||
class FlatNativeLibrary
|
class FlatNativeLibrary
|
||||||
{
|
{
|
||||||
|
private static boolean initialized;
|
||||||
private static NativeLibrary nativeLibrary;
|
private static NativeLibrary nativeLibrary;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -43,28 +46,52 @@ class FlatNativeLibrary
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void initialize() {
|
private static void initialize() {
|
||||||
if( nativeLibrary != null )
|
if( initialized )
|
||||||
|
return;
|
||||||
|
initialized = true;
|
||||||
|
|
||||||
|
if( !FlatSystemProperties.getBoolean( FlatSystemProperties.USE_NATIVE_LIBRARY, true ) )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
String libraryName;
|
String classifier;
|
||||||
if( SystemInfo.isWindows_10_orLater && (SystemInfo.isX86 || SystemInfo.isX86_64) ) {
|
String ext;
|
||||||
// Windows: requires Windows 10/11 (x86 or x86_64)
|
if( SystemInfo.isWindows_10_orLater && (SystemInfo.isX86 || SystemInfo.isX86_64 || SystemInfo.isAARCH64) ) {
|
||||||
|
// Windows: requires Windows 10/11 (x86, x86_64 or aarch64)
|
||||||
|
|
||||||
libraryName = "flatlaf-windows-x86";
|
if( SystemInfo.isAARCH64 )
|
||||||
if( SystemInfo.isX86_64 )
|
classifier = "windows-arm64";
|
||||||
libraryName += "_64";
|
else if( SystemInfo.isX86_64 )
|
||||||
|
classifier = "windows-x86_64";
|
||||||
|
else
|
||||||
|
classifier = "windows-x86";
|
||||||
|
|
||||||
|
ext = "dll";
|
||||||
|
|
||||||
|
// Do not load jawt.dll (part of JRE) here explicitly because
|
||||||
|
// the FlatLaf native library flatlaf.dll may be loaded very early on Windows
|
||||||
|
// (e.g. from class com.formdev.flatlaf.util.SystemInfo) and before AWT is
|
||||||
|
// initialized (and awt.dll is loaded). Loading jawt.dll also loads awt.dll.
|
||||||
|
// In Java 8, loading jawt.dll before AWT is initialized may load
|
||||||
|
// a wrong version of awt.dll if a newer Java version (e.g. 19)
|
||||||
|
// is in PATH environment variable. Then Java 19 awt.dll and Java 8 awt.dll
|
||||||
|
// are loaded at same time and calling JAWT_GetAWT() crashes the application.
|
||||||
|
//
|
||||||
|
// To avoid this, flatlaf.dll is not linked to jawt.dll,
|
||||||
|
// which avoids loading jawt.dll when flatlaf.dll is loaded.
|
||||||
|
// Instead, flatlaf.dll dynamically loads jawt.dll when first used,
|
||||||
|
// which is guaranteed after AWT initialization.
|
||||||
|
|
||||||
|
} else if( SystemInfo.isMacOS_10_14_Mojave_orLater && (SystemInfo.isAARCH64 || SystemInfo.isX86_64) ) {
|
||||||
|
// macOS: requires macOS 10.14 or later (arm64 or x86_64)
|
||||||
|
|
||||||
|
classifier = SystemInfo.isAARCH64 ? "macos-arm64" : "macos-x86_64";
|
||||||
|
ext = "dylib";
|
||||||
|
|
||||||
// In Java 8, load jawt.dll (part of JRE) explicitly because it
|
|
||||||
// is not found when running application with <jdk>/bin/java.exe.
|
|
||||||
// When using <jdk>/jre/bin/java.exe, it is found.
|
|
||||||
// jawt.dll is located in <jdk>/jre/bin/.
|
|
||||||
// Java 9 and later do not have this problem,
|
|
||||||
// but load jawt.dll anyway to be on the safe side.
|
|
||||||
loadJAWT();
|
|
||||||
} else if( SystemInfo.isLinux && SystemInfo.isX86_64 ) {
|
} else if( SystemInfo.isLinux && SystemInfo.isX86_64 ) {
|
||||||
// Linux: requires x86_64
|
// Linux: requires x86_64
|
||||||
|
|
||||||
libraryName = "flatlaf-linux-x86_64";
|
classifier = "linux-x86_64";
|
||||||
|
ext = "so";
|
||||||
|
|
||||||
// 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.
|
||||||
@@ -76,10 +103,13 @@ 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 = createNativeLibrary( libraryName );
|
nativeLibrary = createNativeLibrary( classifier, ext );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static NativeLibrary createNativeLibrary( String libraryName ) {
|
private static NativeLibrary createNativeLibrary( String classifier, String ext ) {
|
||||||
|
String libraryName = "flatlaf-" + classifier;
|
||||||
|
|
||||||
|
// load from "java.library.path" or from path specified in system property "flatlaf.nativeLibraryPath"
|
||||||
String libraryPath = System.getProperty( FlatSystemProperties.NATIVE_LIBRARY_PATH );
|
String libraryPath = System.getProperty( FlatSystemProperties.NATIVE_LIBRARY_PATH );
|
||||||
if( libraryPath != null ) {
|
if( libraryPath != null ) {
|
||||||
if( "system".equals( libraryPath ) ) {
|
if( "system".equals( libraryPath ) ) {
|
||||||
@@ -87,19 +117,118 @@ class FlatNativeLibrary
|
|||||||
if( library.isLoaded() )
|
if( library.isLoaded() )
|
||||||
return library;
|
return library;
|
||||||
|
|
||||||
LoggingFacade.INSTANCE.logSevere( "Did not find library " + libraryName + " in java.library.path, using extracted library instead", null );
|
LoggingFacade.INSTANCE.logSevere( "Did not find library '" + System.mapLibraryName( libraryName )
|
||||||
|
+ "' in java.library.path '" + System.getProperty( "java.library.path" )
|
||||||
|
+ "', using extracted library instead", null );
|
||||||
} else {
|
} else {
|
||||||
|
// try standard library naming scheme
|
||||||
|
// (same as in flatlaf.jar in package 'com/formdev/flatlaf/natives')
|
||||||
File libraryFile = new File( libraryPath, System.mapLibraryName( libraryName ) );
|
File libraryFile = new File( libraryPath, System.mapLibraryName( libraryName ) );
|
||||||
if( libraryFile.exists() )
|
if( libraryFile.exists() )
|
||||||
return new NativeLibrary( libraryFile, true );
|
return new NativeLibrary( libraryFile, true );
|
||||||
|
|
||||||
LoggingFacade.INSTANCE.logSevere( "Did not find external library " + libraryFile + ", using extracted library instead", null );
|
// try Maven naming scheme
|
||||||
|
// (see https://www.formdev.com/flatlaf/native-libraries/)
|
||||||
|
String libraryName2 = null;
|
||||||
|
File jarFile = getJarFile();
|
||||||
|
if( jarFile != null ) {
|
||||||
|
libraryName2 = buildLibraryName( jarFile, classifier, ext );
|
||||||
|
File libraryFile2 = new File( libraryPath, libraryName2 );
|
||||||
|
if( libraryFile2.exists() )
|
||||||
|
return new NativeLibrary( libraryFile2, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
LoggingFacade.INSTANCE.logSevere( "Did not find library '"
|
||||||
|
+ libraryFile.getName()
|
||||||
|
+ (libraryName2 != null ? ("' or '" + libraryName2) : "")
|
||||||
|
+ "' in '" + libraryFile.getParentFile().getAbsolutePath()
|
||||||
|
+ "', using extracted library instead", null );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// load from beside the FlatLaf jar
|
||||||
|
// e.g. for flatlaf-3.1.jar, load flatlaf-3.1-windows-x86_64.dll (from same directory)
|
||||||
|
File libraryFile = findLibraryBesideJar( classifier, ext );
|
||||||
|
if( libraryFile != null )
|
||||||
|
return new NativeLibrary( libraryFile, true );
|
||||||
|
|
||||||
|
// 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, true );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search for a native library beside the jar that contains this class
|
||||||
|
* (usually the FlatLaf jar).
|
||||||
|
* The native library must be in the same directory (or in "../bin" if jar is in "lib")
|
||||||
|
* as the jar and have the same basename as the jar.
|
||||||
|
* If FlatLaf jar is repackaged into fat/uber application jar, "-flatlaf" is appended to jar basename.
|
||||||
|
* The classifier and the extension are appended to the jar basename.
|
||||||
|
*
|
||||||
|
* E.g.
|
||||||
|
* flatlaf-3.1.jar
|
||||||
|
* flatlaf-3.1-windows-x86_64.dll
|
||||||
|
* flatlaf-3.1-linux-x86_64.so
|
||||||
|
*/
|
||||||
|
private static File findLibraryBesideJar( String classifier, String ext ) {
|
||||||
|
// get location of FlatLaf jar (or fat/uber application jar)
|
||||||
|
File jarFile = getJarFile();
|
||||||
|
if( jarFile == null )
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// build library file
|
||||||
|
String libraryName = buildLibraryName( jarFile, classifier, ext );
|
||||||
|
File parent = jarFile.getParentFile();
|
||||||
|
|
||||||
|
// check whether native library exists in same directory as jar
|
||||||
|
File libraryFile = new File( parent, libraryName );
|
||||||
|
if( libraryFile.isFile() )
|
||||||
|
return libraryFile;
|
||||||
|
|
||||||
|
// if jar is in "lib" directory, then also check whether native library exists
|
||||||
|
// in "../bin" directory
|
||||||
|
if( parent.getName().equalsIgnoreCase( "lib" ) ) {
|
||||||
|
libraryFile = new File( parent.getParentFile(), "bin/" + libraryName );
|
||||||
|
if( libraryFile.isFile() )
|
||||||
|
return libraryFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
// native library not found
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static File getJarFile() {
|
||||||
|
try {
|
||||||
|
// get location of FlatLaf jar
|
||||||
|
CodeSource codeSource = FlatNativeLibrary.class.getProtectionDomain().getCodeSource();
|
||||||
|
URL jarUrl = (codeSource != null) ? codeSource.getLocation() : null;
|
||||||
|
if( jarUrl == null )
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// if url is not a file, then we're running in a special environment (e.g. WebStart)
|
||||||
|
if( !"file".equals( jarUrl.getProtocol() ) )
|
||||||
|
return null;
|
||||||
|
|
||||||
|
File jarFile = new File( jarUrl.toURI() );
|
||||||
|
|
||||||
|
// if jarFile is a directory, then we're in a development environment
|
||||||
|
if( !jarFile.isFile() )
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return jarFile;
|
||||||
|
} catch( Exception ex ) {
|
||||||
|
LoggingFacade.INSTANCE.logSevere( ex.getMessage(), ex );
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String buildLibraryName( File jarFile, String classifier, String ext ) {
|
||||||
|
String jarName = jarFile.getName();
|
||||||
|
String jarBasename = jarName.substring( 0, jarName.lastIndexOf( '.' ) );
|
||||||
|
return jarBasename
|
||||||
|
+ (jarBasename.contains( "flatlaf" ) ? "" : "-flatlaf")
|
||||||
|
+ '-' + classifier + '.' + ext;
|
||||||
|
}
|
||||||
|
|
||||||
private static void loadJAWT() {
|
private static void loadJAWT() {
|
||||||
try {
|
try {
|
||||||
System.loadLibrary( "jawt" );
|
System.loadLibrary( "jawt" );
|
||||||
|
|||||||
@@ -23,6 +23,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 com.formdev.flatlaf.util.SystemInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Native methods for Linux.
|
* Native methods for Linux.
|
||||||
@@ -34,8 +35,14 @@ import javax.swing.JFrame;
|
|||||||
*/
|
*/
|
||||||
class FlatNativeLinuxLibrary
|
class FlatNativeLinuxLibrary
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Checks whether native library is loaded/available.
|
||||||
|
* <p>
|
||||||
|
* <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.
|
||||||
|
*/
|
||||||
static boolean isLoaded() {
|
static boolean isLoaded() {
|
||||||
return FlatNativeLibrary.isLoaded();
|
return SystemInfo.isLinux && FlatNativeLibrary.isLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
// direction for _NET_WM_MOVERESIZE message
|
// direction for _NET_WM_MOVERESIZE message
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 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 java.awt.Window;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Native methods for macOS.
|
||||||
|
* <p>
|
||||||
|
* <b>Note</b>: This is private API. Do not use!
|
||||||
|
*
|
||||||
|
* <h2>Methods that use windows as parameter</h2>
|
||||||
|
*
|
||||||
|
* For all methods that accept a {@link java.awt.Window} as parameter,
|
||||||
|
* the underlying macOS window must be already created,
|
||||||
|
* otherwise the method fails. You can use following to ensure this:
|
||||||
|
* <pre>{@code
|
||||||
|
* if( !window.isDisplayable() )
|
||||||
|
* window.addNotify();
|
||||||
|
* }</pre>
|
||||||
|
* or invoke the method after packing the window. E.g.
|
||||||
|
* <pre>{@code
|
||||||
|
* window.pack();
|
||||||
|
* }</pre>
|
||||||
|
*
|
||||||
|
* @author Karl Tauber
|
||||||
|
* @since 3.3
|
||||||
|
*/
|
||||||
|
public class FlatNativeMacLibrary
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Checks whether native library is loaded/available.
|
||||||
|
* <p>
|
||||||
|
* <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.
|
||||||
|
*/
|
||||||
|
public static boolean isLoaded() {
|
||||||
|
return FlatNativeLibrary.isLoaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
public native static boolean setWindowRoundedBorder( Window window, float radius, float borderWidth, int borderColor );
|
||||||
|
}
|
||||||
@@ -17,20 +17,26 @@
|
|||||||
package com.formdev.flatlaf.ui;
|
package com.formdev.flatlaf.ui;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
import java.awt.Component;
|
||||||
import java.awt.Container;
|
import java.awt.Container;
|
||||||
|
import java.awt.Graphics;
|
||||||
|
import java.awt.Graphics2D;
|
||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
|
import java.awt.Toolkit;
|
||||||
import java.awt.Window;
|
import java.awt.Window;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.swing.JDialog;
|
import javax.swing.JDialog;
|
||||||
import javax.swing.JFrame;
|
import javax.swing.JFrame;
|
||||||
import javax.swing.JRootPane;
|
import javax.swing.JRootPane;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.event.ChangeListener;
|
import javax.swing.event.ChangeListener;
|
||||||
|
import javax.swing.plaf.BorderUIResource;
|
||||||
import com.formdev.flatlaf.FlatClientProperties;
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
import com.formdev.flatlaf.FlatLaf;
|
import com.formdev.flatlaf.FlatLaf;
|
||||||
import com.formdev.flatlaf.FlatSystemProperties;
|
import com.formdev.flatlaf.FlatSystemProperties;
|
||||||
import com.formdev.flatlaf.ui.JBRCustomDecorations.JBRWindowTopBorder;
|
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||||
import com.formdev.flatlaf.util.SystemInfo;
|
import com.formdev.flatlaf.util.SystemInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -54,27 +60,15 @@ public class FlatNativeWindowBorder
|
|||||||
!SystemInfo.isWinPE &&
|
!SystemInfo.isWinPE &&
|
||||||
FlatSystemProperties.getBoolean( FlatSystemProperties.USE_WINDOW_DECORATIONS, true );
|
FlatSystemProperties.getBoolean( FlatSystemProperties.USE_WINDOW_DECORATIONS, true );
|
||||||
|
|
||||||
// check this field before using class JBRCustomDecorations to avoid unnecessary loading of that class
|
|
||||||
private static final boolean canUseJBRCustomDecorations =
|
|
||||||
canUseWindowDecorations &&
|
|
||||||
SystemInfo.isJetBrainsJVM_11_orLater &&
|
|
||||||
FlatSystemProperties.getBoolean( FlatSystemProperties.USE_JETBRAINS_CUSTOM_DECORATIONS, false );
|
|
||||||
|
|
||||||
private static Boolean supported;
|
private static Boolean supported;
|
||||||
private static Provider nativeProvider;
|
private static Provider nativeProvider;
|
||||||
|
|
||||||
public static boolean isSupported() {
|
public static boolean isSupported() {
|
||||||
if( canUseJBRCustomDecorations )
|
|
||||||
return JBRCustomDecorations.isSupported();
|
|
||||||
|
|
||||||
initialize();
|
initialize();
|
||||||
return supported;
|
return supported;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Object install( JRootPane rootPane ) {
|
static Object install( JRootPane rootPane ) {
|
||||||
if( canUseJBRCustomDecorations )
|
|
||||||
return JBRCustomDecorations.install( rootPane );
|
|
||||||
|
|
||||||
if( !isSupported() )
|
if( !isSupported() )
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@@ -163,11 +157,6 @@ public class FlatNativeWindowBorder
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void uninstall( JRootPane rootPane, Object data ) {
|
static void uninstall( JRootPane rootPane, Object data ) {
|
||||||
if( canUseJBRCustomDecorations ) {
|
|
||||||
JBRCustomDecorations.uninstall( rootPane, data );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !isSupported() )
|
if( !isSupported() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -215,9 +204,6 @@ public class FlatNativeWindowBorder
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean hasCustomDecoration( Window window ) {
|
public static boolean hasCustomDecoration( Window window ) {
|
||||||
if( canUseJBRCustomDecorations )
|
|
||||||
return JBRCustomDecorations.hasCustomDecoration( window );
|
|
||||||
|
|
||||||
if( !isSupported() )
|
if( !isSupported() )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -225,11 +211,6 @@ public class FlatNativeWindowBorder
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void setHasCustomDecoration( Window window, boolean hasCustomDecoration ) {
|
public static void setHasCustomDecoration( Window window, boolean hasCustomDecoration ) {
|
||||||
if( canUseJBRCustomDecorations ) {
|
|
||||||
JBRCustomDecorations.setHasCustomDecoration( window, hasCustomDecoration );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !isSupported() )
|
if( !isSupported() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -240,11 +221,6 @@ public class FlatNativeWindowBorder
|
|||||||
List<Rectangle> hitTestSpots, Rectangle appIconBounds, Rectangle minimizeButtonBounds,
|
List<Rectangle> hitTestSpots, Rectangle appIconBounds, Rectangle minimizeButtonBounds,
|
||||||
Rectangle maximizeButtonBounds, Rectangle closeButtonBounds )
|
Rectangle maximizeButtonBounds, Rectangle closeButtonBounds )
|
||||||
{
|
{
|
||||||
if( canUseJBRCustomDecorations ) {
|
|
||||||
JBRCustomDecorations.setTitleBarHeightAndHitTestSpots( window, titleBarHeight, hitTestSpots );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !isSupported() )
|
if( !isSupported() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -253,7 +229,7 @@ public class FlatNativeWindowBorder
|
|||||||
}
|
}
|
||||||
|
|
||||||
static boolean showWindow( Window window, int cmd ) {
|
static boolean showWindow( Window window, int cmd ) {
|
||||||
if( canUseJBRCustomDecorations || !isSupported() )
|
if( !isSupported() )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return nativeProvider.showWindow( window, cmd );
|
return nativeProvider.showWindow( window, cmd );
|
||||||
@@ -320,20 +296,36 @@ public class FlatNativeWindowBorder
|
|||||||
* No longer needed since Windows 11.
|
* No longer needed since Windows 11.
|
||||||
*/
|
*/
|
||||||
static class WindowTopBorder
|
static class WindowTopBorder
|
||||||
extends JBRCustomDecorations.JBRWindowTopBorder
|
extends BorderUIResource.EmptyBorderUIResource
|
||||||
{
|
{
|
||||||
private static WindowTopBorder instance;
|
private static WindowTopBorder instance;
|
||||||
|
|
||||||
static JBRWindowTopBorder getInstance() {
|
private final Color activeLightColor = new Color( 0x707070 );
|
||||||
if( canUseJBRCustomDecorations )
|
private final Color activeDarkColor = new Color( 0x2D2E2F );
|
||||||
return JBRWindowTopBorder.getInstance();
|
private final Color inactiveLightColor = new Color( 0xaaaaaa );
|
||||||
|
private final Color inactiveDarkColor = new Color( 0x494A4B );
|
||||||
|
|
||||||
|
private boolean colorizationAffectsBorders;
|
||||||
|
private Color activeColor;
|
||||||
|
|
||||||
|
static WindowTopBorder getInstance() {
|
||||||
if( instance == null )
|
if( instance == null )
|
||||||
instance = new WindowTopBorder();
|
instance = new WindowTopBorder();
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
WindowTopBorder() {
|
||||||
|
super( 1, 0, 0, 0 );
|
||||||
|
|
||||||
|
update();
|
||||||
|
installListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void update() {
|
||||||
|
colorizationAffectsBorders = isColorizationColorAffectsBorders();
|
||||||
|
activeColor = calculateActiveBorderColor();
|
||||||
|
}
|
||||||
|
|
||||||
void installListeners() {
|
void installListeners() {
|
||||||
nativeProvider.addChangeListener( e -> {
|
nativeProvider.addChangeListener( e -> {
|
||||||
update();
|
update();
|
||||||
@@ -346,19 +338,69 @@ public class FlatNativeWindowBorder
|
|||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
boolean isColorizationColorAffectsBorders() {
|
boolean isColorizationColorAffectsBorders() {
|
||||||
return nativeProvider.isColorizationColorAffectsBorders();
|
return nativeProvider.isColorizationColorAffectsBorders();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
Color getColorizationColor() {
|
Color getColorizationColor() {
|
||||||
return nativeProvider.getColorizationColor();
|
return nativeProvider.getColorizationColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
int getColorizationColorBalance() {
|
int getColorizationColorBalance() {
|
||||||
return nativeProvider.getColorizationColorBalance();
|
return nativeProvider.getColorizationColorBalance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Color calculateActiveBorderColor() {
|
||||||
|
if( !colorizationAffectsBorders )
|
||||||
|
return null;
|
||||||
|
|
||||||
|
Color colorizationColor = getColorizationColor();
|
||||||
|
if( colorizationColor != null ) {
|
||||||
|
int colorizationColorBalance = getColorizationColorBalance();
|
||||||
|
if( colorizationColorBalance < 0 || colorizationColorBalance > 100 )
|
||||||
|
colorizationColorBalance = 100;
|
||||||
|
|
||||||
|
if( colorizationColorBalance == 0 )
|
||||||
|
return new Color( 0xD9D9D9 );
|
||||||
|
if( colorizationColorBalance == 100 )
|
||||||
|
return colorizationColor;
|
||||||
|
|
||||||
|
float alpha = colorizationColorBalance / 100.0f;
|
||||||
|
float remainder = 1 - alpha;
|
||||||
|
int r = Math.round( colorizationColor.getRed() * alpha + 0xD9 * remainder );
|
||||||
|
int g = Math.round( colorizationColor.getGreen() * alpha + 0xD9 * remainder );
|
||||||
|
int b = Math.round( colorizationColor.getBlue() * alpha + 0xD9 * remainder );
|
||||||
|
|
||||||
|
// avoid potential IllegalArgumentException in Color constructor
|
||||||
|
r = Math.min( Math.max( r, 0 ), 255 );
|
||||||
|
g = Math.min( Math.max( g, 0 ), 255 );
|
||||||
|
b = Math.min( Math.max( b, 0 ), 255 );
|
||||||
|
|
||||||
|
return new Color( r, g, b );
|
||||||
|
}
|
||||||
|
|
||||||
|
Color activeBorderColor = (Color) Toolkit.getDefaultToolkit().getDesktopProperty( "win.frame.activeBorderColor" );
|
||||||
|
return (activeBorderColor != null) ? activeBorderColor : UIManager.getColor( "MenuBar.borderColor" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||||
|
Window window = SwingUtilities.windowForComponent( c );
|
||||||
|
boolean active = window != null && window.isActive();
|
||||||
|
boolean dark = FlatLaf.isLafDark();
|
||||||
|
|
||||||
|
g.setColor( active
|
||||||
|
? (activeColor != null ? activeColor : (dark ? activeDarkColor : activeLightColor))
|
||||||
|
: (dark ? inactiveDarkColor : inactiveLightColor) );
|
||||||
|
HiDPIUtils.paintAtScale1x( (Graphics2D) g, x, y, width, height, this::paintImpl );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void paintImpl( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
|
||||||
|
g.fillRect( x, y, width, 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
void repaintBorder( Component c ) {
|
||||||
|
c.repaint( 0, 0, c.getWidth(), 1 );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,159 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022 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 java.awt.Color;
|
||||||
|
import java.awt.Window;
|
||||||
|
import com.formdev.flatlaf.util.SystemInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Native methods for Windows.
|
||||||
|
* <p>
|
||||||
|
* <b>Note</b>: This is private API. Do not use!
|
||||||
|
*
|
||||||
|
* @author Karl Tauber
|
||||||
|
* @since 3.1
|
||||||
|
*/
|
||||||
|
public class FlatNativeWindowsLibrary
|
||||||
|
{
|
||||||
|
private static long osBuildNumber = Long.MIN_VALUE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether native library is loaded/available.
|
||||||
|
* <p>
|
||||||
|
* <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.
|
||||||
|
*/
|
||||||
|
public static boolean isLoaded() {
|
||||||
|
return SystemInfo.isWindows && FlatNativeLibrary.isLoaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the Windows operating system build number.
|
||||||
|
* <p>
|
||||||
|
* Invokes Win32 API method {@code GetVersionEx()} and returns {@code OSVERSIONINFO.dwBuildNumber}.
|
||||||
|
* See https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getversionexa
|
||||||
|
*/
|
||||||
|
public static long getOSBuildNumber() {
|
||||||
|
if( osBuildNumber == Long.MIN_VALUE )
|
||||||
|
osBuildNumber = getOSBuildNumberImpl();
|
||||||
|
return osBuildNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invokes Win32 API method {@code GetVersionEx()} and returns {@code OSVERSIONINFO.dwBuildNumber}.
|
||||||
|
* See https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getversionexa
|
||||||
|
*/
|
||||||
|
private native static long getOSBuildNumberImpl();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the Windows window handle (HWND) for the given Swing window.
|
||||||
|
* <p>
|
||||||
|
* Note that the underlying Windows window must be already created,
|
||||||
|
* otherwise this method returns zero. Use following to ensure this:
|
||||||
|
* <pre>{@code
|
||||||
|
* if( !window.isDisplayable() )
|
||||||
|
* window.addNotify();
|
||||||
|
* }</pre>
|
||||||
|
* or invoke this method after packing the window. E.g.
|
||||||
|
* <pre>{@code
|
||||||
|
* window.pack();
|
||||||
|
* long hwnd = getHWND( window );
|
||||||
|
* }</pre>
|
||||||
|
*/
|
||||||
|
public native static long getHWND( Window window );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DWM_WINDOW_CORNER_PREFERENCE
|
||||||
|
* see https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwm_window_corner_preference
|
||||||
|
*/
|
||||||
|
public static final int
|
||||||
|
DWMWCP_DEFAULT = 0,
|
||||||
|
DWMWCP_DONOTROUND = 1,
|
||||||
|
DWMWCP_ROUND = 2,
|
||||||
|
DWMWCP_ROUNDSMALL = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the rounded corner preference for the window.
|
||||||
|
* Allowed values are {@link #DWMWCP_DEFAULT}, {@link #DWMWCP_DONOTROUND},
|
||||||
|
* {@link #DWMWCP_ROUND} and {@link #DWMWCP_ROUNDSMALL}.
|
||||||
|
* <p>
|
||||||
|
* Invokes Win32 API method {@code DwmSetWindowAttribute(DWMWA_WINDOW_CORNER_PREFERENCE)}.
|
||||||
|
* See https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/nf-dwmapi-dwmsetwindowattribute
|
||||||
|
* <p>
|
||||||
|
* Supported since Windows 11 Build 22000.
|
||||||
|
*/
|
||||||
|
public native static boolean setWindowCornerPreference( long hwnd, int cornerPreference );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DWMWINDOWATTRIBUTE
|
||||||
|
* see https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute
|
||||||
|
*
|
||||||
|
* @since 3.3
|
||||||
|
*/
|
||||||
|
public static final int
|
||||||
|
DWMWA_USE_IMMERSIVE_DARK_MODE = 20,
|
||||||
|
DWMWA_BORDER_COLOR = 34,
|
||||||
|
DWMWA_CAPTION_COLOR = 35,
|
||||||
|
DWMWA_TEXT_COLOR = 36;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invokes Win32 API method {@code DwmSetWindowAttribute()} with a {@code BOOL} attribute value.
|
||||||
|
* See https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/nf-dwmapi-dwmsetwindowattribute
|
||||||
|
*
|
||||||
|
* @since 3.3
|
||||||
|
*/
|
||||||
|
public native static boolean dwmSetWindowAttributeBOOL( long hwnd, int attribute, boolean value );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invokes Win32 API method {@code DwmSetWindowAttribute()} with a {@code DWORD} attribute value.
|
||||||
|
* See https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/nf-dwmapi-dwmsetwindowattribute
|
||||||
|
*
|
||||||
|
* @since 3.3
|
||||||
|
*/
|
||||||
|
public native static boolean dwmSetWindowAttributeDWORD( long hwnd, int attribute, int value );
|
||||||
|
|
||||||
|
/** @since 3.3 */
|
||||||
|
public static final int
|
||||||
|
// use this constant to reset any window part colors to the system default behavior
|
||||||
|
DWMWA_COLOR_DEFAULT = 0xFFFFFFFF,
|
||||||
|
// use this constant to specify that a window part should not be rendered
|
||||||
|
DWMWA_COLOR_NONE = 0xFFFFFFFE;
|
||||||
|
|
||||||
|
/** @since 3.3 */
|
||||||
|
public static final Color COLOR_NONE = new Color( 0, true );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invokes Win32 API method {@code DwmSetWindowAttribute()} with a {@code COLORREF} attribute value.
|
||||||
|
* See https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/nf-dwmapi-dwmsetwindowattribute
|
||||||
|
* <p>
|
||||||
|
* Supported since Windows 11 Build 22000.
|
||||||
|
*
|
||||||
|
* @since 3.3
|
||||||
|
*/
|
||||||
|
public static boolean dwmSetWindowAttributeCOLORREF( long hwnd, int attribute, Color color ) {
|
||||||
|
// convert color to Windows RGB value
|
||||||
|
int rgb = (color == COLOR_NONE)
|
||||||
|
? DWMWA_COLOR_NONE
|
||||||
|
: (color != null
|
||||||
|
? (color.getRed() | (color.getGreen() << 8) | (color.getBlue() << 16))
|
||||||
|
: DWMWA_COLOR_DEFAULT);
|
||||||
|
|
||||||
|
// DwmSetWindowAttribute() expects COLORREF as attribute value, which is defined as DWORD
|
||||||
|
return dwmSetWindowAttributeDWORD( hwnd, attribute, rgb );
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,9 +30,7 @@ import javax.swing.JPanel;
|
|||||||
import javax.swing.JRootPane;
|
import javax.swing.JRootPane;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.border.Border;
|
|
||||||
import javax.swing.plaf.ComponentUI;
|
import javax.swing.plaf.ComponentUI;
|
||||||
import javax.swing.plaf.UIResource;
|
|
||||||
import javax.swing.plaf.basic.BasicHTML;
|
import javax.swing.plaf.basic.BasicHTML;
|
||||||
import javax.swing.plaf.basic.BasicOptionPaneUI;
|
import javax.swing.plaf.basic.BasicOptionPaneUI;
|
||||||
import com.formdev.flatlaf.FlatClientProperties;
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
@@ -115,13 +113,6 @@ public class FlatOptionPaneUI
|
|||||||
sameSizeButtons = FlatUIUtils.getUIBoolean( "OptionPane.sameSizeButtons", true );
|
sameSizeButtons = FlatUIUtils.getUIBoolean( "OptionPane.sameSizeButtons", true );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void installComponents() {
|
|
||||||
super.installComponents();
|
|
||||||
|
|
||||||
updateChildPanels( optionPane );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected PropertyChangeListener createPropertyChangeListener() {
|
protected PropertyChangeListener createPropertyChangeListener() {
|
||||||
PropertyChangeListener superListener = super.createPropertyChangeListener();
|
PropertyChangeListener superListener = super.createPropertyChangeListener();
|
||||||
@@ -155,6 +146,13 @@ public class FlatOptionPaneUI
|
|||||||
protected Container createMessageArea() {
|
protected Container createMessageArea() {
|
||||||
Container messageArea = super.createMessageArea();
|
Container messageArea = super.createMessageArea();
|
||||||
|
|
||||||
|
// use non-UIResource OptionPane.messageAreaBorder to avoid that it is replaced when switching LaF
|
||||||
|
// and make panel non-opaque for OptionPane.background
|
||||||
|
updateAreaPanel( messageArea );
|
||||||
|
|
||||||
|
// make known sub-panels non-opaque for OptionPane.background
|
||||||
|
updateKnownChildPanels( messageArea );
|
||||||
|
|
||||||
// set icon-message gap
|
// set icon-message gap
|
||||||
if( iconMessageGap > 0 ) {
|
if( iconMessageGap > 0 ) {
|
||||||
Component iconMessageSeparator = SwingUtils.getComponentByName( messageArea, "OptionPane.separator" );
|
Component iconMessageSeparator = SwingUtils.getComponentByName( messageArea, "OptionPane.separator" );
|
||||||
@@ -169,6 +167,10 @@ public class FlatOptionPaneUI
|
|||||||
protected Container createButtonArea() {
|
protected Container createButtonArea() {
|
||||||
Container buttonArea = super.createButtonArea();
|
Container buttonArea = super.createButtonArea();
|
||||||
|
|
||||||
|
// use non-UIResource OptionPane.buttonAreaBorder to avoid that it is replaced when switching LaF
|
||||||
|
// and make panel non-opaque for OptionPane.background
|
||||||
|
updateAreaPanel( buttonArea );
|
||||||
|
|
||||||
// scale button padding and subtract focusWidth
|
// scale button padding and subtract focusWidth
|
||||||
if( buttonArea.getLayout() instanceof ButtonAreaLayout ) {
|
if( buttonArea.getLayout() instanceof ButtonAreaLayout ) {
|
||||||
ButtonAreaLayout layout = (ButtonAreaLayout) buttonArea.getLayout();
|
ButtonAreaLayout layout = (ButtonAreaLayout) buttonArea.getLayout();
|
||||||
@@ -218,22 +220,33 @@ public class FlatOptionPaneUI
|
|||||||
super.addMessageComponents( container, cons, msg, maxll, internallyCreated );
|
super.addMessageComponents( container, cons, msg, maxll, internallyCreated );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateChildPanels( Container c ) {
|
private void updateAreaPanel( Container area ) {
|
||||||
for( Component child : c.getComponents() ) {
|
if( !(area instanceof JPanel) )
|
||||||
if( child.getClass() == JPanel.class ) {
|
return;
|
||||||
JPanel panel = (JPanel)child;
|
|
||||||
|
|
||||||
// make sub-panel non-opaque for OptionPane.background
|
// use non-UIResource border to avoid that it is replaced when switching LaF
|
||||||
|
// and make panel non-opaque for OptionPane.background
|
||||||
|
JPanel panel = (JPanel) area;
|
||||||
|
panel.setBorder( FlatUIUtils.nonUIResource( panel.getBorder() ) );
|
||||||
panel.setOpaque( false );
|
panel.setOpaque( false );
|
||||||
|
}
|
||||||
|
|
||||||
// use non-UIResource borders to avoid that they are replaced when switching LaF
|
private void updateKnownChildPanels( Container c ) {
|
||||||
Border border = panel.getBorder();
|
for( Component child : c.getComponents() ) {
|
||||||
if( border instanceof UIResource )
|
if( child instanceof JPanel && child.getName() != null ) {
|
||||||
panel.setBorder( FlatUIUtils.nonUIResource( border ) );
|
switch( child.getName() ) {
|
||||||
|
case "OptionPane.realBody":
|
||||||
|
case "OptionPane.body":
|
||||||
|
case "OptionPane.separator":
|
||||||
|
case "OptionPane.break":
|
||||||
|
// make known sub-panels non-opaque for OptionPane.background
|
||||||
|
((JPanel)child).setOpaque( false );
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( child instanceof Container )
|
if( child instanceof Container )
|
||||||
updateChildPanels( (Container) child );
|
updateKnownChildPanels( (Container) child );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,6 @@ import com.formdev.flatlaf.util.UIScale;
|
|||||||
* <!-- FlatTextFieldUI -->
|
* <!-- FlatTextFieldUI -->
|
||||||
*
|
*
|
||||||
* @uiDefault Component.minimumWidth int
|
* @uiDefault Component.minimumWidth int
|
||||||
* @uiDefault Component.isIntelliJTheme boolean
|
|
||||||
* @uiDefault PasswordField.placeholderForeground Color
|
* @uiDefault PasswordField.placeholderForeground Color
|
||||||
* @uiDefault PasswordField.focusedBackground Color optional
|
* @uiDefault PasswordField.focusedBackground Color optional
|
||||||
* @uiDefault PasswordField.iconTextGap int optional, default is 4
|
* @uiDefault PasswordField.iconTextGap int optional, default is 4
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import java.awt.Window;
|
|||||||
import java.awt.event.ComponentEvent;
|
import java.awt.event.ComponentEvent;
|
||||||
import java.awt.event.ComponentListener;
|
import java.awt.event.ComponentListener;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
|
import java.awt.event.WindowFocusListener;
|
||||||
import java.lang.invoke.MethodHandle;
|
import java.lang.invoke.MethodHandle;
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
import java.lang.invoke.MethodType;
|
import java.lang.invoke.MethodType;
|
||||||
@@ -43,6 +44,7 @@ import java.lang.reflect.Method;
|
|||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JLayeredPane;
|
import javax.swing.JLayeredPane;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JPopupMenu;
|
||||||
import javax.swing.JToolTip;
|
import javax.swing.JToolTip;
|
||||||
import javax.swing.JWindow;
|
import javax.swing.JWindow;
|
||||||
import javax.swing.Popup;
|
import javax.swing.Popup;
|
||||||
@@ -52,6 +54,9 @@ import javax.swing.SwingUtilities;
|
|||||||
import javax.swing.ToolTipManager;
|
import javax.swing.ToolTipManager;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.border.Border;
|
import javax.swing.border.Border;
|
||||||
|
import javax.swing.border.EmptyBorder;
|
||||||
|
import javax.swing.border.LineBorder;
|
||||||
|
import javax.swing.plaf.basic.BasicComboPopup;
|
||||||
import com.formdev.flatlaf.FlatClientProperties;
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
import com.formdev.flatlaf.util.SystemInfo;
|
import com.formdev.flatlaf.util.SystemInfo;
|
||||||
import com.formdev.flatlaf.util.UIScale;
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
@@ -66,6 +71,8 @@ import com.formdev.flatlaf.util.UIScale;
|
|||||||
public class FlatPopupFactory
|
public class FlatPopupFactory
|
||||||
extends PopupFactory
|
extends PopupFactory
|
||||||
{
|
{
|
||||||
|
static final String KEY_POPUP_USES_NATIVE_BORDER = "FlatLaf.internal.FlatPopupFactory.popupUsesNativeBorder";
|
||||||
|
|
||||||
private MethodHandle java8getPopupMethod;
|
private MethodHandle java8getPopupMethod;
|
||||||
private MethodHandle java9getPopupMethod;
|
private MethodHandle java9getPopupMethod;
|
||||||
|
|
||||||
@@ -79,14 +86,34 @@ public class FlatPopupFactory
|
|||||||
y = pt.y;
|
y = pt.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fixLinuxWaylandJava21focusIssue( owner );
|
||||||
|
|
||||||
boolean forceHeavyWeight = isOptionEnabled( owner, contents, FlatClientProperties.POPUP_FORCE_HEAVY_WEIGHT, "Popup.forceHeavyWeight" );
|
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 ), contents );
|
return new NonFlashingPopup( getPopupForScreenOfOwner( owner, contents, x, y, forceHeavyWeight ), 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 ) {
|
||||||
return new NonFlashingPopup( getPopupForScreenOfOwner( owner, contents, x, y, true ), contents );
|
NonFlashingPopup popup = new NonFlashingPopup( getPopupForScreenOfOwner( owner, contents, x, y, true ), contents );
|
||||||
|
if( popup.popupWindow != null && SystemInfo.isMacOS && FlatNativeMacLibrary.isLoaded() )
|
||||||
|
setupRoundedBorder( popup.popupWindow, owner, contents );
|
||||||
|
return popup;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Windows 11 with FlatLaf native library can use rounded corners and shows drop shadow for heavy weight popups
|
||||||
|
if( isWindows11BorderSupported() &&
|
||||||
|
getBorderCornerRadius( owner, contents ) > 0 )
|
||||||
|
{
|
||||||
|
NonFlashingPopup popup = new NonFlashingPopup( getPopupForScreenOfOwner( owner, contents, x, y, true ), contents );
|
||||||
|
if( popup.popupWindow != null )
|
||||||
|
setupRoundedBorder( popup.popupWindow, owner, contents );
|
||||||
|
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
|
||||||
return new DropShadowPopup( getPopupForScreenOfOwner( owner, contents, x, y, forceHeavyWeight ), owner, contents );
|
return new DropShadowPopup( getPopupForScreenOfOwner( owner, contents, x, y, forceHeavyWeight ), owner, contents );
|
||||||
@@ -140,47 +167,6 @@ public class FlatPopupFactory
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows the given popup and, if necessary, fixes the location of a heavy weight popup window.
|
|
||||||
* <p>
|
|
||||||
* On a dual screen setup, where screens use different scale factors, it may happen
|
|
||||||
* that the window location changes when showing a heavy weight popup window.
|
|
||||||
* E.g. when opening a dialog on the secondary screen and making combobox popup visible.
|
|
||||||
* <p>
|
|
||||||
* This is a workaround for https://bugs.openjdk.java.net/browse/JDK-8224608
|
|
||||||
*/
|
|
||||||
private static void showPopupAndFixLocation( Popup popup, Window popupWindow ) {
|
|
||||||
if( popupWindow != null ) {
|
|
||||||
// remember location of heavy weight popup window
|
|
||||||
int x = popupWindow.getX();
|
|
||||||
int y = popupWindow.getY();
|
|
||||||
|
|
||||||
popup.show();
|
|
||||||
|
|
||||||
// restore popup window location if it has changed
|
|
||||||
// (probably scaled when screens use different scale factors)
|
|
||||||
if( popupWindow.getX() != x || popupWindow.getY() != y )
|
|
||||||
popupWindow.setLocation( x, y );
|
|
||||||
} else
|
|
||||||
popup.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isOptionEnabled( Component owner, Component contents, String clientKey, String uiKey ) {
|
|
||||||
if( owner instanceof JComponent ) {
|
|
||||||
Boolean b = FlatClientProperties.clientPropertyBooleanStrict( (JComponent) owner, clientKey, null );
|
|
||||||
if( b != null )
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( contents instanceof JComponent ) {
|
|
||||||
Boolean b = FlatClientProperties.clientPropertyBooleanStrict( (JComponent) contents, clientKey, null );
|
|
||||||
if( b != null )
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
return UIManager.getBoolean( uiKey );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* There is no API in Java 8 to force creation of heavy weight popups,
|
* There is no API in Java 8 to force creation of heavy weight popups,
|
||||||
* but it is possible with reflection. Java 9 provides a new method.
|
* but it is possible with reflection. Java 9 provides a new method.
|
||||||
@@ -216,6 +202,33 @@ public class FlatPopupFactory
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isOptionEnabled( Component owner, Component contents, String clientKey, String uiKey ) {
|
||||||
|
Object value = getOption( owner, contents, clientKey, uiKey );
|
||||||
|
return (value instanceof Boolean) ? (Boolean) value : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get option from:
|
||||||
|
* <ol>
|
||||||
|
* <li>client property {@code clientKey} of {@code owner}
|
||||||
|
* <li>client property {@code clientKey} of {@code contents}
|
||||||
|
* <li>UI property {@code uiKey}
|
||||||
|
* </ol>
|
||||||
|
*/
|
||||||
|
private static Object getOption( Component owner, Component contents, String clientKey, String uiKey ) {
|
||||||
|
for( Component c : new Component[] { owner, contents } ) {
|
||||||
|
if( c instanceof JComponent ) {
|
||||||
|
Object value = ((JComponent)c).getClientProperty( clientKey );
|
||||||
|
if( value != null )
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return UIManager.get( uiKey );
|
||||||
|
}
|
||||||
|
|
||||||
|
//---- tooltips -----------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Usually ToolTipManager places a tooltip at (mouseLocation.x, mouseLocation.y + 20).
|
* Usually ToolTipManager places a tooltip at (mouseLocation.x, mouseLocation.y + 20).
|
||||||
* In case that the tooltip would be partly outside of the screen,
|
* In case that the tooltip would be partly outside of the screen,
|
||||||
@@ -300,9 +313,184 @@ public class FlatPopupFactory
|
|||||||
((JComponent)owner).getToolTipLocation( me ) != null;
|
((JComponent)owner).getToolTipLocation( me ) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---- native rounded border ----------------------------------------------
|
||||||
|
|
||||||
|
private static boolean isWindows11BorderSupported() {
|
||||||
|
return SystemInfo.isWindows_11_orLater && FlatNativeWindowsLibrary.isLoaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void setupRoundedBorder( Window popupWindow, Component owner, Component contents ) {
|
||||||
|
// make sure that the native window is created
|
||||||
|
if( !popupWindow.isDisplayable() )
|
||||||
|
popupWindow.addNotify();
|
||||||
|
|
||||||
|
int borderCornerRadius = getBorderCornerRadius( owner, contents );
|
||||||
|
float borderWidth = getRoundedBorderWidth( owner, contents );
|
||||||
|
|
||||||
|
// get Swing border color
|
||||||
|
Color borderColor = null; // use system default color
|
||||||
|
if( contents instanceof JComponent ) {
|
||||||
|
Border border = ((JComponent)contents).getBorder();
|
||||||
|
border = FlatUIUtils.unwrapNonUIResourceBorder( border );
|
||||||
|
|
||||||
|
// get color from border of contents (e.g. JPopupMenu or JToolTip)
|
||||||
|
if( border instanceof FlatLineBorder )
|
||||||
|
borderColor = ((FlatLineBorder)border).getLineColor();
|
||||||
|
else if( border instanceof LineBorder )
|
||||||
|
borderColor = ((LineBorder)border).getLineColor();
|
||||||
|
else if( border instanceof EmptyBorder )
|
||||||
|
borderColor = FlatNativeWindowsLibrary.COLOR_NONE; // do not paint border
|
||||||
|
|
||||||
|
// avoid that FlatLineBorder paints the Swing border
|
||||||
|
((JComponent)contents).putClientProperty( KEY_POPUP_USES_NATIVE_BORDER, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( SystemInfo.isWindows ) {
|
||||||
|
// get native window handle
|
||||||
|
long hwnd = FlatNativeWindowsLibrary.getHWND( popupWindow );
|
||||||
|
|
||||||
|
// set corner preference
|
||||||
|
int cornerPreference = (borderCornerRadius <= 4)
|
||||||
|
? FlatNativeWindowsLibrary.DWMWCP_ROUNDSMALL // 4px
|
||||||
|
: FlatNativeWindowsLibrary.DWMWCP_ROUND; // 8px
|
||||||
|
FlatNativeWindowsLibrary.setWindowCornerPreference( hwnd, cornerPreference );
|
||||||
|
|
||||||
|
// set border color
|
||||||
|
FlatNativeWindowsLibrary.dwmSetWindowAttributeCOLORREF( hwnd, FlatNativeWindowsLibrary.DWMWA_BORDER_COLOR, borderColor );
|
||||||
|
} else if( SystemInfo.isMacOS ) {
|
||||||
|
if( borderColor == null || borderColor == FlatNativeWindowsLibrary.COLOR_NONE )
|
||||||
|
borderWidth = 0;
|
||||||
|
|
||||||
|
// set corner radius, border width and color
|
||||||
|
FlatNativeMacLibrary.setWindowRoundedBorder( popupWindow, borderCornerRadius,
|
||||||
|
borderWidth, (borderColor != null) ? borderColor.getRGB() : 0 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void resetWindows11Border( Window popupWindow ) {
|
||||||
|
// get window handle
|
||||||
|
long hwnd = FlatNativeWindowsLibrary.getHWND( popupWindow );
|
||||||
|
if( hwnd == 0 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// reset corner preference
|
||||||
|
FlatNativeWindowsLibrary.setWindowCornerPreference( hwnd, FlatNativeWindowsLibrary.DWMWCP_DONOTROUND );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getBorderCornerRadius( Component owner, Component contents ) {
|
||||||
|
String uiKey =
|
||||||
|
(contents instanceof BasicComboPopup) ? "ComboBox.borderCornerRadius" :
|
||||||
|
(contents instanceof JPopupMenu) ? "PopupMenu.borderCornerRadius" :
|
||||||
|
(contents instanceof JToolTip) ? "ToolTip.borderCornerRadius" :
|
||||||
|
"Popup.borderCornerRadius";
|
||||||
|
|
||||||
|
Object value = getOption( owner, contents, FlatClientProperties.POPUP_BORDER_CORNER_RADIUS, uiKey );
|
||||||
|
return (value instanceof Integer) ? (Integer) value : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float getRoundedBorderWidth( Component owner, Component contents ) {
|
||||||
|
String uiKey =
|
||||||
|
(contents instanceof BasicComboPopup) ? "ComboBox.roundedBorderWidth" :
|
||||||
|
(contents instanceof JPopupMenu) ? "PopupMenu.roundedBorderWidth" :
|
||||||
|
(contents instanceof JToolTip) ? "ToolTip.roundedBorderWidth" :
|
||||||
|
"Popup.roundedBorderWidth";
|
||||||
|
|
||||||
|
Object value = getOption( owner, contents, FlatClientProperties.POPUP_ROUNDED_BORDER_WIDTH, uiKey );
|
||||||
|
return (value instanceof Number) ? ((Number)value).floatValue() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---- fixes --------------------------------------------------------------
|
||||||
|
|
||||||
|
private static boolean overlapsHeavyWeightComponent( Component owner, Component contents, int x, int y ) {
|
||||||
|
if( owner == null )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Window window = SwingUtilities.getWindowAncestor( owner );
|
||||||
|
if( window == null )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Rectangle r = new Rectangle( new Point( x, y ), contents.getPreferredSize() );
|
||||||
|
return overlapsHeavyWeightComponent( window, r );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean overlapsHeavyWeightComponent( Component parent, Rectangle r ) {
|
||||||
|
if( !parent.isVisible() || !r.intersects( parent.getBounds() ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( !parent.isLightweight() && !(parent instanceof Window) )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if( parent instanceof Container ) {
|
||||||
|
Rectangle r2 = new Rectangle( r.x - parent.getX(), r.y - parent.getY(), r.width, r.height );
|
||||||
|
for( Component c : ((Container)parent).getComponents() ) {
|
||||||
|
if( overlapsHeavyWeightComponent( c, r2 ) )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On Linux with Wayland, since Java 21, Swing adds a window focus listener to popup owner/invoker window,
|
||||||
|
* which hides the popup as soon as the owner/invoker window looses focus.
|
||||||
|
* This works fine for light-weight popups.
|
||||||
|
* It also works for heavy-weight popups if they do not request focus.
|
||||||
|
* Because FlatLaf always uses heavy-weight popups, all popups that request focus
|
||||||
|
* are broken since Java 21.
|
||||||
|
*
|
||||||
|
* This method removes the problematic window focus listener.
|
||||||
|
*
|
||||||
|
* https://bugs.openjdk.org/browse/JDK-8280993
|
||||||
|
* https://github.com/openjdk/jdk/pull/13830
|
||||||
|
*/
|
||||||
|
private static void fixLinuxWaylandJava21focusIssue( Component owner ) {
|
||||||
|
// only necessary on Linux when running in Java 21+
|
||||||
|
if( owner == null || !SystemInfo.isLinux || SystemInfo.javaVersion < SystemInfo.toVersion( 21, 0, 0, 0 ) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// get window
|
||||||
|
Window window = SwingUtilities.getWindowAncestor( owner );
|
||||||
|
if( window == null )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// remove window focus listener, which was added from class sun.awt.UNIXToolkit since Java 21
|
||||||
|
for( WindowFocusListener l : window.getWindowFocusListeners() ) {
|
||||||
|
if( "sun.awt.UNIXToolkit$1".equals( l.getClass().getName() ) ) {
|
||||||
|
window.removeWindowFocusListener( l );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows the given popup and, if necessary, fixes the location of a heavy weight popup window.
|
||||||
|
* <p>
|
||||||
|
* On a dual screen setup, where screens use different scale factors, it may happen
|
||||||
|
* that the window location changes when showing a heavy weight popup window.
|
||||||
|
* E.g. when opening a dialog on the secondary screen and making combobox popup visible.
|
||||||
|
* <p>
|
||||||
|
* This is a workaround for https://bugs.openjdk.java.net/browse/JDK-8224608
|
||||||
|
*/
|
||||||
|
private static void showPopupAndFixLocation( Popup popup, Window popupWindow ) {
|
||||||
|
if( popupWindow != null ) {
|
||||||
|
// remember location of heavy weight popup window
|
||||||
|
int x = popupWindow.getX();
|
||||||
|
int y = popupWindow.getY();
|
||||||
|
|
||||||
|
popup.show();
|
||||||
|
|
||||||
|
// restore popup window location if it has changed
|
||||||
|
// (probably scaled when screens use different scale factors)
|
||||||
|
if( popupWindow.getX() != x || popupWindow.getY() != y )
|
||||||
|
popupWindow.setLocation( x, y );
|
||||||
|
} else
|
||||||
|
popup.show();
|
||||||
|
}
|
||||||
|
|
||||||
//---- class NonFlashingPopup ---------------------------------------------
|
//---- class NonFlashingPopup ---------------------------------------------
|
||||||
|
|
||||||
private class NonFlashingPopup
|
private static class NonFlashingPopup
|
||||||
extends Popup
|
extends Popup
|
||||||
{
|
{
|
||||||
private Popup delegate;
|
private Popup delegate;
|
||||||
@@ -353,6 +541,9 @@ public class FlatPopupFactory
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void hide() {
|
public void hide() {
|
||||||
|
if( contents instanceof JComponent )
|
||||||
|
((JComponent)contents).putClientProperty( KEY_POPUP_USES_NATIVE_BORDER, null );
|
||||||
|
|
||||||
if( delegate != null ) {
|
if( delegate != null ) {
|
||||||
delegate.hide();
|
delegate.hide();
|
||||||
delegate = null;
|
delegate = null;
|
||||||
@@ -431,6 +622,14 @@ public class FlatPopupFactory
|
|||||||
oldDropShadowWindowBackground = dropShadowWindow.getBackground();
|
oldDropShadowWindowBackground = dropShadowWindow.getBackground();
|
||||||
dropShadowWindow.setBackground( new Color( 0, true ) );
|
dropShadowWindow.setBackground( new Color( 0, true ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Windows 11: reset corner preference on reused heavy weight popups
|
||||||
|
if( isWindows11BorderSupported() ) {
|
||||||
|
resetWindows11Border( popupWindow );
|
||||||
|
if( dropShadowWindow != null )
|
||||||
|
resetWindows11Border( dropShadowWindow );
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
mediumWeightPanel = (Panel) SwingUtilities.getAncestorOfClass( Panel.class, contents );
|
mediumWeightPanel = (Panel) SwingUtilities.getAncestorOfClass( Panel.class, contents );
|
||||||
if( mediumWeightPanel != null ) {
|
if( mediumWeightPanel != null ) {
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ import javax.swing.plaf.basic.BasicComboPopup;
|
|||||||
import javax.swing.plaf.basic.BasicMenuItemUI;
|
import javax.swing.plaf.basic.BasicMenuItemUI;
|
||||||
import javax.swing.plaf.basic.BasicPopupMenuUI;
|
import javax.swing.plaf.basic.BasicPopupMenuUI;
|
||||||
import javax.swing.plaf.basic.DefaultMenuLayout;
|
import javax.swing.plaf.basic.DefaultMenuLayout;
|
||||||
|
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.util.LoggingFacade;
|
import com.formdev.flatlaf.util.LoggingFacade;
|
||||||
@@ -192,27 +193,38 @@ public class FlatPopupMenuUI
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Popup getPopup( JPopupMenu popup, int x, int y ) {
|
public Popup getPopup( JPopupMenu popup, int x, int y ) {
|
||||||
|
Dimension popupSize = popup.getPreferredSize();
|
||||||
|
Rectangle screenBounds = getScreenBoundsAt( x, y );
|
||||||
|
|
||||||
|
// make sure that popup does not overlap any task/side bar
|
||||||
|
if( x + popupSize.width > screenBounds.x + screenBounds.width )
|
||||||
|
x = screenBounds.x + screenBounds.width - popupSize.width;
|
||||||
|
if( y + popupSize.height > screenBounds.y + screenBounds.height )
|
||||||
|
y = screenBounds.y + screenBounds.height - popupSize.height;
|
||||||
|
if( x < screenBounds.x )
|
||||||
|
x = screenBounds.x;
|
||||||
|
if( y < screenBounds.y )
|
||||||
|
y = screenBounds.y;
|
||||||
|
|
||||||
// do not add scroller to combobox popups or to popups that already have a scroll pane
|
// do not add scroller to combobox popups or to popups that already have a scroll pane
|
||||||
if( popup instanceof BasicComboPopup ||
|
if( popup instanceof BasicComboPopup ||
|
||||||
(popup.getComponentCount() > 0 && popup.getComponent( 0 ) instanceof JScrollPane) )
|
(popup.getComponentCount() > 0 && popup.getComponent( 0 ) instanceof JScrollPane) )
|
||||||
return super.getPopup( popup, x, y );
|
return super.getPopup( popup, x, y );
|
||||||
|
|
||||||
// do not add scroller if popup fits into screen
|
// do not add scroller if popup fits into screen
|
||||||
Dimension prefSize = popup.getPreferredSize();
|
if( popupSize.height <= screenBounds.height )
|
||||||
int screenHeight = getScreenHeightAt( x, y );
|
|
||||||
if( prefSize.height <= screenHeight )
|
|
||||||
return super.getPopup( popup, x, y );
|
return super.getPopup( popup, x, y );
|
||||||
|
|
||||||
// create scroller
|
// create scroller
|
||||||
FlatPopupScroller scroller = new FlatPopupScroller( popup );
|
FlatPopupScroller scroller = new FlatPopupScroller( popup );
|
||||||
scroller.setPreferredSize( new Dimension( prefSize.width, screenHeight ) );
|
scroller.setPreferredSize( new Dimension( popupSize.width, screenBounds.height ) );
|
||||||
|
|
||||||
// create popup
|
// create popup
|
||||||
PopupFactory popupFactory = PopupFactory.getSharedInstance();
|
PopupFactory popupFactory = PopupFactory.getSharedInstance();
|
||||||
return popupFactory.getPopup( popup.getInvoker(), scroller, x, y );
|
return popupFactory.getPopup( popup.getInvoker(), scroller, x, y );
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getScreenHeightAt( int x, int y ) {
|
private Rectangle getScreenBoundsAt( int x, int y ) {
|
||||||
// find GraphicsConfiguration at popup location (similar to JPopupMenu.getCurrentGraphicsConfiguration())
|
// find GraphicsConfiguration at popup location (similar to JPopupMenu.getCurrentGraphicsConfiguration())
|
||||||
GraphicsConfiguration gc = null;
|
GraphicsConfiguration gc = null;
|
||||||
for( GraphicsDevice device : GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices() ) {
|
for( GraphicsDevice device : GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices() ) {
|
||||||
@@ -233,7 +245,7 @@ public class FlatPopupMenuUI
|
|||||||
Toolkit toolkit = Toolkit.getDefaultToolkit();
|
Toolkit toolkit = Toolkit.getDefaultToolkit();
|
||||||
Rectangle screenBounds = (gc != null) ? gc.getBounds() : new Rectangle( toolkit.getScreenSize() );
|
Rectangle screenBounds = (gc != null) ? gc.getBounds() : new Rectangle( toolkit.getScreenSize() );
|
||||||
Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets( gc );
|
Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets( gc );
|
||||||
return screenBounds.height - screenInsets.top - screenInsets.bottom;
|
return FlatUIUtils.subtractInsets( screenBounds, screenInsets );
|
||||||
}
|
}
|
||||||
|
|
||||||
//---- class FlatPopupMenuLayout ------------------------------------------
|
//---- class FlatPopupMenuLayout ------------------------------------------
|
||||||
@@ -297,6 +309,9 @@ public class FlatPopupMenuUI
|
|||||||
popup.addMenuKeyListener( this );
|
popup.addMenuKeyListener( this );
|
||||||
|
|
||||||
updateArrowButtons();
|
updateArrowButtons();
|
||||||
|
|
||||||
|
putClientProperty( FlatClientProperties.POPUP_BORDER_CORNER_RADIUS,
|
||||||
|
UIManager.getInt( "PopupMenu.borderCornerRadius" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void scroll( int unitsToScroll ) {
|
void scroll( int unitsToScroll ) {
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import javax.swing.CellRendererPane;
|
|||||||
import javax.swing.Icon;
|
import javax.swing.Icon;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.LookAndFeel;
|
import javax.swing.LookAndFeel;
|
||||||
|
import javax.swing.SwingConstants;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.plaf.ComponentUI;
|
import javax.swing.plaf.ComponentUI;
|
||||||
@@ -208,6 +209,9 @@ public class FlatRadioButtonUI
|
|||||||
return ((FlatCheckBoxIcon)icon).applyStyleProperty( key, value );
|
return ((FlatCheckBoxIcon)icon).applyStyleProperty( key, value );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( "iconTextGap".equals( key ) && value instanceof Integer )
|
||||||
|
value = UIScale.scale( (Integer) value );
|
||||||
|
|
||||||
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, b, key, value );
|
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, b, key, value );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,7 +263,7 @@ public class FlatRadioButtonUI
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paint( Graphics g, JComponent c ) {
|
public void paint( Graphics g, JComponent c ) {
|
||||||
// fill background even if not opaque if
|
// fill background even if not opaque and if:
|
||||||
// - contentAreaFilled is true and
|
// - contentAreaFilled is true and
|
||||||
// - if background color is different to default background color
|
// - if background color is different to default background color
|
||||||
// (this paints selection if using the component as cell renderer)
|
// (this paints selection if using the component as cell renderer)
|
||||||
@@ -275,20 +279,27 @@ public class FlatRadioButtonUI
|
|||||||
int focusWidth = getIconFocusWidth( c );
|
int focusWidth = getIconFocusWidth( c );
|
||||||
if( focusWidth > 0 ) {
|
if( focusWidth > 0 ) {
|
||||||
boolean ltr = c.getComponentOrientation().isLeftToRight();
|
boolean ltr = c.getComponentOrientation().isLeftToRight();
|
||||||
|
int halign = ((AbstractButton)c).getHorizontalAlignment();
|
||||||
|
if( halign == SwingConstants.LEADING )
|
||||||
|
halign = ltr ? SwingConstants.LEFT : SwingConstants.RIGHT;
|
||||||
|
else if( halign == SwingConstants.TRAILING )
|
||||||
|
halign = ltr ? SwingConstants.RIGHT : SwingConstants.LEFT;
|
||||||
|
|
||||||
Insets insets = c.getInsets( tempInsets );
|
Insets insets = c.getInsets( tempInsets );
|
||||||
int leftOrRightInset = ltr ? insets.left : insets.right;
|
if( (focusWidth > insets.left || focusWidth > insets.right) &&
|
||||||
if( focusWidth > leftOrRightInset ) {
|
(halign == SwingConstants.LEFT || halign == SwingConstants.RIGHT) )
|
||||||
|
{
|
||||||
// The left (or right) inset is smaller than the focus width, which may be
|
// The left (or right) inset is smaller than the focus width, which may be
|
||||||
// the case if insets were explicitly reduced (e.g. with an EmptyBorder).
|
// the case if insets were explicitly reduced (e.g. with an EmptyBorder).
|
||||||
// In this case the width has been increased in getPreferredSize() and
|
// In this case the width has been increased in getPreferredSize() and
|
||||||
// here it is necessary to fix icon and text painting location.
|
// here it is necessary to fix icon and text painting location.
|
||||||
int offset = focusWidth - leftOrRightInset;
|
int offset = (halign == SwingConstants.LEFT)
|
||||||
if( !ltr )
|
? Math.max( focusWidth - insets.left, 0 )
|
||||||
offset = -offset;
|
: -Math.max( focusWidth - insets.right, 0 );
|
||||||
|
|
||||||
// move the graphics origin to the left (or right)
|
// move the graphics origin to the left (or right)
|
||||||
g.translate( offset, 0 );
|
g.translate( offset, 0 );
|
||||||
super.paint( g, c );
|
super.paint( FlatLabelUI.createGraphicsHTMLTextYCorrection( g, c ), c );
|
||||||
g.translate( -offset, 0 );
|
g.translate( -offset, 0 );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -325,6 +336,11 @@ public class FlatRadioButtonUI
|
|||||||
: 0;
|
: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBaseline( JComponent c, int width, int height ) {
|
||||||
|
return FlatButtonUI.getBaselineImpl( c, width, height );
|
||||||
|
}
|
||||||
|
|
||||||
//---- class FlatRadioButtonListener --------------------------------------
|
//---- class FlatRadioButtonListener --------------------------------------
|
||||||
|
|
||||||
/** @since 2 */
|
/** @since 2 */
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import java.awt.Dimension;
|
|||||||
import java.awt.Frame;
|
import java.awt.Frame;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.IllegalComponentStateException;
|
||||||
import java.awt.Insets;
|
import java.awt.Insets;
|
||||||
import java.awt.LayoutManager;
|
import java.awt.LayoutManager;
|
||||||
import java.awt.LayoutManager2;
|
import java.awt.LayoutManager2;
|
||||||
@@ -49,7 +50,6 @@ import javax.swing.plaf.RootPaneUI;
|
|||||||
import javax.swing.plaf.UIResource;
|
import javax.swing.plaf.UIResource;
|
||||||
import javax.swing.plaf.basic.BasicRootPaneUI;
|
import javax.swing.plaf.basic.BasicRootPaneUI;
|
||||||
import com.formdev.flatlaf.FlatClientProperties;
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
import com.formdev.flatlaf.FlatLaf;
|
|
||||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||||
import com.formdev.flatlaf.util.SystemInfo;
|
import com.formdev.flatlaf.util.SystemInfo;
|
||||||
import com.formdev.flatlaf.util.UIScale;
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
@@ -155,10 +155,6 @@ public class FlatRootPaneUI
|
|||||||
if( background == null || background instanceof UIResource )
|
if( background == null || background instanceof UIResource )
|
||||||
parent.setBackground( UIManager.getColor( "control" ) );
|
parent.setBackground( UIManager.getColor( "control" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
// enable dark window appearance on macOS when running in JetBrains Runtime
|
|
||||||
if( SystemInfo.isJetBrainsJVM && SystemInfo.isMacOS_10_14_Mojave_orLater )
|
|
||||||
c.putClientProperty( "jetbrains.awt.windowDarkAppearance", FlatLaf.isLafDark() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -349,11 +345,28 @@ public class FlatRootPaneUI
|
|||||||
titlePane.updateIcon();
|
titlePane.updateIcon();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case FlatClientProperties.TITLE_BAR_SHOW_TITLE:
|
||||||
|
case FlatClientProperties.TITLE_BAR_SHOW_ICONIFFY:
|
||||||
|
case FlatClientProperties.TITLE_BAR_SHOW_MAXIMIZE:
|
||||||
|
case FlatClientProperties.TITLE_BAR_SHOW_CLOSE:
|
||||||
|
if( titlePane != null )
|
||||||
|
titlePane.updateVisibility();
|
||||||
|
break;
|
||||||
|
|
||||||
case FlatClientProperties.TITLE_BAR_BACKGROUND:
|
case FlatClientProperties.TITLE_BAR_BACKGROUND:
|
||||||
case FlatClientProperties.TITLE_BAR_FOREGROUND:
|
case FlatClientProperties.TITLE_BAR_FOREGROUND:
|
||||||
if( titlePane != null )
|
if( titlePane != null )
|
||||||
titlePane.titleBarColorsChanged();
|
titlePane.titleBarColorsChanged();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case FlatClientProperties.GLASS_PANE_FULL_HEIGHT:
|
||||||
|
rootPane.revalidate();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FlatClientProperties.WINDOW_STYLE:
|
||||||
|
if( rootPane.isDisplayable() )
|
||||||
|
throw new IllegalComponentStateException( "The client property 'Window.style' must be set before the window becomes displayable." );
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -434,11 +447,11 @@ public class FlatRootPaneUI
|
|||||||
int width = rootPane.getWidth() - insets.left - insets.right;
|
int width = rootPane.getWidth() - insets.left - insets.right;
|
||||||
int height = rootPane.getHeight() - insets.top - insets.bottom;
|
int height = rootPane.getHeight() - insets.top - insets.bottom;
|
||||||
|
|
||||||
|
// layered pane
|
||||||
if( rootPane.getLayeredPane() != null )
|
if( rootPane.getLayeredPane() != null )
|
||||||
rootPane.getLayeredPane().setBounds( x, y, width, height );
|
rootPane.getLayeredPane().setBounds( x, y, width, height );
|
||||||
if( rootPane.getGlassPane() != null )
|
|
||||||
rootPane.getGlassPane().setBounds( x, y, width, height );
|
|
||||||
|
|
||||||
|
// title pane
|
||||||
int nextY = 0;
|
int nextY = 0;
|
||||||
if( titlePane != null ) {
|
if( titlePane != null ) {
|
||||||
int prefHeight = !isFullScreen ? titlePane.getPreferredSize().height : 0;
|
int prefHeight = !isFullScreen ? titlePane.getPreferredSize().height : 0;
|
||||||
@@ -446,6 +459,15 @@ public class FlatRootPaneUI
|
|||||||
nextY += prefHeight;
|
nextY += prefHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// glass pane
|
||||||
|
if( rootPane.getGlassPane() != null ) {
|
||||||
|
boolean fullHeight = FlatClientProperties.clientPropertyBoolean(
|
||||||
|
rootPane, FlatClientProperties.GLASS_PANE_FULL_HEIGHT, false );
|
||||||
|
int offset = fullHeight ? 0 : nextY;
|
||||||
|
rootPane.getGlassPane().setBounds( x, y + offset, width, height - offset );
|
||||||
|
}
|
||||||
|
|
||||||
|
// menu bar
|
||||||
JMenuBar menuBar = rootPane.getJMenuBar();
|
JMenuBar menuBar = rootPane.getJMenuBar();
|
||||||
if( menuBar != null && menuBar.isVisible() ) {
|
if( menuBar != null && menuBar.isVisible() ) {
|
||||||
boolean embedded = !isFullScreen && titlePane != null && titlePane.isMenuBarEmbedded();
|
boolean embedded = !isFullScreen && titlePane != null && titlePane.isMenuBarEmbedded();
|
||||||
@@ -459,10 +481,12 @@ public class FlatRootPaneUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// content pane
|
||||||
Container contentPane = rootPane.getContentPane();
|
Container contentPane = rootPane.getContentPane();
|
||||||
if( contentPane != null )
|
if( contentPane != null )
|
||||||
contentPane.setBounds( 0, nextY, width, Math.max( height - nextY, 0 ) );
|
contentPane.setBounds( 0, nextY, width, Math.max( height - nextY, 0 ) );
|
||||||
|
|
||||||
|
// title pane
|
||||||
if( titlePane != null )
|
if( titlePane != null )
|
||||||
titlePane.menuBarLayouted();
|
titlePane.menuBarLayouted();
|
||||||
}
|
}
|
||||||
@@ -470,7 +494,7 @@ public class FlatRootPaneUI
|
|||||||
@Override
|
@Override
|
||||||
public void invalidateLayout( Container parent ) {
|
public void invalidateLayout( Container parent ) {
|
||||||
if( titlePane != null )
|
if( titlePane != null )
|
||||||
titlePane.menuBarChanged();
|
titlePane.menuBarInvalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -528,7 +552,7 @@ public class FlatRootPaneUI
|
|||||||
|
|
||||||
protected boolean isWindowMaximized( Component c ) {
|
protected boolean isWindowMaximized( Component c ) {
|
||||||
Container parent = c.getParent();
|
Container parent = c.getParent();
|
||||||
return parent instanceof Frame && (((Frame)parent).getExtendedState() & Frame.MAXIMIZED_BOTH) != 0;
|
return parent instanceof Frame && (((Frame)parent).getExtendedState() & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_BOTH;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,10 @@
|
|||||||
package com.formdev.flatlaf.ui;
|
package com.formdev.flatlaf.ui;
|
||||||
|
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
|
import java.awt.Graphics;
|
||||||
|
import javax.swing.JSpinner;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
|
import javax.swing.plaf.SpinnerUI;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -35,6 +38,19 @@ public class FlatRoundBorder
|
|||||||
// 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)
|
||||||
/** @since 2 */ @Styleable protected Boolean roundRect;
|
/** @since 2 */ @Styleable protected Boolean roundRect;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||||
|
// make mac style spinner border smaller (border does not surround arrow buttons)
|
||||||
|
if( isMacStyleSpinner( c ) ) {
|
||||||
|
int macStyleButtonsWidth = ((FlatSpinnerUI)((JSpinner)c).getUI()).getMacStyleButtonsWidth();
|
||||||
|
width -= macStyleButtonsWidth;
|
||||||
|
if( !c.getComponentOrientation().isLeftToRight() )
|
||||||
|
x += macStyleButtonsWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
super.paintBorder( c, g, x, y, width, height );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int getArc( Component c ) {
|
protected int getArc( Component c ) {
|
||||||
if( isCellEditor( c ) )
|
if( isCellEditor( c ) )
|
||||||
@@ -43,6 +59,17 @@ public class FlatRoundBorder
|
|||||||
Boolean roundRect = FlatUIUtils.isRoundRect( c );
|
Boolean roundRect = FlatUIUtils.isRoundRect( c );
|
||||||
if( roundRect == null )
|
if( roundRect == null )
|
||||||
roundRect = this.roundRect;
|
roundRect = this.roundRect;
|
||||||
return roundRect != null ? (roundRect ? Short.MAX_VALUE : 0) : arc;
|
return roundRect != null
|
||||||
|
? (roundRect ? Short.MAX_VALUE : 0)
|
||||||
|
: (isMacStyleSpinner( c ) ? 0 : arc);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isMacStyleSpinner( Component c ) {
|
||||||
|
if( c instanceof JSpinner ) {
|
||||||
|
SpinnerUI ui = ((JSpinner)c).getUI();
|
||||||
|
if( ui instanceof FlatSpinnerUI )
|
||||||
|
return ((FlatSpinnerUI)ui).isMacStyle();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -245,7 +245,7 @@ public class FlatScrollBarUI
|
|||||||
// because scroll bars do not receive mouse exited event.
|
// because scroll bars do not receive mouse exited event.
|
||||||
// The scroll pane, including its scroll bars, is not part
|
// The scroll pane, including its scroll bars, is not part
|
||||||
// of the component hierarchy and does not receive mouse events
|
// of the component hierarchy and does not receive mouse events
|
||||||
// directly. Instead LWComponentPeer receives mouse events
|
// directly. Instead, LWComponentPeer receives mouse events
|
||||||
// and delegates them to peers, but entered/exited events
|
// and delegates them to peers, but entered/exited events
|
||||||
// are sent only for the whole scroll pane.
|
// are sent only for the whole scroll pane.
|
||||||
// Exited event is only sent when mouse leaves scroll pane.
|
// Exited event is only sent when mouse leaves scroll pane.
|
||||||
|
|||||||
@@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 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
|
||||||
|
*
|
||||||
|
* http://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 java.awt.Component;
|
||||||
|
import java.awt.Insets;
|
||||||
|
import javax.swing.JList;
|
||||||
|
import javax.swing.JScrollPane;
|
||||||
|
import javax.swing.JTable;
|
||||||
|
import javax.swing.JTree;
|
||||||
|
import javax.swing.UIManager;
|
||||||
|
import javax.swing.text.JTextComponent;
|
||||||
|
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||||
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Border for {@link javax.swing.JScrollPane}.
|
||||||
|
*
|
||||||
|
* @uiDefault ScrollPane.arc int
|
||||||
|
* @uiDefault ScrollPane.List.arc int
|
||||||
|
* @uiDefault ScrollPane.Table.arc int
|
||||||
|
* @uiDefault ScrollPane.TextComponent.arc int
|
||||||
|
* @uiDefault ScrollPane.Tree.arc int
|
||||||
|
|
||||||
|
* @author Karl Tauber
|
||||||
|
* @since 3.3
|
||||||
|
*/
|
||||||
|
public class FlatScrollPaneBorder
|
||||||
|
extends FlatBorder
|
||||||
|
{
|
||||||
|
@Styleable protected int arc = UIManager.getInt( "ScrollPane.arc" );
|
||||||
|
|
||||||
|
private boolean isArcStyled;
|
||||||
|
private final int listArc = FlatUIUtils.getUIInt( "ScrollPane.List.arc", -1 );
|
||||||
|
private final int tableArc = FlatUIUtils.getUIInt( "ScrollPane.Table.arc", -1 );
|
||||||
|
private final int textComponentArc = FlatUIUtils.getUIInt( "ScrollPane.TextComponent.arc", -1 );
|
||||||
|
private final int treeArc = FlatUIUtils.getUIInt( "ScrollPane.Tree.arc", -1 );
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object applyStyleProperty( String key, Object value ) {
|
||||||
|
Object oldValue = super.applyStyleProperty( key, value );
|
||||||
|
|
||||||
|
if( "arc".equals( key ) )
|
||||||
|
isArcStyled = true;
|
||||||
|
|
||||||
|
return oldValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Insets getBorderInsets( Component c, Insets insets ) {
|
||||||
|
insets = super.getBorderInsets( c, insets );
|
||||||
|
|
||||||
|
// if view is rounded, increase left and right insets to avoid that the viewport
|
||||||
|
// is painted over the rounded border on the corners
|
||||||
|
int padding = getLeftRightPadding( c );
|
||||||
|
if( padding > 0 ) {
|
||||||
|
insets.left += padding;
|
||||||
|
insets.right += padding;
|
||||||
|
}
|
||||||
|
|
||||||
|
return insets;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getArc( Component c ) {
|
||||||
|
if( isCellEditor( c ) )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if( isArcStyled )
|
||||||
|
return arc;
|
||||||
|
|
||||||
|
if( c instanceof JScrollPane ) {
|
||||||
|
Component view = FlatScrollPaneUI.getView( (JScrollPane) c );
|
||||||
|
if( listArc >= 0 && view instanceof JList )
|
||||||
|
return listArc;
|
||||||
|
if( tableArc >= 0 && view instanceof JTable )
|
||||||
|
return tableArc;
|
||||||
|
if( textComponentArc >= 0&& view instanceof JTextComponent )
|
||||||
|
return textComponentArc;
|
||||||
|
if( treeArc >= 0 && view instanceof JTree )
|
||||||
|
return treeArc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return arc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the scaled left/right padding used when arc is larger than zero.
|
||||||
|
* <p>
|
||||||
|
* This is the distance from the inside of the left border to the left side of the view component.
|
||||||
|
* On the right side, this is the distance between the right side of the view component and
|
||||||
|
* the vertical scrollbar. Or the inside of the right border if the scrollbar is hidden.
|
||||||
|
*/
|
||||||
|
public int getLeftRightPadding( Component c ) {
|
||||||
|
// Subtract lineWidth from radius because radius is given for the outside
|
||||||
|
// of the painted line, but insets from super already include lineWidth.
|
||||||
|
// Reduce padding by 10% to make padding slightly smaller because it is not recognizable
|
||||||
|
// when the view is minimally painted over the beginning of the border curve.
|
||||||
|
int arc = getArc( c );
|
||||||
|
return (arc > 0)
|
||||||
|
? Math.max( Math.round( UIScale.scale( ((arc / 2f) - getLineWidth( c )) * 0.9f ) ), 0 )
|
||||||
|
: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,9 +17,12 @@
|
|||||||
package com.formdev.flatlaf.ui;
|
package com.formdev.flatlaf.ui;
|
||||||
|
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
|
import java.awt.Container;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
|
import java.awt.Graphics2D;
|
||||||
import java.awt.Insets;
|
import java.awt.Insets;
|
||||||
import java.awt.KeyboardFocusManager;
|
import java.awt.KeyboardFocusManager;
|
||||||
|
import java.awt.LayoutManager;
|
||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
import java.awt.event.ContainerEvent;
|
import java.awt.event.ContainerEvent;
|
||||||
import java.awt.event.ContainerListener;
|
import java.awt.event.ContainerListener;
|
||||||
@@ -41,16 +44,19 @@ import javax.swing.JTree;
|
|||||||
import javax.swing.JViewport;
|
import javax.swing.JViewport;
|
||||||
import javax.swing.LookAndFeel;
|
import javax.swing.LookAndFeel;
|
||||||
import javax.swing.ScrollPaneConstants;
|
import javax.swing.ScrollPaneConstants;
|
||||||
|
import javax.swing.ScrollPaneLayout;
|
||||||
import javax.swing.Scrollable;
|
import javax.swing.Scrollable;
|
||||||
import javax.swing.SwingConstants;
|
import javax.swing.SwingConstants;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
|
import javax.swing.border.Border;
|
||||||
import javax.swing.plaf.ComponentUI;
|
import javax.swing.plaf.ComponentUI;
|
||||||
import javax.swing.plaf.basic.BasicScrollPaneUI;
|
import javax.swing.plaf.basic.BasicScrollPaneUI;
|
||||||
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.util.LoggingFacade;
|
import com.formdev.flatlaf.util.LoggingFacade;
|
||||||
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JScrollPane}.
|
* Provides the Flat LaF UI delegate for {@link javax.swing.JScrollPane}.
|
||||||
@@ -97,7 +103,13 @@ public class FlatScrollPaneUI
|
|||||||
super.installUI( c );
|
super.installUI( c );
|
||||||
|
|
||||||
int focusWidth = UIManager.getInt( "Component.focusWidth" );
|
int focusWidth = UIManager.getInt( "Component.focusWidth" );
|
||||||
LookAndFeel.installProperty( c, "opaque", focusWidth == 0 );
|
int arc = UIManager.getInt( "ScrollPane.arc" );
|
||||||
|
LookAndFeel.installProperty( c, "opaque", focusWidth == 0 && arc == 0 );
|
||||||
|
|
||||||
|
// install layout manager
|
||||||
|
LayoutManager layout = c.getLayout();
|
||||||
|
if( layout != null && layout.getClass() == ScrollPaneLayout.UIResource.class )
|
||||||
|
c.setLayout( createScrollPaneLayout() );
|
||||||
|
|
||||||
installStyle();
|
installStyle();
|
||||||
|
|
||||||
@@ -108,6 +120,10 @@ public class FlatScrollPaneUI
|
|||||||
public void uninstallUI( JComponent c ) {
|
public void uninstallUI( JComponent c ) {
|
||||||
MigLayoutVisualPadding.uninstall( scrollpane );
|
MigLayoutVisualPadding.uninstall( scrollpane );
|
||||||
|
|
||||||
|
// uninstall layout manager
|
||||||
|
if( c.getLayout() instanceof FlatScrollPaneLayout )
|
||||||
|
c.setLayout( new ScrollPaneLayout.UIResource() );
|
||||||
|
|
||||||
super.uninstallUI( c );
|
super.uninstallUI( c );
|
||||||
|
|
||||||
oldStyleValues = null;
|
oldStyleValues = null;
|
||||||
@@ -130,6 +146,13 @@ public class FlatScrollPaneUI
|
|||||||
handler = null;
|
handler = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 3.3
|
||||||
|
*/
|
||||||
|
protected FlatScrollPaneLayout createScrollPaneLayout() {
|
||||||
|
return new FlatScrollPaneLayout();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected MouseWheelListener createMouseWheelListener() {
|
protected MouseWheelListener createMouseWheelListener() {
|
||||||
MouseWheelListener superListener = super.createMouseWheelListener();
|
MouseWheelListener superListener = super.createMouseWheelListener();
|
||||||
@@ -290,8 +313,7 @@ public class FlatScrollPaneUI
|
|||||||
Object corner = e.getNewValue();
|
Object corner = e.getNewValue();
|
||||||
if( corner instanceof JButton &&
|
if( corner instanceof JButton &&
|
||||||
((JButton)corner).getBorder() instanceof FlatButtonBorder &&
|
((JButton)corner).getBorder() instanceof FlatButtonBorder &&
|
||||||
scrollpane.getViewport() != null &&
|
getView( scrollpane ) instanceof JTable )
|
||||||
scrollpane.getViewport().getView() instanceof JTable )
|
|
||||||
{
|
{
|
||||||
((JButton)corner).setBorder( BorderFactory.createEmptyBorder() );
|
((JButton)corner).setBorder( BorderFactory.createEmptyBorder() );
|
||||||
((JButton)corner).setFocusable( false );
|
((JButton)corner).setFocusable( false );
|
||||||
@@ -308,6 +330,18 @@ public class FlatScrollPaneUI
|
|||||||
scrollpane.revalidate();
|
scrollpane.revalidate();
|
||||||
scrollpane.repaint();
|
scrollpane.repaint();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "border":
|
||||||
|
Object newBorder = e.getNewValue();
|
||||||
|
if( newBorder != null && newBorder == UIManager.getBorder( "Table.scrollPaneBorder" ) ) {
|
||||||
|
// JTable.configureEnclosingScrollPaneUI() replaces the scrollpane border
|
||||||
|
// with another one --> re-apply style on new border
|
||||||
|
borderShared = null;
|
||||||
|
installStyle();
|
||||||
|
scrollpane.revalidate();
|
||||||
|
scrollpane.repaint();
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -334,9 +368,10 @@ public class FlatScrollPaneUI
|
|||||||
|
|
||||||
/** @since 2 */
|
/** @since 2 */
|
||||||
protected Object applyStyleProperty( String key, Object value ) {
|
protected Object applyStyleProperty( String key, Object value ) {
|
||||||
if( key.equals( "focusWidth" ) ) {
|
if( key.equals( "focusWidth" ) || key.equals( "arc" ) ) {
|
||||||
int focusWidth = (value instanceof Integer) ? (int) value : UIManager.getInt( "Component.focusWidth" );
|
int focusWidth = (value instanceof Integer) ? (int) value : UIManager.getInt( "Component.focusWidth" );
|
||||||
LookAndFeel.installProperty( scrollpane, "opaque", focusWidth == 0 );
|
int arc = (value instanceof Integer) ? (int) value : UIManager.getInt( "ScrollPane.arc" );
|
||||||
|
LookAndFeel.installProperty( scrollpane, "opaque", focusWidth == 0 && arc == 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( borderShared == null )
|
if( borderShared == null )
|
||||||
@@ -360,8 +395,8 @@ public class FlatScrollPaneUI
|
|||||||
protected void updateViewport( PropertyChangeEvent e ) {
|
protected void updateViewport( PropertyChangeEvent e ) {
|
||||||
super.updateViewport( e );
|
super.updateViewport( e );
|
||||||
|
|
||||||
JViewport oldViewport = (JViewport) (e.getOldValue());
|
JViewport oldViewport = (JViewport) e.getOldValue();
|
||||||
JViewport newViewport = (JViewport) (e.getNewValue());
|
JViewport newViewport = (JViewport) e.getNewValue();
|
||||||
|
|
||||||
removeViewportListeners( oldViewport );
|
removeViewportListeners( oldViewport );
|
||||||
addViewportListeners( newViewport );
|
addViewportListeners( newViewport );
|
||||||
@@ -402,13 +437,46 @@ public class FlatScrollPaneUI
|
|||||||
c.getHeight() - insets.top - insets.bottom );
|
c.getHeight() - insets.top - insets.bottom );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if view is rounded, paint rounded background with view background color
|
||||||
|
// to ensure that free areas at left and right have same color as view
|
||||||
|
Component view;
|
||||||
|
float arc = getBorderArc( scrollpane );
|
||||||
|
if( arc > 0 && (view = getView( scrollpane )) != null ) {
|
||||||
|
float focusWidth = FlatUIUtils.getBorderFocusWidth( c );
|
||||||
|
|
||||||
|
g.setColor( view.getBackground() );
|
||||||
|
|
||||||
|
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g );
|
||||||
|
FlatUIUtils.paintComponentBackground( (Graphics2D) g, 0, 0, c.getWidth(), c.getHeight(), focusWidth, arc );
|
||||||
|
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
|
||||||
|
}
|
||||||
|
|
||||||
paint( g, c );
|
paint( g, c );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void paint( Graphics g, JComponent c ) {
|
||||||
|
Border viewportBorder = scrollpane.getViewportBorder();
|
||||||
|
if( viewportBorder != null ) {
|
||||||
|
Rectangle r = scrollpane.getViewportBorderBounds();
|
||||||
|
int padding = getBorderLeftRightPadding( scrollpane );
|
||||||
|
JScrollBar vsb = scrollpane.getVerticalScrollBar();
|
||||||
|
if( padding > 0 &&
|
||||||
|
vsb != null && vsb.isVisible() &&
|
||||||
|
scrollpane.getLayout() instanceof FlatScrollPaneLayout &&
|
||||||
|
((FlatScrollPaneLayout)scrollpane.getLayout()).canIncreaseViewportWidth( scrollpane ) )
|
||||||
|
{
|
||||||
|
boolean ltr = scrollpane.getComponentOrientation().isLeftToRight();
|
||||||
|
int extraWidth = Math.min( padding, vsb.getWidth() );
|
||||||
|
viewportBorder.paintBorder( scrollpane, g, r.x - (ltr ? 0 : extraWidth), r.y, r.width + extraWidth, r.height );
|
||||||
|
} else
|
||||||
|
viewportBorder.paintBorder( scrollpane, g, r.x, r.y, r.width, r.height );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** @since 1.3 */
|
/** @since 1.3 */
|
||||||
public static boolean isPermanentFocusOwner( JScrollPane scrollPane ) {
|
public static boolean isPermanentFocusOwner( JScrollPane scrollPane ) {
|
||||||
JViewport viewport = scrollPane.getViewport();
|
Component view = getView( scrollPane );
|
||||||
Component view = (viewport != null) ? viewport.getView() : null;
|
|
||||||
if( view == null )
|
if( view == null )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -428,6 +496,25 @@ public class FlatScrollPaneUI
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Component getView( JScrollPane scrollPane ) {
|
||||||
|
JViewport viewport = scrollPane.getViewport();
|
||||||
|
return (viewport != null) ? viewport.getView() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float getBorderArc( JScrollPane scrollPane ) {
|
||||||
|
Border border = scrollPane.getBorder();
|
||||||
|
return (border instanceof FlatScrollPaneBorder)
|
||||||
|
? UIScale.scale( (float) ((FlatScrollPaneBorder)border).getArc( scrollPane ) )
|
||||||
|
: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getBorderLeftRightPadding( JScrollPane scrollPane ) {
|
||||||
|
Border border = scrollPane.getBorder();
|
||||||
|
return (border instanceof FlatScrollPaneBorder)
|
||||||
|
? ((FlatScrollPaneBorder)border).getLeftRightPadding( scrollPane )
|
||||||
|
: 0;
|
||||||
|
}
|
||||||
|
|
||||||
//---- class Handler ------------------------------------------------------
|
//---- class Handler ------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -450,13 +537,71 @@ public class FlatScrollPaneUI
|
|||||||
@Override
|
@Override
|
||||||
public void focusGained( FocusEvent e ) {
|
public void focusGained( FocusEvent e ) {
|
||||||
// necessary to update focus border
|
// necessary to update focus border
|
||||||
|
if( scrollpane.getBorder() instanceof FlatBorder )
|
||||||
scrollpane.repaint();
|
scrollpane.repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void focusLost( FocusEvent e ) {
|
public void focusLost( FocusEvent e ) {
|
||||||
// necessary to update focus border
|
// necessary to update focus border
|
||||||
|
if( scrollpane.getBorder() instanceof FlatBorder )
|
||||||
scrollpane.repaint();
|
scrollpane.repaint();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---- class FlatScrollPaneLayout -----------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 3.3
|
||||||
|
*/
|
||||||
|
protected static class FlatScrollPaneLayout
|
||||||
|
extends ScrollPaneLayout.UIResource
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void layoutContainer( Container parent ) {
|
||||||
|
super.layoutContainer( parent );
|
||||||
|
|
||||||
|
JScrollPane scrollPane = (JScrollPane) parent;
|
||||||
|
int padding = getBorderLeftRightPadding( scrollPane );
|
||||||
|
if( padding > 0 && vsb != null && vsb.isVisible() ) {
|
||||||
|
// move vertical scrollbar to trailing edge
|
||||||
|
Insets insets = scrollPane.getInsets();
|
||||||
|
Rectangle r = vsb.getBounds();
|
||||||
|
int y = Math.max( r.y, insets.top + padding );
|
||||||
|
int y2 = Math.min( r.y + r.height, scrollPane.getHeight() - insets.bottom - padding );
|
||||||
|
boolean ltr = scrollPane.getComponentOrientation().isLeftToRight();
|
||||||
|
|
||||||
|
vsb.setBounds( r.x + (ltr ? padding : -padding), y, r.width, y2 - y );
|
||||||
|
|
||||||
|
// increase width of viewport, column header and horizontal scrollbar
|
||||||
|
if( canIncreaseViewportWidth( scrollPane ) ) {
|
||||||
|
int extraWidth = Math.min( padding, vsb.getWidth() );
|
||||||
|
resizeViewport( viewport, extraWidth, ltr );
|
||||||
|
resizeViewport( colHead, extraWidth, ltr );
|
||||||
|
resizeViewport( hsb, extraWidth, ltr );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean canIncreaseViewportWidth( JScrollPane scrollPane ) {
|
||||||
|
return scrollPane.getComponentOrientation().isLeftToRight()
|
||||||
|
? !isCornerVisible( upperRight ) && !isCornerVisible( lowerRight )
|
||||||
|
: !isCornerVisible( upperLeft ) && !isCornerVisible( lowerLeft );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isCornerVisible( Component corner ) {
|
||||||
|
return corner != null &&
|
||||||
|
corner.getWidth() > 0 &&
|
||||||
|
corner.getHeight() > 0 &&
|
||||||
|
corner.isVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void resizeViewport( Component c, int extraWidth, boolean ltr ) {
|
||||||
|
if( c == null )
|
||||||
|
return;
|
||||||
|
|
||||||
|
Rectangle vr = c.getBounds();
|
||||||
|
c.setBounds( vr.x - (ltr ? 0 : extraWidth), vr.y, vr.width + extraWidth, vr.height );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -531,7 +531,7 @@ debug*/
|
|||||||
public static Shape createDirectionalThumbShape( float x, float y, float w, float h, float arc ) {
|
public static Shape createDirectionalThumbShape( float x, float y, float w, float h, float arc ) {
|
||||||
float wh = w / 2;
|
float wh = w / 2;
|
||||||
|
|
||||||
Path2D path = new Path2D.Float();
|
Path2D path = new Path2D.Float( Path2D.WIND_NON_ZERO, 9 );
|
||||||
path.moveTo( x + wh, y + h );
|
path.moveTo( x + wh, y + h );
|
||||||
path.lineTo( x, y + (h - wh) );
|
path.lineTo( x, y + (h - wh) );
|
||||||
path.lineTo( x, y + arc );
|
path.lineTo( x, y + arc );
|
||||||
|
|||||||
@@ -65,9 +65,8 @@ import com.formdev.flatlaf.util.LoggingFacade;
|
|||||||
* <!-- FlatSpinnerUI -->
|
* <!-- FlatSpinnerUI -->
|
||||||
*
|
*
|
||||||
* @uiDefault Component.minimumWidth int
|
* @uiDefault Component.minimumWidth int
|
||||||
* @uiDefault Spinner.buttonStyle String button (default) or none
|
* @uiDefault Spinner.buttonStyle String button (default), mac or none
|
||||||
* @uiDefault Component.arrowType String chevron (default) or triangle
|
* @uiDefault Component.arrowType String chevron (default) or triangle
|
||||||
* @uiDefault Component.isIntelliJTheme boolean
|
|
||||||
* @uiDefault Spinner.disabledBackground Color
|
* @uiDefault Spinner.disabledBackground Color
|
||||||
* @uiDefault Spinner.disabledForeground Color
|
* @uiDefault Spinner.disabledForeground Color
|
||||||
* @uiDefault Spinner.focusedBackground Color optional
|
* @uiDefault Spinner.focusedBackground Color optional
|
||||||
@@ -92,7 +91,6 @@ public class FlatSpinnerUI
|
|||||||
@Styleable protected int minimumWidth;
|
@Styleable protected int minimumWidth;
|
||||||
@Styleable protected String buttonStyle;
|
@Styleable protected String buttonStyle;
|
||||||
@Styleable protected String arrowType;
|
@Styleable protected String arrowType;
|
||||||
protected boolean isIntelliJTheme;
|
|
||||||
@Styleable protected Color disabledBackground;
|
@Styleable protected Color disabledBackground;
|
||||||
@Styleable protected Color disabledForeground;
|
@Styleable protected Color disabledForeground;
|
||||||
@Styleable protected Color focusedBackground;
|
@Styleable protected Color focusedBackground;
|
||||||
@@ -129,7 +127,6 @@ public class FlatSpinnerUI
|
|||||||
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
||||||
buttonStyle = UIManager.getString( "Spinner.buttonStyle" );
|
buttonStyle = UIManager.getString( "Spinner.buttonStyle" );
|
||||||
arrowType = UIManager.getString( "Component.arrowType" );
|
arrowType = UIManager.getString( "Component.arrowType" );
|
||||||
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
|
||||||
disabledBackground = UIManager.getColor( "Spinner.disabledBackground" );
|
disabledBackground = UIManager.getColor( "Spinner.disabledBackground" );
|
||||||
disabledForeground = UIManager.getColor( "Spinner.disabledForeground" );
|
disabledForeground = UIManager.getColor( "Spinner.disabledForeground" );
|
||||||
focusedBackground = UIManager.getColor( "Spinner.focusedBackground" );
|
focusedBackground = UIManager.getColor( "Spinner.focusedBackground" );
|
||||||
@@ -316,7 +313,7 @@ public class FlatSpinnerUI
|
|||||||
|
|
||||||
return background;
|
return background;
|
||||||
} else
|
} else
|
||||||
return isIntelliJTheme ? FlatUIUtils.getParentBackground( spinner ) : disabledBackground;
|
return disabledBackground;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Color getForeground( boolean enabled ) {
|
protected Color getForeground( boolean enabled ) {
|
||||||
@@ -340,7 +337,25 @@ public class FlatSpinnerUI
|
|||||||
|
|
||||||
private Component createArrowButton( int direction, String name ) {
|
private Component createArrowButton( int direction, String name ) {
|
||||||
FlatArrowButton button = new FlatArrowButton( direction, arrowType, buttonArrowColor,
|
FlatArrowButton button = new FlatArrowButton( direction, arrowType, buttonArrowColor,
|
||||||
buttonDisabledArrowColor, buttonHoverArrowColor, null, buttonPressedArrowColor, null );
|
buttonDisabledArrowColor, buttonHoverArrowColor, null, buttonPressedArrowColor, null )
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public int getArrowWidth() {
|
||||||
|
return isMacStyle() ? 7 : super.getArrowWidth();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public float getArrowThickness() {
|
||||||
|
return isMacStyle() ? 1.5f : super.getArrowThickness();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public float getYOffset() {
|
||||||
|
return isMacStyle() ? 0 : super.getYOffset();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean isRoundBorderAutoXOffset() {
|
||||||
|
return isMacStyle() ? false : super.isRoundBorderAutoXOffset();
|
||||||
|
}
|
||||||
|
};
|
||||||
button.setName( name );
|
button.setName( name );
|
||||||
button.setYOffset( (direction == SwingConstants.NORTH) ? 1.25f : -1.25f );
|
button.setYOffset( (direction == SwingConstants.NORTH) ? 1.25f : -1.25f );
|
||||||
if( direction == SwingConstants.NORTH )
|
if( direction == SwingConstants.NORTH )
|
||||||
@@ -374,10 +389,13 @@ public class FlatSpinnerUI
|
|||||||
int width = c.getWidth();
|
int width = c.getWidth();
|
||||||
int height = c.getHeight();
|
int height = c.getHeight();
|
||||||
boolean enabled = spinner.isEnabled();
|
boolean enabled = spinner.isEnabled();
|
||||||
|
boolean ltr = spinner.getComponentOrientation().isLeftToRight();
|
||||||
|
boolean isMacStyle = isMacStyle();
|
||||||
|
int macStyleButtonsWidth = isMacStyle ? getMacStyleButtonsWidth() : 0;
|
||||||
|
|
||||||
// paint background
|
// paint background
|
||||||
g2.setColor( getBackground( enabled ) );
|
g2.setColor( getBackground( enabled ) );
|
||||||
FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc );
|
FlatUIUtils.paintComponentBackground( g2, ltr ? 0 : macStyleButtonsWidth, 0, width - macStyleButtonsWidth, height, focusWidth, arc );
|
||||||
|
|
||||||
// paint button background and separator
|
// paint button background and separator
|
||||||
boolean paintButton = !"none".equals( buttonStyle );
|
boolean paintButton = !"none".equals( buttonStyle );
|
||||||
@@ -386,13 +404,35 @@ public class FlatSpinnerUI
|
|||||||
Component button = (handler.nextButton != null) ? handler.nextButton : handler.previousButton;
|
Component button = (handler.nextButton != null) ? handler.nextButton : handler.previousButton;
|
||||||
int arrowX = button.getX();
|
int arrowX = button.getX();
|
||||||
int arrowWidth = button.getWidth();
|
int arrowWidth = button.getWidth();
|
||||||
boolean isLeftToRight = spinner.getComponentOrientation().isLeftToRight();
|
Color separatorColor = enabled ? buttonSeparatorColor : buttonDisabledSeparatorColor;
|
||||||
|
|
||||||
|
if( isMacStyle ) {
|
||||||
|
Insets insets = spinner.getInsets();
|
||||||
|
int lineWidth = Math.round( FlatUIUtils.getBorderLineWidth( spinner ) );
|
||||||
|
int bx = arrowX;
|
||||||
|
int by = insets.top - lineWidth;
|
||||||
|
int bw = arrowWidth;
|
||||||
|
int bh = height - insets.top - insets.bottom + (lineWidth * 2);
|
||||||
|
float lw = scale( buttonSeparatorWidth );
|
||||||
|
|
||||||
|
// buttons border
|
||||||
|
FlatUIUtils.paintOutlinedComponent( g2, bx, by, bw, bh,
|
||||||
|
0, 0, 0, lw, scale( 12 ),
|
||||||
|
null, separatorColor, buttonBackground );
|
||||||
|
|
||||||
|
// separator between buttons
|
||||||
|
if( separatorColor != null ) {
|
||||||
|
int thickness = scale( 1 );
|
||||||
|
g2.setColor( separatorColor );
|
||||||
|
g2.fill( new Rectangle2D.Float( bx + lw, by + ((bh - thickness) / 2f),
|
||||||
|
bw - (lw * 2), thickness ) );
|
||||||
|
}
|
||||||
|
} else {
|
||||||
// paint arrow buttons background
|
// paint arrow buttons background
|
||||||
if( enabled && buttonBackground != null ) {
|
if( enabled && buttonBackground != null ) {
|
||||||
g2.setColor( buttonBackground );
|
g2.setColor( buttonBackground );
|
||||||
Shape oldClip = g2.getClip();
|
Shape oldClip = g2.getClip();
|
||||||
if( isLeftToRight )
|
if( ltr )
|
||||||
g2.clipRect( arrowX, 0, width - arrowX, height );
|
g2.clipRect( arrowX, 0, width - arrowX, height );
|
||||||
else
|
else
|
||||||
g2.clipRect( 0, 0, arrowX + arrowWidth, height );
|
g2.clipRect( 0, 0, arrowX + arrowWidth, height );
|
||||||
@@ -401,20 +441,33 @@ public class FlatSpinnerUI
|
|||||||
}
|
}
|
||||||
|
|
||||||
// paint vertical line between value and arrow buttons
|
// paint vertical line between value and arrow buttons
|
||||||
Color separatorColor = enabled ? buttonSeparatorColor : buttonDisabledSeparatorColor;
|
|
||||||
if( separatorColor != null && buttonSeparatorWidth > 0 ) {
|
if( separatorColor != null && buttonSeparatorWidth > 0 ) {
|
||||||
g2.setColor( separatorColor );
|
g2.setColor( separatorColor );
|
||||||
float lw = scale( buttonSeparatorWidth );
|
float lw = scale( buttonSeparatorWidth );
|
||||||
float lx = isLeftToRight ? arrowX : arrowX + arrowWidth - lw;
|
float lx = ltr ? arrowX : arrowX + arrowWidth - lw;
|
||||||
g2.fill( new Rectangle2D.Float( lx, focusWidth, lw, height - 1 - (focusWidth * 2) ) );
|
g2.fill( new Rectangle2D.Float( lx, focusWidth, lw, height - 1 - (focusWidth * 2) ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
paint( g, c );
|
paint( g, c );
|
||||||
|
|
||||||
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
|
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean isMacStyle() {
|
||||||
|
return "mac".equals( buttonStyle );
|
||||||
|
}
|
||||||
|
|
||||||
|
int getMacStyleButtonsWidth() {
|
||||||
|
return (handler.nextButton != null || handler.previousButton != null)
|
||||||
|
? scale( MAC_STEPPER_GAP ) + scale( MAC_STEPPER_WIDTH )
|
||||||
|
: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final int MAC_STEPPER_WIDTH = 15;
|
||||||
|
private static final int MAC_STEPPER_GAP = 3;
|
||||||
|
|
||||||
//---- class Handler ------------------------------------------------------
|
//---- class Handler ------------------------------------------------------
|
||||||
|
|
||||||
private class Handler
|
private class Handler
|
||||||
@@ -471,6 +524,7 @@ public class FlatSpinnerUI
|
|||||||
Insets insets = parent.getInsets();
|
Insets insets = parent.getInsets();
|
||||||
Rectangle r = FlatUIUtils.subtractInsets( new Rectangle( size ), insets );
|
Rectangle r = FlatUIUtils.subtractInsets( new Rectangle( size ), insets );
|
||||||
|
|
||||||
|
// editor gets all space if there are no buttons
|
||||||
if( nextButton == null && previousButton == null ) {
|
if( nextButton == null && previousButton == null ) {
|
||||||
if( editor != null )
|
if( editor != null )
|
||||||
editor.setBounds( r );
|
editor.setBounds( r );
|
||||||
@@ -486,20 +540,36 @@ public class FlatSpinnerUI
|
|||||||
int minButtonWidth = (maxButtonWidth * 3) / 4;
|
int minButtonWidth = (maxButtonWidth * 3) / 4;
|
||||||
|
|
||||||
// make button area square (except if width is limited)
|
// make button area square (except if width is limited)
|
||||||
int buttonsWidth = Math.min( Math.max( buttonsRect.height, minButtonWidth ), maxButtonWidth );
|
boolean isMacStyle = isMacStyle();
|
||||||
buttonsRect.width = buttonsWidth;
|
int buttonsGap = isMacStyle ? scale( MAC_STEPPER_GAP ) : 0;
|
||||||
|
int prefButtonWidth = isMacStyle ? scale( MAC_STEPPER_WIDTH ) : buttonsRect.height;
|
||||||
|
int buttonsWidth = Math.min( Math.max( prefButtonWidth, minButtonWidth ), maxButtonWidth );
|
||||||
|
|
||||||
if( parent.getComponentOrientation().isLeftToRight() ) {
|
// update editor and buttons bounds
|
||||||
editorRect.width -= buttonsWidth;
|
buttonsRect.width = buttonsWidth;
|
||||||
buttonsRect.x += editorRect.width;
|
editorRect.width -= buttonsWidth + buttonsGap;
|
||||||
} else {
|
boolean ltr = parent.getComponentOrientation().isLeftToRight();
|
||||||
editorRect.x += buttonsWidth;
|
if( ltr )
|
||||||
editorRect.width -= buttonsWidth;
|
buttonsRect.x += editorRect.width + buttonsGap;
|
||||||
|
else
|
||||||
|
editorRect.x += buttonsWidth + buttonsGap;
|
||||||
|
|
||||||
|
// in mac button style increase buttons height and move to the right
|
||||||
|
// for exact alignment with border
|
||||||
|
if( isMacStyle ) {
|
||||||
|
int lineWidth = Math.round( FlatUIUtils.getBorderLineWidth( spinner ) );
|
||||||
|
if( lineWidth > 0 ) {
|
||||||
|
buttonsRect.x += ltr ? lineWidth : -lineWidth;
|
||||||
|
buttonsRect.y -= lineWidth;
|
||||||
|
buttonsRect.height += lineWidth * 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set editor bounds
|
||||||
if( editor != null )
|
if( editor != null )
|
||||||
editor.setBounds( editorRect );
|
editor.setBounds( editorRect );
|
||||||
|
|
||||||
|
// set buttons bounds
|
||||||
int nextHeight = (buttonsRect.height / 2) + (buttonsRect.height % 2); // round up
|
int nextHeight = (buttonsRect.height / 2) + (buttonsRect.height % 2); // round up
|
||||||
if( nextButton != null )
|
if( nextButton != null )
|
||||||
nextButton.setBounds( buttonsRect.x, buttonsRect.y, buttonsRect.width, nextHeight );
|
nextButton.setBounds( buttonsRect.x, buttonsRect.y, buttonsRect.width, nextHeight );
|
||||||
|
|||||||
@@ -16,7 +16,9 @@
|
|||||||
|
|
||||||
package com.formdev.flatlaf.ui;
|
package com.formdev.flatlaf.ui;
|
||||||
|
|
||||||
|
import java.awt.Canvas;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
import java.awt.Component;
|
||||||
import java.awt.Container;
|
import java.awt.Container;
|
||||||
import java.awt.Cursor;
|
import java.awt.Cursor;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
@@ -67,6 +69,8 @@ import com.formdev.flatlaf.util.UIScale;
|
|||||||
* <!-- FlatSplitPaneUI -->
|
* <!-- FlatSplitPaneUI -->
|
||||||
*
|
*
|
||||||
* @uiDefault Component.arrowType String chevron (default) or triangle
|
* @uiDefault Component.arrowType String chevron (default) or triangle
|
||||||
|
* @uiDefault SplitPaneDivider.hoverColor Color optional
|
||||||
|
* @uiDefault SplitPaneDivider.pressedColor Color optional
|
||||||
* @uiDefault SplitPaneDivider.oneTouchArrowColor Color
|
* @uiDefault SplitPaneDivider.oneTouchArrowColor Color
|
||||||
* @uiDefault SplitPaneDivider.oneTouchHoverArrowColor Color
|
* @uiDefault SplitPaneDivider.oneTouchHoverArrowColor Color
|
||||||
* @uiDefault SplitPaneDivider.oneTouchPressedArrowColor Color
|
* @uiDefault SplitPaneDivider.oneTouchPressedArrowColor Color
|
||||||
@@ -83,11 +87,11 @@ public class FlatSplitPaneUI
|
|||||||
implements StyleableUI
|
implements StyleableUI
|
||||||
{
|
{
|
||||||
@Styleable protected String arrowType;
|
@Styleable protected String arrowType;
|
||||||
|
/** @since 3.3 */ @Styleable protected Color draggingColor;
|
||||||
@Styleable protected Color oneTouchArrowColor;
|
@Styleable protected Color oneTouchArrowColor;
|
||||||
@Styleable protected Color oneTouchHoverArrowColor;
|
@Styleable protected Color oneTouchHoverArrowColor;
|
||||||
@Styleable protected Color oneTouchPressedArrowColor;
|
@Styleable protected Color oneTouchPressedArrowColor;
|
||||||
|
|
||||||
private PropertyChangeListener propertyChangeListener;
|
|
||||||
private Map<String, Object> oldStyleValues;
|
private Map<String, Object> oldStyleValues;
|
||||||
|
|
||||||
public static ComponentUI createUI( JComponent c ) {
|
public static ComponentUI createUI( JComponent c ) {
|
||||||
@@ -105,6 +109,8 @@ public class FlatSplitPaneUI
|
|||||||
protected void installDefaults() {
|
protected void installDefaults() {
|
||||||
arrowType = UIManager.getString( "Component.arrowType" );
|
arrowType = UIManager.getString( "Component.arrowType" );
|
||||||
|
|
||||||
|
draggingColor = UIManager.getColor( "SplitPaneDivider.draggingColor" );
|
||||||
|
|
||||||
// get one-touch colors before invoking super.installDefaults() because they are
|
// get one-touch colors before invoking super.installDefaults() because they are
|
||||||
// used in there on LaF switching
|
// used in there on LaF switching
|
||||||
oneTouchArrowColor = UIManager.getColor( "SplitPaneDivider.oneTouchArrowColor" );
|
oneTouchArrowColor = UIManager.getColor( "SplitPaneDivider.oneTouchArrowColor" );
|
||||||
@@ -118,6 +124,8 @@ public class FlatSplitPaneUI
|
|||||||
protected void uninstallDefaults() {
|
protected void uninstallDefaults() {
|
||||||
super.uninstallDefaults();
|
super.uninstallDefaults();
|
||||||
|
|
||||||
|
draggingColor = null;
|
||||||
|
|
||||||
oneTouchArrowColor = null;
|
oneTouchArrowColor = null;
|
||||||
oneTouchHoverArrowColor = null;
|
oneTouchHoverArrowColor = null;
|
||||||
oneTouchPressedArrowColor = null;
|
oneTouchPressedArrowColor = null;
|
||||||
@@ -126,19 +134,9 @@ public class FlatSplitPaneUI
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void installListeners() {
|
protected PropertyChangeListener createPropertyChangeListener() {
|
||||||
super.installListeners();
|
return FlatStylingSupport.createPropertyChangeListener( splitPane, this::installStyle,
|
||||||
|
super.createPropertyChangeListener() );
|
||||||
propertyChangeListener = FlatStylingSupport.createPropertyChangeListener( splitPane, this::installStyle, null );
|
|
||||||
splitPane.addPropertyChangeListener( propertyChangeListener );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void uninstallListeners() {
|
|
||||||
super.uninstallListeners();
|
|
||||||
|
|
||||||
splitPane.removePropertyChangeListener( propertyChangeListener );
|
|
||||||
propertyChangeListener = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -194,12 +192,49 @@ public class FlatSplitPaneUI
|
|||||||
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
|
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Component createDefaultNonContinuousLayoutDivider() {
|
||||||
|
// only used for non-continuous layout if left or right component is heavy weight
|
||||||
|
return new Canvas() {
|
||||||
|
@Override
|
||||||
|
public void paint( Graphics g ) {
|
||||||
|
if( !isContinuousLayout() && getLastDragLocation() != -1 )
|
||||||
|
paintDragDivider( g, 0 );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finishedPaintingChildren( JSplitPane sp, Graphics g ) {
|
||||||
|
if( sp == splitPane && getLastDragLocation() != -1 && !isContinuousLayout() && !draggingHW )
|
||||||
|
paintDragDivider( g, getLastDragLocation() );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void paintDragDivider( Graphics g, int dividerLocation ) {
|
||||||
|
// divider bounds
|
||||||
|
boolean horizontal = (getOrientation() == JSplitPane.HORIZONTAL_SPLIT);
|
||||||
|
int x = horizontal ? dividerLocation : 0;
|
||||||
|
int y = !horizontal ? dividerLocation : 0;
|
||||||
|
int width = horizontal ? dividerSize : splitPane.getWidth();
|
||||||
|
int height = !horizontal ? dividerSize : splitPane.getHeight();
|
||||||
|
|
||||||
|
// paint background
|
||||||
|
g.setColor( FlatUIUtils.deriveColor( draggingColor, splitPane.getBackground() ) );
|
||||||
|
g.fillRect( x, y, width, height );
|
||||||
|
|
||||||
|
// paint divider style (e.g. grip)
|
||||||
|
if( divider instanceof FlatSplitPaneDivider )
|
||||||
|
((FlatSplitPaneDivider)divider).paintStyle( g, x, y, width, height );
|
||||||
|
}
|
||||||
|
|
||||||
//---- class FlatSplitPaneDivider -----------------------------------------
|
//---- class FlatSplitPaneDivider -----------------------------------------
|
||||||
|
|
||||||
protected class FlatSplitPaneDivider
|
protected class FlatSplitPaneDivider
|
||||||
extends BasicSplitPaneDivider
|
extends BasicSplitPaneDivider
|
||||||
{
|
{
|
||||||
@Styleable protected String style = UIManager.getString( "SplitPaneDivider.style" );
|
@Styleable protected String style = UIManager.getString( "SplitPaneDivider.style" );
|
||||||
|
/** @since 3.3 */ @Styleable protected Color hoverColor = UIManager.getColor( "SplitPaneDivider.hoverColor" );
|
||||||
|
/** @since 3.3 */ @Styleable protected Color pressedColor = UIManager.getColor( "SplitPaneDivider.pressedColor" );
|
||||||
@Styleable protected Color gripColor = UIManager.getColor( "SplitPaneDivider.gripColor" );
|
@Styleable protected Color gripColor = UIManager.getColor( "SplitPaneDivider.gripColor" );
|
||||||
@Styleable protected int gripDotCount = FlatUIUtils.getUIInt( "SplitPaneDivider.gripDotCount", 3 );
|
@Styleable protected int gripDotCount = FlatUIUtils.getUIInt( "SplitPaneDivider.gripDotCount", 3 );
|
||||||
@Styleable protected int gripDotSize = FlatUIUtils.getUIInt( "SplitPaneDivider.gripDotSize", 3 );
|
@Styleable protected int gripDotSize = FlatUIUtils.getUIInt( "SplitPaneDivider.gripDotSize", 3 );
|
||||||
@@ -262,15 +297,31 @@ public class FlatSplitPaneUI
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paint( Graphics g ) {
|
public void paint( Graphics g ) {
|
||||||
|
// paint hover or pressed background
|
||||||
|
Color hoverOrPressedColor = (isContinuousLayout() && dragger != null)
|
||||||
|
? pressedColor
|
||||||
|
: (isMouseOver() && dragger == null
|
||||||
|
? hoverColor
|
||||||
|
: null);
|
||||||
|
if( hoverOrPressedColor != null ) {
|
||||||
|
g.setColor( FlatUIUtils.deriveColor( hoverOrPressedColor, splitPane.getBackground() ) );
|
||||||
|
g.fillRect( 0, 0, getWidth(), getHeight() );
|
||||||
|
}
|
||||||
|
|
||||||
super.paint( g );
|
super.paint( g );
|
||||||
|
|
||||||
|
paintStyle( g, 0, 0, getWidth(), getHeight() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @since 3.3 */
|
||||||
|
protected void paintStyle( Graphics g, int x, int y, int width, int height ) {
|
||||||
if( "plain".equals( style ) )
|
if( "plain".equals( style ) )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g );
|
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g );
|
||||||
|
|
||||||
g.setColor( gripColor );
|
g.setColor( gripColor );
|
||||||
paintGrip( g, 0, 0, getWidth(), getHeight() );
|
paintGrip( g, x, y, width, height );
|
||||||
|
|
||||||
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
|
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
|
||||||
}
|
}
|
||||||
@@ -297,6 +348,29 @@ public class FlatSplitPaneUI
|
|||||||
: location == (splitPane.getWidth() - getWidth() - insets.right);
|
: location == (splitPane.getWidth() - getWidth() - insets.right);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setMouseOver( boolean mouseOver ) {
|
||||||
|
super.setMouseOver( mouseOver );
|
||||||
|
repaintIfNecessary();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void prepareForDragging() {
|
||||||
|
super.prepareForDragging();
|
||||||
|
repaintIfNecessary();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void finishDraggingTo( int location ) {
|
||||||
|
super.finishDraggingTo( location );
|
||||||
|
repaintIfNecessary();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void repaintIfNecessary() {
|
||||||
|
if( hoverColor != null || pressedColor != null )
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
|
|
||||||
//---- class FlatOneTouchButton ---------------------------------------
|
//---- class FlatOneTouchButton ---------------------------------------
|
||||||
|
|
||||||
protected class FlatOneTouchButton
|
protected class FlatOneTouchButton
|
||||||
|
|||||||
@@ -100,15 +100,15 @@ public class FlatStylingSupport
|
|||||||
|
|
||||||
/** @since 2 */
|
/** @since 2 */
|
||||||
public interface StyleableUI {
|
public interface StyleableUI {
|
||||||
Map<String, Class<?>> getStyleableInfos( JComponent c );
|
Map<String, Class<?>> getStyleableInfos( JComponent c ) throws IllegalArgumentException;
|
||||||
/** @since 2.5 */ Object getStyleableValue( JComponent c, String key );
|
/** @since 2.5 */ Object getStyleableValue( JComponent c, String key ) throws IllegalArgumentException;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @since 2 */
|
/** @since 2 */
|
||||||
public interface StyleableBorder {
|
public interface StyleableBorder {
|
||||||
Object applyStyleProperty( String key, Object value );
|
Object applyStyleProperty( String key, Object value );
|
||||||
Map<String, Class<?>> getStyleableInfos();
|
Map<String, Class<?>> getStyleableInfos() throws IllegalArgumentException;
|
||||||
/** @since 2.5 */ Object getStyleableValue( String key );
|
/** @since 2.5 */ Object getStyleableValue( String key ) throws IllegalArgumentException;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @since 2.5 */
|
/** @since 2.5 */
|
||||||
@@ -135,7 +135,9 @@ public class FlatStylingSupport
|
|||||||
return getStyle( c ) != null || getStyleClass( c ) != null;
|
return getStyle( c ) != null || getStyleClass( c ) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object getResolvedStyle( JComponent c, String type ) {
|
public static Object getResolvedStyle( JComponent c, String type )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
Object style = getStyle( c );
|
Object style = getStyle( c );
|
||||||
Object styleClass = getStyleClass( c );
|
Object styleClass = getStyleClass( c );
|
||||||
Object styleForClasses = getStyleForClasses( styleClass, type );
|
Object styleForClasses = getStyleForClasses( styleClass, type );
|
||||||
@@ -175,7 +177,9 @@ public class FlatStylingSupport
|
|||||||
* @param type the type of the component
|
* @param type the type of the component
|
||||||
* @return the styles
|
* @return the styles
|
||||||
*/
|
*/
|
||||||
public static Object getStyleForClasses( Object styleClass, String type ) {
|
public static Object getStyleForClasses( Object styleClass, String type )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
if( styleClass == null )
|
if( styleClass == null )
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@@ -198,7 +202,9 @@ public class FlatStylingSupport
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object getStyleForClass( String styleClass, String type ) {
|
private static Object getStyleForClass( String styleClass, String type )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
return joinStyles(
|
return joinStyles(
|
||||||
UIManager.get( "[style]." + styleClass ),
|
UIManager.get( "[style]." + styleClass ),
|
||||||
UIManager.get( "[style]" + type + '.' + styleClass ) );
|
UIManager.get( "[style]" + type + '.' + styleClass ) );
|
||||||
@@ -218,7 +224,9 @@ public class FlatStylingSupport
|
|||||||
* @return new joined style
|
* @return new joined style
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings( "unchecked" )
|
@SuppressWarnings( "unchecked" )
|
||||||
public static Object joinStyles( Object style1, Object style2 ) {
|
public static Object joinStyles( Object style1, Object style2 )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
if( style1 == null )
|
if( style1 == null )
|
||||||
return style2;
|
return style2;
|
||||||
if( style2 == null )
|
if( style2 == null )
|
||||||
@@ -278,6 +286,7 @@ public class FlatStylingSupport
|
|||||||
* @throws IllegalArgumentException on syntax errors
|
* @throws IllegalArgumentException on syntax errors
|
||||||
* @throws ClassCastException if value type does not fit to expected type
|
* @throws ClassCastException if value type does not fit to expected type
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings( "ReturnValueIgnored" ) // Error Prone
|
||||||
public static Map<String, Object> parseAndApply( Map<String, Object> oldStyleValues,
|
public static Map<String, Object> parseAndApply( Map<String, Object> oldStyleValues,
|
||||||
Object style, BiFunction<String, Object, Object> applyProperty )
|
Object style, BiFunction<String, Object, Object> applyProperty )
|
||||||
throws UnknownStyleException, IllegalArgumentException
|
throws UnknownStyleException, IllegalArgumentException
|
||||||
@@ -379,7 +388,9 @@ public class FlatStylingSupport
|
|||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object parseValue( String key, String value ) {
|
private static Object parseValue( String key, String value )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
// simple reference
|
// simple reference
|
||||||
if( value.startsWith( "$" ) )
|
if( value.startsWith( "$" ) )
|
||||||
return UIManager.get( value.substring( 1 ) );
|
return UIManager.get( value.substring( 1 ) );
|
||||||
@@ -474,7 +485,9 @@ public class FlatStylingSupport
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object applyToField( Field f, Object obj, Object value, boolean useMethodHandles ) {
|
private static Object applyToField( Field f, Object obj, Object value, boolean useMethodHandles )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
checkValidField( f );
|
checkValidField( f );
|
||||||
|
|
||||||
if( useMethodHandles && obj instanceof StyleableLookupProvider ) {
|
if( useMethodHandles && obj instanceof StyleableLookupProvider ) {
|
||||||
@@ -504,7 +517,9 @@ public class FlatStylingSupport
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object getFieldValue( Field f, Object obj, boolean useMethodHandles ) {
|
private static Object getFieldValue( Field f, Object obj, boolean useMethodHandles )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
checkValidField( f );
|
checkValidField( f );
|
||||||
|
|
||||||
if( useMethodHandles && obj instanceof StyleableLookupProvider ) {
|
if( useMethodHandles && obj instanceof StyleableLookupProvider ) {
|
||||||
@@ -529,7 +544,9 @@ public class FlatStylingSupport
|
|||||||
return new IllegalArgumentException( "failed to access field '" + f.getDeclaringClass().getName() + "." + f.getName() + "'", ex );
|
return new IllegalArgumentException( "failed to access field '" + f.getDeclaringClass().getName() + "." + f.getName() + "'", ex );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void checkValidField( Field f ) {
|
private static void checkValidField( Field f )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
if( !isValidField( f ) )
|
if( !isValidField( f ) )
|
||||||
throw new IllegalArgumentException( "field '" + f.getDeclaringClass().getName() + "." + f.getName() + "' is final or static" );
|
throw new IllegalArgumentException( "field '" + f.getDeclaringClass().getName() + "." + f.getName() + "' is final or static" );
|
||||||
}
|
}
|
||||||
@@ -539,7 +556,9 @@ public class FlatStylingSupport
|
|||||||
return (modifiers & (Modifier.FINAL|Modifier.STATIC)) == 0 && !f.isSynthetic();
|
return (modifiers & (Modifier.FINAL|Modifier.STATIC)) == 0 && !f.isSynthetic();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Field getStyleableField( StyleableField styleableField ) {
|
private static Field getStyleableField( StyleableField styleableField )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
String fieldName = styleableField.fieldName();
|
String fieldName = styleableField.fieldName();
|
||||||
if( fieldName.isEmpty() )
|
if( fieldName.isEmpty() )
|
||||||
fieldName = styleableField.key();
|
fieldName = styleableField.key();
|
||||||
@@ -647,6 +666,7 @@ public class FlatStylingSupport
|
|||||||
|
|
||||||
static Object applyToAnnotatedObjectOrBorder( Object obj, String key, Object value,
|
static Object applyToAnnotatedObjectOrBorder( Object obj, String key, Object value,
|
||||||
JComponent c, AtomicBoolean borderShared )
|
JComponent c, AtomicBoolean borderShared )
|
||||||
|
throws IllegalArgumentException
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
return applyToAnnotatedObject( obj, key, value );
|
return applyToAnnotatedObject( obj, key, value );
|
||||||
@@ -695,7 +715,9 @@ public class FlatStylingSupport
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static Border cloneBorder( Border border ) {
|
static Border cloneBorder( Border border )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
Class<? extends Border> borderClass = border.getClass();
|
Class<? extends Border> borderClass = border.getClass();
|
||||||
try {
|
try {
|
||||||
return borderClass.getDeclaredConstructor().newInstance();
|
return borderClass.getDeclaredConstructor().newInstance();
|
||||||
@@ -704,7 +726,9 @@ public class FlatStylingSupport
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Icon cloneIcon( Icon icon ) {
|
static Icon cloneIcon( Icon icon )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
Class<? extends Icon> iconClass = icon.getClass();
|
Class<? extends Icon> iconClass = icon.getClass();
|
||||||
try {
|
try {
|
||||||
return iconClass.getDeclaredConstructor().newInstance();
|
return iconClass.getDeclaredConstructor().newInstance();
|
||||||
@@ -717,11 +741,15 @@ public class FlatStylingSupport
|
|||||||
* Returns a map of all fields annotated with {@link Styleable}.
|
* Returns a map of all fields annotated with {@link Styleable}.
|
||||||
* The key is the name of the field and the value the type of the field.
|
* The key is the name of the field and the value the type of the field.
|
||||||
*/
|
*/
|
||||||
public static Map<String, Class<?>> getAnnotatedStyleableInfos( Object obj ) {
|
public static Map<String, Class<?>> getAnnotatedStyleableInfos( Object obj )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
return getAnnotatedStyleableInfos( obj, null );
|
return getAnnotatedStyleableInfos( obj, null );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Map<String, Class<?>> getAnnotatedStyleableInfos( Object obj, Border border ) {
|
public static Map<String, Class<?>> getAnnotatedStyleableInfos( Object obj, Border border )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
Map<String, Class<?>> infos = new StyleableInfosMap<>();
|
Map<String, Class<?>> infos = new StyleableInfosMap<>();
|
||||||
collectAnnotatedStyleableInfos( obj, infos );
|
collectAnnotatedStyleableInfos( obj, infos );
|
||||||
collectStyleableInfos( border, infos );
|
collectStyleableInfos( border, infos );
|
||||||
@@ -732,7 +760,9 @@ public class FlatStylingSupport
|
|||||||
* Search for all fields annotated with {@link Styleable} and add them to the given map.
|
* Search for all fields annotated with {@link Styleable} and add them to the given map.
|
||||||
* The key is the name of the field and the value the type of the field.
|
* The key is the name of the field and the value the type of the field.
|
||||||
*/
|
*/
|
||||||
public static void collectAnnotatedStyleableInfos( Object obj, Map<String, Class<?>> infos ) {
|
public static void collectAnnotatedStyleableInfos( Object obj, Map<String, Class<?>> infos )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
HashSet<String> processedFields = new HashSet<>();
|
HashSet<String> processedFields = new HashSet<>();
|
||||||
Class<?> cls = obj.getClass();
|
Class<?> cls = obj.getClass();
|
||||||
|
|
||||||
@@ -810,7 +840,9 @@ public class FlatStylingSupport
|
|||||||
infos.put( keyPrefix.concat( e.getKey() ), e.getValue() );
|
infos.put( keyPrefix.concat( e.getKey() ), e.getValue() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object getAnnotatedStyleableValue( Object obj, String key ) {
|
public static Object getAnnotatedStyleableValue( Object obj, String key )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
String fieldName = keyToFieldName( key );
|
String fieldName = keyToFieldName( key );
|
||||||
Class<?> cls = obj.getClass();
|
Class<?> cls = obj.getClass();
|
||||||
|
|
||||||
@@ -877,7 +909,9 @@ public class FlatStylingSupport
|
|||||||
extends LinkedHashMap<K,V>
|
extends LinkedHashMap<K,V>
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public V put( K key, V value ) {
|
public V put( K key, V value )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
V oldValue = super.put( key, value );
|
V oldValue = super.put( key, value );
|
||||||
if( oldValue != null )
|
if( oldValue != null )
|
||||||
throw new IllegalArgumentException( "duplicate key '" + key + "'" );
|
throw new IllegalArgumentException( "duplicate key '" + key + "'" );
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -24,6 +24,7 @@ import java.util.function.Function;
|
|||||||
import javax.swing.JTable;
|
import javax.swing.JTable;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
|
import javax.swing.border.Border;
|
||||||
import javax.swing.plaf.TableUI;
|
import javax.swing.plaf.TableUI;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -107,17 +108,55 @@ public class FlatTableCellBorder
|
|||||||
public static class Focused
|
public static class Focused
|
||||||
extends FlatTableCellBorder
|
extends FlatTableCellBorder
|
||||||
{
|
{
|
||||||
|
@Override
|
||||||
|
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||||
|
if( c != null && c.getClass().getName().equals( "javax.swing.JTable$BooleanRenderer" ) ) {
|
||||||
|
// boolean renderer in JTable does not use Table.focusSelectedCellHighlightBorder
|
||||||
|
// if cell is selected and focused (as DefaultTableCellRenderer does)
|
||||||
|
// --> delegate to Table.focusSelectedCellHighlightBorder
|
||||||
|
// to make FlatLaf "focus indicator border hiding" work
|
||||||
|
JTable table = (JTable) SwingUtilities.getAncestorOfClass( JTable.class, c );
|
||||||
|
if( table != null &&
|
||||||
|
c.getForeground() == table.getSelectionForeground() &&
|
||||||
|
c.getBackground() == table.getSelectionBackground() )
|
||||||
|
{
|
||||||
|
Border border = UIManager.getBorder( "Table.focusSelectedCellHighlightBorder" );
|
||||||
|
if( border != null ) {
|
||||||
|
border.paintBorder( c, g, x, y, width, height );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
super.paintBorder( c, g, x, y, width, height );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//---- class Selected -----------------------------------------------------
|
//---- class Selected -----------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Border for selected cell that uses margins and paints focus indicator border
|
* Border for selected cell that uses margins and paints focus indicator border.
|
||||||
* if enabled (Table.showCellFocusIndicator=true) or at least one selected cell is editable.
|
* The focus indicator is shown under following conditions:
|
||||||
|
* <ul>
|
||||||
|
* <li>always if enabled via UI property {@code Table.showCellFocusIndicator=true}
|
||||||
|
* <li>for row selection mode if exactly one row is selected and at least one cell in that row is editable
|
||||||
|
* <li>for column selection mode if exactly one column is selected and at least one cell in that column is editable
|
||||||
|
* <li>never for cell selection mode
|
||||||
|
* </ul>
|
||||||
|
* The reason for this logic is to hide the focus indicator when it is not needed,
|
||||||
|
* and only show it when there are editable cells and the user needs to know
|
||||||
|
* which cell is focused to start editing.
|
||||||
|
* <p>
|
||||||
|
* To avoid possible performance issues, checking for editable cells is limited
|
||||||
|
* to {@link #maxCheckCellsEditable}. If there are more cells to check,
|
||||||
|
* the focus indicator is always shown.
|
||||||
*/
|
*/
|
||||||
public static class Selected
|
public static class Selected
|
||||||
extends FlatTableCellBorder
|
extends FlatTableCellBorder
|
||||||
{
|
{
|
||||||
|
/** @since 3.1 */
|
||||||
|
public int maxCheckCellsEditable = 50;
|
||||||
|
|
||||||
@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 ) {
|
||||||
Boolean b = getStyleFromTableUI( c, ui -> ui.showCellFocusIndicator );
|
Boolean b = getStyleFromTableUI( c, ui -> ui.showCellFocusIndicator );
|
||||||
@@ -125,7 +164,7 @@ public class FlatTableCellBorder
|
|||||||
|
|
||||||
if( !showCellFocusIndicator ) {
|
if( !showCellFocusIndicator ) {
|
||||||
JTable table = (JTable) SwingUtilities.getAncestorOfClass( JTable.class, c );
|
JTable table = (JTable) SwingUtilities.getAncestorOfClass( JTable.class, c );
|
||||||
if( table != null && !isSelectionEditable( table ) )
|
if( table != null && !shouldShowCellFocusIndicator( table ) )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,30 +172,59 @@ public class FlatTableCellBorder
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether at least one selected cell is editable.
|
* Returns whether focus indicator border should be shown.
|
||||||
|
*
|
||||||
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
protected boolean isSelectionEditable( JTable table ) {
|
protected boolean shouldShowCellFocusIndicator( JTable table ) {
|
||||||
if( table.getRowSelectionAllowed() ) {
|
boolean rowSelectionAllowed = table.getRowSelectionAllowed();
|
||||||
|
boolean columnSelectionAllowed = table.getColumnSelectionAllowed();
|
||||||
|
|
||||||
|
// do not show for cell selection mode
|
||||||
|
// (unlikely that user wants edit cell in case that multiple cells are selected;
|
||||||
|
// if only a single cell is selected then it is clear where the focus is)
|
||||||
|
if( rowSelectionAllowed && columnSelectionAllowed )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( rowSelectionAllowed ) {
|
||||||
|
// row selection mode
|
||||||
|
|
||||||
|
// do not show if more than one row is selected
|
||||||
|
// (unlikely that user wants edit cell in this case)
|
||||||
|
if( table.getSelectedRowCount() != 1 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// show always if there are too many columns to check for editable
|
||||||
int columnCount = table.getColumnCount();
|
int columnCount = table.getColumnCount();
|
||||||
int[] selectedRows = table.getSelectedRows();
|
if( columnCount > maxCheckCellsEditable )
|
||||||
for( int selectedRow : selectedRows ) {
|
return true;
|
||||||
|
|
||||||
|
// check whether at least one selected cell is editable
|
||||||
|
int selectedRow = table.getSelectedRow();
|
||||||
for( int column = 0; column < columnCount; column++ ) {
|
for( int column = 0; column < columnCount; column++ ) {
|
||||||
if( table.isCellEditable( selectedRow, column ) )
|
if( table.isCellEditable( selectedRow, column ) )
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
} else if( columnSelectionAllowed ) {
|
||||||
}
|
// column selection mode
|
||||||
|
|
||||||
if( table.getColumnSelectionAllowed() ) {
|
// do not show if more than one column is selected
|
||||||
|
// (unlikely that user wants edit cell in this case)
|
||||||
|
if( table.getSelectedColumnCount() != 1 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// show always if there are too many rows to check for editable
|
||||||
int rowCount = table.getRowCount();
|
int rowCount = table.getRowCount();
|
||||||
int[] selectedColumns = table.getSelectedColumns();
|
if( rowCount > maxCheckCellsEditable )
|
||||||
for( int selectedColumn : selectedColumns ) {
|
return true;
|
||||||
|
|
||||||
|
// check whether at least one selected cell is editable
|
||||||
|
int selectedColumn = table.getSelectedColumn();
|
||||||
for( int row = 0; row < rowCount; row++ ) {
|
for( int row = 0; row < rowCount; row++ ) {
|
||||||
if( table.isCellEditable( row, selectedColumn ) )
|
if( table.isCellEditable( row, selectedColumn ) )
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package com.formdev.flatlaf.ui;
|
|||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
|
import java.awt.Container;
|
||||||
import java.awt.Cursor;
|
import java.awt.Cursor;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
@@ -28,16 +29,15 @@ import java.awt.event.MouseEvent;
|
|||||||
import java.awt.geom.Rectangle2D;
|
import java.awt.geom.Rectangle2D;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import javax.swing.CellRendererPane;
|
||||||
import javax.swing.Icon;
|
import javax.swing.Icon;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import javax.swing.JTable;
|
import javax.swing.JTable;
|
||||||
import javax.swing.SwingConstants;
|
import javax.swing.SwingConstants;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.border.Border;
|
|
||||||
import javax.swing.event.MouseInputListener;
|
import javax.swing.event.MouseInputListener;
|
||||||
import javax.swing.plaf.ComponentUI;
|
import javax.swing.plaf.ComponentUI;
|
||||||
import javax.swing.plaf.UIResource;
|
|
||||||
import javax.swing.plaf.basic.BasicTableHeaderUI;
|
import javax.swing.plaf.basic.BasicTableHeaderUI;
|
||||||
import javax.swing.table.JTableHeader;
|
import javax.swing.table.JTableHeader;
|
||||||
import javax.swing.table.TableCellRenderer;
|
import javax.swing.table.TableCellRenderer;
|
||||||
@@ -59,6 +59,10 @@ import com.formdev.flatlaf.util.UIScale;
|
|||||||
*
|
*
|
||||||
* <!-- FlatTableHeaderUI -->
|
* <!-- FlatTableHeaderUI -->
|
||||||
*
|
*
|
||||||
|
* @uiDefault TableHeader.hoverBackground Color optional
|
||||||
|
* @uiDefault TableHeader.hoverForeground Color optional
|
||||||
|
* @uiDefault TableHeader.pressedBackground Color optional
|
||||||
|
* @uiDefault TableHeader.pressedForeground Color optional
|
||||||
* @uiDefault TableHeader.bottomSeparatorColor Color
|
* @uiDefault TableHeader.bottomSeparatorColor Color
|
||||||
* @uiDefault TableHeader.height int
|
* @uiDefault TableHeader.height int
|
||||||
* @uiDefault TableHeader.sortIconPosition String right (default), left, top or bottom
|
* @uiDefault TableHeader.sortIconPosition String right (default), left, top or bottom
|
||||||
@@ -81,6 +85,10 @@ public class FlatTableHeaderUI
|
|||||||
extends BasicTableHeaderUI
|
extends BasicTableHeaderUI
|
||||||
implements StyleableUI
|
implements StyleableUI
|
||||||
{
|
{
|
||||||
|
/** @since 3.1 */ @Styleable protected Color hoverBackground;
|
||||||
|
/** @since 3.1 */ @Styleable protected Color hoverForeground;
|
||||||
|
/** @since 3.1 */ @Styleable protected Color pressedBackground;
|
||||||
|
/** @since 3.1 */ @Styleable protected Color pressedForeground;
|
||||||
@Styleable protected Color bottomSeparatorColor;
|
@Styleable protected Color bottomSeparatorColor;
|
||||||
@Styleable protected int height;
|
@Styleable protected int height;
|
||||||
@Styleable(type=String.class) protected int sortIconPosition;
|
@Styleable(type=String.class) protected int sortIconPosition;
|
||||||
@@ -106,6 +114,11 @@ public class FlatTableHeaderUI
|
|||||||
public void installUI( JComponent c ) {
|
public void installUI( JComponent c ) {
|
||||||
super.installUI( c );
|
super.installUI( c );
|
||||||
|
|
||||||
|
// replace cell renderer pane
|
||||||
|
header.remove( rendererPane );
|
||||||
|
rendererPane = new FlatTableHeaderCellRendererPane();
|
||||||
|
header.add( rendererPane );
|
||||||
|
|
||||||
installStyle();
|
installStyle();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,6 +126,10 @@ public class FlatTableHeaderUI
|
|||||||
protected void installDefaults() {
|
protected void installDefaults() {
|
||||||
super.installDefaults();
|
super.installDefaults();
|
||||||
|
|
||||||
|
hoverBackground = UIManager.getColor( "TableHeader.hoverBackground" );
|
||||||
|
hoverForeground = UIManager.getColor( "TableHeader.hoverForeground" );
|
||||||
|
pressedBackground = UIManager.getColor( "TableHeader.pressedBackground" );
|
||||||
|
pressedForeground = UIManager.getColor( "TableHeader.pressedForeground" );
|
||||||
bottomSeparatorColor = UIManager.getColor( "TableHeader.bottomSeparatorColor" );
|
bottomSeparatorColor = UIManager.getColor( "TableHeader.bottomSeparatorColor" );
|
||||||
height = UIManager.getInt( "TableHeader.height" );
|
height = UIManager.getInt( "TableHeader.height" );
|
||||||
sortIconPosition = parseSortIconPosition( UIManager.getString( "TableHeader.sortIconPosition" ) );
|
sortIconPosition = parseSortIconPosition( UIManager.getString( "TableHeader.sortIconPosition" ) );
|
||||||
@@ -122,6 +139,10 @@ public class FlatTableHeaderUI
|
|||||||
protected void uninstallDefaults() {
|
protected void uninstallDefaults() {
|
||||||
super.uninstallDefaults();
|
super.uninstallDefaults();
|
||||||
|
|
||||||
|
hoverBackground = null;
|
||||||
|
hoverForeground = null;
|
||||||
|
pressedBackground = null;
|
||||||
|
pressedForeground = null;
|
||||||
bottomSeparatorColor = null;
|
bottomSeparatorColor = null;
|
||||||
|
|
||||||
oldStyleValues = null;
|
oldStyleValues = null;
|
||||||
@@ -211,6 +232,12 @@ public class FlatTableHeaderUI
|
|||||||
return super.getRolloverColumn();
|
return super.getRolloverColumn();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void rolloverColumnUpdated( int oldColumn, int newColumn ) {
|
||||||
|
header.repaint( header.getHeaderRect( oldColumn ) );
|
||||||
|
header.repaint( header.getHeaderRect( newColumn ) );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paint( Graphics g, JComponent c ) {
|
public void paint( Graphics g, JComponent c ) {
|
||||||
fixDraggedAndResizingColumns( header );
|
fixDraggedAndResizingColumns( header );
|
||||||
@@ -243,21 +270,8 @@ public class FlatTableHeaderUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// temporary use own default renderer if necessary
|
|
||||||
FlatTableCellHeaderRenderer sortIconRenderer = null;
|
|
||||||
if( sortIconPosition != SwingConstants.RIGHT ) {
|
|
||||||
sortIconRenderer = new FlatTableCellHeaderRenderer( header.getDefaultRenderer() );
|
|
||||||
header.setDefaultRenderer( sortIconRenderer );
|
|
||||||
}
|
|
||||||
|
|
||||||
// paint header
|
// paint header
|
||||||
super.paint( g, c );
|
super.paint( g, c );
|
||||||
|
|
||||||
// restore default renderer
|
|
||||||
if( sortIconRenderer != null ) {
|
|
||||||
sortIconRenderer.reset();
|
|
||||||
header.setDefaultRenderer( sortIconRenderer.delegate );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isSystemDefaultRenderer( Object headerRenderer ) {
|
private boolean isSystemDefaultRenderer( Object headerRenderer ) {
|
||||||
@@ -315,80 +329,129 @@ public class FlatTableHeaderUI
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//---- class FlatTableCellHeaderRenderer ----------------------------------
|
//---- class FlatTableHeaderCellRendererPane ------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A delegating header renderer that is only used to paint sort arrows at
|
* Cell renderer pane that is used to paint hover and pressed background/foreground
|
||||||
* top, bottom or left position.
|
* and to paint sort arrows at top, bottom or left position.
|
||||||
*/
|
*/
|
||||||
private class FlatTableCellHeaderRenderer
|
private class FlatTableHeaderCellRendererPane
|
||||||
implements TableCellRenderer, Border, UIResource
|
extends CellRendererPane
|
||||||
{
|
{
|
||||||
private final TableCellRenderer delegate;
|
private final Icon ascendingSortIcon;
|
||||||
|
private final Icon descendingSortIcon;
|
||||||
|
|
||||||
private JLabel l;
|
public FlatTableHeaderCellRendererPane() {
|
||||||
private int oldHorizontalTextPosition = -1;
|
ascendingSortIcon = UIManager.getIcon( "Table.ascendingSortIcon" );
|
||||||
private Border origBorder;
|
descendingSortIcon = UIManager.getIcon( "Table.descendingSortIcon" );
|
||||||
private Icon sortIcon;
|
|
||||||
|
|
||||||
FlatTableCellHeaderRenderer( TableCellRenderer delegate ) {
|
|
||||||
this.delegate = delegate;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Component getTableCellRendererComponent( JTable table, Object value, boolean isSelected,
|
public void paintComponent( Graphics g, Component c, Container p, int x, int y, int w, int h, boolean shouldValidate ) {
|
||||||
boolean hasFocus, int row, int column )
|
if( !(c instanceof JLabel) ) {
|
||||||
|
super.paintComponent( g, c, p, x, y, w, h, shouldValidate );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JLabel l = (JLabel) c;
|
||||||
|
Color oldBackground = null;
|
||||||
|
Color oldForeground = null;
|
||||||
|
boolean oldOpaque = false;
|
||||||
|
Icon oldIcon = null;
|
||||||
|
int oldHorizontalTextPosition = -1;
|
||||||
|
|
||||||
|
// hover and pressed background/foreground
|
||||||
|
TableColumn draggedColumn = header.getDraggedColumn();
|
||||||
|
Color background = null;
|
||||||
|
Color foreground = null;
|
||||||
|
if( draggedColumn != null &&
|
||||||
|
header.getTable().convertColumnIndexToView( draggedColumn.getModelIndex() )
|
||||||
|
== getColumn( x - header.getDraggedDistance(), w ) )
|
||||||
{
|
{
|
||||||
Component c = delegate.getTableCellRendererComponent( table, value, isSelected, hasFocus, row, column );
|
background = pressedBackground;
|
||||||
if( !(c instanceof JLabel) )
|
foreground = pressedForeground;
|
||||||
return c;
|
} else if( getRolloverColumn() >= 0 && getRolloverColumn() == getColumn( x, w ) ) {
|
||||||
|
background = hoverBackground;
|
||||||
l = (JLabel) c;
|
foreground = hoverForeground;
|
||||||
|
}
|
||||||
|
if( background != null ) {
|
||||||
|
oldBackground = l.getBackground();
|
||||||
|
oldOpaque = l.isOpaque();
|
||||||
|
l.setBackground( FlatUIUtils.deriveColor( background, header.getBackground() ) );
|
||||||
|
l.setOpaque( true );
|
||||||
|
}
|
||||||
|
if( foreground != null ) {
|
||||||
|
oldForeground = l.getForeground();
|
||||||
|
l.setForeground( FlatUIUtils.deriveColor( foreground, header.getForeground() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort icon position
|
||||||
|
Icon icon = l.getIcon();
|
||||||
|
boolean isSortIcon = (icon != null && (icon == ascendingSortIcon || icon == descendingSortIcon));
|
||||||
|
if( isSortIcon ) {
|
||||||
if( sortIconPosition == SwingConstants.LEFT ) {
|
if( sortIconPosition == SwingConstants.LEFT ) {
|
||||||
if( oldHorizontalTextPosition < 0 )
|
// left
|
||||||
oldHorizontalTextPosition = l.getHorizontalTextPosition();
|
oldHorizontalTextPosition = l.getHorizontalTextPosition();
|
||||||
l.setHorizontalTextPosition( SwingConstants.RIGHT );
|
l.setHorizontalTextPosition( SwingConstants.RIGHT );
|
||||||
} else {
|
} else if( sortIconPosition == SwingConstants.TOP || sortIconPosition == SwingConstants.BOTTOM ) {
|
||||||
// top or bottom
|
// top or bottom
|
||||||
sortIcon = l.getIcon();
|
oldIcon = icon;
|
||||||
origBorder = l.getBorder();
|
|
||||||
l.setIcon( null );
|
l.setIcon( null );
|
||||||
l.setBorder( this );
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return l;
|
// paint renderer component
|
||||||
|
super.paintComponent( g, c, p, x, y, w, h, shouldValidate );
|
||||||
|
|
||||||
|
// paint top or bottom sort icon
|
||||||
|
if( isSortIcon && (sortIconPosition == SwingConstants.TOP || sortIconPosition == SwingConstants.BOTTOM) ) {
|
||||||
|
int xi = x + ((w - icon.getIconWidth()) / 2);
|
||||||
|
int yi = (sortIconPosition == SwingConstants.TOP)
|
||||||
|
? y + UIScale.scale( 1 )
|
||||||
|
: y + height - icon.getIconHeight()
|
||||||
|
- 1 // for gap
|
||||||
|
- (int) (1 * UIScale.getUserScaleFactor()); // for bottom border
|
||||||
|
icon.paintIcon( c, g, xi, yi );
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset() {
|
// restore modified renderer component properties
|
||||||
if( l != null && sortIconPosition == SwingConstants.LEFT && oldHorizontalTextPosition >= 0 )
|
if( background != null ) {
|
||||||
|
l.setBackground( oldBackground );
|
||||||
|
l.setOpaque( oldOpaque );
|
||||||
|
}
|
||||||
|
if( foreground != null )
|
||||||
|
l.setForeground( oldForeground );
|
||||||
|
if( oldIcon != null )
|
||||||
|
l.setIcon( oldIcon );
|
||||||
|
if( oldHorizontalTextPosition >= 0 )
|
||||||
l.setHorizontalTextPosition( oldHorizontalTextPosition );
|
l.setHorizontalTextPosition( oldHorizontalTextPosition );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
* Get column index for given coordinates.
|
||||||
if( origBorder != null )
|
*/
|
||||||
origBorder.paintBorder( c, g, x, y, width, height );
|
private int getColumn( int x, int width ) {
|
||||||
|
TableColumnModel columnModel = header.getColumnModel();
|
||||||
|
int columnCount = columnModel.getColumnCount();
|
||||||
|
boolean ltr = header.getComponentOrientation().isLeftToRight();
|
||||||
|
int cx = ltr ? 0 : getWidthInRightToLef();
|
||||||
|
|
||||||
if( sortIcon != null ) {
|
for( int i = 0; i < columnCount; i++ ) {
|
||||||
int xi = x + ((width - sortIcon.getIconWidth()) / 2);
|
int cw = columnModel.getColumn( i ).getWidth();
|
||||||
int yi = (sortIconPosition == SwingConstants.TOP)
|
if( x == cx - (ltr ? 0 : cw) && width == cw )
|
||||||
? y + UIScale.scale( 1 )
|
return i;
|
||||||
: y + height - sortIcon.getIconHeight()
|
|
||||||
- 1 // for gap
|
cx += ltr ? cw : -cw;
|
||||||
- (int) (1 * UIScale.getUserScaleFactor()); // for bottom border
|
|
||||||
sortIcon.paintIcon( c, g, xi, yi );
|
|
||||||
}
|
}
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
// similar to JTableHeader.getWidthInRightToLeft()
|
||||||
public Insets getBorderInsets( Component c ) {
|
private int getWidthInRightToLef() {
|
||||||
return (origBorder != null) ? origBorder.getBorderInsets( c ) : new Insets( 0, 0, 0, 0 );
|
JTable table = header.getTable();
|
||||||
}
|
return (table != null && table.getAutoResizeMode() != JTable.AUTO_RESIZE_OFF)
|
||||||
|
? table.getWidth()
|
||||||
@Override
|
: header.getWidth();
|
||||||
public boolean isBorderOpaque() {
|
|
||||||
return (origBorder != null) ? origBorder.isBorderOpaque() : false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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.Component;
|
||||||
import java.awt.Container;
|
import java.awt.Container;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.EventQueue;
|
import java.awt.EventQueue;
|
||||||
@@ -26,18 +27,25 @@ import java.awt.Insets;
|
|||||||
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.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JScrollPane;
|
import javax.swing.JScrollPane;
|
||||||
|
import javax.swing.JTable;
|
||||||
import javax.swing.JViewport;
|
import javax.swing.JViewport;
|
||||||
import javax.swing.LookAndFeel;
|
import javax.swing.LookAndFeel;
|
||||||
|
import javax.swing.SwingConstants;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.plaf.ComponentUI;
|
import javax.swing.plaf.ComponentUI;
|
||||||
|
import javax.swing.plaf.UIResource;
|
||||||
import javax.swing.plaf.basic.BasicTableUI;
|
import javax.swing.plaf.basic.BasicTableUI;
|
||||||
|
import javax.swing.table.DefaultTableCellRenderer;
|
||||||
import javax.swing.table.JTableHeader;
|
import javax.swing.table.JTableHeader;
|
||||||
|
import javax.swing.table.TableCellRenderer;
|
||||||
import com.formdev.flatlaf.FlatClientProperties;
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
|
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.util.Graphics2DProxy;
|
import com.formdev.flatlaf.util.Graphics2DProxy;
|
||||||
@@ -116,6 +124,7 @@ public class FlatTableUI
|
|||||||
private boolean oldShowHorizontalLines;
|
private boolean oldShowHorizontalLines;
|
||||||
private boolean oldShowVerticalLines;
|
private boolean oldShowVerticalLines;
|
||||||
private Dimension oldIntercellSpacing;
|
private Dimension oldIntercellSpacing;
|
||||||
|
private TableCellRenderer oldBooleanRenderer;
|
||||||
|
|
||||||
private PropertyChangeListener propertyChangeListener;
|
private PropertyChangeListener propertyChangeListener;
|
||||||
private Map<String, Object> oldStyleValues;
|
private Map<String, Object> oldStyleValues;
|
||||||
@@ -151,19 +160,35 @@ public class FlatTableUI
|
|||||||
if( rowHeight > 0 )
|
if( rowHeight > 0 )
|
||||||
LookAndFeel.installProperty( table, "rowHeight", UIScale.scale( rowHeight ) );
|
LookAndFeel.installProperty( table, "rowHeight", UIScale.scale( rowHeight ) );
|
||||||
|
|
||||||
if( !showHorizontalLines ) {
|
FlatTablePropertyWatcher watcher = FlatTablePropertyWatcher.get( table );
|
||||||
|
if( watcher != null )
|
||||||
|
watcher.enabled = false;
|
||||||
|
|
||||||
|
if( !showHorizontalLines && (watcher == null || !watcher.showHorizontalLinesChanged) ) {
|
||||||
oldShowHorizontalLines = table.getShowHorizontalLines();
|
oldShowHorizontalLines = table.getShowHorizontalLines();
|
||||||
table.setShowHorizontalLines( false );
|
table.setShowHorizontalLines( false );
|
||||||
}
|
}
|
||||||
if( !showVerticalLines ) {
|
if( !showVerticalLines && (watcher == null || !watcher.showVerticalLinesChanged) ) {
|
||||||
oldShowVerticalLines = table.getShowVerticalLines();
|
oldShowVerticalLines = table.getShowVerticalLines();
|
||||||
table.setShowVerticalLines( false );
|
table.setShowVerticalLines( false );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( intercellSpacing != null ) {
|
if( intercellSpacing != null && (watcher == null || !watcher.intercellSpacingChanged) ) {
|
||||||
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
|
||||||
|
oldBooleanRenderer = table.getDefaultRenderer( Boolean.class );
|
||||||
|
if( oldBooleanRenderer instanceof UIResource )
|
||||||
|
table.setDefaultRenderer( Boolean.class, new FlatBooleanRenderer() );
|
||||||
|
else
|
||||||
|
oldBooleanRenderer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -177,15 +202,36 @@ 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) )
|
||||||
table.setShowHorizontalLines( true );
|
table.setShowHorizontalLines( true );
|
||||||
if( !showVerticalLines && oldShowVerticalLines && !table.getShowVerticalLines() )
|
if( !showVerticalLines && oldShowVerticalLines && !table.getShowVerticalLines() &&
|
||||||
|
(watcher == null || !watcher.showVerticalLinesChanged) )
|
||||||
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) )
|
||||||
table.setIntercellSpacing( oldIntercellSpacing );
|
table.setIntercellSpacing( oldIntercellSpacing );
|
||||||
|
|
||||||
|
if( watcher != null )
|
||||||
|
watcher.enabled = true;
|
||||||
|
|
||||||
|
// uninstall boolean renderer
|
||||||
|
if( table.getDefaultRenderer( Boolean.class ) instanceof FlatBooleanRenderer ) {
|
||||||
|
if( oldBooleanRenderer instanceof Component ) {
|
||||||
|
// because the old renderer component was not attached to any component hierarchy,
|
||||||
|
// its UI was not yet updated, and it is necessary to do it here
|
||||||
|
SwingUtilities.updateComponentTreeUI( (Component) oldBooleanRenderer );
|
||||||
|
}
|
||||||
|
table.setDefaultRenderer( Boolean.class, oldBooleanRenderer );
|
||||||
|
}
|
||||||
|
oldBooleanRenderer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -277,6 +323,9 @@ public class FlatTableUI
|
|||||||
|
|
||||||
/** @since 2 */
|
/** @since 2 */
|
||||||
protected Object applyStyleProperty( String key, Object value ) {
|
protected Object applyStyleProperty( String key, Object value ) {
|
||||||
|
if( "rowHeight".equals( key ) && value instanceof Integer )
|
||||||
|
value = UIScale.scale( (Integer) value );
|
||||||
|
|
||||||
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, table, key, value );
|
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, table, key, value );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -464,4 +513,70 @@ 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 ------------------------------------------
|
||||||
|
|
||||||
|
private static class FlatBooleanRenderer
|
||||||
|
extends DefaultTableCellRenderer
|
||||||
|
implements UIResource
|
||||||
|
{
|
||||||
|
private boolean selected;
|
||||||
|
|
||||||
|
FlatBooleanRenderer() {
|
||||||
|
setHorizontalAlignment( SwingConstants.CENTER );
|
||||||
|
setIcon( new FlatCheckBoxIcon() {
|
||||||
|
@Override
|
||||||
|
protected boolean isSelected( Component c ) {
|
||||||
|
return selected;
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setValue( Object value ) {
|
||||||
|
selected = (value != null && (Boolean) value);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,6 @@ import com.formdev.flatlaf.util.LoggingFacade;
|
|||||||
* <!-- FlatTextAreaUI -->
|
* <!-- FlatTextAreaUI -->
|
||||||
*
|
*
|
||||||
* @uiDefault Component.minimumWidth int
|
* @uiDefault Component.minimumWidth int
|
||||||
* @uiDefault Component.isIntelliJTheme boolean
|
|
||||||
* @uiDefault TextArea.disabledBackground Color used if not enabled
|
* @uiDefault TextArea.disabledBackground Color used if not enabled
|
||||||
* @uiDefault TextArea.inactiveBackground Color used if not editable
|
* @uiDefault TextArea.inactiveBackground Color used if not editable
|
||||||
* @uiDefault TextArea.focusedBackground Color optional
|
* @uiDefault TextArea.focusedBackground Color optional
|
||||||
@@ -66,7 +65,6 @@ public class FlatTextAreaUI
|
|||||||
implements StyleableUI
|
implements StyleableUI
|
||||||
{
|
{
|
||||||
@Styleable protected int minimumWidth;
|
@Styleable protected int minimumWidth;
|
||||||
protected boolean isIntelliJTheme;
|
|
||||||
private Color background;
|
private Color background;
|
||||||
@Styleable protected Color disabledBackground;
|
@Styleable protected Color disabledBackground;
|
||||||
@Styleable protected Color inactiveBackground;
|
@Styleable protected Color inactiveBackground;
|
||||||
@@ -103,7 +101,6 @@ public class FlatTextAreaUI
|
|||||||
super.installDefaults();
|
super.installDefaults();
|
||||||
|
|
||||||
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
||||||
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
|
||||||
background = UIManager.getColor( "TextArea.background" );
|
background = UIManager.getColor( "TextArea.background" );
|
||||||
disabledBackground = UIManager.getColor( "TextArea.disabledBackground" );
|
disabledBackground = UIManager.getColor( "TextArea.disabledBackground" );
|
||||||
inactiveBackground = UIManager.getColor( "TextArea.inactiveBackground" );
|
inactiveBackground = UIManager.getColor( "TextArea.inactiveBackground" );
|
||||||
@@ -227,6 +224,6 @@ public class FlatTextAreaUI
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void paintBackground( Graphics g ) {
|
protected void paintBackground( Graphics g ) {
|
||||||
FlatEditorPaneUI.paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground );
|
FlatEditorPaneUI.paintBackground( g, getComponent(), focusedBackground );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ import javax.swing.JTextField;
|
|||||||
import javax.swing.JToggleButton;
|
import javax.swing.JToggleButton;
|
||||||
import javax.swing.JToolBar;
|
import javax.swing.JToolBar;
|
||||||
import javax.swing.LookAndFeel;
|
import javax.swing.LookAndFeel;
|
||||||
|
import javax.swing.SwingConstants;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.event.DocumentEvent;
|
import javax.swing.event.DocumentEvent;
|
||||||
import javax.swing.event.DocumentListener;
|
import javax.swing.event.DocumentListener;
|
||||||
@@ -81,7 +82,6 @@ import com.formdev.flatlaf.util.LoggingFacade;
|
|||||||
* <!-- FlatTextFieldUI -->
|
* <!-- FlatTextFieldUI -->
|
||||||
*
|
*
|
||||||
* @uiDefault Component.minimumWidth int
|
* @uiDefault Component.minimumWidth int
|
||||||
* @uiDefault Component.isIntelliJTheme boolean
|
|
||||||
* @uiDefault TextField.placeholderForeground Color
|
* @uiDefault TextField.placeholderForeground Color
|
||||||
* @uiDefault TextField.focusedBackground Color optional
|
* @uiDefault TextField.focusedBackground Color optional
|
||||||
* @uiDefault TextField.iconTextGap int optional, default is 4
|
* @uiDefault TextField.iconTextGap int optional, default is 4
|
||||||
@@ -95,7 +95,6 @@ public class FlatTextFieldUI
|
|||||||
implements StyleableUI
|
implements StyleableUI
|
||||||
{
|
{
|
||||||
@Styleable protected int minimumWidth;
|
@Styleable protected int minimumWidth;
|
||||||
protected boolean isIntelliJTheme;
|
|
||||||
private Color background;
|
private Color background;
|
||||||
@Styleable protected Color disabledBackground;
|
@Styleable protected Color disabledBackground;
|
||||||
@Styleable protected Color inactiveBackground;
|
@Styleable protected Color inactiveBackground;
|
||||||
@@ -165,7 +164,6 @@ public class FlatTextFieldUI
|
|||||||
|
|
||||||
String prefix = getPropertyPrefix();
|
String prefix = getPropertyPrefix();
|
||||||
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
||||||
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
|
||||||
background = UIManager.getColor( prefix + ".background" );
|
background = UIManager.getColor( prefix + ".background" );
|
||||||
disabledBackground = UIManager.getColor( prefix + ".disabledBackground" );
|
disabledBackground = UIManager.getColor( prefix + ".disabledBackground" );
|
||||||
inactiveBackground = UIManager.getColor( prefix + ".inactiveBackground" );
|
inactiveBackground = UIManager.getColor( prefix + ".inactiveBackground" );
|
||||||
@@ -402,7 +400,7 @@ public class FlatTextFieldUI
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void paintSafely( Graphics g ) {
|
protected void paintSafely( Graphics g ) {
|
||||||
paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground );
|
paintBackground( g, getComponent(), focusedBackground );
|
||||||
paintPlaceholder( g );
|
paintPlaceholder( g );
|
||||||
|
|
||||||
if( hasLeadingIcon() || hasTrailingIcon() )
|
if( hasLeadingIcon() || hasTrailingIcon() )
|
||||||
@@ -422,7 +420,7 @@ debug*/
|
|||||||
// background is painted elsewhere
|
// background is painted elsewhere
|
||||||
}
|
}
|
||||||
|
|
||||||
static void paintBackground( Graphics g, JTextComponent c, boolean isIntelliJTheme, Color focusedBackground ) {
|
static void paintBackground( Graphics g, JTextComponent c, Color focusedBackground ) {
|
||||||
// do not paint background if:
|
// do not paint background if:
|
||||||
// - not opaque and
|
// - not opaque and
|
||||||
// - border is not a flat border and
|
// - border is not a flat border and
|
||||||
@@ -443,14 +441,14 @@ debug*/
|
|||||||
try {
|
try {
|
||||||
FlatUIUtils.setRenderingHints( g2 );
|
FlatUIUtils.setRenderingHints( g2 );
|
||||||
|
|
||||||
g2.setColor( getBackground( c, isIntelliJTheme, focusedBackground ) );
|
g2.setColor( getBackground( c, focusedBackground ) );
|
||||||
FlatUIUtils.paintComponentBackground( g2, 0, 0, c.getWidth(), c.getHeight(), focusWidth, arc );
|
FlatUIUtils.paintComponentBackground( g2, 0, 0, c.getWidth(), c.getHeight(), focusWidth, arc );
|
||||||
} finally {
|
} finally {
|
||||||
g2.dispose();
|
g2.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Color getBackground( JTextComponent c, boolean isIntelliJTheme, Color focusedBackground ) {
|
static Color getBackground( JTextComponent c, Color focusedBackground ) {
|
||||||
Color background = c.getBackground();
|
Color background = c.getBackground();
|
||||||
|
|
||||||
// always use explicitly set color
|
// always use explicitly set color
|
||||||
@@ -461,10 +459,6 @@ debug*/
|
|||||||
if( focusedBackground != null && FlatUIUtils.isPermanentFocusOwner( c ) )
|
if( focusedBackground != null && FlatUIUtils.isPermanentFocusOwner( c ) )
|
||||||
return focusedBackground;
|
return focusedBackground;
|
||||||
|
|
||||||
// for compatibility with IntelliJ themes
|
|
||||||
if( isIntelliJTheme && (!c.isEnabled() || !c.isEditable()) )
|
|
||||||
return FlatUIUtils.getParentBackground( c );
|
|
||||||
|
|
||||||
return background;
|
return background;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -487,10 +481,22 @@ debug*/
|
|||||||
// compute placeholder location
|
// compute placeholder location
|
||||||
Rectangle r = getVisibleEditorRect();
|
Rectangle r = getVisibleEditorRect();
|
||||||
FontMetrics fm = c.getFontMetrics( c.getFont() );
|
FontMetrics fm = c.getFontMetrics( c.getFont() );
|
||||||
String clippedPlaceholder = JavaCompatibility.getClippedString( c, fm, placeholder, r.width );
|
int x = r.x;
|
||||||
int x = r.x + (isLeftToRight() ? 0 : r.width - fm.stringWidth( clippedPlaceholder ));
|
|
||||||
int y = r.y + fm.getAscent() + ((r.height - fm.getHeight()) / 2);
|
int y = r.y + fm.getAscent() + ((r.height - fm.getHeight()) / 2);
|
||||||
|
|
||||||
|
// apply horizontal alignment to x location
|
||||||
|
String clippedPlaceholder = JavaCompatibility.getClippedString( c, fm, placeholder, r.width );
|
||||||
|
int stringWidth = fm.stringWidth( clippedPlaceholder );
|
||||||
|
int halign = (c instanceof JTextField) ? ((JTextField)c).getHorizontalAlignment() : SwingConstants.LEADING;
|
||||||
|
if( halign == SwingConstants.LEADING )
|
||||||
|
halign = isLeftToRight() ? SwingConstants.LEFT : SwingConstants.RIGHT;
|
||||||
|
else if( halign == SwingConstants.TRAILING )
|
||||||
|
halign = isLeftToRight() ? SwingConstants.RIGHT : SwingConstants.LEFT;
|
||||||
|
if( halign == SwingConstants.RIGHT )
|
||||||
|
x += r.width - stringWidth;
|
||||||
|
else if( halign == SwingConstants.CENTER )
|
||||||
|
x = Math.max( 0, x + (r.width / 2) - (stringWidth / 2) );
|
||||||
|
|
||||||
// paint placeholder
|
// paint placeholder
|
||||||
g.setColor( placeholderForeground );
|
g.setColor( placeholderForeground );
|
||||||
FlatUIUtils.drawString( c, g, clippedPlaceholder, x, y );
|
FlatUIUtils.drawString( c, g, clippedPlaceholder, x, y );
|
||||||
|
|||||||
@@ -56,7 +56,6 @@ import com.formdev.flatlaf.util.LoggingFacade;
|
|||||||
* <!-- FlatTextPaneUI -->
|
* <!-- FlatTextPaneUI -->
|
||||||
*
|
*
|
||||||
* @uiDefault Component.minimumWidth int
|
* @uiDefault Component.minimumWidth int
|
||||||
* @uiDefault Component.isIntelliJTheme boolean
|
|
||||||
* @uiDefault TextPane.focusedBackground Color optional
|
* @uiDefault TextPane.focusedBackground Color optional
|
||||||
*
|
*
|
||||||
* @author Karl Tauber
|
* @author Karl Tauber
|
||||||
@@ -66,7 +65,6 @@ public class FlatTextPaneUI
|
|||||||
implements StyleableUI
|
implements StyleableUI
|
||||||
{
|
{
|
||||||
@Styleable protected int minimumWidth;
|
@Styleable protected int minimumWidth;
|
||||||
protected boolean isIntelliJTheme;
|
|
||||||
private Color background;
|
private Color background;
|
||||||
@Styleable protected Color disabledBackground;
|
@Styleable protected Color disabledBackground;
|
||||||
@Styleable protected Color inactiveBackground;
|
@Styleable protected Color inactiveBackground;
|
||||||
@@ -98,7 +96,6 @@ public class FlatTextPaneUI
|
|||||||
|
|
||||||
String prefix = getPropertyPrefix();
|
String prefix = getPropertyPrefix();
|
||||||
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
||||||
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
|
||||||
background = UIManager.getColor( prefix + ".background" );
|
background = UIManager.getColor( prefix + ".background" );
|
||||||
disabledBackground = UIManager.getColor( prefix + ".disabledBackground" );
|
disabledBackground = UIManager.getColor( prefix + ".disabledBackground" );
|
||||||
inactiveBackground = UIManager.getColor( prefix + ".inactiveBackground" );
|
inactiveBackground = UIManager.getColor( prefix + ".inactiveBackground" );
|
||||||
@@ -220,6 +217,6 @@ public class FlatTextPaneUI
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void paintBackground( Graphics g ) {
|
protected void paintBackground( Graphics g ) {
|
||||||
FlatEditorPaneUI.paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground );
|
FlatEditorPaneUI.paintBackground( g, getComponent(), focusedBackground );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ import javax.swing.Icon;
|
|||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JDialog;
|
import javax.swing.JDialog;
|
||||||
|
import javax.swing.JInternalFrame;
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import javax.swing.JMenuBar;
|
import javax.swing.JMenuBar;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
@@ -96,6 +97,7 @@ import com.formdev.flatlaf.util.UIScale;
|
|||||||
* @uiDefault TitlePane.centerTitleIfMenuBarEmbedded boolean
|
* @uiDefault TitlePane.centerTitleIfMenuBarEmbedded boolean
|
||||||
* @uiDefault TitlePane.showIconBesideTitle boolean
|
* @uiDefault TitlePane.showIconBesideTitle boolean
|
||||||
* @uiDefault TitlePane.menuBarTitleGap int
|
* @uiDefault TitlePane.menuBarTitleGap int
|
||||||
|
* @uiDefault TitlePane.menuBarTitleMinimumGap int
|
||||||
* @uiDefault TitlePane.menuBarResizeHeight int
|
* @uiDefault TitlePane.menuBarResizeHeight int
|
||||||
* @uiDefault TitlePane.closeIcon Icon
|
* @uiDefault TitlePane.closeIcon Icon
|
||||||
* @uiDefault TitlePane.iconifyIcon Icon
|
* @uiDefault TitlePane.iconifyIcon Icon
|
||||||
@@ -107,29 +109,32 @@ import com.formdev.flatlaf.util.UIScale;
|
|||||||
public class FlatTitlePane
|
public class FlatTitlePane
|
||||||
extends JComponent
|
extends JComponent
|
||||||
{
|
{
|
||||||
/** @since 2.5 */ protected final Font titleFont = UIManager.getFont( "TitlePane.font" );
|
private static final String KEY_DEBUG_SHOW_RECTANGLES = "FlatLaf.debug.titlebar.showRectangles";
|
||||||
protected final Color activeBackground = UIManager.getColor( "TitlePane.background" );
|
|
||||||
protected final Color inactiveBackground = UIManager.getColor( "TitlePane.inactiveBackground" );
|
|
||||||
protected final Color activeForeground = UIManager.getColor( "TitlePane.foreground" );
|
|
||||||
protected final Color inactiveForeground = UIManager.getColor( "TitlePane.inactiveForeground" );
|
|
||||||
protected final Color embeddedForeground = UIManager.getColor( "TitlePane.embeddedForeground" );
|
|
||||||
protected final Color borderColor = UIManager.getColor( "TitlePane.borderColor" );
|
|
||||||
|
|
||||||
/** @since 2 */ protected final boolean showIcon = FlatUIUtils.getUIBoolean( "TitlePane.showIcon", true );
|
/** @since 2.5 */ protected final Font titleFont;
|
||||||
/** @since 2.5 */ protected final boolean showIconInDialogs = FlatUIUtils.getUIBoolean( "TitlePane.showIconInDialogs", true );
|
protected final Color activeBackground;
|
||||||
/** @since 2 */ protected final int noIconLeftGap = FlatUIUtils.getUIInt( "TitlePane.noIconLeftGap", 8 );
|
protected final Color inactiveBackground;
|
||||||
protected final Dimension iconSize = UIManager.getDimension( "TitlePane.iconSize" );
|
protected final Color activeForeground;
|
||||||
/** @since 2.4 */ protected final int titleMinimumWidth = FlatUIUtils.getUIInt( "TitlePane.titleMinimumWidth", 60 );
|
protected final Color inactiveForeground;
|
||||||
/** @since 2.4 */ protected final int buttonMinimumWidth = FlatUIUtils.getUIInt( "TitlePane.buttonMinimumWidth", 30 );
|
protected final Color embeddedForeground;
|
||||||
protected final int buttonMaximizedHeight = UIManager.getInt( "TitlePane.buttonMaximizedHeight" );
|
protected final Color borderColor;
|
||||||
protected final boolean centerTitle = UIManager.getBoolean( "TitlePane.centerTitle" );
|
|
||||||
protected final boolean centerTitleIfMenuBarEmbedded = FlatUIUtils.getUIBoolean( "TitlePane.centerTitleIfMenuBarEmbedded", true );
|
/** @since 2 */ protected final boolean showIcon;
|
||||||
/** @since 2.4 */ protected final boolean showIconBesideTitle = UIManager.getBoolean( "TitlePane.showIconBesideTitle" );
|
/** @since 2.5 */ protected final boolean showIconInDialogs;
|
||||||
protected final int menuBarTitleGap = FlatUIUtils.getUIInt( "TitlePane.menuBarTitleGap", 40 );
|
/** @since 2 */ protected final int noIconLeftGap;
|
||||||
/** @since 2.4 */ protected final int menuBarTitleMinimumGap = FlatUIUtils.getUIInt( "TitlePane.menuBarTitleMinimumGap", 12 );
|
protected final Dimension iconSize;
|
||||||
/** @since 2.4 */ protected final int menuBarResizeHeight = FlatUIUtils.getUIInt( "TitlePane.menuBarResizeHeight", 4 );
|
/** @since 2.4 */ protected final int titleMinimumWidth;
|
||||||
|
/** @since 2.4 */ protected final int buttonMinimumWidth;
|
||||||
|
protected final int buttonMaximizedHeight;
|
||||||
|
protected final boolean centerTitle;
|
||||||
|
protected final boolean centerTitleIfMenuBarEmbedded;
|
||||||
|
/** @since 2.4 */ protected final boolean showIconBesideTitle;
|
||||||
|
protected final int menuBarTitleGap;
|
||||||
|
/** @since 2.4 */ protected final int menuBarTitleMinimumGap;
|
||||||
|
/** @since 2.4 */ protected final int menuBarResizeHeight;
|
||||||
|
|
||||||
protected final JRootPane rootPane;
|
protected final JRootPane rootPane;
|
||||||
|
protected final String windowStyle;
|
||||||
|
|
||||||
protected JPanel leftPanel;
|
protected JPanel leftPanel;
|
||||||
protected JLabel iconLabel;
|
protected JLabel iconLabel;
|
||||||
@@ -148,6 +153,34 @@ public class FlatTitlePane
|
|||||||
public FlatTitlePane( JRootPane rootPane ) {
|
public FlatTitlePane( JRootPane rootPane ) {
|
||||||
this.rootPane = rootPane;
|
this.rootPane = rootPane;
|
||||||
|
|
||||||
|
Window w = SwingUtilities.getWindowAncestor( 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 );
|
||||||
|
activeBackground = FlatUIUtils.getSubUIColor( "TitlePane.background", windowStyle );
|
||||||
|
inactiveBackground = FlatUIUtils.getSubUIColor( "TitlePane.inactiveBackground", windowStyle );
|
||||||
|
activeForeground = FlatUIUtils.getSubUIColor( "TitlePane.foreground", windowStyle );
|
||||||
|
inactiveForeground = FlatUIUtils.getSubUIColor( "TitlePane.inactiveForeground", windowStyle );
|
||||||
|
embeddedForeground = FlatUIUtils.getSubUIColor( "TitlePane.embeddedForeground", windowStyle );
|
||||||
|
// not using windowStyle here because TitlePane.borderColor is also used in FlatRootPaneUI
|
||||||
|
borderColor = UIManager.getColor( "TitlePane.borderColor" );
|
||||||
|
|
||||||
|
showIcon = FlatUIUtils.getSubUIBoolean( "TitlePane.showIcon", windowStyle, true );
|
||||||
|
showIconInDialogs = FlatUIUtils.getSubUIBoolean( "TitlePane.showIconInDialogs", windowStyle, true );
|
||||||
|
noIconLeftGap = FlatUIUtils.getSubUIInt( "TitlePane.noIconLeftGap", windowStyle, 8 );
|
||||||
|
iconSize = FlatUIUtils.getSubUIDimension( "TitlePane.iconSize", windowStyle );
|
||||||
|
titleMinimumWidth = FlatUIUtils.getSubUIInt( "TitlePane.titleMinimumWidth", windowStyle, 60 );
|
||||||
|
buttonMinimumWidth = FlatUIUtils.getSubUIInt( "TitlePane.buttonMinimumWidth", windowStyle, 30 );
|
||||||
|
buttonMaximizedHeight = FlatUIUtils.getSubUIInt( "TitlePane.buttonMaximizedHeight", windowStyle, 0 );
|
||||||
|
centerTitle = FlatUIUtils.getSubUIBoolean( "TitlePane.centerTitle", windowStyle, false );
|
||||||
|
centerTitleIfMenuBarEmbedded = FlatUIUtils.getSubUIBoolean( "TitlePane.centerTitleIfMenuBarEmbedded", windowStyle, true );
|
||||||
|
showIconBesideTitle = FlatUIUtils.getSubUIBoolean( "TitlePane.showIconBesideTitle", windowStyle, false );
|
||||||
|
menuBarTitleGap = FlatUIUtils.getSubUIInt( "TitlePane.menuBarTitleGap", windowStyle, 40 );
|
||||||
|
menuBarTitleMinimumGap = FlatUIUtils.getSubUIInt( "TitlePane.menuBarTitleMinimumGap", windowStyle, 12 );
|
||||||
|
menuBarResizeHeight = FlatUIUtils.getSubUIInt( "TitlePane.menuBarResizeHeight", windowStyle, 4 );
|
||||||
|
|
||||||
|
|
||||||
handler = createHandler();
|
handler = createHandler();
|
||||||
setBorder( createTitlePaneBorder() );
|
setBorder( createTitlePaneBorder() );
|
||||||
|
|
||||||
@@ -180,8 +213,8 @@ public class FlatTitlePane
|
|||||||
setUI( new FlatTitleLabelUI() );
|
setUI( new FlatTitleLabelUI() );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
iconLabel.setBorder( new FlatEmptyBorder( UIManager.getInsets( "TitlePane.iconMargins" ) ) );
|
iconLabel.setBorder( new FlatEmptyBorder( FlatUIUtils.getSubUIInsets( "TitlePane.iconMargins", windowStyle ) ) );
|
||||||
titleLabel.setBorder( new FlatEmptyBorder( UIManager.getInsets( "TitlePane.titleMargins" ) ) );
|
titleLabel.setBorder( new FlatEmptyBorder( FlatUIUtils.getSubUIInsets( "TitlePane.titleMargins", windowStyle ) ) );
|
||||||
|
|
||||||
leftPanel.setLayout( new BoxLayout( leftPanel, BoxLayout.LINE_AXIS ) );
|
leftPanel.setLayout( new BoxLayout( leftPanel, BoxLayout.LINE_AXIS ) );
|
||||||
leftPanel.setOpaque( false );
|
leftPanel.setOpaque( false );
|
||||||
@@ -308,7 +341,7 @@ public class FlatTitlePane
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected JButton createButton( String iconKey, String accessibleName, ActionListener action ) {
|
protected JButton createButton( String iconKey, String accessibleName, ActionListener action ) {
|
||||||
JButton button = new JButton( UIManager.getIcon( iconKey ) ) {
|
JButton button = new JButton( FlatUIUtils.getSubUIIcon( iconKey, windowStyle ) ) {
|
||||||
@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
|
||||||
@@ -354,16 +387,12 @@ public class FlatTitlePane
|
|||||||
if( window == null || rootPane.getWindowDecorationStyle() != JRootPane.FRAME )
|
if( window == null || rootPane.getWindowDecorationStyle() != JRootPane.FRAME )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
updateVisibility();
|
||||||
|
|
||||||
if( window instanceof Frame ) {
|
if( window instanceof Frame ) {
|
||||||
Frame frame = (Frame) window;
|
Frame frame = (Frame) window;
|
||||||
boolean resizable = frame.isResizable();
|
|
||||||
boolean maximized = ((frame.getExtendedState() & Frame.MAXIMIZED_BOTH) != 0);
|
|
||||||
|
|
||||||
iconifyButton.setVisible( true );
|
if( isWindowMaximized() &&
|
||||||
maximizeButton.setVisible( resizable && !maximized );
|
|
||||||
restoreButton.setVisible( resizable && maximized );
|
|
||||||
|
|
||||||
if( maximized &&
|
|
||||||
!(SystemInfo.isLinux && FlatNativeLinuxLibrary.isWMUtilsSupported( window )) &&
|
!(SystemInfo.isLinux && FlatNativeLinuxLibrary.isWMUtilsSupported( window )) &&
|
||||||
rootPane.getClientProperty( "_flatlaf.maximizedBoundsUpToDate" ) == null )
|
rootPane.getClientProperty( "_flatlaf.maximizedBoundsUpToDate" ) == null )
|
||||||
{
|
{
|
||||||
@@ -383,14 +412,27 @@ public class FlatTitlePane
|
|||||||
frame.setExtendedState( oldExtendedState );
|
frame.setExtendedState( oldExtendedState );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @since 3 */
|
||||||
|
protected void updateVisibility() {
|
||||||
|
titleLabel.setVisible( clientPropertyBoolean( rootPane, TITLE_BAR_SHOW_TITLE, true ) );
|
||||||
|
closeButton.setVisible( clientPropertyBoolean( rootPane, TITLE_BAR_SHOW_CLOSE, true ) );
|
||||||
|
|
||||||
|
if( window instanceof Frame ) {
|
||||||
|
Frame frame = (Frame) window;
|
||||||
|
boolean maximizable = frame.isResizable() && clientPropertyBoolean( rootPane, TITLE_BAR_SHOW_MAXIMIZE, true );
|
||||||
|
boolean maximized = isWindowMaximized();
|
||||||
|
|
||||||
|
iconifyButton.setVisible( clientPropertyBoolean( rootPane, TITLE_BAR_SHOW_ICONIFFY, true ) );
|
||||||
|
maximizeButton.setVisible( maximizable && !maximized );
|
||||||
|
restoreButton.setVisible( maximizable && maximized );
|
||||||
} else {
|
} else {
|
||||||
// hide buttons because they are only supported in frames
|
// hide buttons because they are only supported in frames
|
||||||
iconifyButton.setVisible( false );
|
iconifyButton.setVisible( false );
|
||||||
maximizeButton.setVisible( false );
|
maximizeButton.setVisible( false );
|
||||||
restoreButton.setVisible( false );
|
restoreButton.setVisible( false );
|
||||||
|
|
||||||
revalidate();
|
|
||||||
repaint();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -566,11 +608,17 @@ public class FlatTitlePane
|
|||||||
doLayout();
|
doLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*debug
|
void menuBarInvalidate() {
|
||||||
|
menuBarPlaceholder.invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paint( Graphics g ) {
|
public void paint( Graphics g ) {
|
||||||
super.paint( g );
|
super.paint( g );
|
||||||
|
|
||||||
|
if( !UIManager.getBoolean( KEY_DEBUG_SHOW_RECTANGLES ) )
|
||||||
|
return;
|
||||||
|
|
||||||
if( debugTitleBarHeight > 0 ) {
|
if( debugTitleBarHeight > 0 ) {
|
||||||
g.setColor( Color.green );
|
g.setColor( Color.green );
|
||||||
g.drawLine( 0, debugTitleBarHeight, getWidth(), debugTitleBarHeight );
|
g.drawLine( 0, debugTitleBarHeight, getWidth(), debugTitleBarHeight );
|
||||||
@@ -594,7 +642,6 @@ public class FlatTitlePane
|
|||||||
Point offset = SwingUtilities.convertPoint( this, 0, 0, window );
|
Point offset = SwingUtilities.convertPoint( this, 0, 0, window );
|
||||||
g.drawRect( r.x - offset.x, r.y - offset.y, r.width - 1, r.height - 1 );
|
g.drawRect( r.x - offset.x, r.y - offset.y, r.width - 1, r.height - 1 );
|
||||||
}
|
}
|
||||||
debug*/
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void paintComponent( Graphics g ) {
|
protected void paintComponent( Graphics g ) {
|
||||||
@@ -630,7 +677,10 @@ debug*/
|
|||||||
|
|
||||||
/** @since 2.4 */
|
/** @since 2.4 */
|
||||||
protected boolean isWindowMaximized() {
|
protected boolean isWindowMaximized() {
|
||||||
return window instanceof Frame && (((Frame)window).getExtendedState() & Frame.MAXIMIZED_BOTH) != 0;
|
// Windows and macOS use always MAXIMIZED_BOTH.
|
||||||
|
// Only Linux uses MAXIMIZED_VERT and MAXIMIZED_HORIZ (when dragging window to left or right edge).
|
||||||
|
// (searched jdk source code)
|
||||||
|
return window instanceof Frame && (((Frame)window).getExtendedState() & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_BOTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -648,8 +698,30 @@ debug*/
|
|||||||
rootPane.putClientProperty( "_flatlaf.maximizedBoundsUpToDate", true );
|
rootPane.putClientProperty( "_flatlaf.maximizedBoundsUpToDate", true );
|
||||||
|
|
||||||
// maximize window
|
// maximize window
|
||||||
if( !FlatNativeWindowBorder.showWindow( frame, FlatNativeWindowBorder.Provider.SW_MAXIMIZE ) )
|
if( !FlatNativeWindowBorder.showWindow( frame, FlatNativeWindowBorder.Provider.SW_MAXIMIZE ) ) {
|
||||||
frame.setExtendedState( frame.getExtendedState() | Frame.MAXIMIZED_BOTH );
|
int oldState = frame.getExtendedState();
|
||||||
|
int newState = oldState | Frame.MAXIMIZED_BOTH;
|
||||||
|
|
||||||
|
if( SystemInfo.isLinux ) {
|
||||||
|
// Linux supports vertical and horizontal maximization:
|
||||||
|
// - dragging a window to left or right edge of screen vertically maximizes
|
||||||
|
// the window to the left or right half of the screen
|
||||||
|
// - don't know whether user can do horizontal maximization
|
||||||
|
// (Windows and macOS use only MAXIMIZED_BOTH)
|
||||||
|
//
|
||||||
|
// If a window is maximized vertically or horizontally (but not both),
|
||||||
|
// then Frame.setExtendedState() behaves not as expected on Linux.
|
||||||
|
// E.g. if window state is MAXIMIZED_VERT, calling setExtendedState(MAXIMIZED_BOTH)
|
||||||
|
// changes state to MAXIMIZED_HORIZ. But calling setExtendedState(MAXIMIZED_HORIZ)
|
||||||
|
// changes state from MAXIMIZED_VERT to MAXIMIZED_BOTH.
|
||||||
|
// Seems to be a bug in sun.awt.X11.XNETProtocol.requestState(),
|
||||||
|
// which does some strange state XOR-ing...
|
||||||
|
if( (oldState & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_VERT )
|
||||||
|
newState = (oldState & ~Frame.MAXIMIZED_BOTH) | Frame.MAXIMIZED_HORIZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame.setExtendedState( newState );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void updateMaximizedBounds() {
|
protected void updateMaximizedBounds() {
|
||||||
@@ -753,8 +825,7 @@ debug*/
|
|||||||
if( !(window instanceof Frame) || !((Frame)window).isResizable() )
|
if( !(window instanceof Frame) || !((Frame)window).isResizable() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Frame frame = (Frame) window;
|
if( isWindowMaximized() )
|
||||||
if( (frame.getExtendedState() & Frame.MAXIMIZED_BOTH) != 0 )
|
|
||||||
restore();
|
restore();
|
||||||
else
|
else
|
||||||
maximize();
|
maximize();
|
||||||
@@ -768,10 +839,6 @@ debug*/
|
|||||||
window.dispatchEvent( new WindowEvent( window, WindowEvent.WINDOW_CLOSING ) );
|
window.dispatchEvent( new WindowEvent( window, WindowEvent.WINDOW_CLOSING ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasJBRCustomDecoration() {
|
|
||||||
return window != null && JBRCustomDecorations.hasCustomDecoration( window );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether windows uses native window border and has custom decorations enabled.
|
* Returns whether windows uses native window border and has custom decorations enabled.
|
||||||
*/
|
*/
|
||||||
@@ -829,9 +896,6 @@ debug*/
|
|||||||
iconBounds.width += iconInsets.right;
|
iconBounds.width += iconInsets.right;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( hasJBRCustomDecoration() )
|
|
||||||
hitTestSpots.add( iconBounds );
|
|
||||||
else
|
|
||||||
appIconBounds = iconBounds;
|
appIconBounds = iconBounds;
|
||||||
} else if( showIconBesideTitle && titleLabel.getIcon() != null && titleLabel.getUI() instanceof FlatTitleLabelUI ) {
|
} else if( showIconBesideTitle && titleLabel.getIcon() != null && titleLabel.getUI() instanceof FlatTitleLabelUI ) {
|
||||||
FlatTitleLabelUI ui = (FlatTitleLabelUI) titleLabel.getUI();
|
FlatTitleLabelUI ui = (FlatTitleLabelUI) titleLabel.getUI();
|
||||||
@@ -860,9 +924,6 @@ debug*/
|
|||||||
iconR.width += 2;
|
iconR.width += 2;
|
||||||
iconR.height += 2;
|
iconR.height += 2;
|
||||||
|
|
||||||
if( hasJBRCustomDecoration() )
|
|
||||||
hitTestSpots.add( iconR );
|
|
||||||
else
|
|
||||||
appIconBounds = iconR;
|
appIconBounds = iconR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -916,6 +977,13 @@ debug*/
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// allow internal frames in layered pane to be moved/resized when placed over title bar
|
||||||
|
for( Component c : rootPane.getLayeredPane().getComponents() ) {
|
||||||
|
r = (c instanceof JInternalFrame) ? getNativeHitTestSpot( (JInternalFrame) c ) : null;
|
||||||
|
if( r != null )
|
||||||
|
hitTestSpots.add( r );
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle minimizeButtonBounds = boundsInWindow( iconifyButton );
|
Rectangle minimizeButtonBounds = boundsInWindow( iconifyButton );
|
||||||
Rectangle maximizeButtonBounds = boundsInWindow( maximizeButton.isVisible() ? maximizeButton : restoreButton );
|
Rectangle maximizeButtonBounds = boundsInWindow( maximizeButton.isVisible() ? maximizeButton : restoreButton );
|
||||||
Rectangle closeButtonBounds = boundsInWindow( closeButton );
|
Rectangle closeButtonBounds = boundsInWindow( closeButton );
|
||||||
@@ -923,15 +991,14 @@ debug*/
|
|||||||
FlatNativeWindowBorder.setTitleBarHeightAndHitTestSpots( window, titleBarHeight,
|
FlatNativeWindowBorder.setTitleBarHeightAndHitTestSpots( window, titleBarHeight,
|
||||||
hitTestSpots, appIconBounds, minimizeButtonBounds, maximizeButtonBounds, closeButtonBounds );
|
hitTestSpots, appIconBounds, minimizeButtonBounds, maximizeButtonBounds, closeButtonBounds );
|
||||||
|
|
||||||
/*debug
|
|
||||||
debugTitleBarHeight = titleBarHeight;
|
debugTitleBarHeight = titleBarHeight;
|
||||||
debugHitTestSpots = hitTestSpots;
|
debugHitTestSpots = hitTestSpots;
|
||||||
debugAppIconBounds = appIconBounds;
|
debugAppIconBounds = appIconBounds;
|
||||||
debugMinimizeButtonBounds = minimizeButtonBounds;
|
debugMinimizeButtonBounds = minimizeButtonBounds;
|
||||||
debugMaximizeButtonBounds = maximizeButtonBounds;
|
debugMaximizeButtonBounds = maximizeButtonBounds;
|
||||||
debugCloseButtonBounds = closeButtonBounds;
|
debugCloseButtonBounds = closeButtonBounds;
|
||||||
|
if( UIManager.getBoolean( KEY_DEBUG_SHOW_RECTANGLES ) )
|
||||||
repaint();
|
repaint();
|
||||||
debug*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Rectangle boundsInWindow( JComponent c ) {
|
private Rectangle boundsInWindow( JComponent c ) {
|
||||||
@@ -950,14 +1017,12 @@ debug*/
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*debug
|
|
||||||
private int debugTitleBarHeight;
|
private int debugTitleBarHeight;
|
||||||
private List<Rectangle> debugHitTestSpots;
|
private List<Rectangle> debugHitTestSpots;
|
||||||
private Rectangle debugAppIconBounds;
|
private Rectangle debugAppIconBounds;
|
||||||
private Rectangle debugMinimizeButtonBounds;
|
private Rectangle debugMinimizeButtonBounds;
|
||||||
private Rectangle debugMaximizeButtonBounds;
|
private Rectangle debugMaximizeButtonBounds;
|
||||||
private Rectangle debugCloseButtonBounds;
|
private Rectangle debugCloseButtonBounds;
|
||||||
debug*/
|
|
||||||
|
|
||||||
//---- class FlatTitlePaneBorder ------------------------------------------
|
//---- class FlatTitlePaneBorder ------------------------------------------
|
||||||
|
|
||||||
@@ -1178,6 +1243,13 @@ debug*/
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void windowStateChanged( WindowEvent e ) {
|
public void windowStateChanged( WindowEvent e ) {
|
||||||
|
/*debug
|
||||||
|
System.out.println( "state " + e.getOldState() + " -> " + e.getNewState() + " "
|
||||||
|
+ ((e.getNewState() & Frame.MAXIMIZED_HORIZ) != 0 ? " HORIZ" : "")
|
||||||
|
+ ((e.getNewState() & Frame.MAXIMIZED_VERT) != 0 ? " VERT" : "")
|
||||||
|
);
|
||||||
|
debug*/
|
||||||
|
|
||||||
frameStateChanged();
|
frameStateChanged();
|
||||||
updateNativeTitleBarHeightAndHitTestSpots();
|
updateNativeTitleBarHeightAndHitTestSpots();
|
||||||
}
|
}
|
||||||
@@ -1185,15 +1257,15 @@ debug*/
|
|||||||
//---- interface MouseListener ----
|
//---- interface MouseListener ----
|
||||||
|
|
||||||
private Point dragOffset;
|
private Point dragOffset;
|
||||||
private boolean nativeMove;
|
private boolean linuxNativeMove;
|
||||||
private long lastSingleClickWhen;
|
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
|
// on Linux, when using native library, the mouse clicked event
|
||||||
// is usually not sent and maximize/restore is done in mouse pressed 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 thru for some reason
|
// this check is here for the case that a mouse clicked event comes through for some reason
|
||||||
if( SystemInfo.isLinux && FlatNativeLinuxLibrary.isWMUtilsSupported( window ) ) {
|
if( linuxNativeMove && SystemInfo.isLinux && FlatNativeLinuxLibrary.isWMUtilsSupported( window ) ) {
|
||||||
// see comment in mousePressed()
|
// see comment in mousePressed()
|
||||||
if( lastSingleClickWhen != 0 && (e.getWhen() - lastSingleClickWhen) <= getMultiClickInterval() ) {
|
if( lastSingleClickWhen != 0 && (e.getWhen() - lastSingleClickWhen) <= getMultiClickInterval() ) {
|
||||||
lastSingleClickWhen = 0;
|
lastSingleClickWhen = 0;
|
||||||
@@ -1231,7 +1303,7 @@ debug*/
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
dragOffset = SwingUtilities.convertPoint( FlatTitlePane.this, e.getPoint(), window );
|
dragOffset = SwingUtilities.convertPoint( FlatTitlePane.this, e.getPoint(), window );
|
||||||
nativeMove = false;
|
linuxNativeMove = false;
|
||||||
|
|
||||||
// on Linux, move or maximize/restore window
|
// on Linux, move or maximize/restore window
|
||||||
if( SystemInfo.isLinux && FlatNativeLinuxLibrary.isWMUtilsSupported( window ) ) {
|
if( SystemInfo.isLinux && FlatNativeLinuxLibrary.isWMUtilsSupported( window ) ) {
|
||||||
@@ -1251,7 +1323,7 @@ debug*/
|
|||||||
case 1:
|
case 1:
|
||||||
// move window via _NET_WM_MOVERESIZE message
|
// move window via _NET_WM_MOVERESIZE message
|
||||||
e.consume();
|
e.consume();
|
||||||
nativeMove = FlatNativeLinuxLibrary.moveOrResizeWindow( window, e, FlatNativeLinuxLibrary.MOVE );
|
linuxNativeMove = FlatNativeLinuxLibrary.moveOrResizeWindow( window, e, FlatNativeLinuxLibrary.MOVE );
|
||||||
lastSingleClickWhen = e.getWhen();
|
lastSingleClickWhen = e.getWhen();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -1281,7 +1353,7 @@ debug*/
|
|||||||
if( window == null || dragOffset == null )
|
if( window == null || dragOffset == null )
|
||||||
return; // should newer occur
|
return; // should newer occur
|
||||||
|
|
||||||
if( nativeMove )
|
if( linuxNativeMove )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if( !SwingUtilities.isLeftMouseButton( e ) )
|
if( !SwingUtilities.isLeftMouseButton( e ) )
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user