mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2026-02-11 06:27:13 -06:00
Compare commits
320 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
073a25f381 | ||
|
|
40592ab876 | ||
|
|
bbfe624b51 | ||
|
|
a2af9e4c65 | ||
|
|
0123a8895f | ||
|
|
53854a4d13 | ||
|
|
4fdd44858f | ||
|
|
3c58879ce5 | ||
|
|
a7c6a881b3 | ||
|
|
ef065d31a0 | ||
|
|
d059d6b448 | ||
|
|
2d0a6f1bec | ||
|
|
a3cc5a1938 | ||
|
|
435068515a | ||
|
|
956001dbd7 | ||
|
|
460f0d9dee | ||
|
|
5155ec93c9 | ||
|
|
8bb8883e22 | ||
|
|
ffb7a6dfbb | ||
|
|
176de6f245 | ||
|
|
11f9740dbf | ||
|
|
42a91ba26c | ||
|
|
234003e2b1 | ||
|
|
534384438b | ||
|
|
ab51f35d5d | ||
|
|
511a4044d7 | ||
|
|
821efaff40 | ||
|
|
91bc994532 | ||
|
|
1323b46ac7 | ||
|
|
3a8b30ca8e | ||
|
|
923d58519f | ||
|
|
eabb1f84f6 | ||
|
|
cfbe44b946 | ||
|
|
81c35eab46 | ||
|
|
a1c7c29113 | ||
|
|
1293e2a074 | ||
|
|
b5deca7f22 | ||
|
|
604ba236c0 | ||
|
|
14df490b2a | ||
|
|
dd2f73e8ad | ||
|
|
56bfdc8ef9 | ||
|
|
91dbf1e144 | ||
|
|
e07ae90d09 | ||
|
|
5ef0c9aae1 | ||
|
|
aefed7c481 | ||
|
|
0d66d9f9a3 | ||
|
|
d0ffc4f979 | ||
|
|
f149d2b7cd | ||
|
|
21a12b8dd4 | ||
|
|
6c8b8e8949 | ||
|
|
539737d1c5 | ||
|
|
33ff5828da | ||
|
|
1fb0783808 | ||
|
|
b5e7aa8553 | ||
|
|
1d3ce76b27 | ||
|
|
0101171159 | ||
|
|
8b8ed0b9ff | ||
|
|
413b60e630 | ||
|
|
10b2a94c70 | ||
|
|
e337e5bbd8 | ||
|
|
6e55e0a183 | ||
|
|
8ee1d26935 | ||
|
|
80bdf69eaf | ||
|
|
18e838bffd | ||
|
|
d95b1b0ec4 | ||
|
|
d16a3c117b | ||
|
|
d04ec982ab | ||
|
|
cce99c803e | ||
|
|
19ed538573 | ||
|
|
a1f78345e6 | ||
|
|
f8c7ccf064 | ||
|
|
4d5242cd61 | ||
|
|
7ad176f98d | ||
|
|
57df7d28b5 | ||
|
|
f784ff2c84 | ||
|
|
a0f6affb68 | ||
|
|
0c679167fa | ||
|
|
4fe707e519 | ||
|
|
d83704b7cb | ||
|
|
2177ee45cc | ||
|
|
ccd4f99aea | ||
|
|
cd6b55c846 | ||
|
|
d923c8df81 | ||
|
|
59879f493e | ||
|
|
06cab0d4b5 | ||
|
|
a16db38a6f | ||
|
|
de93e19a80 | ||
|
|
47bb7d0de7 | ||
|
|
896e808db4 | ||
|
|
6fe6d1ffa0 | ||
|
|
4c6f7a66e2 | ||
|
|
4b5646ec88 | ||
|
|
66a5f350da | ||
|
|
f9e34cbab7 | ||
|
|
634f7b5ba3 | ||
|
|
7dbc6ff8a3 | ||
|
|
afccdc4749 | ||
|
|
c98ec041d4 | ||
|
|
9e0c62092e | ||
|
|
9aea006f50 | ||
|
|
c16c3759cf | ||
|
|
cbc1fe27ef | ||
|
|
f57dbf94c8 | ||
|
|
c0f15d2e6f | ||
|
|
cb525fafb6 | ||
|
|
5cae3a8141 | ||
|
|
8594e78287 | ||
|
|
5b8f922273 | ||
|
|
847b41752c | ||
|
|
7c08489cb3 | ||
|
|
605c77ecbc | ||
|
|
fd0c2a5cd1 | ||
|
|
a80790fc8e | ||
|
|
206d449d0d | ||
|
|
2323dc099f | ||
|
|
642583479f | ||
|
|
082e5842d0 | ||
|
|
c67ba02839 | ||
|
|
4c6cb7618f | ||
|
|
c15100f129 | ||
|
|
6dfb3cc84e | ||
|
|
18d8c7d086 | ||
|
|
ab3adf4ae3 | ||
|
|
7e6619af00 | ||
|
|
a7e2a10403 | ||
|
|
3a784375d0 | ||
|
|
b8c9433259 | ||
|
|
815d9d6012 | ||
|
|
feb91aa056 | ||
|
|
cd264586ca | ||
|
|
c6d561f2df | ||
|
|
6167c5f855 | ||
|
|
1a31cb96b8 | ||
|
|
9b8df64c35 | ||
|
|
a47565afec | ||
|
|
c2ee815cbe | ||
|
|
e45a2df6b6 | ||
|
|
a19979c233 | ||
|
|
e2a297fa40 | ||
|
|
df13b338b2 | ||
|
|
da9d7a0dee | ||
|
|
0374c65159 | ||
|
|
71b1e07ba6 | ||
|
|
c3781dc4b5 | ||
|
|
dc92d0913c | ||
|
|
a5adf29001 | ||
|
|
8861bfe4fa | ||
|
|
c8d280f418 | ||
|
|
09c98359af | ||
|
|
6f8a7471c2 | ||
|
|
4c141fe47c | ||
|
|
b37ff348fb | ||
|
|
09798d33b0 | ||
|
|
717ab95fbe | ||
|
|
3f616e3608 | ||
|
|
c590157561 | ||
|
|
2b50431081 | ||
|
|
6d38e44f91 | ||
|
|
9bc656a5c5 | ||
|
|
700bb9b567 | ||
|
|
8ccda81d9a | ||
|
|
3818790ced | ||
|
|
c34ce389a4 | ||
|
|
15718cdb46 | ||
|
|
10746a454a | ||
|
|
f0fd02e81f | ||
|
|
bfaac6d164 | ||
|
|
a909f1012a | ||
|
|
201581a07c | ||
|
|
8cef5ecf7e | ||
|
|
2c1075f471 | ||
|
|
1f5e08fdc6 | ||
|
|
c0408045ef | ||
|
|
c58f5a6ca7 | ||
|
|
ae445c9343 | ||
|
|
ad7ff2ba0b | ||
|
|
4b7ef6e853 | ||
|
|
87f2acc2d9 | ||
|
|
ec2fef02ed | ||
|
|
ebe0d74dbe | ||
|
|
029dc51f8b | ||
|
|
3fc85cd7b2 | ||
|
|
a46bdef079 | ||
|
|
3de489f693 | ||
|
|
eddb9eee46 | ||
|
|
5b0c96cd6d | ||
|
|
15ac77107f | ||
|
|
a7c906091c | ||
|
|
de870c546c | ||
|
|
2f3427e6ad | ||
|
|
203426bd55 | ||
|
|
16242080e0 | ||
|
|
57655d8859 | ||
|
|
62ffd57108 | ||
|
|
8db05f47b5 | ||
|
|
c684761eef | ||
|
|
0a8ece8c9c | ||
|
|
01058bde1b | ||
|
|
9c2c03cddb | ||
|
|
f0778a83a0 | ||
|
|
b86ae1f122 | ||
|
|
dfd6831b02 | ||
|
|
a4ddc13c1a | ||
|
|
fd63a1b7c2 | ||
|
|
d83c3689d0 | ||
|
|
d52bf9d318 | ||
|
|
80f56dec15 | ||
|
|
358c226b96 | ||
|
|
9de9983416 | ||
|
|
c9da4fcaf1 | ||
|
|
932ca6f9d4 | ||
|
|
4487c9985c | ||
|
|
a53ce99977 | ||
|
|
5444719895 | ||
|
|
b66139281d | ||
|
|
8925c27eb9 | ||
|
|
99be346387 | ||
|
|
81d46ba8ee | ||
|
|
ef4c467b20 | ||
|
|
44d196fb8c | ||
|
|
867c4fff58 | ||
|
|
5643546117 | ||
|
|
549832ba96 | ||
|
|
a8744b2bb4 | ||
|
|
e292d3444c | ||
|
|
ee6a1da709 | ||
|
|
8c15bc746b | ||
|
|
aebb083180 | ||
|
|
5438549b6d | ||
|
|
0077708235 | ||
|
|
2fd99ec9f3 | ||
|
|
0d266c4990 | ||
|
|
0982675b5f | ||
|
|
3bac5d3c80 | ||
|
|
58338f4848 | ||
|
|
9c261d3a3f | ||
|
|
5441ac6640 | ||
|
|
015b04a29a | ||
|
|
12ec0abf54 | ||
|
|
c8d461cdee | ||
|
|
faecffeadd | ||
|
|
b3c76c21b4 | ||
|
|
1697735162 | ||
|
|
ecb94bac6d | ||
|
|
7ebeacf16e | ||
|
|
d0079ab66b | ||
|
|
147e400bd6 | ||
|
|
c44905ea5e | ||
|
|
98b9df06fe | ||
|
|
02473080a5 | ||
|
|
c6beb9dc0a | ||
|
|
dcce14b122 | ||
|
|
a2ac24ac74 | ||
|
|
600f812f45 | ||
|
|
e945f46f25 | ||
|
|
c78c653b0a | ||
|
|
e0b3663239 | ||
|
|
3cc9c98040 | ||
|
|
ec8213b891 | ||
|
|
ae61383742 | ||
|
|
cc90a2ad75 | ||
|
|
28634cda56 | ||
|
|
3b71fcd690 | ||
|
|
5923ac65df | ||
|
|
faffc9393d | ||
|
|
6da220f36c | ||
|
|
21d78671d6 | ||
|
|
af5a0ec0b7 | ||
|
|
ff214455a3 | ||
|
|
3e941e3e42 | ||
|
|
2f876d553f | ||
|
|
b208017117 | ||
|
|
a1dab94a61 | ||
|
|
e55b2afd60 | ||
|
|
535c3ddf6c | ||
|
|
3008d99fcd | ||
|
|
fd37339e2f | ||
|
|
e29eca203c | ||
|
|
f1fd6dcdd2 | ||
|
|
2975ed2eae | ||
|
|
5a27d03faa | ||
|
|
8bcf9dbcaf | ||
|
|
56ebd26361 | ||
|
|
b0426b81a7 | ||
|
|
368fbcdeb0 | ||
|
|
30747b7776 | ||
|
|
4eb4ddf5d8 | ||
|
|
b1d24680b2 | ||
|
|
ef38f3805e | ||
|
|
2f5ca20ca4 | ||
|
|
f29d3d84d4 | ||
|
|
02132c5fcd | ||
|
|
7057e3c6ad | ||
|
|
a8f4c8e843 | ||
|
|
a2b6e66a13 | ||
|
|
e3b3cc2896 | ||
|
|
a5b2c50f24 | ||
|
|
5ebdf64d30 | ||
|
|
2640ab2e8b | ||
|
|
e29436da04 | ||
|
|
7b35325f9a | ||
|
|
f2ab7fafcf | ||
|
|
e3cda9905a | ||
|
|
a8423f7741 | ||
|
|
5a9e620c17 | ||
|
|
9f41ec3986 | ||
|
|
5a2c0672d4 | ||
|
|
38d853b5b2 | ||
|
|
5166d4bb0f | ||
|
|
2ffd5437a9 | ||
|
|
797830ff96 | ||
|
|
008ecabd21 | ||
|
|
2cdcde8a5e | ||
|
|
e7ec3988e2 | ||
|
|
093dd9f3ef | ||
|
|
b491202ec7 | ||
|
|
8603ca827e | ||
|
|
6b148a59da | ||
|
|
de6d45fee6 | ||
|
|
65e2071937 |
142
.github/workflows/ci.yml
vendored
Normal file
142
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,142 @@
|
||||
# https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
|
||||
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
tags:
|
||||
- '[0-9]*'
|
||||
pull_request:
|
||||
branches:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
# test against
|
||||
# - Java 1.8 (minimum requirement)
|
||||
# - Java 9 (first version with JPMS)
|
||||
# - Java LTS versions (11, 17, ...)
|
||||
# - lastest Java version(s)
|
||||
java:
|
||||
- 1.8
|
||||
- 9
|
||||
- 11 # LTS
|
||||
- 14
|
||||
- 15
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Setup Java ${{ matrix.java }}
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: ${{ matrix.java }}
|
||||
|
||||
- name: Cache Gradle wrapper
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.gradle/wrapper
|
||||
key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }}
|
||||
|
||||
- name: Cache Gradle cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.gradle/caches
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}
|
||||
restore-keys: ${{ runner.os }}-gradle
|
||||
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew build
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
if: matrix.java == '11'
|
||||
with:
|
||||
name: FlatLaf-build-artifacts
|
||||
path: |
|
||||
flatlaf-core/build/libs
|
||||
flatlaf-demo/build/libs
|
||||
flatlaf-extras/build/libs
|
||||
flatlaf-intellij-themes/build/libs
|
||||
flatlaf-jide-oss/build/libs
|
||||
flatlaf-swingx/build/libs
|
||||
!**/*-javadoc.jar
|
||||
!**/*-sources.jar
|
||||
|
||||
|
||||
snapshot:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
if: |
|
||||
github.event_name == 'push' &&
|
||||
github.ref == 'refs/heads/master' &&
|
||||
github.repository == 'JFormDesigner/FlatLaf'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Setup Java 11
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
|
||||
- name: Cache Gradle wrapper
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.gradle/wrapper
|
||||
key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }}
|
||||
|
||||
- name: Cache Gradle cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.gradle/caches
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}
|
||||
restore-keys: ${{ runner.os }}-gradle
|
||||
|
||||
- name: Publish snapshot to oss.jfrog.org
|
||||
run: ./gradlew artifactoryPublish
|
||||
env:
|
||||
BINTRAY_USER: ${{ secrets.BINTRAY_USER }}
|
||||
BINTRAY_KEY: ${{ secrets.BINTRAY_KEY }}
|
||||
|
||||
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
if: |
|
||||
github.event_name == 'push' &&
|
||||
startsWith( github.ref, 'refs/tags/' ) &&
|
||||
github.repository == 'JFormDesigner/FlatLaf'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Setup Java 11
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
|
||||
- name: Cache Gradle wrapper
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.gradle/wrapper
|
||||
key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }}
|
||||
|
||||
- name: Cache Gradle cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.gradle/caches
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}
|
||||
restore-keys: ${{ runner.os }}-gradle
|
||||
|
||||
- name: Release a new stable version to bintray
|
||||
run: ./gradlew bintrayUpload -Drelease=true
|
||||
env:
|
||||
BINTRAY_USER: ${{ secrets.BINTRAY_USER }}
|
||||
BINTRAY_KEY: ${{ secrets.BINTRAY_KEY }}
|
||||
39
.travis.yml
39
.travis.yml
@@ -1,39 +0,0 @@
|
||||
language: java
|
||||
sudo: false
|
||||
|
||||
jdk:
|
||||
- openjdk8
|
||||
- openjdk9
|
||||
- openjdk11
|
||||
- openjdk14
|
||||
|
||||
before_cache:
|
||||
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
|
||||
- rm -fr $HOME/.gradle/caches/*/plugin-resolution/
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.gradle/caches/
|
||||
- $HOME/.gradle/wrapper/
|
||||
|
||||
before_install:
|
||||
- ./gradlew --version
|
||||
- java -version
|
||||
|
||||
stages:
|
||||
- name: test
|
||||
- name: snapshot
|
||||
if: branch = master AND type IN (push) AND tag IS blank
|
||||
- name: release
|
||||
if: type IN (push) AND tag IS present
|
||||
|
||||
jobs:
|
||||
include:
|
||||
# publish snapshot to oss.jfrog.org
|
||||
- stage: snapshot
|
||||
jdk: openjdk11
|
||||
script: ./gradlew artifactoryPublish
|
||||
|
||||
# release a new stable version to bintray
|
||||
- stage: release
|
||||
jdk: openjdk11
|
||||
script: ./gradlew bintrayUpload -Drelease=true
|
||||
279
CHANGELOG.md
279
CHANGELOG.md
@@ -1,6 +1,282 @@
|
||||
FlatLaf Change Log
|
||||
==================
|
||||
|
||||
## 0.46
|
||||
|
||||
#### New features and improvements
|
||||
|
||||
- Slider and JIDE RangeSlider: Clicking on track now immediately moves the thumb
|
||||
to mouse location and starts dragging the thumb. Use `UIManager.put(
|
||||
"Slider.scrollOnTrackClick", true )` to enable old behavior that scrolls the
|
||||
thumb when clicking on track.
|
||||
- Slider: Snap to ticks is now done while dragging the thumb. Use
|
||||
`UIManager.put( "Slider.snapToTicksOnReleased", true )` to enable old behavior
|
||||
that snaps to ticks on mouse released.
|
||||
- Extras: Added standard component extension classes that provides easy access
|
||||
to FlatLaf specific client properties (see package
|
||||
`com.formdev.flatlaf.extras.components`).
|
||||
- Extras: Renamed tri-state check box class from
|
||||
`com.formdev.flatlaf.extras.TriStateCheckBox` to
|
||||
`com.formdev.flatlaf.extras.components.FlatTriStateCheckBox`. Also
|
||||
changed/improved API and added javadoc.
|
||||
- Extras: Renamed SVG utility class from `com.formdev.flatlaf.extras.SVGUtils`
|
||||
to `com.formdev.flatlaf.extras.FlatSVGUtils`.
|
||||
- IntelliJ Themes: Added flag whether a theme is dark to
|
||||
`FlatAllIJThemes.INFOS`. (issue #221)
|
||||
- JIDE Common Layer: Support `TristateCheckBox`.
|
||||
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- Slider: Fixed painting of colored track if `JSlider.inverted` is `true`.
|
||||
- Table and TableHeader: Fixed missing right vertical grid line if using table
|
||||
as row header in scroll pane. (issues #152 and #46)
|
||||
- TableHeader: Fixed position of column separators in right-to-left component
|
||||
orientation.
|
||||
- ToolTip: Fixed drop shadow for wide tooltips on Windows and Java 9+. (issue
|
||||
#224)
|
||||
- SwingX: Fixed striping background highlighting color (e.g. alternating table
|
||||
rows) in dark themes.
|
||||
- Fixed: If text antialiasing is disabled (in OS system settings or via
|
||||
`-Dawt.useSystemAAFontSettings=off`), then some components still did use
|
||||
antialiasing to render text (not-editable ComboBox, ProgressBar, Slider,
|
||||
TabbedPane and multiline ToolTip). (issue #227)
|
||||
|
||||
|
||||
## 0.45
|
||||
|
||||
#### New features and improvements
|
||||
|
||||
- Slider: New design, added hover and pressed feedback and improved customizing.
|
||||
(PR #214)
|
||||
- JIDE Common Layer: Support `RangeSlider`. (PR #209)
|
||||
- IntelliJ Themes:
|
||||
- Added "Gradianto Nature Green" theme.
|
||||
- Updated "Arc Dark", "Cyan", "Dark purple", "Gradianto", "Gray", "Gruvbox"
|
||||
and "One Dark" themes.
|
||||
- TabbedPane: Support hiding tab area if it contains only one tab. (set client
|
||||
property `JTabbedPane.hideTabAreaWithOneTab` to `true`)
|
||||
- MenuBar: Support different underline menu selection style UI defaults for
|
||||
`MenuBar` and `MenuItem`. (PR #217; issue #216)
|
||||
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- Table: Do not paint last vertical grid line if auto-resize mode is not off.
|
||||
(issue #46)
|
||||
- Table: Fixed unstable grid line thickness when scaled on HiDPI screens. (issue
|
||||
#152)
|
||||
- TabbedPane: No longer add (internal) tab close button component as child to
|
||||
`JTabbedPane`. (issue #219)
|
||||
- Custom window decorations: Title bar was not hidden if window is in
|
||||
full-screen mode. (issue #212)
|
||||
|
||||
|
||||
## 0.44
|
||||
|
||||
#### New features and improvements
|
||||
|
||||
- TabbedPane: In scroll tab layout, added "Show Hidden Tabs" button to trailing
|
||||
side of tab area. If pressed, it shows a popup menu that contains (partly)
|
||||
hidden tabs and selecting one activates that tab. (PR #190; issue #40)
|
||||
- TabbedPane: Support forward/backward scroll arrow buttons on both sides of tab
|
||||
area. Backward button on left side, forward button on right side. Not
|
||||
applicable scroll buttons are hidden. (PR #211; issue #40)
|
||||
- TabbedPane: Support specifying default tab layout policy for all tabbed panes
|
||||
in the application via UI value `TabbedPane.tabLayoutPolicy`. E.g. invoke
|
||||
`UIManager.put( "TabbedPane.tabLayoutPolicy", "scroll" );` to use scroll
|
||||
layout.
|
||||
- TabbedPane: Support tab scrolling with mouse wheel (in scroll tab layout). (PR
|
||||
#187; issue #40)
|
||||
- TabbedPane: Repeat scrolling as long as scroll arrow buttons are pressed. (PR
|
||||
#187; issue #40)
|
||||
- TabbedPane: Support adding custom components to left and right sides of tab
|
||||
area. (set client property `JTabbedPane.leadingComponent` or
|
||||
`JTabbedPane.trailingComponent` to a `java.awt.Component`) (PR #192; issue
|
||||
#40)
|
||||
- TabbedPane: Support closable tabs. (PR #193; issues #31 and #40)
|
||||
- TabbedPane: Support minimum or maximum tab widths. (set client property
|
||||
`JTabbedPane.minimumTabWidth` or `JTabbedPane.maximumTabWidth` to an integer)
|
||||
(PR #199)
|
||||
- TabbedPane: Support alignment of tab area. (set client property
|
||||
`JTabbedPane.tabAreaAlignment` to `"leading"`, `"trailing"`, `"center"` or
|
||||
`"fill"`) (PR #199)
|
||||
- TabbedPane: Support horizontal alignment of tab title and icon. (set client
|
||||
property `JTabbedPane.tabAlignment` to `SwingConstants.LEADING`,
|
||||
`SwingConstants.TRAILING` or `SwingConstants.CENTER`)
|
||||
- TabbedPane: Support equal and compact tab width modes. (set client property
|
||||
`JTabbedPane.tabWidthMode` to `"preferred"`, `"equal"` or `"compact"`) (PR
|
||||
#199)
|
||||
- TabbedPane: Support left, right, top and bottom tab icon placement. (set
|
||||
client property `JTabbedPane.tabIconPlacement` to `SwingConstants.LEADING`,
|
||||
`SwingConstants.TRAILING`, `SwingConstants.TOP` or `SwingConstants.BOTTOM`)
|
||||
(PR #199)
|
||||
- Support painting separator line between window title and content (use UI value
|
||||
`TitlePane.borderColor`). (issue #184)
|
||||
- Extras: `FlatSVGIcon` now allows specifying icon width and height in
|
||||
constructors. (issue #196)
|
||||
- SplitPane: Hide not applicable expand/collapse buttons. Added tooltips to
|
||||
expand/collapse buttons. (issue #198)
|
||||
- SplitPane: Added grip to divider. Can be disabled with `UIManager.put(
|
||||
"SplitPaneDivider.style", "plain" )`. (issue #179)
|
||||
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- Custom window decorations: Not visible menu bar is now ignored in layout.
|
||||
- Popups using `JToolTip` components did not respect their location. (issue
|
||||
#188; regression in 0.42 in fix for #164)
|
||||
- IntelliJ Themes: Added suffix "(Material)" to names of all Material UI Lite
|
||||
themes to avoid duplicate theme names. (issue #201)
|
||||
- Extras: `FlatSVGIcon` icons were not painted in disabled labels and disabled
|
||||
tabs. (issue #205)
|
||||
|
||||
|
||||
## 0.43
|
||||
|
||||
#### New features and improvements
|
||||
|
||||
- TabbedPane: Made tabs separator color lighter in dark themes so that it is
|
||||
easier to recognize the tabbed pane.
|
||||
- TabbedPane: Added top and bottom tab insets to avoid that large tab icons are
|
||||
painted over active tab underline.
|
||||
- TabbedPane: Support hiding separator between tabs and content area (set client
|
||||
property `JTabbedPane.showContentSeparator` to `false`).
|
||||
- CheckBoxMenuItem and RadioButtonMenuItem: Improved checkmark background colors
|
||||
of selected menu items that have also an icon. This makes it is easier to
|
||||
recognize selected menu items.
|
||||
- Windows: Made scaling compatible with Windows OS scaling, which distinguish
|
||||
between "screen scaling" and "text scaling". (issue #175)
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- ComboBox: If using own `JTextField` as editor, default text field border is
|
||||
now removed to avoid duplicate border.
|
||||
- ComboBox: Limit popup width to screen width for very long items. (issue #182)
|
||||
- FileChooser: Fixed localizing special Windows folders (e.g. "Documents") and
|
||||
enabled hiding known file extensions (if enabled in Windows Explorer). (issue
|
||||
#178)
|
||||
- Spinner: Fixed `NullPointerException` in case that arrow buttons were removed
|
||||
to create button-less spinner. (issue #181)
|
||||
|
||||
|
||||
## 0.42
|
||||
|
||||
#### New features and improvements
|
||||
|
||||
- Demo: Improved "SplitPane & Tabs" and "Data Components" tabs.
|
||||
- Demo: Menu items "File > Open" and "File > Save As" now show file choosers.
|
||||
- InternalFrame: Support draggable border for resizing frame inside of the
|
||||
visible frame border. (issue #121)
|
||||
- `FlatUIDefaultsInspector` added (see [FlatLaf Extras](flatlaf-extras)). A
|
||||
simple UI defaults inspector that shows a window with all UI defaults used in
|
||||
current theme (look and feel).
|
||||
- Made disabled text color slightly lighter in dark themes for better
|
||||
readability. (issue #174)
|
||||
- PasswordField: Support disabling Caps Lock warning icon. (issue #172)
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- TextComponents: Fixed text color of disabled text components in dark themes.
|
||||
- Custom window decorations: Fixed wrong window placement when moving window to
|
||||
another screen with different scaling factor. (issue #166)
|
||||
- Custom window decorations: Fixed wrong window bounds when resizing window to
|
||||
another screen with different scaling factor. (issue #166)
|
||||
- Fixed occasional wrong positioning of heavy weight popups when using multiple
|
||||
screens with different scaling factors. (issue #166)
|
||||
- ToolTip: Avoid that tooltip hides owner component. (issue #164)
|
||||
|
||||
|
||||
## 0.41
|
||||
|
||||
#### New features and improvements
|
||||
|
||||
- Added API to register packages or folders where FlatLaf searches for
|
||||
application specific properties files with custom UI defaults (see
|
||||
`FlatLaf.registerCustomDefaultsSource(...)` methods).
|
||||
- Demo: Show hint popups to guide users to some features of the FlatLaf Demo
|
||||
application.
|
||||
- Extras: `FlatSVGIcon` now allows specifying `ClassLoader` that is used to load
|
||||
SVG file. (issue #163)
|
||||
- Smoother transition from old to new theme, independent of UI complexity, when
|
||||
using animated theme change (see [FlatLaf Extras](flatlaf-extras)).
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- Button: "selected" state was not shown. (issue #161)
|
||||
- TextArea: Update background color property if enabled or editable state
|
||||
changes in the same way as Swing does it for all other text components. (issue
|
||||
#147)
|
||||
- Demo: Fixed restoring last used theme on startup. (regression in 0.39)
|
||||
- Custom window decorations: Fixed iconify, maximize and close icon colors if
|
||||
window is inactive.
|
||||
- Custom window decorations: Fixed title pane background color in IntelliJ
|
||||
themes if window is inactive.
|
||||
- Fixed sub-pixel text rendering in animated theme change (see
|
||||
[FlatLaf Extras](flatlaf-extras)).
|
||||
|
||||
#### Other Changes
|
||||
|
||||
- Extras: Updated dependency
|
||||
[svgSalamander](https://github.com/JFormDesigner/svgSalamander) to version
|
||||
1.1.2.3.
|
||||
|
||||
|
||||
## 0.40
|
||||
|
||||
#### New features
|
||||
|
||||
- Table: Detect whether component is used in cell editor and automatically
|
||||
disable round border style and reduce cell editor outer border width (used for
|
||||
focus indicator) to zero. (issue #148)
|
||||
- ComboBox, Spinner and TextField: Support disabling round border style per
|
||||
component, if globally enabled (set client property `JComponent.roundRect` to
|
||||
`false`). (issue #148)
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- Custom window decorations: Embedded menu bar did not always respond to mouse
|
||||
events after adding menus and when running in JetBrains Runtime. (issue #151)
|
||||
- IntelliJ Themes: Fixed NPE in Solarized themes on scroll bar hover.
|
||||
|
||||
|
||||
## 0.39
|
||||
|
||||
#### New features
|
||||
|
||||
- Animated theme change (see [FlatLaf Extras](flatlaf-extras)). Used in Demo.
|
||||
- Demo: Added combo box above themes list to show only light or dark themes.
|
||||
- IntelliJ Themes:
|
||||
- Added "Arc Dark", "Arc Dark - Orange", "Carbon" and "Cobalt 2" themes.
|
||||
- Replaced "Solarized" themes with much better ones from 4lex4.
|
||||
- Updated "Arc", "One Dark" and "Vuesion" themes.
|
||||
- ScrollPane: Enable/disable smooth scrolling per component if client property
|
||||
"JScrollPane.smoothScrolling" is set to a `Boolean` on `JScrollPane`.
|
||||
- ScrollBar: Increased minimum thumb size on macOS and Linux from 8 to 18
|
||||
pixels. On Windows, it is now 10 pixels. (issue #131)
|
||||
- Button: Support specifying button border width.
|
||||
- ComboBox: Changed maximum row count of popup list to 15 (was 20). Set UI value
|
||||
`ComboBox.maximumRowCount` to any integer to use a different value.
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- Custom window decorations: Fixed maximized window bounds when programmatically
|
||||
maximizing window. E.g. restoring window state at startup. (issue #129)
|
||||
- InternalFrame: Title pane height was too small when iconify, maximize and
|
||||
close buttons are hidden. (issue #132)
|
||||
- ToolTip: Do not show empty tooltip component if tooltip text is an empty
|
||||
string. (issue #134)
|
||||
- ToolTip: Fixed truncated text in HTML formatted tooltip on HiDPI displays.
|
||||
(issue #142)
|
||||
- ComboBox: Fixed width of popup, which was too small if popup is wider than
|
||||
combo box and vertical scroll bar is visible. (issue #137)
|
||||
- MenuItem on macOS: Removed plus characters from accelerator text and made
|
||||
modifier key order conform with macOS standard. (issue #141)
|
||||
- FileChooser: Fixed too small text field when renaming a file/directory in Flat
|
||||
IntelliJ/Darcula themes. (issue #143)
|
||||
- IntelliJ Themes: Fixed text colors in ProgressBar. (issue #138)
|
||||
|
||||
|
||||
## 0.38
|
||||
|
||||
- Hide focus indicator when window is inactive.
|
||||
@@ -9,7 +285,8 @@ FlatLaf Change Log
|
||||
- Custom window decorations: Center title if menu bar is embedded.
|
||||
- Custom window decorations: Cursor of components (e.g. TextField) was not
|
||||
changed. (issue #125)
|
||||
- CheckBox: Fixed colors in light IntelliJ themes. (issue #126)
|
||||
- CheckBox: Fixed colors in light IntelliJ themes. (issue #126; regression in
|
||||
0.37)
|
||||
- InternalFrame: Use default icon in internal frames. (issue #122)
|
||||
|
||||
|
||||
|
||||
81
README.md
81
README.md
@@ -11,9 +11,9 @@ scales on **HiDPI** displays and runs on Java 8 or newer.
|
||||
The look is heavily inspired by **Darcula** and **IntelliJ** themes from
|
||||
IntelliJ IDEA 2019.2+ and uses almost the same colors and icons.
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
IntelliJ Platform Themes
|
||||
@@ -22,9 +22,7 @@ IntelliJ Platform Themes
|
||||
FlatLaf can use 3rd party themes created for IntelliJ Platform (see
|
||||
[IntelliJ Themes Pack](flatlaf-intellij-themes)):
|
||||
|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
Demo
|
||||
@@ -78,35 +76,76 @@ Addons
|
||||
Projects using FlatLaf
|
||||
----------------------
|
||||
|
||||
- [NetBeans](https://netbeans.apache.org/) 11.3
|
||||
- [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
|
||||
- [OWASP Zed Attack Proxy (ZAP)](https://www.zaproxy.org/) (in weekly releases)
|
||||
-  [OWASP ZAP](https://www.zaproxy.org/) 2.10 - the worlds
|
||||
most widely used web app scanner
|
||||
-  [JOSM](https://josm.openstreetmap.de/) - an extensible
|
||||
editor for [OpenStreetMap](https://www.openstreetmap.org/) (requires FlatLaf
|
||||
JOSM plugin)
|
||||
- [jAlbum](https://jalbum.net/) 21 (commercial) - creates photo album websites
|
||||
- [XMLmind XML Editor](https://www.xmlmind.com/xmleditor/) 9.3 (commercial)
|
||||
- [Total Validator](https://www.totalvalidator.com/) 15 (commercial)
|
||||
- [j-lawyer](https://github.com/jlawyerorg/j-lawyer-org)
|
||||
- [Total Validator](https://www.totalvalidator.com/) 15 (commercial) - checks
|
||||
your website
|
||||
- [j-lawyer](https://github.com/jlawyerorg/j-lawyer-org) - Kanzleisoftware
|
||||
- [MegaMek](https://github.com/MegaMek/megamek) v0.47.4 and
|
||||
[MekHQ](https://github.com/MegaMek/mekhq) v0.47.5
|
||||
[MekHQ](https://github.com/MegaMek/mekhq) v0.47.5 - a turn-based sci-fi board
|
||||
game
|
||||
- [GUIslice Builder](https://github.com/ImpulseAdventure/GUIslice-Builder)
|
||||
0.13.b024
|
||||
- [Rest Suite](https://github.com/supanadit/restsuite)
|
||||
- [ControllerBuddy](https://github.com/bwRavencl/ControllerBuddy)
|
||||
- [SpringRemote](https://github.com/HaleyWang/SpringRemote)
|
||||
0.13.b024 - GUI builder for
|
||||
[GUIslice](https://github.com/ImpulseAdventure/GUIslice), a lightweight GUI
|
||||
framework for embedded displays
|
||||
- [Rest Suite](https://github.com/supanadit/restsuite) - Rest API testing
|
||||
- [ControllerBuddy](https://github.com/bwRavencl/ControllerBuddy) - advanced
|
||||
gamepad mapping software
|
||||
- [SpringRemote](https://github.com/HaleyWang/SpringRemote) - remote Linux SSH
|
||||
connections manager
|
||||
-  [jEnTunnel](https://github.com/ggrandes/jentunnel) -
|
||||
manage SSH Tunnels made easy
|
||||
- [mendelson AS2](https://sourceforge.net/projects/mec-as2/),
|
||||
[AS4](https://sourceforge.net/projects/mendelson-as4/) and
|
||||
[OFTP2](https://sourceforge.net/projects/mendelson-oftp2/) (open-source) and
|
||||
[mendelson AS2](https://mendelson-e-c.com/as2/),
|
||||
[AS4](https://mendelson-e-c.com/as4/) and
|
||||
[OFTP2](https://mendelson-e-c.com/oftp2) (commercial)
|
||||
- [MeteoInfo](https://github.com/meteoinfo/MeteoInfo) 2.2
|
||||
- [lsfusion platform](https://github.com/lsfusion/platform)
|
||||
- [MeteoInfo](https://github.com/meteoinfo/MeteoInfo) 2.2 - GIS and scientific
|
||||
computation environment for meteorological community
|
||||
- [lsfusion platform](https://github.com/lsfusion/platform) - information
|
||||
systems development platform
|
||||
-  [JPass](https://github.com/gaborbata/jpass) - password
|
||||
manager with strong encryption
|
||||
- [Jes - Die Java-EÜR](https://www.jes-eur.de)
|
||||
- [Mapton](https://mapton.org/) 2.0
|
||||
([source code](https://github.com/trixon/mapton)) based on NetBeans platform
|
||||
- [Pseudo Assembler IDE](https://github.com/tomasz-herman/PseudoAssemblerIDE)
|
||||
- [Sound Analysis](https://github.com/tomasz-herman/SoundAnalysis)
|
||||
- [RemoteLight](https://github.com/Drumber/RemoteLight) - Multifunctional LED
|
||||
Control Software
|
||||
([source code](https://github.com/trixon/mapton)) based on NetBeans platform -
|
||||
some kind of map application
|
||||
- [Pseudo Assembler IDE](https://github.com/tomasz-herman/PseudoAssemblerIDE) -
|
||||
IDE for Pseudo-Assembler
|
||||
-  [Linotte](https://github.com/cpc6128/LangageLinotte)
|
||||
3.1 - French programming language created to learn programming
|
||||
-  [MEKA](https://github.com/Waikato/meka) 1.9.3 -
|
||||
multi-label classifiers and evaluation procedures using the Weka machine
|
||||
learning framework
|
||||
-  [Shutter Encoder](https://www.shutterencoder.com/) 14.2
|
||||
([source code](https://github.com/paulpacifico/shutter-encoder)) -
|
||||
professional video converter and compression tool (screenshots show **old**
|
||||
look)
|
||||
- [Sound Analysis](https://github.com/tomasz-herman/SoundAnalysis) - analyze
|
||||
sound files in time or frequency domain
|
||||
- [RemoteLight](https://github.com/Drumber/RemoteLight) - multifunctional LED
|
||||
control software
|
||||
- 
|
||||
[ThunderFocus](https://github.com/marcocipriani01/ThunderFocus) -
|
||||
Arduino-based telescope focuser
|
||||
- 
|
||||
[Novel-Grabber](https://github.com/Flameish/Novel-Grabber) - download novels
|
||||
from any webnovel and lightnovel site
|
||||
-  [lectureStudio](https://www.lecturestudio.org/)
|
||||
4.3.1060 - digitize your lectures with ease
|
||||
- 
|
||||
[Android Tool](https://github.com/fast-geek/Android-Tool) - makes popular adb
|
||||
and fastboot commands easier to use
|
||||
- and more...
|
||||
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
val releaseVersion = "0.38"
|
||||
val developmentVersion = "0.39-SNAPSHOT"
|
||||
val releaseVersion = "0.46"
|
||||
val developmentVersion = "0.47-SNAPSHOT"
|
||||
|
||||
version = if( java.lang.Boolean.getBoolean( "release" ) ) releaseVersion else developmentVersion
|
||||
|
||||
@@ -48,7 +48,7 @@ extra["bintray.dryRun"] = false
|
||||
|
||||
// if true, uploaded artifacts are visible to all
|
||||
// if false, only visible to owner when logged into bintray
|
||||
extra["bintray.publish"] = true
|
||||
extra["bintray.publish"] = false
|
||||
|
||||
|
||||
allprojects {
|
||||
|
||||
@@ -19,19 +19,26 @@ package com.formdev.flatlaf;
|
||||
import java.awt.Color;
|
||||
import java.util.Objects;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.SwingConstants;
|
||||
|
||||
/**
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public interface FlatClientProperties
|
||||
{
|
||||
//---- JButton ------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Specifies type of a button.
|
||||
* <p>
|
||||
* <strong>Components</strong> {@link javax.swing.JButton} and {@link javax.swing.JToggleButton}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.String}<br>
|
||||
* <strong>Allowed Values</strong> {@link #BUTTON_TYPE_SQUARE}, {@link #BUTTON_TYPE_ROUND_RECT},
|
||||
* {@link #BUTTON_TYPE_TAB}, {@link #BUTTON_TYPE_HELP} and {@link BUTTON_TYPE_TOOLBAR_BUTTON}
|
||||
* <strong>Allowed Values</strong>
|
||||
* {@link #BUTTON_TYPE_SQUARE},
|
||||
* {@link #BUTTON_TYPE_ROUND_RECT},
|
||||
* {@link #BUTTON_TYPE_TAB},
|
||||
* {@link #BUTTON_TYPE_HELP} or
|
||||
* {@link BUTTON_TYPE_TOOLBAR_BUTTON}
|
||||
*/
|
||||
String BUTTON_TYPE = "JButton.buttonType";
|
||||
|
||||
@@ -99,17 +106,19 @@ public interface FlatClientProperties
|
||||
/**
|
||||
* Specifies whether the button preferred size will be made square (quadratically).
|
||||
* <p>
|
||||
* <strong>Components</strong> {@link javax.swing.JButton} and {@link javax.swing.JToggleButton}
|
||||
* <strong>Components</strong> {@link javax.swing.JButton} and {@link javax.swing.JToggleButton}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
*/
|
||||
String SQUARE_SIZE = "JButton.squareSize";
|
||||
|
||||
//---- JComponent ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Specifies minimum width of a component.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JButton}, {@link javax.swing.JToggleButton},
|
||||
* {@link javax.swing.JComboBox}, {@link javax.swing.JSpinner} and {@link javax.swing.text.JTextComponent}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Integer}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Integer}
|
||||
*/
|
||||
String MINIMUM_WIDTH = "JComponent.minimumWidth";
|
||||
|
||||
@@ -117,10 +126,19 @@ public interface FlatClientProperties
|
||||
* Specifies minimum height of a component.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JButton} and {@link javax.swing.JToggleButton}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Integer}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Integer}
|
||||
*/
|
||||
String MINIMUM_HEIGHT = "JComponent.minimumHeight";
|
||||
|
||||
/**
|
||||
* Paint the component with round edges.
|
||||
* <p>
|
||||
* <strong>Components</strong> {@link javax.swing.JComboBox}, {@link javax.swing.JSpinner},
|
||||
* {@link javax.swing.JTextField}, {@link javax.swing.JFormattedTextField} and {@link javax.swing.JPasswordField}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
*/
|
||||
String COMPONENT_ROUND_RECT = "JComponent.roundRect";
|
||||
|
||||
/**
|
||||
* Specifies the outline color of the component border.
|
||||
* <p>
|
||||
@@ -129,9 +147,12 @@ public interface FlatClientProperties
|
||||
* {@link javax.swing.JScrollPane}, {@link javax.swing.JSpinner},
|
||||
* {@link javax.swing.JTextField} and {@link javax.swing.JToggleButton}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.String} or {@link java.awt.Color} or {@link java.awt.Color}[2]<br>
|
||||
* <strong>Allowed Values</strong> {@link #OUTLINE_ERROR}, {@link #OUTLINE_WARNING},
|
||||
* any color (type {@link java.awt.Color}) or an array of two colors (type {@link java.awt.Color}[2])
|
||||
* where the first color is for focused state and the second for unfocused state
|
||||
* <strong>Allowed Values</strong>
|
||||
* {@link #OUTLINE_ERROR},
|
||||
* {@link #OUTLINE_WARNING},
|
||||
* any color (type {@link java.awt.Color}) or
|
||||
* an array of two colors (type {@link java.awt.Color}[2]) where the first color
|
||||
* is for focused state and the second for unfocused state
|
||||
*/
|
||||
String OUTLINE = "JComponent.outline";
|
||||
|
||||
@@ -149,14 +170,7 @@ public interface FlatClientProperties
|
||||
*/
|
||||
String OUTLINE_WARNING = "warning";
|
||||
|
||||
/**
|
||||
* Paint the component with round edges.
|
||||
* <p>
|
||||
* <strong>Components</strong> {@link javax.swing.JComboBox}, {@link javax.swing.JSpinner},
|
||||
* {@link javax.swing.JTextField}, {@link javax.swing.JFormattedTextField} and {@link javax.swing.JPasswordField}
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
*/
|
||||
String COMPONENT_ROUND_RECT = "JComponent.roundRect";
|
||||
//---- Popup --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Specifies whether a drop shadow is painted if the component is shown in a popup
|
||||
@@ -167,6 +181,17 @@ public interface FlatClientProperties
|
||||
*/
|
||||
String POPUP_DROP_SHADOW_PAINTED = "Popup.dropShadowPainted";
|
||||
|
||||
/**
|
||||
* Specifies whether a heavy weight window should be used 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>
|
||||
* <strong>Component</strong> {@link javax.swing.JComponent}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
*/
|
||||
String POPUP_FORCE_HEAVY_WEIGHT = "Popup.forceHeavyWeight";
|
||||
|
||||
//---- JProgressBar -------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Specifies whether the progress bar has always the larger height even if no string is painted.
|
||||
* <p>
|
||||
@@ -183,6 +208,8 @@ public interface FlatClientProperties
|
||||
*/
|
||||
String PROGRESS_BAR_SQUARE = "JProgressBar.square";
|
||||
|
||||
//---- JRootPane ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Specifies whether the menu bar is embedded into the title pane if custom
|
||||
* window decorations are enabled. Default is {@code true}.
|
||||
@@ -192,6 +219,8 @@ public interface FlatClientProperties
|
||||
*/
|
||||
String MENU_BAR_EMBEDDED = "JRootPane.menuBarEmbedded";
|
||||
|
||||
//---- JScrollBar / JScrollPane -------------------------------------------
|
||||
|
||||
/**
|
||||
* Specifies whether the decrease/increase arrow buttons of a scrollbar are shown.
|
||||
* <p>
|
||||
@@ -200,6 +229,16 @@ public interface FlatClientProperties
|
||||
*/
|
||||
String SCROLL_BAR_SHOW_BUTTONS = "JScrollBar.showButtons";
|
||||
|
||||
/**
|
||||
* Specifies whether the scroll pane uses smooth scrolling.
|
||||
* <p>
|
||||
* <strong>Component</strong> {{@link javax.swing.JScrollPane}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
*/
|
||||
String SCROLL_PANE_SMOOTH_SCROLLING = "JScrollPane.smoothScrolling";
|
||||
|
||||
//---- JTabbedPane --------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Specifies whether separators are shown between tabs.
|
||||
* <p>
|
||||
@@ -208,6 +247,14 @@ public interface FlatClientProperties
|
||||
*/
|
||||
String TABBED_PANE_SHOW_TAB_SEPARATORS = "JTabbedPane.showTabSeparators";
|
||||
|
||||
/**
|
||||
* Specifies whether the separator between tabs area and content area should be shown.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
*/
|
||||
String TABBED_PANE_SHOW_CONTENT_SEPARATOR = "JTabbedPane.showContentSeparator";
|
||||
|
||||
/**
|
||||
* Specifies whether a full border is painted around a tabbed pane.
|
||||
* <p>
|
||||
@@ -216,6 +263,35 @@ public interface FlatClientProperties
|
||||
*/
|
||||
String TABBED_PANE_HAS_FULL_BORDER = "JTabbedPane.hasFullBorder";
|
||||
|
||||
/**
|
||||
* Specifies whether the tab area should be hidden if it contains only one tab.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
*/
|
||||
String TABBED_PANE_HIDE_TAB_AREA_WITH_ONE_TAB = "JTabbedPane.hideTabAreaWithOneTab";
|
||||
|
||||
/**
|
||||
* Specifies the minimum width of a tab.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}
|
||||
* or tab content components (see {@link javax.swing.JTabbedPane#setComponentAt(int, java.awt.Component)})<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Integer}
|
||||
*/
|
||||
String TABBED_PANE_MINIMUM_TAB_WIDTH = "JTabbedPane.minimumTabWidth";
|
||||
|
||||
/**
|
||||
* Specifies the maximum width of a tab.
|
||||
* <p>
|
||||
* Applied only if tab does not have a custom tab component
|
||||
* (see {@link javax.swing.JTabbedPane#setTabComponentAt(int, java.awt.Component)}).
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}
|
||||
* or tab content components (see {@link javax.swing.JTabbedPane#setComponentAt(int, java.awt.Component)})<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Integer}
|
||||
*/
|
||||
String TABBED_PANE_MAXIMUM_TAB_WIDTH = "JTabbedPane.maximumTabWidth";
|
||||
|
||||
/**
|
||||
* Specifies the height of a tab.
|
||||
* <p>
|
||||
@@ -224,14 +300,316 @@ public interface FlatClientProperties
|
||||
*/
|
||||
String TABBED_PANE_TAB_HEIGHT = "JTabbedPane.tabHeight";
|
||||
|
||||
/**
|
||||
* Specifies the insets of a tab.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}
|
||||
* or tab content components (see {@link javax.swing.JTabbedPane#setComponentAt(int, java.awt.Component)})<br>
|
||||
* <strong>Value type</strong> {@link java.awt.Insets}
|
||||
*/
|
||||
String TABBED_PANE_TAB_INSETS = "JTabbedPane.tabInsets";
|
||||
|
||||
/**
|
||||
* Specifies the insets of the tab area.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
|
||||
* <strong>Value type</strong> {@link java.awt.Insets}
|
||||
*/
|
||||
String TABBED_PANE_TAB_AREA_INSETS = "JTabbedPane.tabAreaInsets";
|
||||
|
||||
/**
|
||||
* Specifies whether tabs are closable.
|
||||
* If set to {@code true} on a tabbed pane component, all tabs in that tabbed pane are closable.
|
||||
* To make individual tabs closable, set it to {@code true} on a tab content component.
|
||||
* <p>
|
||||
* Note that you have to specify a callback (see {@link #TABBED_PANE_TAB_CLOSABLE})
|
||||
* that is invoked when the user clicks a tab close button.
|
||||
* The callback is responsible for closing the tab.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}
|
||||
* or tab content components (see {@link javax.swing.JTabbedPane#setComponentAt(int, java.awt.Component)})<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
*
|
||||
* @see #TABBED_PANE_TAB_CLOSE_CALLBACK
|
||||
*/
|
||||
String TABBED_PANE_TAB_CLOSABLE = "JTabbedPane.tabClosable";
|
||||
|
||||
/**
|
||||
* Specifies the tooltip text used for tab close buttons.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}
|
||||
* or tab content components (see {@link javax.swing.JTabbedPane#setComponentAt(int, java.awt.Component)})<br>
|
||||
* <strong>Value type</strong> {@link java.lang.String}
|
||||
*
|
||||
* @see #TABBED_PANE_TAB_CLOSABLE
|
||||
*/
|
||||
String TABBED_PANE_TAB_CLOSE_TOOLTIPTEXT = "JTabbedPane.tabCloseToolTipText";
|
||||
|
||||
/**
|
||||
* Specifies the callback that is invoked when a tab close button is clicked.
|
||||
* The callback is responsible for closing the tab.
|
||||
* <p>
|
||||
* Either use a {@link java.util.function.IntConsumer} that receives the tab index as parameter:
|
||||
* <pre>{@code
|
||||
* myTabbedPane.putClientProperty( "JTabbedPane.tabCloseCallback",
|
||||
* (IntConsumer) tabIndex -> {
|
||||
* // close tab here
|
||||
* } );
|
||||
* }</pre>
|
||||
* Or use a {@link java.util.function.BiConsumer}<javax.swing.JTabbedPane, Integer>
|
||||
* that receives the tabbed pane and the tab index as parameters:
|
||||
* <pre>{@code
|
||||
* myTabbedPane.putClientProperty( "JTabbedPane.tabCloseCallback",
|
||||
* (BiConsumer<JTabbedPane, Integer>) (tabbedPane, tabIndex) -> {
|
||||
* // close tab here
|
||||
* } );
|
||||
* }</pre>
|
||||
* If you need to check whether a modifier key (e.g. Alt or Shift) was pressed
|
||||
* while the user clicked the tab close button, use {@link java.awt.EventQueue#getCurrentEvent}
|
||||
* to get current event, check whether it is a {@link java.awt.event.MouseEvent}
|
||||
* and invoke its methods. E.g.
|
||||
* <pre>{@code
|
||||
* AWTEvent e = EventQueue.getCurrentEvent();
|
||||
* boolean shift = (e instanceof MouseEvent) ? ((MouseEvent)e).isShiftDown() : false;
|
||||
* }</pre>
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}
|
||||
* or tab content components (see {@link javax.swing.JTabbedPane#setComponentAt(int, java.awt.Component)})<br>
|
||||
* <strong>Value type</strong> {@link java.util.function.IntConsumer}
|
||||
* or {@link java.util.function.BiConsumer}<javax.swing.JTabbedPane, Integer>
|
||||
*
|
||||
* @see #TABBED_PANE_TAB_CLOSABLE
|
||||
*/
|
||||
String TABBED_PANE_TAB_CLOSE_CALLBACK = "JTabbedPane.tabCloseCallback";
|
||||
|
||||
/**
|
||||
* Specifies the display policy for the "more tabs" button,
|
||||
* which shows a popup menu with the (partly) hidden tabs.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.String}<br>
|
||||
* <strong>Allowed Values</strong>
|
||||
* {@link #TABBED_PANE_POLICY_NEVER} or
|
||||
* {@link #TABBED_PANE_POLICY_AS_NEEDED}
|
||||
*/
|
||||
String TABBED_PANE_TABS_POPUP_POLICY = "JTabbedPane.tabsPopupPolicy";
|
||||
|
||||
/**
|
||||
* Specifies the display policy for the forward/backward scroll arrow buttons.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.String}<br>
|
||||
* <strong>Allowed Values</strong>
|
||||
* {@link #TABBED_PANE_POLICY_NEVER},
|
||||
* {@link #TABBED_PANE_POLICY_AS_NEEDED} or
|
||||
* {@link #TABBED_PANE_POLICY_AS_NEEDED_SINGLE}
|
||||
*/
|
||||
String TABBED_PANE_SCROLL_BUTTONS_POLICY = "JTabbedPane.scrollButtonsPolicy";
|
||||
|
||||
/**
|
||||
* Display never.
|
||||
*
|
||||
* @see #TABBED_PANE_TABS_POPUP_POLICY
|
||||
* @see #TABBED_PANE_SCROLL_BUTTONS_POLICY
|
||||
*/
|
||||
String TABBED_PANE_POLICY_NEVER = "never";
|
||||
|
||||
/**
|
||||
* Display only when needed.
|
||||
* <p>
|
||||
* If used for {@link #TABBED_PANE_SCROLL_BUTTONS_POLICY}, both scroll arrow buttons
|
||||
* are either shown or hidden. Buttons are disabled if scrolling in that
|
||||
* direction is not applicable.
|
||||
*
|
||||
* @see #TABBED_PANE_TABS_POPUP_POLICY
|
||||
* @see #TABBED_PANE_SCROLL_BUTTONS_POLICY
|
||||
*/
|
||||
String TABBED_PANE_POLICY_AS_NEEDED = "asNeeded";
|
||||
|
||||
/**
|
||||
* Display single button only when needed.
|
||||
* <p>
|
||||
* If scroll button placement is trailing, then this option is ignored
|
||||
* and both buttons are shown or hidden as needed.
|
||||
*
|
||||
* @see #TABBED_PANE_SCROLL_BUTTONS_POLICY
|
||||
*/
|
||||
String TABBED_PANE_POLICY_AS_NEEDED_SINGLE = "asNeededSingle";
|
||||
|
||||
/**
|
||||
* Specifies the placement of the forward/backward scroll arrow buttons.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.String}<br>
|
||||
* <strong>Allowed Values</strong>
|
||||
* {@link #TABBED_PANE_PLACEMENT_BOTH} or
|
||||
* {@link #TABBED_PANE_PLACEMENT_TRAILING}
|
||||
*/
|
||||
String TABBED_PANE_SCROLL_BUTTONS_PLACEMENT = "JTabbedPane.scrollButtonsPlacement";
|
||||
|
||||
/**
|
||||
* The forward/backward scroll arrow buttons are placed on both sides of the tab area.
|
||||
* The backward scroll button at the left/top side.
|
||||
* The forward scroll button at the right/bottom side.
|
||||
*
|
||||
* @see #TABBED_PANE_SCROLL_BUTTONS_PLACEMENT
|
||||
*/
|
||||
String TABBED_PANE_PLACEMENT_BOTH = "both";
|
||||
|
||||
/**
|
||||
* The forward/backward scroll arrow buttons are placed on the trailing side of the tab area.
|
||||
*
|
||||
* @see #TABBED_PANE_SCROLL_BUTTONS_PLACEMENT
|
||||
*/
|
||||
String TABBED_PANE_PLACEMENT_TRAILING = "trailing";
|
||||
|
||||
/**
|
||||
* Specifies the alignment of the tab area.
|
||||
* <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#LEADING} (default)
|
||||
* {@link SwingConstants#TRAILING},
|
||||
* {@link SwingConstants#CENTER},
|
||||
* {@link #TABBED_PANE_ALIGN_LEADING} (default),
|
||||
* {@link #TABBED_PANE_ALIGN_TRAILING},
|
||||
* {@link #TABBED_PANE_ALIGN_CENTER} or
|
||||
* {@link #TABBED_PANE_ALIGN_FILL}
|
||||
*/
|
||||
String TABBED_PANE_TAB_AREA_ALIGNMENT = "JTabbedPane.tabAreaAlignment";
|
||||
|
||||
/**
|
||||
* Specifies the horizontal alignment of the tab title and icon.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}
|
||||
* or tab content components (see {@link javax.swing.JTabbedPane#setComponentAt(int, java.awt.Component)})<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Integer} or {@link java.lang.String}<br>
|
||||
* <strong>Allowed Values</strong>
|
||||
* {@link SwingConstants#LEADING},
|
||||
* {@link SwingConstants#TRAILING},
|
||||
* {@link SwingConstants#CENTER} (default),
|
||||
* {@link #TABBED_PANE_ALIGN_LEADING},
|
||||
* {@link #TABBED_PANE_ALIGN_TRAILING} or
|
||||
* {@link #TABBED_PANE_ALIGN_CENTER} (default)
|
||||
*/
|
||||
String TABBED_PANE_TAB_ALIGNMENT = "JTabbedPane.tabAlignment";
|
||||
|
||||
/**
|
||||
* Align to the leading edge.
|
||||
*
|
||||
* @see #TABBED_PANE_TAB_AREA_ALIGNMENT
|
||||
* @see #TABBED_PANE_TAB_ALIGNMENT
|
||||
*/
|
||||
String TABBED_PANE_ALIGN_LEADING = "leading";
|
||||
|
||||
/**
|
||||
* Align to the trailing edge.
|
||||
*
|
||||
* @see #TABBED_PANE_TAB_AREA_ALIGNMENT
|
||||
* @see #TABBED_PANE_TAB_ALIGNMENT
|
||||
*/
|
||||
String TABBED_PANE_ALIGN_TRAILING = "trailing";
|
||||
|
||||
/**
|
||||
* Align to center.
|
||||
*
|
||||
* @see #TABBED_PANE_TAB_AREA_ALIGNMENT
|
||||
* @see #TABBED_PANE_TAB_ALIGNMENT
|
||||
*/
|
||||
String TABBED_PANE_ALIGN_CENTER = "center";
|
||||
|
||||
/**
|
||||
* Stretch to fill all available space.
|
||||
*
|
||||
* @see #TABBED_PANE_TAB_AREA_ALIGNMENT
|
||||
*/
|
||||
String TABBED_PANE_ALIGN_FILL = "fill";
|
||||
|
||||
/**
|
||||
* Specifies how the tabs should be sized.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.String}<br>
|
||||
* <strong>Allowed Values</strong>
|
||||
* {@link #TABBED_PANE_TAB_WIDTH_MODE_PREFERRED} (default),
|
||||
* {@link #TABBED_PANE_TAB_WIDTH_MODE_EQUAL} or
|
||||
* {@link #TABBED_PANE_TAB_WIDTH_MODE_COMPACT}
|
||||
*/
|
||||
String TABBED_PANE_TAB_WIDTH_MODE = "JTabbedPane.tabWidthMode";
|
||||
|
||||
/**
|
||||
* Tab width is adjusted to tab icon and title.
|
||||
*
|
||||
* @see #TABBED_PANE_TAB_WIDTH_MODE
|
||||
*/
|
||||
String TABBED_PANE_TAB_WIDTH_MODE_PREFERRED = "preferred";
|
||||
|
||||
/**
|
||||
* All tabs in a tabbed pane has same width.
|
||||
*
|
||||
* @see #TABBED_PANE_TAB_WIDTH_MODE
|
||||
*/
|
||||
String TABBED_PANE_TAB_WIDTH_MODE_EQUAL = "equal";
|
||||
|
||||
/**
|
||||
* Unselected tabs are smaller because they show only the tab icon, but no tab title.
|
||||
* Selected tabs show both.
|
||||
*
|
||||
* @see #TABBED_PANE_TAB_WIDTH_MODE
|
||||
*/
|
||||
String TABBED_PANE_TAB_WIDTH_MODE_COMPACT = "compact";
|
||||
|
||||
/**
|
||||
* Specifies the tab icon placement (relative to tab title).
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Integer}<br>
|
||||
* <strong>Allowed Values</strong>
|
||||
* {@link SwingConstants#LEADING} (default),
|
||||
* {@link SwingConstants#TRAILING},
|
||||
* {@link SwingConstants#TOP} or
|
||||
* {@link SwingConstants#BOTTOM}
|
||||
*/
|
||||
String TABBED_PANE_TAB_ICON_PLACEMENT = "JTabbedPane.tabIconPlacement";
|
||||
|
||||
/**
|
||||
* Specifies a component that will be placed at the leading edge of the tabs area.
|
||||
* <p>
|
||||
* For top and bottom tab placement, the layed out component size will be
|
||||
* the preferred component width and the tab area height.<br>
|
||||
* For left and right tab placement, the layed out component size will be
|
||||
* the tab area width and the preferred component height.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
|
||||
* <strong>Value type</strong> {@link java.awt.Component}
|
||||
*/
|
||||
String TABBED_PANE_LEADING_COMPONENT = "JTabbedPane.leadingComponent";
|
||||
|
||||
/**
|
||||
* Specifies a component that will be placed at the trailing edge of the tabs area.
|
||||
* <p>
|
||||
* For top and bottom tab placement, the layed out component size will be
|
||||
* the available horizontal space (minimum is preferred component width) and the tab area height.<br>
|
||||
* For left and right tab placement, the layed out component size will be
|
||||
* the tab area width and the available vertical space (minimum is preferred component height).
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
|
||||
* <strong>Value type</strong> {@link java.awt.Component}
|
||||
*/
|
||||
String TABBED_PANE_TRAILING_COMPONENT = "JTabbedPane.trailingComponent";
|
||||
|
||||
//---- JTextField ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Specifies whether all text is selected when the text component gains focus.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTextField} (and subclasses)<br>
|
||||
* <strong>Value type</strong> {@link java.lang.String}<br>
|
||||
* <strong>Allowed Values</strong> {@link #SELECT_ALL_ON_FOCUS_POLICY_NEVER},
|
||||
* {@link #SELECT_ALL_ON_FOCUS_POLICY_ONCE} (default) or
|
||||
* {@link #SELECT_ALL_ON_FOCUS_POLICY_ALWAYS}
|
||||
* <strong>Allowed Values</strong>
|
||||
* {@link #SELECT_ALL_ON_FOCUS_POLICY_NEVER},
|
||||
* {@link #SELECT_ALL_ON_FOCUS_POLICY_ONCE} (default) or
|
||||
* {@link #SELECT_ALL_ON_FOCUS_POLICY_ALWAYS}
|
||||
*/
|
||||
String SELECT_ALL_ON_FOCUS_POLICY = "JTextField.selectAllOnFocusPolicy";
|
||||
|
||||
@@ -266,6 +644,8 @@ public interface FlatClientProperties
|
||||
*/
|
||||
String PLACEHOLDER_TEXT = "JTextField.placeholderText";
|
||||
|
||||
//---- JToggleButton ------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Height of underline if toggle button type is {@link #BUTTON_TYPE_TAB}.
|
||||
* <p>
|
||||
@@ -290,6 +670,8 @@ public interface FlatClientProperties
|
||||
*/
|
||||
String TAB_BUTTON_SELECTED_BACKGROUND = "JToggleButton.tab.selectedBackground";
|
||||
|
||||
//---- helper methods -----------------------------------------------------
|
||||
|
||||
/**
|
||||
* Checks whether a client property of a component has the given value.
|
||||
*/
|
||||
@@ -306,6 +688,15 @@ public interface FlatClientProperties
|
||||
return (value instanceof Boolean) ? (boolean) value : defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a client property of a component is a {@link Boolean} and returns its value.
|
||||
* If the client property is not set, or not a {@link Boolean}, defaultValue is returned.
|
||||
*/
|
||||
static Boolean clientPropertyBooleanStrict( JComponent c, String key, Boolean defaultValue ) {
|
||||
Object value = c.getClientProperty( key );
|
||||
return (value instanceof Boolean) ? (Boolean) value : defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a client property of a component is an integer and returns its value.
|
||||
* If the client property is not set, or not an integer, defaultValue is returned.
|
||||
@@ -323,14 +714,4 @@ public interface FlatClientProperties
|
||||
Object value = c.getClientProperty( key );
|
||||
return (value instanceof Color) ? (Color) value : defaultValue;
|
||||
}
|
||||
|
||||
static int clientPropertyChoice( JComponent c, String key, String... choices ) {
|
||||
Object value = c.getClientProperty( key );
|
||||
for( int i = 0; i < choices.length; i++ ) {
|
||||
if( choices[i].equals( value ) )
|
||||
return i;
|
||||
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,21 +18,28 @@ package com.formdev.flatlaf;
|
||||
|
||||
/**
|
||||
* A Flat LaF that has a dark color scheme and looks like Darcula LaF.
|
||||
*
|
||||
* The UI defaults are loaded from FlatDarculaLaf.properties, FlatDarkLaf.properties and FlatLaf.properties
|
||||
* <p>
|
||||
* The UI defaults are loaded from {@code FlatDarculaLaf.properties},
|
||||
* {@code FlatDarkLaf.properties} and {@code FlatLaf.properties}.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatDarculaLaf
|
||||
extends FlatDarkLaf
|
||||
{
|
||||
public static boolean install( ) {
|
||||
public static final String NAME = "FlatLaf Darcula";
|
||||
|
||||
public static boolean install() {
|
||||
return install( new FlatDarculaLaf() );
|
||||
}
|
||||
|
||||
public static void installLafInfo() {
|
||||
installLafInfo( NAME, FlatDarculaLaf.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "FlatLaf Darcula";
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,23 +16,41 @@
|
||||
|
||||
package com.formdev.flatlaf;
|
||||
|
||||
import javax.swing.UIManager;
|
||||
|
||||
/**
|
||||
* A Flat LaF that has a dark color scheme.
|
||||
*
|
||||
* The UI defaults are loaded from FlatDarkLaf.properties and FlatLaf.properties
|
||||
* <p>
|
||||
* The UI defaults are loaded from {@code FlatDarkLaf.properties} and {@code FlatLaf.properties}.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatDarkLaf
|
||||
extends FlatLaf
|
||||
{
|
||||
public static boolean install( ) {
|
||||
public static final String NAME = "FlatLaf Dark";
|
||||
|
||||
/**
|
||||
* Sets the application look and feel to this LaF
|
||||
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
|
||||
*/
|
||||
public static boolean install() {
|
||||
return install( new FlatDarkLaf() );
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, FlatDarkLaf.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "FlatLaf Dark";
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -22,9 +22,11 @@ import javax.swing.KeyStroke;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.UIDefaults;
|
||||
import javax.swing.UIDefaults.LazyValue;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.InputMapUIResource;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
import static javax.swing.text.DefaultEditorKit.*;
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
/**
|
||||
* @author Karl Tauber
|
||||
@@ -35,7 +37,7 @@ class FlatInputMaps
|
||||
initBasicInputMaps( defaults );
|
||||
initTextComponentInputMaps( defaults );
|
||||
|
||||
if( SystemInfo.IS_MAC )
|
||||
if( SystemInfo.isMacOS )
|
||||
initMacInputMaps( defaults );
|
||||
}
|
||||
|
||||
@@ -59,7 +61,7 @@ class FlatInputMaps
|
||||
mac( "alt KP_DOWN", null ), "togglePopup"
|
||||
);
|
||||
|
||||
if( !SystemInfo.IS_MAC ) {
|
||||
if( !SystemInfo.isMacOS ) {
|
||||
modifyInputMap( defaults, "FileChooser.ancestorInputMap",
|
||||
"F2", "editFileName",
|
||||
"BACK_SPACE", "Go Up"
|
||||
@@ -81,8 +83,11 @@ class FlatInputMaps
|
||||
"shift ctrl TAB", "navigatePrevious"
|
||||
);
|
||||
|
||||
modifyInputMap( defaults, "Table.ancestorInputMap",
|
||||
// swap to make it consistent with List and Tree
|
||||
// swap Home/End with Ctrl+Home/End to make it consistent with List and Tree
|
||||
modifyInputMap( () -> {
|
||||
return UIManager.getBoolean( "Table.consistentHomeEndKeyBehavior" );
|
||||
},
|
||||
defaults, "Table.ancestorInputMap",
|
||||
"HOME", "selectFirstRow",
|
||||
"END", "selectLastRow",
|
||||
"shift HOME", "selectFirstRowExtendSelection",
|
||||
@@ -93,7 +98,7 @@ class FlatInputMaps
|
||||
mac( "shift ctrl END", null ), "selectLastColumnExtendSelection"
|
||||
);
|
||||
|
||||
if( !SystemInfo.IS_MAC ) {
|
||||
if( !SystemInfo.isMacOS ) {
|
||||
modifyInputMap( defaults, "Tree.focusInputMap",
|
||||
"ADD", "expand",
|
||||
"SUBTRACT", "collapse"
|
||||
@@ -164,7 +169,7 @@ class FlatInputMaps
|
||||
"control shift O", "toggle-componentOrientation", // DefaultEditorKit.toggleComponentOrientation
|
||||
};
|
||||
|
||||
Object[] macCommonTextComponentBindings = SystemInfo.IS_MAC ? new Object[] {
|
||||
Object[] macCommonTextComponentBindings = SystemInfo.isMacOS ? new Object[] {
|
||||
// move caret one character (without selecting text)
|
||||
"ctrl B", backwardAction,
|
||||
"ctrl F", forwardAction,
|
||||
@@ -211,7 +216,7 @@ class FlatInputMaps
|
||||
"ENTER", JTextField.notifyAction,
|
||||
};
|
||||
|
||||
Object[] macSingleLineTextComponentBindings = SystemInfo.IS_MAC ? new Object[] {
|
||||
Object[] macSingleLineTextComponentBindings = SystemInfo.isMacOS ? new Object[] {
|
||||
// move caret to line begin/end (without selecting text)
|
||||
"UP", beginLineAction,
|
||||
"DOWN", endLineAction,
|
||||
@@ -289,7 +294,7 @@ class FlatInputMaps
|
||||
mac( "ctrl SPACE", "meta SPACE" ), "activate-link-action",
|
||||
};
|
||||
|
||||
Object[] macMultiLineTextComponentBindings = SystemInfo.IS_MAC ? new Object[] {
|
||||
Object[] macMultiLineTextComponentBindings = SystemInfo.isMacOS ? new Object[] {
|
||||
// move caret one line (without selecting text)
|
||||
"ctrl N", downAction,
|
||||
"ctrl P", upAction,
|
||||
@@ -574,12 +579,16 @@ class FlatInputMaps
|
||||
}
|
||||
|
||||
private static void modifyInputMap( UIDefaults defaults, String key, Object... bindings ) {
|
||||
// Note: not using `defaults.get(key)` here because this would resolve the lazy value
|
||||
defaults.put( key, new LazyModifyInputMap( defaults.remove( key ), bindings ) );
|
||||
modifyInputMap( null, defaults, key, bindings );
|
||||
}
|
||||
|
||||
private static void modifyInputMap( BooleanSupplier condition, UIDefaults defaults, String key, Object... bindings ) {
|
||||
// Note: not using `defaults.get(key)` here because this would resolve a lazy value
|
||||
defaults.put( key, new LazyModifyInputMap( condition, defaults.remove( key ), bindings ) );
|
||||
}
|
||||
|
||||
private static <T> T mac( T value, T macValue ) {
|
||||
return SystemInfo.IS_MAC ? macValue : value;
|
||||
return SystemInfo.isMacOS ? macValue : value;
|
||||
}
|
||||
|
||||
//---- class LazyInputMapEx -----------------------------------------------
|
||||
@@ -614,10 +623,12 @@ class FlatInputMaps
|
||||
private static class LazyModifyInputMap
|
||||
implements LazyValue
|
||||
{
|
||||
private final BooleanSupplier condition;
|
||||
private final Object baseInputMap;
|
||||
private final Object[] bindings;
|
||||
|
||||
LazyModifyInputMap( Object baseInputMap, Object[] bindings ) {
|
||||
LazyModifyInputMap( BooleanSupplier condition, Object baseInputMap, Object[] bindings ) {
|
||||
this.condition = condition;
|
||||
this.baseInputMap = baseInputMap;
|
||||
this.bindings = bindings;
|
||||
}
|
||||
@@ -629,6 +640,9 @@ class FlatInputMaps
|
||||
? (InputMap) ((LazyValue)baseInputMap).createValue( table )
|
||||
: (InputMap) baseInputMap;
|
||||
|
||||
if( condition != null && !condition.getAsBoolean() )
|
||||
return inputMap;
|
||||
|
||||
// modify input map (replace or remove)
|
||||
for( int i = 0; i < bindings.length; i += 2 ) {
|
||||
KeyStroke keyStroke = KeyStroke.getKeyStroke( (String) bindings[i] );
|
||||
|
||||
@@ -18,21 +18,28 @@ package com.formdev.flatlaf;
|
||||
|
||||
/**
|
||||
* A Flat LaF that has a light color scheme and looks like IntelliJ LaF.
|
||||
*
|
||||
* The UI defaults are loaded from FlatIntelliJLaf.properties, FlatLightLaf.properties and FlatLaf.properties
|
||||
* <p>
|
||||
* The UI defaults are loaded from {@code FlatIntelliJLaf.properties},
|
||||
* {@code FlatLightLaf.properties} and {@code FlatLaf.properties}.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatIntelliJLaf
|
||||
extends FlatLightLaf
|
||||
{
|
||||
public static boolean install( ) {
|
||||
public static final String NAME = "FlatLaf IntelliJ";
|
||||
|
||||
public static boolean install() {
|
||||
return install( new FlatIntelliJLaf() );
|
||||
}
|
||||
|
||||
public static void installLafInfo() {
|
||||
installLafInfo( NAME, FlatIntelliJLaf.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "FlatLaf IntelliJ";
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -29,6 +29,7 @@ import java.awt.image.ImageFilter;
|
||||
import java.awt.image.ImageProducer;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -49,9 +50,9 @@ import javax.swing.LookAndFeel;
|
||||
import javax.swing.PopupFactory;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIDefaults;
|
||||
import javax.swing.UIDefaults.ActiveValue;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.UnsupportedLookAndFeelException;
|
||||
import javax.swing.UIDefaults.ActiveValue;
|
||||
import javax.swing.plaf.ColorUIResource;
|
||||
import javax.swing.plaf.FontUIResource;
|
||||
import javax.swing.plaf.UIResource;
|
||||
@@ -76,6 +77,8 @@ public abstract class FlatLaf
|
||||
static final Logger LOG = Logger.getLogger( FlatLaf.class.getName() );
|
||||
private static final String DESKTOPFONTHINTS = "awt.font.desktophints";
|
||||
|
||||
private static List<Object> customDefaultsSources;
|
||||
|
||||
private String desktopPropertyName;
|
||||
private String desktopPropertyName2;
|
||||
private PropertyChangeListener desktopPropertyListener;
|
||||
@@ -91,6 +94,10 @@ public abstract class FlatLaf
|
||||
private Boolean oldFrameWindowDecorated;
|
||||
private Boolean oldDialogWindowDecorated;
|
||||
|
||||
/**
|
||||
* Sets the application look and feel to the given LaF
|
||||
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
|
||||
*/
|
||||
public static boolean install( LookAndFeel newLookAndFeel ) {
|
||||
try {
|
||||
UIManager.setLookAndFeel( newLookAndFeel );
|
||||
@@ -101,6 +108,16 @@ public abstract class FlatLaf
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given 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( String lafName, Class<? extends LookAndFeel> lafClass ) {
|
||||
UIManager.installLookAndFeel( new UIManager.LookAndFeelInfo( lafName, lafClass.getName() ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the look and feel identifier.
|
||||
* <p>
|
||||
@@ -147,12 +164,12 @@ public abstract class FlatLaf
|
||||
*/
|
||||
@Override
|
||||
public boolean getSupportsWindowDecorations() {
|
||||
if( SystemInfo.IS_JETBRAINS_JVM_11_OR_LATER &&
|
||||
SystemInfo.IS_WINDOWS_10_OR_LATER &&
|
||||
if( SystemInfo.isJetBrainsJVM_11_orLater &&
|
||||
SystemInfo.isWindows_10_orLater &&
|
||||
JBRCustomDecorations.isSupported() )
|
||||
return false;
|
||||
|
||||
return SystemInfo.IS_WINDOWS_10_OR_LATER;
|
||||
return SystemInfo.isWindows_10_orLater;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -167,6 +184,9 @@ public abstract class FlatLaf
|
||||
|
||||
@Override
|
||||
public Icon getDisabledIcon( JComponent component, Icon icon ) {
|
||||
if( icon instanceof DisabledIconProvider )
|
||||
return ((DisabledIconProvider)icon).getDisabledIcon();
|
||||
|
||||
if( icon instanceof ImageIcon ) {
|
||||
Object grayFilter = UIManager.get( "Component.grayFilter" );
|
||||
ImageFilter filter = (grayFilter instanceof ImageFilter)
|
||||
@@ -187,7 +207,7 @@ public abstract class FlatLaf
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
if( SystemInfo.IS_MAC )
|
||||
if( SystemInfo.isMacOS )
|
||||
initializeAqua();
|
||||
|
||||
super.initialize();
|
||||
@@ -201,11 +221,11 @@ public abstract class FlatLaf
|
||||
mnemonicHandler.install();
|
||||
|
||||
// listen to desktop property changes to update UI if system font or scaling changes
|
||||
if( SystemInfo.IS_WINDOWS ) {
|
||||
if( SystemInfo.isWindows ) {
|
||||
// Windows 10 allows increasing font size independent of scaling:
|
||||
// Settings > Ease of Access > Display > Make text bigger (100% - 225%)
|
||||
desktopPropertyName = "win.messagebox.font";
|
||||
} else if( SystemInfo.IS_LINUX ) {
|
||||
} else if( SystemInfo.isLinux ) {
|
||||
// Linux/Gnome allows changing font in "Tweaks" app
|
||||
desktopPropertyName = "gnome.Gtk/FontName";
|
||||
|
||||
@@ -315,7 +335,7 @@ public abstract class FlatLaf
|
||||
String aquaLafClassName = "com.apple.laf.AquaLookAndFeel";
|
||||
BasicLookAndFeel aquaLaf;
|
||||
try {
|
||||
if( SystemInfo.IS_JAVA_9_OR_LATER ) {
|
||||
if( SystemInfo.isJava_9_orLater ) {
|
||||
Method m = UIManager.class.getMethod( "createLookAndFeel", String.class );
|
||||
aquaLaf = (BasicLookAndFeel) m.invoke( null, "Mac OS X" );
|
||||
} else
|
||||
@@ -341,6 +361,10 @@ public abstract class FlatLaf
|
||||
public UIDefaults getDefaults() {
|
||||
UIDefaults defaults = super.getDefaults();
|
||||
|
||||
// add flag that indicates whether the LaF is light or dark
|
||||
// (can be queried without using FlatLaf API)
|
||||
defaults.put( "laf.dark", isDark() );
|
||||
|
||||
// add resource bundle for localized texts
|
||||
defaults.addResourceBundle( "com.formdev.flatlaf.resources.Bundle" );
|
||||
|
||||
@@ -391,7 +415,7 @@ public abstract class FlatLaf
|
||||
UIDefaultsLoader.loadDefaultsFromProperties( getClass(), addons, getAdditionalDefaults(), isDark(), defaults );
|
||||
|
||||
// use Aqua MenuBarUI if Mac screen menubar is enabled
|
||||
if( SystemInfo.IS_MAC && Boolean.getBoolean( "apple.laf.useScreenMenuBar" ) ) {
|
||||
if( SystemInfo.isMacOS && Boolean.getBoolean( "apple.laf.useScreenMenuBar" ) ) {
|
||||
defaults.put( "MenuBarUI", "com.apple.laf.AquaMenuBarUI" );
|
||||
|
||||
// add defaults necessary for AquaMenuBarUI
|
||||
@@ -435,17 +459,17 @@ public abstract class FlatLaf
|
||||
private void initFonts( UIDefaults defaults ) {
|
||||
FontUIResource uiFont = null;
|
||||
|
||||
if( SystemInfo.IS_WINDOWS ) {
|
||||
if( SystemInfo.isWindows ) {
|
||||
Font winFont = (Font) Toolkit.getDefaultToolkit().getDesktopProperty( "win.messagebox.font" );
|
||||
if( winFont != null )
|
||||
uiFont = createCompositeFont( winFont.getFamily(), winFont.getStyle(), winFont.getSize() );
|
||||
|
||||
} else if( SystemInfo.IS_MAC ) {
|
||||
} else if( SystemInfo.isMacOS ) {
|
||||
String fontName;
|
||||
if( SystemInfo.IS_MAC_OS_10_15_CATALINA_OR_LATER ) {
|
||||
if( SystemInfo.isMacOS_10_15_Catalina_orLater ) {
|
||||
// use Helvetica Neue font
|
||||
fontName = "Helvetica Neue";
|
||||
} else if( SystemInfo.IS_MAC_OS_10_11_EL_CAPITAN_OR_LATER ) {
|
||||
} else if( SystemInfo.isMacOS_10_11_ElCapitan_orLater ) {
|
||||
// use San Francisco Text font
|
||||
fontName = ".SF NS Text";
|
||||
} else {
|
||||
@@ -455,14 +479,16 @@ public abstract class FlatLaf
|
||||
|
||||
uiFont = createCompositeFont( fontName, Font.PLAIN, 13 );
|
||||
|
||||
} else if( SystemInfo.IS_LINUX ) {
|
||||
} else if( SystemInfo.isLinux ) {
|
||||
Font font = LinuxFontPolicy.getFont();
|
||||
uiFont = (font instanceof FontUIResource) ? (FontUIResource) font : new FontUIResource( font );
|
||||
}
|
||||
|
||||
// fallback
|
||||
if( uiFont == null )
|
||||
uiFont = createCompositeFont( Font.SANS_SERIF, Font.PLAIN, 12 );
|
||||
|
||||
// increase font size if system property "flatlaf.uiScale" is set
|
||||
uiFont = UIScale.applyCustomScaleFactor( uiFont );
|
||||
|
||||
// use active value for all fonts to allow changing fonts in all components
|
||||
@@ -515,7 +541,7 @@ public abstract class FlatLaf
|
||||
}
|
||||
|
||||
private void putAATextInfo( UIDefaults defaults ) {
|
||||
if( SystemInfo.IS_JAVA_9_OR_LATER ) {
|
||||
if( SystemInfo.isJava_9_orLater ) {
|
||||
Object desktopHints = Toolkit.getDefaultToolkit().getDesktopProperty( DESKTOPFONTHINTS );
|
||||
if( desktopHints instanceof Map ) {
|
||||
@SuppressWarnings( "unchecked" )
|
||||
@@ -552,6 +578,87 @@ public abstract class FlatLaf
|
||||
defaults.put( key, value );
|
||||
}
|
||||
|
||||
static List<Object> getCustomDefaultsSources() {
|
||||
return customDefaultsSources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a package where FlatLaf searches for properties files with custom UI defaults.
|
||||
* <p>
|
||||
* This can be used to specify application specific UI defaults that override UI values
|
||||
* of existing themes or to define own UI values used in custom controls.
|
||||
* <p>
|
||||
* There may be multiple properties files in that package for multiple themes.
|
||||
* The properties file name must match the used theme class names.
|
||||
* E.g. {@code FlatLightLaf.properties} for class {@link FlatLightLaf}
|
||||
* or {@code FlatDarkLaf.properties} for class {@link FlatDarkLaf}.
|
||||
* {@code FlatLaf.properties} is loaded first for all themes.
|
||||
* <p>
|
||||
* These properties files are loaded after theme and addon properties files
|
||||
* and can therefore override all UI defaults.
|
||||
* <p>
|
||||
* Invoke this method before setting the look and feel.
|
||||
*
|
||||
* @param packageName a package name (e.g. "com.myapp.resources")
|
||||
*/
|
||||
public static void registerCustomDefaultsSource( String packageName ) {
|
||||
registerCustomDefaultsSource( packageName, null );
|
||||
}
|
||||
|
||||
public static void unregisterCustomDefaultsSource( String packageName ) {
|
||||
unregisterCustomDefaultsSource( packageName, null );
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a package where FlatLaf searches for properties files with custom UI defaults.
|
||||
* <p>
|
||||
* See {@link #registerCustomDefaultsSource(String)} for details.
|
||||
*
|
||||
* @param packageName a package name (e.g. "com.myapp.resources")
|
||||
* @param classLoader a class loader used to find resources, or {@code null}
|
||||
*/
|
||||
public static void registerCustomDefaultsSource( String packageName, ClassLoader classLoader ) {
|
||||
if( customDefaultsSources == null )
|
||||
customDefaultsSources = new ArrayList<>();
|
||||
customDefaultsSources.add( packageName );
|
||||
customDefaultsSources.add( classLoader );
|
||||
}
|
||||
|
||||
public static void unregisterCustomDefaultsSource( String packageName, ClassLoader classLoader ) {
|
||||
if( customDefaultsSources == null )
|
||||
return;
|
||||
|
||||
int size = customDefaultsSources.size();
|
||||
for( int i = 0; i < size - 1; i++ ) {
|
||||
Object source = customDefaultsSources.get( i );
|
||||
if( packageName.equals( source ) && customDefaultsSources.get( i + 1 ) == classLoader ) {
|
||||
customDefaultsSources.remove( i + 1 );
|
||||
customDefaultsSources.remove( i );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a folder where FlatLaf searches for properties files with custom UI defaults.
|
||||
* <p>
|
||||
* See {@link #registerCustomDefaultsSource(String)} for details.
|
||||
*
|
||||
* @param folder a folder
|
||||
*/
|
||||
public static void registerCustomDefaultsSource( File folder ) {
|
||||
if( customDefaultsSources == null )
|
||||
customDefaultsSources = new ArrayList<>();
|
||||
customDefaultsSources.add( folder );
|
||||
}
|
||||
|
||||
public static void unregisterCustomDefaultsSource( File folder ) {
|
||||
if( customDefaultsSources == null )
|
||||
return;
|
||||
|
||||
customDefaultsSources.remove( folder );
|
||||
}
|
||||
|
||||
private static void reSetLookAndFeel() {
|
||||
EventQueue.invokeLater( () -> {
|
||||
LookAndFeel lookAndFeel = UIManager.getLookAndFeel();
|
||||
@@ -612,6 +719,18 @@ public abstract class FlatLaf
|
||||
MnemonicHandler.showMnemonics( false, null );
|
||||
}
|
||||
|
||||
// do not allow overriding to avoid issues in FlatUIUtils.createSharedUI()
|
||||
@Override
|
||||
public final boolean equals( Object obj ) {
|
||||
return super.equals( obj );
|
||||
}
|
||||
|
||||
// do not allow overriding to avoid issues in FlatUIUtils.createSharedUI()
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
return super.hashCode();
|
||||
}
|
||||
|
||||
//---- class ActiveFont ---------------------------------------------------
|
||||
|
||||
private static class ActiveFont
|
||||
@@ -660,4 +779,24 @@ public abstract class FlatLaf
|
||||
super( image );
|
||||
}
|
||||
}
|
||||
|
||||
//---- interface DisabledIconProvider -------------------------------------
|
||||
|
||||
/**
|
||||
* A provider for disabled icons.
|
||||
* <p>
|
||||
* This is intended to be implemented by {@link javax.swing.Icon} implementations
|
||||
* that provide the ability to paint disabled state.
|
||||
* <p>
|
||||
* Used in {@link FlatLaf#getDisabledIcon(JComponent, Icon)} to create a disabled icon from an enabled icon.
|
||||
*/
|
||||
public interface DisabledIconProvider
|
||||
{
|
||||
/**
|
||||
* Returns an icon with a disabled appearance.
|
||||
*
|
||||
* @return a disabled icon
|
||||
*/
|
||||
Icon getDisabledIcon();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,23 +16,41 @@
|
||||
|
||||
package com.formdev.flatlaf;
|
||||
|
||||
import javax.swing.UIManager;
|
||||
|
||||
/**
|
||||
* A Flat LaF that has a light color scheme.
|
||||
*
|
||||
* The UI defaults are loaded from FlatLightLaf.properties and FlatLaf.properties
|
||||
* <p>
|
||||
* The UI defaults are loaded from {@code FlatLightLaf.properties} and {@code FlatLaf.properties}.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatLightLaf
|
||||
extends FlatLaf
|
||||
{
|
||||
public static boolean install( ) {
|
||||
public static final String NAME = "FlatLaf Light";
|
||||
|
||||
/**
|
||||
* Sets the application look and feel to this LaF
|
||||
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
|
||||
*/
|
||||
public static boolean install() {
|
||||
return install( new FlatLightLaf() );
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, FlatLightLaf.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "FlatLaf Light";
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -88,6 +88,10 @@ public class FlatPropertiesLaf
|
||||
return dark;
|
||||
}
|
||||
|
||||
public Properties getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ArrayList<Class<?>> getLafClassesForDefaultsLoading() {
|
||||
ArrayList<Class<?>> lafClasses = new ArrayList<>();
|
||||
|
||||
@@ -39,6 +39,14 @@ public interface FlatSystemProperties
|
||||
*/
|
||||
String UI_SCALE = "flatlaf.uiScale";
|
||||
|
||||
/**
|
||||
* Specifies whether user scaling mode is enabled.
|
||||
* <p>
|
||||
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
||||
* <strong>Default</strong> {@code true}
|
||||
*/
|
||||
String UI_SCALE_ENABLED = "flatlaf.uiScale.enabled";
|
||||
|
||||
/**
|
||||
* Specifies whether Ubuntu font should be used on Ubuntu Linux.
|
||||
* By default, if not running in a JetBrains Runtime, the Liberation Sans font
|
||||
@@ -84,6 +92,14 @@ public interface FlatSystemProperties
|
||||
*/
|
||||
String MENUBAR_EMBEDDED = "flatlaf.menuBarEmbedded";
|
||||
|
||||
/**
|
||||
* Specifies whether animations are enabled.
|
||||
* <p>
|
||||
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
||||
* <strong>Default</strong> {@code true}
|
||||
*/
|
||||
String ANIMATION = "flatlaf.animation";
|
||||
|
||||
/**
|
||||
* Specifies whether vertical text position is corrected when UI is scaled on HiDPI screens.
|
||||
* <p>
|
||||
|
||||
@@ -147,6 +147,10 @@ public class IntelliJTheme
|
||||
applyColorPalette( defaults );
|
||||
applyCheckBoxColors( defaults );
|
||||
|
||||
// copy values
|
||||
for( Map.Entry<String, String> e : uiKeyCopying.entrySet() )
|
||||
defaults.put( e.getKey(), defaults.get( e.getValue() ) );
|
||||
|
||||
// IDEA does not paint button background if disabled, but FlatLaf does
|
||||
Object panelBackground = defaults.get( "Panel.background" );
|
||||
defaults.put( "Button.disabledBackground", panelBackground );
|
||||
@@ -259,6 +263,9 @@ public class IntelliJTheme
|
||||
for( Map.Entry<String, Object> e : ((Map<String, Object>)value).entrySet() )
|
||||
apply( key + '.' + e.getKey(), e.getValue(), defaults, defaultsKeysCache, uiKeys );
|
||||
} else {
|
||||
if( "".equals( value ) )
|
||||
return; // ignore empty value
|
||||
|
||||
uiKeys.add( key );
|
||||
|
||||
// fix ComboBox size and Spinner border in all Material UI Lite themes
|
||||
@@ -466,13 +473,11 @@ public class IntelliJTheme
|
||||
defaults.remove( "CheckBox.icon[filled].selectedHoverBackground" );
|
||||
defaults.remove( "CheckBox.icon[filled].selectedPressedBackground" );
|
||||
}
|
||||
|
||||
// copy values
|
||||
for( Map.Entry<String, String> e : uiKeyCopying.entrySet() )
|
||||
defaults.put( e.getKey(), defaults.get( e.getValue() ) );
|
||||
}
|
||||
|
||||
/** Rename UI default keys (key --> value). */
|
||||
private static Map<String, String> uiKeyMapping = new HashMap<>();
|
||||
/** Copy UI default keys (value --> key). */
|
||||
private static Map<String, String> uiKeyCopying = new HashMap<>();
|
||||
private static Map<String, String> uiKeyInverseMapping = new HashMap<>();
|
||||
private static Map<String, String> checkboxKeyMapping = new HashMap<>();
|
||||
@@ -514,6 +519,8 @@ public class IntelliJTheme
|
||||
uiKeyMapping.put( "ProgressBar.foreground", "" ); // ignore
|
||||
uiKeyMapping.put( "ProgressBar.trackColor", "ProgressBar.background" );
|
||||
uiKeyMapping.put( "ProgressBar.progressColor", "ProgressBar.foreground" );
|
||||
uiKeyCopying.put( "ProgressBar.selectionForeground", "ProgressBar.background" );
|
||||
uiKeyCopying.put( "ProgressBar.selectionBackground", "ProgressBar.foreground" );
|
||||
|
||||
// ScrollBar
|
||||
uiKeyMapping.put( "ScrollBar.trackColor", "ScrollBar.track" );
|
||||
@@ -524,8 +531,12 @@ public class IntelliJTheme
|
||||
|
||||
// Slider
|
||||
uiKeyMapping.put( "Slider.trackWidth", "" ); // ignore (used in Material Theme UI Lite)
|
||||
uiKeyCopying.put( "Slider.trackValueColor", "ProgressBar.foreground" );
|
||||
uiKeyCopying.put( "Slider.thumbColor", "ProgressBar.foreground" );
|
||||
uiKeyCopying.put( "Slider.trackColor", "ProgressBar.background" );
|
||||
|
||||
// TitlePane
|
||||
uiKeyCopying.put( "TitlePane.inactiveBackground", "TitlePane.background" );
|
||||
uiKeyMapping.put( "TitlePane.infoForeground", "TitlePane.foreground" );
|
||||
uiKeyMapping.put( "TitlePane.inactiveInfoForeground", "TitlePane.inactiveForeground" );
|
||||
|
||||
@@ -577,7 +588,7 @@ public class IntelliJTheme
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return theme.name;
|
||||
return getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -39,7 +39,7 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
class LinuxFontPolicy
|
||||
{
|
||||
static Font getFont() {
|
||||
return SystemInfo.IS_KDE ? getKDEFont() : getGnomeFont();
|
||||
return SystemInfo.isKDE ? getKDEFont() : getGnomeFont();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -77,7 +77,7 @@ class LinuxFontPolicy
|
||||
// Ubuntu font is rendered poorly (except if running in JetBrains VM)
|
||||
// --> use Liberation Sans font
|
||||
if( family.startsWith( "Ubuntu" ) &&
|
||||
!SystemInfo.IS_JETBRAINS_JVM &&
|
||||
!SystemInfo.isJetBrainsJVM &&
|
||||
!FlatSystemProperties.getBoolean( FlatSystemProperties.USE_UBUNTU_FONT, false ) )
|
||||
family = "Liberation Sans";
|
||||
|
||||
|
||||
@@ -71,13 +71,13 @@ class MnemonicHandler
|
||||
@Override
|
||||
public boolean postProcessKeyEvent( KeyEvent e ) {
|
||||
int keyCode = e.getKeyCode();
|
||||
if( SystemInfo.IS_MAC ) {
|
||||
if( SystemInfo.isMacOS ) {
|
||||
// Ctrl+Alt keys must be pressed on Mac
|
||||
if( keyCode == KeyEvent.VK_CONTROL || keyCode == KeyEvent.VK_ALT )
|
||||
showMnemonics( shouldShowMnemonics( e ) && e.isControlDown() && e.isAltDown(), e.getComponent() );
|
||||
} else {
|
||||
// Alt key must be pressed on Windows and Linux
|
||||
if( SystemInfo.IS_WINDOWS )
|
||||
if( SystemInfo.isWindows )
|
||||
return processKeyEventOnWindows( e );
|
||||
|
||||
if( keyCode == KeyEvent.VK_ALT )
|
||||
|
||||
@@ -19,14 +19,18 @@ package com.formdev.flatlaf;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Insets;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Properties;
|
||||
import java.util.function.Function;
|
||||
import java.util.logging.Level;
|
||||
@@ -115,6 +119,46 @@ class UIDefaultsLoader
|
||||
addonClassLoaders.add( addonClassLoader );
|
||||
}
|
||||
|
||||
// load custom properties files (usually provides by applications)
|
||||
List<Object> customDefaultsSources = FlatLaf.getCustomDefaultsSources();
|
||||
int size = (customDefaultsSources != null) ? customDefaultsSources.size() : 0;
|
||||
for( int i = 0; i < size; i++ ) {
|
||||
Object source = customDefaultsSources.get( i );
|
||||
if( source instanceof String && i + 1 < size ) {
|
||||
// load from package in classloader
|
||||
String packageName = (String) source;
|
||||
ClassLoader classLoader = (ClassLoader) customDefaultsSources.get( ++i );
|
||||
|
||||
// use class loader also for instantiating classes specified in values
|
||||
if( classLoader != null && !addonClassLoaders.contains( classLoader ) )
|
||||
addonClassLoaders.add( classLoader );
|
||||
|
||||
packageName = packageName.replace( '.', '/' );
|
||||
if( classLoader == null )
|
||||
classLoader = FlatLaf.class.getClassLoader();
|
||||
|
||||
for( Class<?> lafClass : lafClasses ) {
|
||||
String propertiesName = packageName + '/' + lafClass.getSimpleName() + ".properties";
|
||||
try( InputStream in = classLoader.getResourceAsStream( propertiesName ) ) {
|
||||
if( in != null )
|
||||
properties.load( in );
|
||||
}
|
||||
}
|
||||
} else if( source instanceof File ) {
|
||||
// load from folder
|
||||
File folder = (File) source;
|
||||
for( Class<?> lafClass : lafClasses ) {
|
||||
File propertiesFile = new File( folder, lafClass.getSimpleName() + ".properties" );
|
||||
if( !propertiesFile.isFile() )
|
||||
continue;
|
||||
|
||||
try( InputStream in = new FileInputStream( propertiesFile ) ) {
|
||||
properties.load( in );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add additional defaults
|
||||
if( additionalDefaults != null )
|
||||
properties.putAll( additionalDefaults );
|
||||
@@ -144,9 +188,9 @@ class UIDefaultsLoader
|
||||
|
||||
// handle platform specific properties
|
||||
String platformPrefix =
|
||||
SystemInfo.IS_WINDOWS ? "[win]" :
|
||||
SystemInfo.IS_MAC ? "[mac]" :
|
||||
SystemInfo.IS_LINUX ? "[linux]" : "[unknown]";
|
||||
SystemInfo.isWindows ? "[win]" :
|
||||
SystemInfo.isMacOS ? "[mac]" :
|
||||
SystemInfo.isLinux ? "[linux]" : "[unknown]";
|
||||
for( String key : platformSpecificKeys ) {
|
||||
Object value = properties.remove( key );
|
||||
if( key.startsWith( platformPrefix ) )
|
||||
@@ -154,6 +198,32 @@ class UIDefaultsLoader
|
||||
}
|
||||
}
|
||||
|
||||
// get (and remove) globals, which override all other defaults that end with same suffix
|
||||
HashMap<String, String> globals = new HashMap<>();
|
||||
Iterator<Entry<Object, Object>> it = properties.entrySet().iterator();
|
||||
while( it.hasNext() ) {
|
||||
Entry<Object, Object> e = it.next();
|
||||
String key = (String) e.getKey();
|
||||
if( key.startsWith( GLOBAL_PREFIX ) ) {
|
||||
globals.put( key.substring( GLOBAL_PREFIX.length() ), (String) e.getValue() );
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
// override UI defaults with globals
|
||||
for( Object key : defaults.keySet() ) {
|
||||
int dot;
|
||||
if( !(key instanceof String) ||
|
||||
properties.containsKey( key ) ||
|
||||
(dot = ((String)key).lastIndexOf( '.' )) < 0 )
|
||||
continue;
|
||||
|
||||
String globalKey = ((String)key).substring( dot + 1 );
|
||||
String globalValue = globals.get( globalKey );
|
||||
if( globalValue != null )
|
||||
properties.put( key, globalValue );
|
||||
}
|
||||
|
||||
Function<String, String> propertiesGetter = key -> {
|
||||
return properties.getProperty( key );
|
||||
};
|
||||
@@ -161,37 +231,10 @@ class UIDefaultsLoader
|
||||
return resolveValue( value, propertiesGetter );
|
||||
};
|
||||
|
||||
// get globals, which override all other defaults that end with same suffix
|
||||
HashMap<String, Object> globals = new HashMap<>();
|
||||
// parse and add properties to UI defaults
|
||||
for( Map.Entry<Object, Object> e : properties.entrySet() ) {
|
||||
String key = (String) e.getKey();
|
||||
if( !key.startsWith( GLOBAL_PREFIX ) )
|
||||
continue;
|
||||
|
||||
String value = resolveValue( (String) e.getValue(), propertiesGetter );
|
||||
try {
|
||||
globals.put( key.substring( GLOBAL_PREFIX.length() ),
|
||||
parseValue( key, value, null, resolver, addonClassLoaders ) );
|
||||
} catch( RuntimeException ex ) {
|
||||
logParseError( Level.SEVERE, key, value, ex );
|
||||
}
|
||||
}
|
||||
|
||||
// override UI defaults with globals
|
||||
for( Object key : defaults.keySet() ) {
|
||||
if( key instanceof String && ((String)key).contains( "." ) ) {
|
||||
String skey = (String) key;
|
||||
String globalKey = skey.substring( skey.lastIndexOf( '.' ) + 1 );
|
||||
Object globalValue = globals.get( globalKey );
|
||||
if( globalValue != null )
|
||||
defaults.put( key, globalValue );
|
||||
}
|
||||
}
|
||||
|
||||
// add non-global properties to UI defaults
|
||||
for( Map.Entry<Object, Object> e : properties.entrySet() ) {
|
||||
String key = (String) e.getKey();
|
||||
if( key.startsWith( VARIABLE_PREFIX ) || key.startsWith( GLOBAL_PREFIX ) )
|
||||
if( key.startsWith( VARIABLE_PREFIX ) )
|
||||
continue;
|
||||
|
||||
String value = resolveValue( (String) e.getValue(), propertiesGetter );
|
||||
@@ -543,13 +586,17 @@ class UIDefaultsLoader
|
||||
case "darken": return parseColorHSLIncreaseDecrease( 2, false, params, resolver, reportError );
|
||||
case "saturate": return parseColorHSLIncreaseDecrease( 1, true, params, resolver, reportError );
|
||||
case "desaturate": return parseColorHSLIncreaseDecrease( 1, false, params, resolver, reportError );
|
||||
case "fadein": return parseColorHSLIncreaseDecrease( 3, true, params, resolver, reportError );
|
||||
case "fadeout": return parseColorHSLIncreaseDecrease( 3, false, params, resolver, reportError );
|
||||
case "fade": return parseColorFade( params, resolver, reportError );
|
||||
case "spin": return parseColorSpin( params, resolver, reportError );
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException( "unknown color function '" + value + "'" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Syntax: rgb(red,green,blue) or rgba(red,green,blue,alpha) or rgba(color,alpha)
|
||||
* Syntax: rgb(red,green,blue) or rgba(red,green,blue,alpha)
|
||||
* - red: an integer 0-255 or a percentage 0-100%
|
||||
* - green: an integer 0-255 or a percentage 0-100%
|
||||
* - blue: an integer 0-255 or a percentage 0-100%
|
||||
@@ -560,6 +607,8 @@ class UIDefaultsLoader
|
||||
{
|
||||
if( hasAlpha && params.size() == 2 ) {
|
||||
// syntax rgba(color,alpha), which allows adding alpha to any color
|
||||
// NOTE: this syntax is deprecated
|
||||
// use fade(color,alpha) instead
|
||||
String colorStr = params.get( 0 );
|
||||
int alpha = parseInteger( params.get( 1 ), 0, 255, true );
|
||||
|
||||
@@ -596,7 +645,8 @@ class UIDefaultsLoader
|
||||
|
||||
/**
|
||||
* Syntax: lighten(color,amount[,options]) or darken(color,amount[,options]) or
|
||||
* saturate(color,amount[,options]) or desaturate(color,amount[,options])
|
||||
* saturate(color,amount[,options]) or desaturate(color,amount[,options]) or
|
||||
* fadein(color,amount[,options]) or fadeout(color,amount[,options])
|
||||
* - color: a color (e.g. #f00) or a color function
|
||||
* - amount: percentage 0-100%
|
||||
* - options: [relative] [autoInverse] [noAutoInverse] [lazy] [derived]
|
||||
@@ -636,9 +686,64 @@ class UIDefaultsLoader
|
||||
};
|
||||
}
|
||||
|
||||
// parse base color, apply function and create derived color
|
||||
return parseFunctionBaseColor( colorStr, function, derived, resolver, reportError );
|
||||
}
|
||||
|
||||
/**
|
||||
* Syntax: fade(color,amount[,options])
|
||||
* - color: a color (e.g. #f00) or a color function
|
||||
* - amount: percentage 0-100%
|
||||
* - options: [derived]
|
||||
*/
|
||||
private static Object parseColorFade( List<String> params, Function<String, String> resolver, boolean reportError ) {
|
||||
String colorStr = params.get( 0 );
|
||||
int amount = parsePercentage( params.get( 1 ) );
|
||||
boolean derived = false;
|
||||
|
||||
if( params.size() > 2 ) {
|
||||
String options = params.get( 2 );
|
||||
derived = options.contains( "derived" );
|
||||
}
|
||||
|
||||
// create function
|
||||
ColorFunction function = new ColorFunctions.Fade( amount );
|
||||
|
||||
// parse base color, apply function and create derived color
|
||||
return parseFunctionBaseColor( colorStr, function, derived, resolver, reportError );
|
||||
}
|
||||
|
||||
/**
|
||||
* Syntax: spin(color,angle[,options])
|
||||
* - color: a color (e.g. #f00) or a color function
|
||||
* - angle: number of degrees to rotate
|
||||
* - options: [derived]
|
||||
*/
|
||||
private static Object parseColorSpin( List<String> params, Function<String, String> resolver, boolean reportError ) {
|
||||
String colorStr = params.get( 0 );
|
||||
int amount = parseInteger( params.get( 1 ), true );
|
||||
boolean derived = false;
|
||||
|
||||
if( params.size() > 2 ) {
|
||||
String options = params.get( 2 );
|
||||
derived = options.contains( "derived" );
|
||||
}
|
||||
|
||||
// create function
|
||||
ColorFunction function = new ColorFunctions.HSLIncreaseDecrease( 0, true, amount, false, false );
|
||||
|
||||
// parse base color, apply function and create derived color
|
||||
return parseFunctionBaseColor( colorStr, function, derived, resolver, reportError );
|
||||
}
|
||||
|
||||
private static Object parseFunctionBaseColor( String colorStr, ColorFunction function,
|
||||
boolean derived, Function<String, String> resolver, boolean reportError )
|
||||
{
|
||||
// parse base color
|
||||
String resolvedColorStr = resolver.apply( colorStr );
|
||||
ColorUIResource baseColor = (ColorUIResource) parseColorOrFunction( resolvedColorStr, resolver, reportError );
|
||||
if( baseColor == null )
|
||||
return null;
|
||||
|
||||
// apply this function to base color
|
||||
Color newColor = ColorFunctions.applyFunctions( baseColor, function );
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2020 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.icons;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import com.formdev.flatlaf.util.AnimatedIcon;
|
||||
|
||||
/**
|
||||
* Base class for animated icons that scales width and height, creates and initializes
|
||||
* a scaled graphics context for icon painting.
|
||||
* <p>
|
||||
* Subclasses do not need to scale icon painting.
|
||||
* <p>
|
||||
* This class does not store any state information (needed for animation) in its instance.
|
||||
* Instead a client property is set on the painted component.
|
||||
* This makes it possible to use a share icon instance for multiple components.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public abstract class FlatAnimatedIcon
|
||||
extends FlatAbstractIcon
|
||||
implements AnimatedIcon
|
||||
{
|
||||
public FlatAnimatedIcon( int width, int height, Color color ) {
|
||||
super( width, height, color );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintIcon( Component c, Graphics g, int x, int y ) {
|
||||
super.paintIcon( c, g, x, y );
|
||||
AnimatedIcon.AnimationSupport.saveIconLocation( this, c, x, y );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintIcon( Component c, Graphics2D g ) {
|
||||
AnimatedIcon.AnimationSupport.paintIcon( this, c, g, 0, 0 );
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
/**
|
||||
* "ascendingSort" icon for {@link javax.swing.table.JTableHeader}.
|
||||
*
|
||||
* @uiDefault Component.arrowType String triangle (default) or chevron
|
||||
* @uiDefault Component.arrowType String chevron (default) or triangle
|
||||
* @uiDefault Table.sortIconColor Color
|
||||
*
|
||||
* @author Karl Tauber
|
||||
@@ -35,7 +35,7 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
public class FlatAscendingSortIcon
|
||||
extends FlatAbstractIcon
|
||||
{
|
||||
protected final boolean chevron = "chevron".equals( UIManager.getString( "Component.arrowType" ) );
|
||||
protected final boolean chevron = FlatUIUtils.isChevron( UIManager.getString( "Component.arrowType" ) );
|
||||
protected final Color sortIconColor = UIManager.getColor( "Table.sortIconColor" );
|
||||
|
||||
public FlatAscendingSortIcon() {
|
||||
|
||||
@@ -129,78 +129,101 @@ public class FlatCheckBoxIcon
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintIcon( Component c, Graphics2D g2 ) {
|
||||
boolean indeterminate = c instanceof JComponent && clientPropertyEquals( (JComponent) c, SELECTED_STATE, SELECTED_STATE_INDETERMINATE );
|
||||
boolean selected = indeterminate || (c instanceof AbstractButton && ((AbstractButton)c).isSelected());
|
||||
protected void paintIcon( Component c, Graphics2D g ) {
|
||||
boolean indeterminate = isIndeterminate( c );
|
||||
boolean selected = indeterminate || isSelected( c );
|
||||
boolean isFocused = FlatUIUtils.isPermanentFocusOwner( c );
|
||||
|
||||
// paint focused border
|
||||
if( isFocused && focusWidth > 0 && FlatButtonUI.isFocusPainted( c ) ) {
|
||||
g2.setColor( focusColor );
|
||||
paintFocusBorder( g2 );
|
||||
g.setColor( getFocusColor( c ) );
|
||||
paintFocusBorder( c, g );
|
||||
}
|
||||
|
||||
// paint border
|
||||
g2.setColor( FlatButtonUI.buttonStateColor( c,
|
||||
selected ? selectedBorderColor : borderColor,
|
||||
disabledBorderColor,
|
||||
selected && selectedFocusedBorderColor != null ? selectedFocusedBorderColor : focusedBorderColor,
|
||||
hoverBorderColor,
|
||||
null ) );
|
||||
paintBorder( g2 );
|
||||
g.setColor( getBorderColor( c, selected ) );
|
||||
paintBorder( c, g );
|
||||
|
||||
// paint background
|
||||
g2.setColor( FlatUIUtils.deriveColor( FlatButtonUI.buttonStateColor( c,
|
||||
selected ? selectedBackground : background,
|
||||
disabledBackground,
|
||||
(selected && selectedFocusedBackground != null) ? selectedFocusedBackground : focusedBackground,
|
||||
(selected && selectedHoverBackground != null) ? selectedHoverBackground : hoverBackground,
|
||||
(selected && selectedPressedBackground != null) ? selectedPressedBackground : pressedBackground ),
|
||||
background ) );
|
||||
paintBackground( g2 );
|
||||
g.setColor( FlatUIUtils.deriveColor( getBackground( c, selected ), background ) );
|
||||
paintBackground( c, g );
|
||||
|
||||
// paint checkmark
|
||||
if( selected || indeterminate ) {
|
||||
g2.setColor( c.isEnabled()
|
||||
? ((selected && isFocused && selectedFocusedCheckmarkColor != null)
|
||||
? selectedFocusedCheckmarkColor
|
||||
: checkmarkColor)
|
||||
: disabledCheckmarkColor );
|
||||
g.setColor( getCheckmarkColor( c, selected, isFocused ) );
|
||||
if( indeterminate )
|
||||
paintIndeterminate( g2 );
|
||||
paintIndeterminate( c, g );
|
||||
else
|
||||
paintCheckmark( g2 );
|
||||
paintCheckmark( c, g );
|
||||
}
|
||||
}
|
||||
|
||||
protected void paintFocusBorder( Graphics2D g2 ) {
|
||||
protected void paintFocusBorder( Component c, Graphics2D g ) {
|
||||
// the outline focus border is painted outside of the icon
|
||||
int wh = ICON_SIZE - 1 + (focusWidth * 2);
|
||||
int arcwh = arc + (focusWidth * 2);
|
||||
g2.fillRoundRect( -focusWidth + 1, -focusWidth, wh, wh, arcwh, arcwh );
|
||||
g.fillRoundRect( -focusWidth + 1, -focusWidth, wh, wh, arcwh, arcwh );
|
||||
}
|
||||
|
||||
protected void paintBorder( Graphics2D g2 ) {
|
||||
protected void paintBorder( Component c, Graphics2D g ) {
|
||||
int arcwh = arc;
|
||||
g2.fillRoundRect( 1, 0, 14, 14, arcwh, arcwh );
|
||||
g.fillRoundRect( 1, 0, 14, 14, arcwh, arcwh );
|
||||
}
|
||||
|
||||
protected void paintBackground( Graphics2D g2 ) {
|
||||
protected void paintBackground( Component c, Graphics2D g ) {
|
||||
int arcwh = arc - 1;
|
||||
g2.fillRoundRect( 2, 1, 12, 12, arcwh, arcwh );
|
||||
g.fillRoundRect( 2, 1, 12, 12, arcwh, arcwh );
|
||||
}
|
||||
|
||||
protected void paintCheckmark( Graphics2D g2 ) {
|
||||
protected void paintCheckmark( Component c, Graphics2D g ) {
|
||||
Path2D.Float path = new Path2D.Float();
|
||||
path.moveTo( 4.5f, 7.5f );
|
||||
path.lineTo( 6.6f, 10f );
|
||||
path.lineTo( 11.25f, 3.5f );
|
||||
|
||||
g2.setStroke( new BasicStroke( 1.9f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) );
|
||||
g2.draw( path );
|
||||
g.setStroke( new BasicStroke( 1.9f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) );
|
||||
g.draw( path );
|
||||
}
|
||||
|
||||
protected void paintIndeterminate( Graphics2D g2 ) {
|
||||
g2.fill( new RoundRectangle2D.Float( 3.75f, 5.75f, 8.5f, 2.5f, 2f, 2f ) );
|
||||
protected void paintIndeterminate( Component c, Graphics2D g ) {
|
||||
g.fill( new RoundRectangle2D.Float( 3.75f, 5.75f, 8.5f, 2.5f, 2f, 2f ) );
|
||||
}
|
||||
|
||||
protected boolean isIndeterminate( Component c ) {
|
||||
return c instanceof JComponent && clientPropertyEquals( (JComponent) c, SELECTED_STATE, SELECTED_STATE_INDETERMINATE );
|
||||
}
|
||||
|
||||
protected boolean isSelected( Component c ) {
|
||||
return c instanceof AbstractButton && ((AbstractButton)c).isSelected();
|
||||
}
|
||||
|
||||
protected Color getFocusColor( Component c ) {
|
||||
return focusColor;
|
||||
}
|
||||
|
||||
protected Color getBorderColor( Component c, boolean selected ) {
|
||||
return FlatButtonUI.buttonStateColor( c,
|
||||
selected ? selectedBorderColor : borderColor,
|
||||
disabledBorderColor,
|
||||
selected && selectedFocusedBorderColor != null ? selectedFocusedBorderColor : focusedBorderColor,
|
||||
hoverBorderColor,
|
||||
null );
|
||||
}
|
||||
|
||||
protected Color getBackground( Component c, boolean selected ) {
|
||||
return FlatButtonUI.buttonStateColor( c,
|
||||
selected ? selectedBackground : background,
|
||||
disabledBackground,
|
||||
(selected && selectedFocusedBackground != null) ? selectedFocusedBackground : focusedBackground,
|
||||
(selected && selectedHoverBackground != null) ? selectedHoverBackground : hoverBackground,
|
||||
(selected && selectedPressedBackground != null) ? selectedPressedBackground : pressedBackground );
|
||||
}
|
||||
|
||||
protected Color getCheckmarkColor( Component c, boolean selected, boolean isFocused ) {
|
||||
return c.isEnabled()
|
||||
? ((selected && isFocused && selectedFocusedCheckmarkColor != null)
|
||||
? selectedFocusedCheckmarkColor
|
||||
: checkmarkColor)
|
||||
: disabledCheckmarkColor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
/**
|
||||
* "descendingSort" icon for {@link javax.swing.table.JTableHeader}.
|
||||
*
|
||||
* @uiDefault Component.arrowType String triangle (default) or chevron
|
||||
* @uiDefault Component.arrowType String chevron (default) or triangle
|
||||
* @uiDefault Table.sortIconColor Color
|
||||
*
|
||||
* @author Karl Tauber
|
||||
@@ -35,7 +35,7 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
public class FlatDescendingSortIcon
|
||||
extends FlatAbstractIcon
|
||||
{
|
||||
protected final boolean chevron = "chevron".equals( UIManager.getString( "Component.arrowType" ) );
|
||||
protected final boolean chevron = FlatUIUtils.isChevron( UIManager.getString( "Component.arrowType" ) );
|
||||
protected final Color sortIconColor = UIManager.getColor( "Table.sortIconColor" );
|
||||
|
||||
public FlatDescendingSortIcon() {
|
||||
|
||||
@@ -28,7 +28,7 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
/**
|
||||
* "arrow" icon for {@link javax.swing.JMenu}.
|
||||
*
|
||||
* @uiDefault Component.arrowType String triangle (default) or chevron
|
||||
* @uiDefault Component.arrowType String chevron (default) or triangle
|
||||
* @uiDefault Menu.icon.arrowColor Color
|
||||
* @uiDefault Menu.icon.disabledArrowColor Color
|
||||
* @uiDefault Menu.selectionForeground Color
|
||||
@@ -39,7 +39,7 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
public class FlatMenuArrowIcon
|
||||
extends FlatAbstractIcon
|
||||
{
|
||||
protected final boolean chevron = "chevron".equals( UIManager.getString( "Component.arrowType" ) );
|
||||
protected final boolean chevron = FlatUIUtils.isChevron( UIManager.getString( "Component.arrowType" ) );
|
||||
protected final Color arrowColor = UIManager.getColor( "Menu.icon.arrowColor" );
|
||||
protected final Color disabledArrowColor = UIManager.getColor( "Menu.icon.disabledArrowColor" );
|
||||
protected final Color selectionForeground = UIManager.getColor( "Menu.selectionForeground" );
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.formdev.flatlaf.icons;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
|
||||
@@ -36,25 +37,25 @@ public class FlatRadioButtonIcon
|
||||
protected final int centerDiameter = getUIInt( "RadioButton.icon.centerDiameter", 8, style );
|
||||
|
||||
@Override
|
||||
protected void paintFocusBorder( Graphics2D g2 ) {
|
||||
protected void paintFocusBorder( Component c, Graphics2D g ) {
|
||||
// the outline focus border is painted outside of the icon
|
||||
int wh = ICON_SIZE + (focusWidth * 2);
|
||||
g2.fillOval( -focusWidth, -focusWidth, wh, wh );
|
||||
g.fillOval( -focusWidth, -focusWidth, wh, wh );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintBorder( Graphics2D g2 ) {
|
||||
g2.fillOval( 0, 0, 15, 15 );
|
||||
protected void paintBorder( Component c, Graphics2D g ) {
|
||||
g.fillOval( 0, 0, 15, 15 );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintBackground( Graphics2D g2 ) {
|
||||
g2.fillOval( 1, 1, 13, 13 );
|
||||
protected void paintBackground( Component c, Graphics2D g ) {
|
||||
g.fillOval( 1, 1, 13, 13 );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintCheckmark( Graphics2D g2 ) {
|
||||
protected void paintCheckmark( Component c, Graphics2D g ) {
|
||||
float xy = (ICON_SIZE - centerDiameter) / 2f;
|
||||
g2.fill( new Ellipse2D.Float( xy, xy, centerDiameter, centerDiameter ) );
|
||||
g.fill( new Ellipse2D.Float( xy, xy, centerDiameter, centerDiameter ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2020 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.icons;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Line2D;
|
||||
import java.awt.geom.Path2D;
|
||||
import javax.swing.UIManager;
|
||||
import com.formdev.flatlaf.ui.FlatButtonUI;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
|
||||
/**
|
||||
* "close" icon for closable tabs in {@link javax.swing.JTabbedPane}.
|
||||
*
|
||||
* @uiDefault TabbedPane.closeSize Dimension
|
||||
* @uiDefault TabbedPane.closeArc int
|
||||
* @uiDefault TabbedPane.closeCrossPlainSize float
|
||||
* @uiDefault TabbedPane.closeCrossFilledSize float
|
||||
* @uiDefault TabbedPane.closeCrossLineWidth float
|
||||
* @uiDefault TabbedPane.closeBackground Color
|
||||
* @uiDefault TabbedPane.closeForeground Color
|
||||
* @uiDefault TabbedPane.closeHoverBackground Color
|
||||
* @uiDefault TabbedPane.closeHoverForeground Color
|
||||
* @uiDefault TabbedPane.closePressedBackground Color
|
||||
* @uiDefault TabbedPane.closePressedForeground Color
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatTabbedPaneCloseIcon
|
||||
extends FlatAbstractIcon
|
||||
{
|
||||
protected final Dimension size = UIManager.getDimension( "TabbedPane.closeSize" );
|
||||
protected final int arc = UIManager.getInt( "TabbedPane.closeArc" );
|
||||
protected final float crossPlainSize = FlatUIUtils.getUIFloat( "TabbedPane.closeCrossPlainSize", 7.5f );
|
||||
protected final float crossFilledSize = FlatUIUtils.getUIFloat( "TabbedPane.closeCrossFilledSize", crossPlainSize );
|
||||
protected final float closeCrossLineWidth = FlatUIUtils.getUIFloat( "TabbedPane.closeCrossLineWidth", 1f );
|
||||
protected final Color background = UIManager.getColor( "TabbedPane.closeBackground" );
|
||||
protected final Color foreground = UIManager.getColor( "TabbedPane.closeForeground" );
|
||||
protected final Color hoverBackground = UIManager.getColor( "TabbedPane.closeHoverBackground" );
|
||||
protected final Color hoverForeground = UIManager.getColor( "TabbedPane.closeHoverForeground" );
|
||||
protected final Color pressedBackground = UIManager.getColor( "TabbedPane.closePressedBackground" );
|
||||
protected final Color pressedForeground = UIManager.getColor( "TabbedPane.closePressedForeground" );
|
||||
|
||||
public FlatTabbedPaneCloseIcon() {
|
||||
super( 16, 16, null );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintIcon( Component c, Graphics2D g ) {
|
||||
// paint background
|
||||
Color bg = FlatButtonUI.buttonStateColor( c, background, null, null, hoverBackground, pressedBackground );
|
||||
if( bg != null ) {
|
||||
g.setColor( FlatUIUtils.deriveColor( bg, c.getBackground() ) );
|
||||
g.fillRoundRect( (width - size.width) / 2, (height - size.height) / 2,
|
||||
size.width, size.height, arc, arc );
|
||||
}
|
||||
|
||||
// set cross color
|
||||
Color fg = FlatButtonUI.buttonStateColor( c, foreground, null, null, hoverForeground, pressedForeground );
|
||||
g.setColor( FlatUIUtils.deriveColor( fg, c.getForeground() ) );
|
||||
|
||||
float mx = width / 2;
|
||||
float my = height / 2;
|
||||
float r = ((bg != null) ? crossFilledSize : crossPlainSize) / 2;
|
||||
|
||||
// paint cross
|
||||
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
||||
path.append( new Line2D.Float( mx - r, my - r, mx + r, my + r ), false );
|
||||
path.append( new Line2D.Float( mx - r, my + r, mx + r, my - r ), false );
|
||||
g.setStroke( new BasicStroke( closeCrossLineWidth ) );
|
||||
g.draw( path );
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
/**
|
||||
* "collapsed" icon for {@link javax.swing.JTree}.
|
||||
*
|
||||
* @uiDefault Component.arrowType String triangle (default) or chevron
|
||||
* @uiDefault Component.arrowType String chevron (default) or triangle
|
||||
* @uiDefault Tree.icon.collapsedColor Color
|
||||
*
|
||||
* @author Karl Tauber
|
||||
@@ -41,7 +41,7 @@ public class FlatTreeCollapsedIcon
|
||||
|
||||
FlatTreeCollapsedIcon( Color color ) {
|
||||
super( 11, 11, color );
|
||||
chevron = "chevron".equals( UIManager.getString( "Component.arrowType" ) );
|
||||
chevron = FlatUIUtils.isChevron( UIManager.getString( "Component.arrowType" ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -42,12 +42,13 @@ public class FlatArrowButton
|
||||
{
|
||||
public static final int DEFAULT_ARROW_WIDTH = 8;
|
||||
|
||||
private final boolean chevron;
|
||||
private final Color foreground;
|
||||
private final Color disabledForeground;
|
||||
private final Color hoverForeground;
|
||||
private final Color hoverBackground;
|
||||
private final Color pressedBackground;
|
||||
protected final boolean chevron;
|
||||
protected final Color foreground;
|
||||
protected final Color disabledForeground;
|
||||
protected final Color hoverForeground;
|
||||
protected final Color hoverBackground;
|
||||
protected final Color pressedForeground;
|
||||
protected final Color pressedBackground;
|
||||
|
||||
private int arrowWidth = DEFAULT_ARROW_WIDTH;
|
||||
private int xOffset = 0;
|
||||
@@ -64,14 +65,21 @@ public class FlatArrowButton
|
||||
|
||||
public FlatArrowButton( int direction, String type, Color foreground, Color disabledForeground,
|
||||
Color hoverForeground, Color hoverBackground, Color pressedBackground )
|
||||
{
|
||||
this( direction, type, foreground, disabledForeground, hoverForeground, hoverBackground, null, pressedBackground );
|
||||
}
|
||||
|
||||
public FlatArrowButton( int direction, String type, Color foreground, Color disabledForeground,
|
||||
Color hoverForeground, Color hoverBackground, Color pressedForeground, Color pressedBackground )
|
||||
{
|
||||
super( direction, Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE );
|
||||
|
||||
this.chevron = "chevron".equals( type );
|
||||
this.chevron = FlatUIUtils.isChevron( type );
|
||||
this.foreground = foreground;
|
||||
this.disabledForeground = disabledForeground;
|
||||
this.hoverForeground = hoverForeground;
|
||||
this.hoverBackground = hoverBackground;
|
||||
this.pressedForeground = pressedForeground;
|
||||
this.pressedBackground = pressedBackground;
|
||||
|
||||
setOpaque( false );
|
||||
@@ -142,6 +150,10 @@ public class FlatArrowButton
|
||||
return background;
|
||||
}
|
||||
|
||||
protected Color deriveForeground( Color foreground ) {
|
||||
return foreground;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
return scale( super.getPreferredSize() );
|
||||
@@ -154,27 +166,40 @@ public class FlatArrowButton
|
||||
|
||||
@Override
|
||||
public void paint( Graphics g ) {
|
||||
Graphics2D g2 = (Graphics2D)g;
|
||||
FlatUIUtils.setRenderingHints( g2 );
|
||||
|
||||
int width = getWidth();
|
||||
int height = getHeight();
|
||||
boolean enabled = isEnabled();
|
||||
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g );
|
||||
|
||||
// paint hover or pressed background
|
||||
if( enabled ) {
|
||||
if( isEnabled() ) {
|
||||
Color background = (pressedBackground != null && isPressed())
|
||||
? deriveBackground( pressedBackground )
|
||||
: ((hoverBackground != null && isHover())
|
||||
? deriveBackground( hoverBackground )
|
||||
? pressedBackground
|
||||
: (hoverBackground != null && isHover()
|
||||
? hoverBackground
|
||||
: null);
|
||||
|
||||
if( background != null ) {
|
||||
g.setColor( background );
|
||||
g.fillRect( 0, 0, width, height );
|
||||
g.setColor( deriveBackground( background ) );
|
||||
paintBackground( (Graphics2D) g );
|
||||
}
|
||||
}
|
||||
|
||||
// paint arrow
|
||||
g.setColor( deriveForeground( isEnabled()
|
||||
? (pressedForeground != null && isPressed()
|
||||
? pressedForeground
|
||||
: (hoverForeground != null && isHover()
|
||||
? hoverForeground
|
||||
: foreground))
|
||||
: disabledForeground ) );
|
||||
paintArrow( (Graphics2D) g );
|
||||
|
||||
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
|
||||
}
|
||||
|
||||
protected void paintBackground( Graphics2D g ) {
|
||||
g.fillRect( 0, 0, getWidth(), getHeight() );
|
||||
}
|
||||
|
||||
protected void paintArrow( Graphics2D g ) {
|
||||
int direction = getDirection();
|
||||
boolean vert = (direction == NORTH || direction == SOUTH);
|
||||
|
||||
@@ -193,8 +218,8 @@ public class FlatArrowButton
|
||||
rh++;
|
||||
}
|
||||
|
||||
int x = Math.round( (width - rw) / 2f + scale( (float) xOffset ) );
|
||||
int y = Math.round( (height - rh) / 2f + scale( (float) yOffset ) );
|
||||
int x = Math.round( (getWidth() - rw) / 2f + scale( (float) xOffset ) );
|
||||
int y = Math.round( (getHeight() - rh) / 2f + scale( (float) yOffset ) );
|
||||
|
||||
// move arrow for round borders
|
||||
Container parent = getParent();
|
||||
@@ -202,20 +227,17 @@ public class FlatArrowButton
|
||||
x -= scale( parent.getComponentOrientation().isLeftToRight() ? 1 : -1 );
|
||||
|
||||
// paint arrow
|
||||
g.setColor( enabled
|
||||
? (isHover() && hoverForeground != null ? hoverForeground : foreground)
|
||||
: disabledForeground );
|
||||
g.translate( x, y );
|
||||
/*debug
|
||||
debugPaint( g2, vert, rw, rh );
|
||||
debugPaint( g, vert, rw, rh );
|
||||
debug*/
|
||||
Shape arrowShape = createArrowShape( direction, chevron, w, h );
|
||||
if( chevron ) {
|
||||
g2.setStroke( new BasicStroke( scale( 1f ) ) );
|
||||
g2.draw( arrowShape );
|
||||
g.setStroke( new BasicStroke( scale( 1f ) ) );
|
||||
g.draw( arrowShape );
|
||||
} else {
|
||||
// triangle
|
||||
g2.fill( arrowShape );
|
||||
g.fill( arrowShape );
|
||||
}
|
||||
g.translate( -x, -y );
|
||||
}
|
||||
|
||||
@@ -43,24 +43,24 @@ import com.formdev.flatlaf.util.DerivedColor;
|
||||
* Border for various components (e.g. {@link javax.swing.JTextField}).
|
||||
*
|
||||
* There is empty space around the component border, if Component.focusWidth is greater than zero,
|
||||
* which is used to paint focus border.
|
||||
* which is used to paint outer focus border.
|
||||
*
|
||||
* Because there is empty space (if focus border is not painted),
|
||||
* Because there is empty space (if outer focus border is not painted),
|
||||
* UI delegates that use this border (or subclasses) must invoke
|
||||
* {@link FlatUIUtils#paintParentBackground} to paint the empty space correctly.
|
||||
*
|
||||
* @uiDefault Component.focusWidth int
|
||||
* @uiDefault Component.innerFocusWidth int or float
|
||||
* @uiDefault Component.focusColor Color
|
||||
* @uiDefault Component.borderColor Color
|
||||
* @uiDefault Component.disabledBorderColor Color
|
||||
* @uiDefault Component.focusedBorderColor Color
|
||||
* @uiDefault Component.focusWidth int
|
||||
* @uiDefault Component.innerFocusWidth int or float
|
||||
* @uiDefault Component.focusColor Color
|
||||
* @uiDefault Component.borderColor Color
|
||||
* @uiDefault Component.disabledBorderColor Color
|
||||
* @uiDefault Component.focusedBorderColor Color
|
||||
*
|
||||
* @uiDefault Component.error.borderColor Color
|
||||
* @uiDefault Component.error.focusedBorderColor Color
|
||||
* @uiDefault Component.warning.borderColor Color
|
||||
* @uiDefault Component.warning.focusedBorderColor Color
|
||||
* @uiDefault Component.custom.borderColor Color
|
||||
* @uiDefault Component.error.borderColor Color
|
||||
* @uiDefault Component.error.focusedBorderColor Color
|
||||
* @uiDefault Component.warning.borderColor Color
|
||||
* @uiDefault Component.warning.focusedBorderColor Color
|
||||
* @uiDefault Component.custom.borderColor Color
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
@@ -87,22 +87,23 @@ public class FlatBorder
|
||||
try {
|
||||
FlatUIUtils.setRenderingHints( g2 );
|
||||
|
||||
boolean isCellEditor = isTableCellEditor( c );
|
||||
float focusWidth = isCellEditor ? 0 : scale( (float) getFocusWidth( c ) );
|
||||
float focusWidth = scale( (float) getFocusWidth( c ) );
|
||||
float borderWidth = scale( (float) getBorderWidth( c ) );
|
||||
float arc = isCellEditor ? 0 : scale( (float) getArc( c ) );
|
||||
float arc = scale( (float) getArc( c ) );
|
||||
Color outlineColor = getOutlineColor( c );
|
||||
|
||||
// paint outer border
|
||||
if( outlineColor != null || isFocused( c ) ) {
|
||||
float innerFocusWidth = !(c instanceof JScrollPane)
|
||||
? (outlineColor != null ? innerOutlineWidth : this.innerFocusWidth)
|
||||
float innerWidth = !isCellEditor( c ) && !(c instanceof JScrollPane)
|
||||
? (outlineColor != null ? innerOutlineWidth : innerFocusWidth)
|
||||
: 0;
|
||||
|
||||
g2.setColor( (outlineColor != null) ? outlineColor : getFocusColor( c ) );
|
||||
FlatUIUtils.paintComponentOuterBorder( g2, x, y, width, height, focusWidth,
|
||||
scale( (float) getLineWidth( c ) ) + scale( innerFocusWidth ), arc );
|
||||
FlatUIUtils.paintComponentOuterBorder( g2, x, y, width, height,
|
||||
focusWidth, borderWidth + scale( innerWidth ), arc );
|
||||
}
|
||||
|
||||
// paint border
|
||||
g2.setPaint( (outlineColor != null) ? outlineColor : getBorderColor( c ) );
|
||||
FlatUIUtils.paintComponentBorder( g2, x, y, width, height, focusWidth, borderWidth, arc );
|
||||
} finally {
|
||||
@@ -110,6 +111,10 @@ public class FlatBorder
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the outline color of the component border specified in client property
|
||||
* {@link FlatClientProperties#OUTLINE}.
|
||||
*/
|
||||
protected Color getOutlineColor( Component c ) {
|
||||
if( !(c instanceof JComponent) )
|
||||
return null;
|
||||
@@ -192,14 +197,13 @@ public class FlatBorder
|
||||
return FlatUIUtils.isPermanentFocusOwner( c );
|
||||
}
|
||||
|
||||
protected boolean isTableCellEditor( Component c ) {
|
||||
return FlatUIUtils.isTableCellEditor( c );
|
||||
protected boolean isCellEditor( Component c ) {
|
||||
return FlatUIUtils.isCellEditor( c );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Insets getBorderInsets( Component c, Insets insets ) {
|
||||
boolean isCellEditor = isTableCellEditor( c );
|
||||
float focusWidth = isCellEditor ? 0 : scale( (float) getFocusWidth( c ) );
|
||||
float focusWidth = scale( (float) getFocusWidth( c ) );
|
||||
float ow = focusWidth + scale( (float) getLineWidth( c ) );
|
||||
|
||||
insets = super.getBorderInsets( c, insets );
|
||||
@@ -207,6 +211,18 @@ public class FlatBorder
|
||||
insets.left = Math.round( scale( (float) insets.left ) + ow );
|
||||
insets.bottom = Math.round( scale( (float) insets.bottom ) + ow );
|
||||
insets.right = Math.round( scale( (float) insets.right ) + ow );
|
||||
|
||||
if( isCellEditor( c ) ) {
|
||||
// remove top and bottom insets if used as cell editor
|
||||
insets.top = insets.bottom = 0;
|
||||
|
||||
// remove right/left insets to avoid that text is truncated (e.g. in file chooser)
|
||||
if( c.getComponentOrientation().isLeftToRight() )
|
||||
insets.right = 0;
|
||||
else
|
||||
insets.left = 0;
|
||||
}
|
||||
|
||||
return insets;
|
||||
}
|
||||
|
||||
@@ -214,6 +230,9 @@ public class FlatBorder
|
||||
* Returns the (unscaled) thickness of the outer focus border.
|
||||
*/
|
||||
protected int getFocusWidth( Component c ) {
|
||||
if( isCellEditor( c ) )
|
||||
return 0;
|
||||
|
||||
return focusWidth;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault Button.default.hoverBorderColor Color optional
|
||||
* @uiDefault Button.default.focusedBorderColor Color
|
||||
* @uiDefault Button.default.focusColor Color
|
||||
* @uiDefault Button.borderWidth int
|
||||
* @uiDefault Button.default.borderWidth int
|
||||
* @uiDefault Button.toolbar.margin Insets
|
||||
* @uiDefault Button.toolbar.spacingInsets Insets
|
||||
@@ -62,6 +63,7 @@ public class FlatButtonBorder
|
||||
protected final Color defaultHoverBorderColor = UIManager.getColor( "Button.default.hoverBorderColor" );
|
||||
protected final Color defaultFocusedBorderColor = UIManager.getColor( "Button.default.focusedBorderColor" );
|
||||
protected final Color defaultFocusColor = UIManager.getColor( "Button.default.focusColor" );
|
||||
protected final int borderWidth = UIManager.getInt( "Button.borderWidth" );
|
||||
protected final int defaultBorderWidth = UIManager.getInt( "Button.default.borderWidth" );
|
||||
protected final Insets toolbarMargin = UIManager.getInsets( "Button.toolbar.margin" );
|
||||
protected final Insets toolbarSpacingInsets = UIManager.getInsets( "Button.toolbar.spacingInsets" );
|
||||
@@ -134,11 +136,14 @@ public class FlatButtonBorder
|
||||
|
||||
@Override
|
||||
protected int getBorderWidth( Component c ) {
|
||||
return FlatButtonUI.isDefaultButton( c ) ? defaultBorderWidth : super.getBorderWidth( c );
|
||||
return FlatButtonUI.isDefaultButton( c ) ? defaultBorderWidth : borderWidth;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getArc( Component c ) {
|
||||
if( isCellEditor( c ) )
|
||||
return 0;
|
||||
|
||||
switch( FlatButtonUI.getButtonType( c ) ) {
|
||||
case FlatButtonUI.TYPE_SQUARE: return 0;
|
||||
case FlatButtonUI.TYPE_ROUND_RECT: return Short.MAX_VALUE;
|
||||
|
||||
@@ -67,8 +67,11 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault Button.focusedBackground Color optional
|
||||
* @uiDefault Button.hoverBackground Color optional
|
||||
* @uiDefault Button.pressedBackground Color optional
|
||||
* @uiDefault Button.selectedBackground Color
|
||||
* @uiDefault Button.selectedForeground Color
|
||||
* @uiDefault Button.disabledBackground Color optional
|
||||
* @uiDefault Button.disabledText Color
|
||||
* @uiDefault Button.disabledSelectedBackground Color
|
||||
* @uiDefault Button.default.background Color
|
||||
* @uiDefault Button.default.startBackground Color optional; if set, a gradient paint is used and Button.default.background is ignored
|
||||
* @uiDefault Button.default.endBackground Color optional; if set, a gradient paint is used
|
||||
@@ -84,6 +87,7 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault Button.toolbar.spacingInsets Insets
|
||||
* @uiDefault Button.toolbar.hoverBackground Color
|
||||
* @uiDefault Button.toolbar.pressedBackground Color
|
||||
* @uiDefault Button.toolbar.selectedBackground Color
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
@@ -101,8 +105,11 @@ public class FlatButtonUI
|
||||
protected Color focusedBackground;
|
||||
protected Color hoverBackground;
|
||||
protected Color pressedBackground;
|
||||
protected Color selectedBackground;
|
||||
protected Color selectedForeground;
|
||||
protected Color disabledBackground;
|
||||
protected Color disabledText;
|
||||
protected Color disabledSelectedBackground;
|
||||
|
||||
protected Color defaultBackground;
|
||||
protected Color defaultEndBackground;
|
||||
@@ -119,17 +126,14 @@ public class FlatButtonUI
|
||||
protected Insets toolbarSpacingInsets;
|
||||
protected Color toolbarHoverBackground;
|
||||
protected Color toolbarPressedBackground;
|
||||
protected Color toolbarSelectedBackground;
|
||||
|
||||
private Icon helpButtonIcon;
|
||||
|
||||
private boolean defaults_initialized = false;
|
||||
|
||||
private static ComponentUI instance;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
if( instance == null )
|
||||
instance = new FlatButtonUI();
|
||||
return instance;
|
||||
return FlatUIUtils.createSharedUI( FlatButtonUI.class, FlatButtonUI::new );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -150,8 +154,11 @@ public class FlatButtonUI
|
||||
focusedBackground = UIManager.getColor( prefix + "focusedBackground" );
|
||||
hoverBackground = UIManager.getColor( prefix + "hoverBackground" );
|
||||
pressedBackground = UIManager.getColor( prefix + "pressedBackground" );
|
||||
selectedBackground = UIManager.getColor( prefix + "selectedBackground" );
|
||||
selectedForeground = UIManager.getColor( prefix + "selectedForeground" );
|
||||
disabledBackground = UIManager.getColor( prefix + "disabledBackground" );
|
||||
disabledText = UIManager.getColor( prefix + "disabledText" );
|
||||
disabledSelectedBackground = UIManager.getColor( prefix + "disabledSelectedBackground" );
|
||||
|
||||
if( UIManager.getBoolean( "Button.paintShadow" ) ) {
|
||||
shadowWidth = FlatUIUtils.getUIInt( "Button.shadowWidth", 2 );
|
||||
@@ -174,6 +181,7 @@ public class FlatButtonUI
|
||||
toolbarSpacingInsets = UIManager.getInsets( "Button.toolbar.spacingInsets" );
|
||||
toolbarHoverBackground = UIManager.getColor( prefix + "toolbar.hoverBackground" );
|
||||
toolbarPressedBackground = UIManager.getColor( prefix + "toolbar.pressedBackground" );
|
||||
toolbarSelectedBackground = UIManager.getColor( prefix + "toolbar.selectedBackground" );
|
||||
|
||||
helpButtonIcon = UIManager.getIcon( "HelpButton.icon" );
|
||||
|
||||
@@ -246,15 +254,23 @@ public class FlatButtonUI
|
||||
(icon == null && text != null && ("...".equals( text ) || text.length() == 1));
|
||||
}
|
||||
|
||||
// same indices as in parameters to clientPropertyChoice()
|
||||
static final int TYPE_OTHER = -1;
|
||||
static final int TYPE_SQUARE = 0;
|
||||
static final int TYPE_ROUND_RECT = 1;
|
||||
|
||||
static int getButtonType( Component c ) {
|
||||
return (c instanceof AbstractButton)
|
||||
? clientPropertyChoice( (AbstractButton) c, BUTTON_TYPE, BUTTON_TYPE_SQUARE, BUTTON_TYPE_ROUND_RECT )
|
||||
: TYPE_OTHER;
|
||||
if( !(c instanceof AbstractButton) )
|
||||
return TYPE_OTHER;
|
||||
|
||||
Object value = ((AbstractButton)c).getClientProperty( BUTTON_TYPE );
|
||||
if( !(value instanceof String) )
|
||||
return TYPE_OTHER;
|
||||
|
||||
switch( (String) value ) {
|
||||
case BUTTON_TYPE_SQUARE: return TYPE_SQUARE;
|
||||
case BUTTON_TYPE_ROUND_RECT: return TYPE_ROUND_RECT;
|
||||
default: return TYPE_OTHER;
|
||||
}
|
||||
}
|
||||
|
||||
static boolean isHelpButton( Component c ) {
|
||||
@@ -369,6 +385,17 @@ public class FlatButtonUI
|
||||
}
|
||||
|
||||
protected Color getBackground( JComponent c ) {
|
||||
if( ((AbstractButton)c).isSelected() ) {
|
||||
// in toolbar use same colors for disabled and enabled because
|
||||
// we assume that toolbar icon is shown disabled
|
||||
boolean toolBarButton = isToolBarButton( c );
|
||||
return buttonStateColor( c,
|
||||
toolBarButton ? toolbarSelectedBackground : selectedBackground,
|
||||
toolBarButton ? toolbarSelectedBackground : disabledSelectedBackground,
|
||||
null, null,
|
||||
toolBarButton ? toolbarPressedBackground : pressedBackground );
|
||||
}
|
||||
|
||||
if( !c.isEnabled() )
|
||||
return disabledBackground;
|
||||
|
||||
@@ -430,6 +457,9 @@ public class FlatButtonUI
|
||||
if( !c.isEnabled() )
|
||||
return disabledText;
|
||||
|
||||
if( ((AbstractButton)c).isSelected() && !isToolBarButton( c ) )
|
||||
return selectedForeground;
|
||||
|
||||
// use component foreground if explicitly set
|
||||
Color fg = c.getForeground();
|
||||
if( isCustomForeground( fg ) )
|
||||
|
||||
@@ -36,13 +36,15 @@ public class FlatCaret
|
||||
implements UIResource
|
||||
{
|
||||
private final String selectAllOnFocusPolicy;
|
||||
private final boolean selectAllOnMouseClick;
|
||||
|
||||
private boolean wasFocused;
|
||||
private boolean wasTemporaryLost;
|
||||
private boolean isMousePressed;
|
||||
|
||||
public FlatCaret( String selectAllOnFocusPolicy ) {
|
||||
public FlatCaret( String selectAllOnFocusPolicy, boolean selectAllOnMouseClick ) {
|
||||
this.selectAllOnFocusPolicy = selectAllOnFocusPolicy;
|
||||
this.selectAllOnMouseClick = selectAllOnMouseClick;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -61,7 +63,7 @@ public class FlatCaret
|
||||
|
||||
@Override
|
||||
public void focusGained( FocusEvent e ) {
|
||||
if( !wasTemporaryLost && !isMousePressed )
|
||||
if( !wasTemporaryLost && (!isMousePressed || selectAllOnMouseClick) )
|
||||
selectAllOnFocusGained();
|
||||
wasTemporaryLost = false;
|
||||
wasFocused = true;
|
||||
|
||||
@@ -42,12 +42,8 @@ import javax.swing.plaf.ComponentUI;
|
||||
public class FlatCheckBoxUI
|
||||
extends FlatRadioButtonUI
|
||||
{
|
||||
private static ComponentUI instance;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
if( instance == null )
|
||||
instance = new FlatCheckBoxUI();
|
||||
return instance;
|
||||
return FlatUIUtils.createSharedUI( FlatCheckBoxUI.class, FlatCheckBoxUI::new );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -24,10 +24,12 @@ import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.Insets;
|
||||
import java.awt.LayoutManager;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Shape;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.FocusEvent;
|
||||
@@ -47,6 +49,7 @@ import javax.swing.JComboBox;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollBar;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.ListCellRenderer;
|
||||
@@ -82,7 +85,7 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault ComboBox.editorColumns int
|
||||
* @uiDefault ComboBox.maximumRowCount int
|
||||
* @uiDefault ComboBox.buttonStyle String auto (default), button or none
|
||||
* @uiDefault Component.arrowType String triangle (default) or chevron
|
||||
* @uiDefault Component.arrowType String chevron (default) or triangle
|
||||
* @uiDefault Component.isIntelliJTheme boolean
|
||||
* @uiDefault Component.borderColor Color
|
||||
* @uiDefault Component.disabledBorderColor Color
|
||||
@@ -297,6 +300,10 @@ public class FlatComboBoxUI
|
||||
protected void configureEditor() {
|
||||
super.configureEditor();
|
||||
|
||||
// remove default text field border from editor
|
||||
if( editor instanceof JTextField && ((JTextField)editor).getBorder() instanceof FlatTextBorder )
|
||||
((JTextField)editor).setBorder( BorderFactory.createEmptyBorder() );
|
||||
|
||||
// explicitly make non-opaque
|
||||
if( editor instanceof JComponent )
|
||||
((JComponent)editor).setOpaque( false );
|
||||
@@ -306,7 +313,7 @@ public class FlatComboBoxUI
|
||||
updateEditorColors();
|
||||
|
||||
// macOS
|
||||
if( SystemInfo.IS_MAC && editor instanceof JTextComponent ) {
|
||||
if( SystemInfo.isMacOS && editor instanceof JTextComponent ) {
|
||||
// delegate actions from editor text field to combobox, which is necessary
|
||||
// because text field on macOS already handle those keys
|
||||
InputMap inputMap = ((JTextComponent)editor).getInputMap();
|
||||
@@ -345,7 +352,7 @@ public class FlatComboBoxUI
|
||||
FlatUIUtils.paintParentBackground( g, c );
|
||||
|
||||
Graphics2D g2 = (Graphics2D) g;
|
||||
FlatUIUtils.setRenderingHints( g2 );
|
||||
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g2 );
|
||||
|
||||
int width = c.getWidth();
|
||||
int height = c.getHeight();
|
||||
@@ -379,6 +386,9 @@ public class FlatComboBoxUI
|
||||
g2.fill( new Rectangle2D.Float( lx, focusWidth, lw, height - 1 - (focusWidth * 2)) );
|
||||
}
|
||||
|
||||
// avoid that the "current value" renderer is invoked with enabled antialiasing
|
||||
FlatUIUtils.resetRenderingHints( g2, oldRenderingHints );
|
||||
|
||||
paint( g, c );
|
||||
}
|
||||
|
||||
@@ -544,13 +554,37 @@ public class FlatComboBoxUI
|
||||
|
||||
@Override
|
||||
protected Rectangle computePopupBounds( int px, int py, int pw, int ph ) {
|
||||
// get maximum display size of all items
|
||||
Dimension displaySize = getDisplaySize();
|
||||
// get maximum display width of all items
|
||||
int displayWidth = getDisplaySize().width;
|
||||
|
||||
// add border insets
|
||||
for( Border border : new Border[] { scroller.getViewportBorder(), scroller.getBorder() } ) {
|
||||
if( border != null ) {
|
||||
Insets borderInsets = border.getBorderInsets( null );
|
||||
displayWidth += borderInsets.left + borderInsets.right;
|
||||
}
|
||||
}
|
||||
|
||||
// add width of vertical scroll bar
|
||||
JScrollBar verticalScrollBar = scroller.getVerticalScrollBar();
|
||||
if( verticalScrollBar != null )
|
||||
displayWidth += verticalScrollBar.getPreferredSize().width;
|
||||
|
||||
// make popup wider if necessary
|
||||
if( displaySize.width > pw ) {
|
||||
int diff = displaySize.width - pw;
|
||||
pw = displaySize.width;
|
||||
if( displayWidth > pw ) {
|
||||
// limit popup width to screen width
|
||||
GraphicsConfiguration gc = comboBox.getGraphicsConfiguration();
|
||||
if( gc != null ) {
|
||||
Rectangle screenBounds = gc.getBounds();
|
||||
Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets( gc );
|
||||
displayWidth = Math.min( displayWidth, screenBounds.width - screenInsets.left - screenInsets.right );
|
||||
} else {
|
||||
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
|
||||
displayWidth = Math.min( displayWidth, screenSize.width );
|
||||
}
|
||||
|
||||
int diff = displayWidth - pw;
|
||||
pw = displayWidth;
|
||||
|
||||
if( !comboBox.getComponentOrientation().isLeftToRight() )
|
||||
px -= diff;
|
||||
|
||||
@@ -57,4 +57,8 @@ public class FlatEmptyBorder
|
||||
insets.bottom = scale( bottom );
|
||||
return insets;
|
||||
}
|
||||
|
||||
public Insets getUnscaledBorderInsets() {
|
||||
return super.getBorderInsets();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ import javax.swing.plaf.ComponentUI;
|
||||
* @uiDefault Component.isIntelliJTheme boolean
|
||||
* @uiDefault FormattedTextField.placeholderForeground Color
|
||||
* @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always
|
||||
* @uiDefault TextComponent.selectAllOnMouseClick boolean
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
|
||||
@@ -92,7 +92,21 @@ public class FlatInternalFrameTitlePane
|
||||
updateFrameIcon();
|
||||
updateColors();
|
||||
|
||||
buttonPanel = new JPanel();
|
||||
buttonPanel = new JPanel() {
|
||||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
Dimension size = super.getPreferredSize();
|
||||
int height = size.height;
|
||||
// use height of invisible buttons to always have same title pane height
|
||||
if( !iconButton.isVisible() )
|
||||
height = Math.max( height, iconButton.getPreferredSize().height );
|
||||
if( !maxButton.isVisible() )
|
||||
height = Math.max( height, maxButton.getPreferredSize().height );
|
||||
if( !closeButton.isVisible() )
|
||||
height = Math.max( height, closeButton.getPreferredSize().height );
|
||||
return new Dimension( size.width, height );
|
||||
}
|
||||
};
|
||||
buttonPanel.setLayout( new BoxLayout( buttonPanel, BoxLayout.LINE_AXIS ) );
|
||||
buttonPanel.setOpaque( false );
|
||||
|
||||
|
||||
@@ -84,6 +84,8 @@ import javax.swing.plaf.basic.BasicInternalFrameUI;
|
||||
public class FlatInternalFrameUI
|
||||
extends BasicInternalFrameUI
|
||||
{
|
||||
protected FlatWindowResizer windowResizer;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatInternalFrameUI( (JInternalFrame) c );
|
||||
}
|
||||
@@ -97,6 +99,18 @@ public class FlatInternalFrameUI
|
||||
super.installUI( c );
|
||||
|
||||
LookAndFeel.installProperty( frame, "opaque", false );
|
||||
|
||||
windowResizer = createWindowResizer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uninstallUI( JComponent c ) {
|
||||
super.uninstallUI( c );
|
||||
|
||||
if( windowResizer != null ) {
|
||||
windowResizer.uninstall();
|
||||
windowResizer = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -104,6 +118,10 @@ public class FlatInternalFrameUI
|
||||
return new FlatInternalFrameTitlePane( w );
|
||||
}
|
||||
|
||||
protected FlatWindowResizer createWindowResizer() {
|
||||
return new FlatWindowResizer.InternalFrameResizer( frame, this::getDesktopManager );
|
||||
}
|
||||
|
||||
//---- class FlatInternalFrameBorder --------------------------------------
|
||||
|
||||
public static class FlatInternalFrameBorder
|
||||
|
||||
@@ -56,12 +56,8 @@ public class FlatLabelUI
|
||||
|
||||
private boolean defaults_initialized = false;
|
||||
|
||||
private static ComponentUI instance;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
if( instance == null )
|
||||
instance = new FlatLabelUI();
|
||||
return instance;
|
||||
return FlatUIUtils.createSharedUI( FlatLabelUI.class, FlatLabelUI::new );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -126,6 +126,9 @@ public class FlatListUI
|
||||
* or the application has to be changed to extend a FlatLaf renderer.
|
||||
*/
|
||||
private void toggleSelectionColors() {
|
||||
if( list == null )
|
||||
return;
|
||||
|
||||
if( FlatUIUtils.isPermanentFocusOwner( list ) ) {
|
||||
if( list.getSelectionBackground() == selectionInactiveBackground )
|
||||
list.setSelectionBackground( selectionBackground );
|
||||
|
||||
@@ -20,9 +20,7 @@ import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.UIManager;
|
||||
|
||||
@@ -40,16 +38,8 @@ public class FlatMenuBarBorder
|
||||
|
||||
@Override
|
||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
try {
|
||||
float lineHeight = scale( (float) 1 );
|
||||
|
||||
FlatUIUtils.setRenderingHints( g2 );
|
||||
g2.setColor( borderColor );
|
||||
g2.fill( new Rectangle2D.Float( x, y + height - lineHeight, width, lineHeight ) );
|
||||
} finally {
|
||||
g2.dispose();
|
||||
}
|
||||
float lineHeight = scale( (float) 1 );
|
||||
FlatUIUtils.paintFilledRectangle( g, borderColor, x, y + height - lineHeight, width, lineHeight );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -82,7 +82,7 @@ public class FlatMenuBarUI
|
||||
JMenuBar menuBar = (JMenuBar) e.getSource();
|
||||
JMenu menu = menuBar.getMenu( 0 );
|
||||
if( menu != null ) {
|
||||
MenuSelectionManager.defaultManager().setSelectedPath( SystemInfo.IS_WINDOWS
|
||||
MenuSelectionManager.defaultManager().setSelectedPath( SystemInfo.isWindows
|
||||
? new MenuElement[] { menuBar, menu }
|
||||
: new MenuElement[] { menuBar, menu, menu.getPopupMenu() } );
|
||||
|
||||
|
||||
@@ -39,8 +39,10 @@ import javax.swing.UIManager;
|
||||
import javax.swing.plaf.basic.BasicHTML;
|
||||
import javax.swing.text.View;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.util.DerivedColor;
|
||||
import com.formdev.flatlaf.util.Graphics2DProxy;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
|
||||
/**
|
||||
* Renderer for menu items.
|
||||
@@ -54,7 +56,7 @@ import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
* @uiDefault MenuItem.underlineSelectionBackground Color
|
||||
* @uiDefault MenuItem.underlineSelectionCheckBackground Color
|
||||
* @uiDefault MenuItem.underlineSelectionColor Color
|
||||
* @uiDefault MenuItem.underlineSelectionHeight Color
|
||||
* @uiDefault MenuItem.underlineSelectionHeight int
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
@@ -245,8 +247,11 @@ public class FlatMenuItemRenderer
|
||||
g.setColor( Color.orange ); g.drawRect( arrowRect.x, arrowRect.y, arrowRect.width - 1, arrowRect.height - 1 );
|
||||
debug*/
|
||||
|
||||
paintBackground( g, selectionBackground );
|
||||
paintIcon( g, iconRect, getIconForPainting() );
|
||||
boolean underlineSelection = isUnderlineSelection();
|
||||
paintBackground( g, underlineSelection ? underlineSelectionBackground : selectionBackground );
|
||||
if( underlineSelection && isArmedOrSelected( menuItem ) )
|
||||
paintUnderlineSelection( g, underlineSelectionColor, underlineSelectionHeight );
|
||||
paintIcon( g, iconRect, getIconForPainting(), underlineSelection ? underlineSelectionCheckBackground : checkBackground );
|
||||
paintText( g, textRect, menuItem.getText(), selectionForeground, disabledForeground );
|
||||
paintAccelerator( g, accelRect, getAcceleratorText(), acceleratorForeground, acceleratorSelectionForeground, disabledForeground );
|
||||
if( !isTopLevelMenu( menuItem ) )
|
||||
@@ -256,36 +261,36 @@ debug*/
|
||||
protected void paintBackground( Graphics g, Color selectionBackground ) {
|
||||
boolean armedOrSelected = isArmedOrSelected( menuItem );
|
||||
if( menuItem.isOpaque() || armedOrSelected ) {
|
||||
int width = menuItem.getWidth();
|
||||
int height = menuItem.getHeight();
|
||||
|
||||
// paint background
|
||||
g.setColor( armedOrSelected
|
||||
? (isUnderlineSelection()
|
||||
? deriveBackground( underlineSelectionBackground )
|
||||
: selectionBackground)
|
||||
? deriveBackground( selectionBackground )
|
||||
: menuItem.getBackground() );
|
||||
g.fillRect( 0, 0, width, height );
|
||||
g.fillRect( 0, 0, menuItem.getWidth(), menuItem.getHeight() );
|
||||
}
|
||||
}
|
||||
|
||||
// paint underline
|
||||
if( armedOrSelected && isUnderlineSelection() ) {
|
||||
int underlineHeight = scale( underlineSelectionHeight );
|
||||
g.setColor( underlineSelectionColor );
|
||||
if( isTopLevelMenu( menuItem ) ) {
|
||||
// paint underline at bottom
|
||||
g.fillRect( 0, height - underlineHeight, width, underlineHeight );
|
||||
} else if( menuItem.getComponentOrientation().isLeftToRight() ) {
|
||||
// paint underline at left side
|
||||
g.fillRect( 0, 0, underlineHeight, height );
|
||||
} else {
|
||||
// paint underline at right side
|
||||
g.fillRect( width - underlineHeight, 0, underlineHeight, height );
|
||||
}
|
||||
}
|
||||
protected void paintUnderlineSelection( Graphics g, Color underlineSelectionColor, int underlineSelectionHeight ) {
|
||||
int width = menuItem.getWidth();
|
||||
int height = menuItem.getHeight();
|
||||
|
||||
int underlineHeight = scale( underlineSelectionHeight );
|
||||
g.setColor( underlineSelectionColor );
|
||||
if( isTopLevelMenu( menuItem ) ) {
|
||||
// paint underline at bottom
|
||||
g.fillRect( 0, height - underlineHeight, width, underlineHeight );
|
||||
} else if( menuItem.getComponentOrientation().isLeftToRight() ) {
|
||||
// paint underline at left side
|
||||
g.fillRect( 0, 0, underlineHeight, height );
|
||||
} else {
|
||||
// paint underline at right side
|
||||
g.fillRect( width - underlineHeight, 0, underlineHeight, height );
|
||||
}
|
||||
}
|
||||
|
||||
protected Color deriveBackground( Color background ) {
|
||||
if( !(background instanceof DerivedColor) )
|
||||
return background;
|
||||
|
||||
Color baseColor = menuItem.isOpaque()
|
||||
? menuItem.getBackground()
|
||||
: FlatUIUtils.getParentBackground( menuItem );
|
||||
@@ -293,12 +298,12 @@ debug*/
|
||||
return FlatUIUtils.deriveColor( background, baseColor );
|
||||
}
|
||||
|
||||
protected void paintIcon( Graphics g, Rectangle iconRect, Icon icon ) {
|
||||
protected void paintIcon( Graphics g, Rectangle iconRect, Icon icon, Color checkBackground ) {
|
||||
// if checkbox/radiobutton menu item is selected and also has a custom icon,
|
||||
// then use filled icon background to indicate selection (instead of using checkIcon)
|
||||
if( menuItem.isSelected() && checkIcon != null && icon != checkIcon ) {
|
||||
Rectangle r = FlatUIUtils.addInsets( iconRect, scale( checkMargins ) );
|
||||
g.setColor( deriveBackground( isUnderlineSelection() ? underlineSelectionCheckBackground : checkBackground ) );
|
||||
g.setColor( deriveBackground( checkBackground ) );
|
||||
g.fillRect( r.x, r.y, r.width, r.height );
|
||||
}
|
||||
|
||||
@@ -418,36 +423,78 @@ debug*/
|
||||
|
||||
private KeyStroke cachedAccelerator;
|
||||
private String cachedAcceleratorText;
|
||||
private boolean cachedAcceleratorLeftToRight;
|
||||
|
||||
private String getAcceleratorText() {
|
||||
KeyStroke accelerator = menuItem.getAccelerator();
|
||||
if( accelerator == null )
|
||||
return null;
|
||||
|
||||
if( accelerator == cachedAccelerator )
|
||||
boolean leftToRight = menuItem.getComponentOrientation().isLeftToRight();
|
||||
|
||||
if( accelerator == cachedAccelerator && leftToRight == cachedAcceleratorLeftToRight )
|
||||
return cachedAcceleratorText;
|
||||
|
||||
cachedAccelerator = accelerator;
|
||||
cachedAcceleratorText = getTextForAccelerator( accelerator );
|
||||
cachedAcceleratorLeftToRight = leftToRight;
|
||||
|
||||
return cachedAcceleratorText;
|
||||
}
|
||||
|
||||
protected String getTextForAccelerator( KeyStroke accelerator ) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
int modifiers = accelerator.getModifiers();
|
||||
if( modifiers != 0 )
|
||||
buf.append( InputEvent.getModifiersExText( modifiers ) ).append( acceleratorDelimiter );
|
||||
boolean leftToRight = menuItem.getComponentOrientation().isLeftToRight();
|
||||
|
||||
// modifiers
|
||||
int modifiers = accelerator.getModifiers();
|
||||
if( modifiers != 0 ) {
|
||||
if( SystemInfo.isMacOS ) {
|
||||
if( leftToRight )
|
||||
buf.append( getMacOSModifiersExText( modifiers, leftToRight ) );
|
||||
} else
|
||||
buf.append( InputEvent.getModifiersExText( modifiers ) ).append( acceleratorDelimiter );
|
||||
}
|
||||
|
||||
// key
|
||||
int keyCode = accelerator.getKeyCode();
|
||||
if( keyCode != 0 )
|
||||
buf.append( KeyEvent.getKeyText( keyCode ) );
|
||||
else
|
||||
buf.append( accelerator.getKeyChar() );
|
||||
|
||||
// modifiers if right-to-left on macOS
|
||||
if( modifiers != 0 && !leftToRight && SystemInfo.isMacOS )
|
||||
buf.append( getMacOSModifiersExText( modifiers, leftToRight ) );
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
protected String getMacOSModifiersExText( int modifiers, boolean leftToRight ) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
|
||||
if( (modifiers & InputEvent.CTRL_DOWN_MASK) != 0 )
|
||||
buf.append( controlGlyph );
|
||||
if( (modifiers & (InputEvent.ALT_DOWN_MASK | InputEvent.ALT_GRAPH_DOWN_MASK)) != 0 )
|
||||
buf.append( optionGlyph );
|
||||
if( (modifiers & InputEvent.SHIFT_DOWN_MASK) != 0 )
|
||||
buf.append( shiftGlyph );
|
||||
if( (modifiers & InputEvent.META_DOWN_MASK) != 0 )
|
||||
buf.append( commandGlyph );
|
||||
|
||||
// reverse order for right-to-left
|
||||
if( !leftToRight )
|
||||
buf.reverse();
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private static final char
|
||||
controlGlyph = 0x2303,
|
||||
optionGlyph = 0x2325,
|
||||
shiftGlyph = 0x21E7,
|
||||
commandGlyph = 0x2318;
|
||||
|
||||
//---- class MinSizeIcon --------------------------------------------------
|
||||
|
||||
private class MinSizeIcon
|
||||
|
||||
@@ -62,6 +62,12 @@ import javax.swing.plaf.basic.BasicMenuUI;
|
||||
* @uiDefault MenuItem.iconTextGap int
|
||||
* @uiDefault MenuBar.hoverBackground Color
|
||||
*
|
||||
* <!-- FlatMenuRenderer -->
|
||||
*
|
||||
* @uiDefault MenuBar.underlineSelectionBackground Color
|
||||
* @uiDefault MenuBar.underlineSelectionColor Color
|
||||
* @uiDefault MenuBar.underlineSelectionHeight int
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatMenuUI
|
||||
@@ -123,6 +129,14 @@ public class FlatMenuUI
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize( JComponent c ) {
|
||||
// avoid that top-level menus (in menu bar) are made smaller if horizontal space is rare
|
||||
// same code is in BasicMenuUI since Java 10
|
||||
// see https://bugs.openjdk.java.net/browse/JDK-8178430
|
||||
return ((JMenu)menuItem).isTopLevelMenu() ? c.getPreferredSize() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dimension getPreferredMenuItemSize( JComponent c, Icon checkIcon, Icon arrowIcon, int defaultTextIconGap ) {
|
||||
return renderer.getPreferredMenuItemSize();
|
||||
@@ -139,6 +153,10 @@ public class FlatMenuUI
|
||||
protected class FlatMenuRenderer
|
||||
extends FlatMenuItemRenderer
|
||||
{
|
||||
protected final Color menuBarUnderlineSelectionBackground = FlatUIUtils.getUIColor( "MenuBar.underlineSelectionBackground", underlineSelectionBackground );
|
||||
protected final Color menuBarUnderlineSelectionColor = FlatUIUtils.getUIColor( "MenuBar.underlineSelectionColor", underlineSelectionColor );
|
||||
protected final int menuBarUnderlineSelectionHeight = FlatUIUtils.getUIInt( "MenuBar.underlineSelectionHeight", underlineSelectionHeight );
|
||||
|
||||
protected FlatMenuRenderer( JMenuItem menuItem, Icon checkIcon, Icon arrowIcon,
|
||||
Font acceleratorFont, String acceleratorDelimiter )
|
||||
{
|
||||
@@ -147,6 +165,9 @@ public class FlatMenuUI
|
||||
|
||||
@Override
|
||||
protected void paintBackground( Graphics g, Color selectionBackground ) {
|
||||
if( isUnderlineSelection() && ((JMenu)menuItem).isTopLevelMenu() )
|
||||
selectionBackground = menuBarUnderlineSelectionBackground;
|
||||
|
||||
ButtonModel model = menuItem.getModel();
|
||||
if( model.isRollover() && !model.isArmed() && !model.isSelected() &&
|
||||
model.isEnabled() && ((JMenu)menuItem).isTopLevelMenu() )
|
||||
@@ -156,5 +177,15 @@ public class FlatMenuUI
|
||||
} else
|
||||
super.paintBackground( g, selectionBackground );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintUnderlineSelection( Graphics g, Color underlineSelectionColor, int underlineSelectionHeight ) {
|
||||
if( ((JMenu)menuItem).isTopLevelMenu() ) {
|
||||
underlineSelectionColor = menuBarUnderlineSelectionColor;
|
||||
underlineSelectionHeight = menuBarUnderlineSelectionHeight;
|
||||
}
|
||||
|
||||
super.paintUnderlineSelection( g, underlineSelectionColor, underlineSelectionHeight );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,11 +35,7 @@ import javax.swing.plaf.basic.BasicPanelUI;
|
||||
public class FlatPanelUI
|
||||
extends BasicPanelUI
|
||||
{
|
||||
private static ComponentUI instance;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
if( instance == null )
|
||||
instance = new FlatPanelUI();
|
||||
return instance;
|
||||
return FlatUIUtils.createSharedUI( FlatPanelUI.class, FlatPanelUI::new );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,8 +60,10 @@ import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
* @uiDefault Component.minimumWidth int
|
||||
* @uiDefault Component.isIntelliJTheme boolean
|
||||
* @uiDefault PasswordField.placeholderForeground Color
|
||||
* @uiDefault PasswordField.showCapsLock boolean
|
||||
* @uiDefault PasswordField.capsLockIcon Icon
|
||||
* @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always
|
||||
* @uiDefault TextComponent.selectAllOnMouseClick boolean
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
@@ -71,6 +73,7 @@ public class FlatPasswordFieldUI
|
||||
protected int minimumWidth;
|
||||
protected boolean isIntelliJTheme;
|
||||
protected Color placeholderForeground;
|
||||
protected boolean showCapsLock;
|
||||
protected Icon capsLockIcon;
|
||||
|
||||
private FocusListener focusListener;
|
||||
@@ -88,6 +91,7 @@ public class FlatPasswordFieldUI
|
||||
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
||||
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
||||
placeholderForeground = UIManager.getColor( prefix + ".placeholderForeground" );
|
||||
showCapsLock = UIManager.getBoolean( "PasswordField.showCapsLock" );
|
||||
capsLockIcon = UIManager.getIcon( "PasswordField.capsLockIcon" );
|
||||
|
||||
LookAndFeel.installProperty( getComponent(), "opaque", false );
|
||||
@@ -141,7 +145,8 @@ public class FlatPasswordFieldUI
|
||||
|
||||
@Override
|
||||
protected Caret createCaret() {
|
||||
return new FlatCaret( UIManager.getString( "TextComponent.selectAllOnFocusPolicy" ) );
|
||||
return new FlatCaret( UIManager.getString( "TextComponent.selectAllOnFocusPolicy" ),
|
||||
UIManager.getBoolean( "TextComponent.selectAllOnMouseClick" ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -160,6 +165,9 @@ public class FlatPasswordFieldUI
|
||||
}
|
||||
|
||||
protected void paintCapsLock( Graphics g ) {
|
||||
if( !showCapsLock )
|
||||
return;
|
||||
|
||||
JTextComponent c = getComponent();
|
||||
if( !FlatUIUtils.isPermanentFocusOwner( c ) ||
|
||||
!Toolkit.getDefaultToolkit().getLockingKeyState( KeyEvent.VK_CAPS_LOCK ) )
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Insets;
|
||||
import java.awt.MouseInfo;
|
||||
import java.awt.Panel;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
@@ -32,6 +33,8 @@ import java.lang.reflect.Method;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLayeredPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JToolTip;
|
||||
import javax.swing.JWindow;
|
||||
import javax.swing.Popup;
|
||||
import javax.swing.PopupFactory;
|
||||
import javax.swing.RootPaneContainer;
|
||||
@@ -40,6 +43,7 @@ import javax.swing.UIManager;
|
||||
import javax.swing.border.Border;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
* A popup factory that adds drop shadows to popups on Windows.
|
||||
@@ -58,39 +62,111 @@ public class FlatPopupFactory
|
||||
public Popup getPopup( Component owner, Component contents, int x, int y )
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
if( !isDropShadowPainted( owner, contents ) )
|
||||
return new NonFlashingPopup( super.getPopup( owner, contents, x, y ), contents );
|
||||
|
||||
// macOS and Linux adds drop shadow to heavy weight popups
|
||||
if( SystemInfo.IS_MAC || SystemInfo.IS_LINUX ) {
|
||||
Popup popup = getHeavyWeightPopup( owner, contents, x, y );
|
||||
if( popup == null )
|
||||
popup = super.getPopup( owner, contents, x, y );
|
||||
return new NonFlashingPopup( popup, contents );
|
||||
Point pt = fixToolTipLocation( owner, contents, x, y );
|
||||
if( pt != null ) {
|
||||
x = pt.x;
|
||||
y = pt.y;
|
||||
}
|
||||
|
||||
boolean forceHeavyWeight = isOptionEnabled( owner, contents, FlatClientProperties.POPUP_FORCE_HEAVY_WEIGHT, "Popup.forceHeavyWeight" );
|
||||
|
||||
if( !isOptionEnabled( owner, contents, FlatClientProperties.POPUP_DROP_SHADOW_PAINTED, "Popup.dropShadowPainted" ) )
|
||||
return new NonFlashingPopup( getPopupForScreenOfOwner( owner, contents, x, y, forceHeavyWeight ), contents );
|
||||
|
||||
// macOS and Linux adds drop shadow to heavy weight popups
|
||||
if( SystemInfo.isMacOS || SystemInfo.isLinux )
|
||||
return new NonFlashingPopup( getPopupForScreenOfOwner( owner, contents, x, y, true ), contents );
|
||||
|
||||
// create drop shadow popup
|
||||
return new DropShadowPopup( super.getPopup( owner, contents, x, y ), owner, contents );
|
||||
return new DropShadowPopup( getPopupForScreenOfOwner( owner, contents, x, y, forceHeavyWeight ), owner, contents );
|
||||
}
|
||||
|
||||
private boolean isDropShadowPainted( Component owner, Component contents ) {
|
||||
Boolean b = isDropShadowPainted( owner );
|
||||
if( b != null )
|
||||
return b;
|
||||
/**
|
||||
* Creates a popup for the screen that the owner component is on.
|
||||
* <p>
|
||||
* PopupFactory caches heavy weight popup windows and reuses them.
|
||||
* On a dual screen setup, if the popup owner has moved from one screen to the other one,
|
||||
* then the cached heavy weight popup window may be connected to the wrong screen.
|
||||
* If the two screens use different scaling factors, then the popup location and size
|
||||
* is scaled when the popup becomes visible, which shows the popup in the wrong location
|
||||
* (or on wrong screen). The re-scaling is done in WWindowPeer.setBounds() (Java 9+).
|
||||
* <p>
|
||||
* To fix this, dispose popup windows that are on wrong screen and get new popup.
|
||||
* <p>
|
||||
* This is a workaround for https://bugs.openjdk.java.net/browse/JDK-8224608
|
||||
*/
|
||||
private Popup getPopupForScreenOfOwner( Component owner, Component contents, int x, int y, boolean forceHeavyWeight )
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
b = isDropShadowPainted( contents );
|
||||
if( b != null )
|
||||
return b;
|
||||
for(;;) {
|
||||
// create new or get cached popup
|
||||
Popup popup = forceHeavyWeight
|
||||
? getHeavyWeightPopup( owner, contents, x, y )
|
||||
: super.getPopup( owner, contents, x, y );
|
||||
|
||||
return UIManager.getBoolean( "Popup.dropShadowPainted" );
|
||||
// get heavy weight popup window; is null for non-heavy weight popup
|
||||
Window popupWindow = SwingUtilities.windowForComponent( contents );
|
||||
|
||||
// check whether heavy weight popup window is on same screen as owner component
|
||||
if( popupWindow == null ||
|
||||
popupWindow.getGraphicsConfiguration() == owner.getGraphicsConfiguration() )
|
||||
return popup;
|
||||
|
||||
// remove contents component from popup window
|
||||
if( popupWindow instanceof JWindow )
|
||||
((JWindow)popupWindow).getContentPane().removeAll();
|
||||
|
||||
// dispose unused popup
|
||||
// (do not invoke popup.hide() because this would cache the popup window)
|
||||
popupWindow.dispose();
|
||||
|
||||
// avoid endless loop (should newer happen; PopupFactory cache size is 5)
|
||||
if( ++count > 10 )
|
||||
return popup;
|
||||
}
|
||||
}
|
||||
|
||||
private Boolean isDropShadowPainted( Component c ) {
|
||||
if( !(c instanceof JComponent) )
|
||||
return null;
|
||||
/**
|
||||
* 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 an 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();
|
||||
|
||||
Object value = ((JComponent)c).getClientProperty( FlatClientProperties.POPUP_DROP_SHADOW_PAINTED );
|
||||
return (value instanceof Boolean ) ? (Boolean) value : null;
|
||||
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 );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,7 +181,7 @@ public class FlatPopupFactory
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
try {
|
||||
if( SystemInfo.IS_JAVA_9_OR_LATER ) {
|
||||
if( SystemInfo.isJava_9_orLater ) {
|
||||
if( java9getPopupMethod == null ) {
|
||||
java9getPopupMethod = PopupFactory.class.getDeclaredMethod(
|
||||
"getPopup", Component.class, Component.class, int.class, int.class, boolean.class );
|
||||
@@ -126,12 +202,48 @@ public class FlatPopupFactory
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Usually ToolTipManager places a tooltip at (mouseLocation.x, mouseLocation.y + 20).
|
||||
* In case that the tooltip would be partly outside of the screen,
|
||||
* ToolTipManagerthe changes the location so that the entire tooltip fits on screen.
|
||||
* But this can place the tooltip under the mouse location and hide the owner component.
|
||||
* <p>
|
||||
* This method checks whether the current mouse location is within tooltip bounds
|
||||
* and corrects the y-location so that the tooltip is placed above the mouse location.
|
||||
*/
|
||||
private Point fixToolTipLocation( Component owner, Component contents, int x, int y ) {
|
||||
if( !(contents instanceof JToolTip) || !wasInvokedFromToolTipManager() )
|
||||
return null;
|
||||
|
||||
Point mouseLocation = MouseInfo.getPointerInfo().getLocation();
|
||||
Dimension tipSize = contents.getPreferredSize();
|
||||
|
||||
// check whether mouse location is within tooltip bounds
|
||||
Rectangle tipBounds = new Rectangle( x, y, tipSize.width, tipSize.height );
|
||||
if( !tipBounds.contains( mouseLocation ) )
|
||||
return null;
|
||||
|
||||
// place tooltip above mouse location
|
||||
return new Point( x, mouseLocation.y - tipSize.height - UIScale.scale( 20 ) );
|
||||
}
|
||||
|
||||
private boolean wasInvokedFromToolTipManager() {
|
||||
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
|
||||
for( StackTraceElement stackTraceElement : stackTrace ) {
|
||||
if( "javax.swing.ToolTipManager".equals( stackTraceElement.getClassName() ) &&
|
||||
"showTipWindow".equals( stackTraceElement.getMethodName() ) )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//---- class NonFlashingPopup ---------------------------------------------
|
||||
|
||||
private class NonFlashingPopup
|
||||
extends Popup
|
||||
{
|
||||
private Popup delegate;
|
||||
private Component contents;
|
||||
|
||||
// heavy weight
|
||||
protected Window popupWindow;
|
||||
@@ -139,6 +251,7 @@ public class FlatPopupFactory
|
||||
|
||||
NonFlashingPopup( Popup delegate, Component contents ) {
|
||||
this.delegate = delegate;
|
||||
this.contents = contents;
|
||||
|
||||
popupWindow = SwingUtilities.windowForComponent( contents );
|
||||
if( popupWindow != null ) {
|
||||
@@ -153,8 +266,26 @@ public class FlatPopupFactory
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
if( delegate != null )
|
||||
delegate.show();
|
||||
if( delegate != null ) {
|
||||
showPopupAndFixLocation( delegate, popupWindow );
|
||||
|
||||
// increase tooltip size if necessary because it may be too small on HiDPI screens
|
||||
// https://bugs.openjdk.java.net/browse/JDK-8213535
|
||||
if( contents instanceof JToolTip && popupWindow == null ) {
|
||||
Container parent = contents.getParent();
|
||||
if( parent instanceof JPanel ) {
|
||||
Dimension prefSize = parent.getPreferredSize();
|
||||
if( !prefSize.equals( parent.getSize() ) ) {
|
||||
Container mediumWeightPanel = SwingUtilities.getAncestorOfClass( Panel.class, parent );
|
||||
Container c = (mediumWeightPanel != null)
|
||||
? mediumWeightPanel // medium weight popup
|
||||
: parent; // light weight popup
|
||||
c.setSize( prefSize );
|
||||
c.validate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -162,6 +293,7 @@ public class FlatPopupFactory
|
||||
if( delegate != null ) {
|
||||
delegate.hide();
|
||||
delegate = null;
|
||||
contents = null;
|
||||
}
|
||||
|
||||
if( popupWindow != null ) {
|
||||
@@ -228,7 +360,7 @@ public class FlatPopupFactory
|
||||
// create heavy weight popup for drop shadow
|
||||
int x = popupWindow.getX() - insets.left;
|
||||
int y = popupWindow.getY() - insets.top;
|
||||
dropShadowDelegate = getHeavyWeightPopup( owner, dropShadowPanel, x, y );
|
||||
dropShadowDelegate = getPopupForScreenOfOwner( owner, dropShadowPanel, x, y, true );
|
||||
|
||||
// make drop shadow popup window translucent
|
||||
dropShadowWindow = SwingUtilities.windowForComponent( dropShadowPanel );
|
||||
@@ -270,7 +402,7 @@ public class FlatPopupFactory
|
||||
@Override
|
||||
public void show() {
|
||||
if( dropShadowDelegate != null )
|
||||
dropShadowDelegate.show();
|
||||
showPopupAndFixLocation( dropShadowDelegate, dropShadowWindow );
|
||||
|
||||
if( mediumWeightPanel != null )
|
||||
showMediumWeightDropShadow();
|
||||
|
||||
@@ -38,12 +38,8 @@ import javax.swing.plaf.ComponentUI;
|
||||
public class FlatPopupMenuSeparatorUI
|
||||
extends FlatSeparatorUI
|
||||
{
|
||||
private static ComponentUI instance;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
if( instance == null )
|
||||
instance = new FlatPopupMenuSeparatorUI();
|
||||
return instance;
|
||||
return FlatUIUtils.createSharedUI( FlatPopupMenuSeparatorUI.class, FlatPopupMenuSeparatorUI::new );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -155,7 +155,7 @@ public class FlatProgressBarUI
|
||||
? 0
|
||||
: Math.min( UIScale.scale( this.arc ), horizontal ? height : width );
|
||||
|
||||
FlatUIUtils.setRenderingHints( (Graphics2D) g );
|
||||
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g );
|
||||
|
||||
// paint track
|
||||
RoundRectangle2D.Float trackShape = new RoundRectangle2D.Float( x, y, width, height, arc, arc );
|
||||
@@ -163,6 +163,7 @@ public class FlatProgressBarUI
|
||||
((Graphics2D)g).fill( trackShape );
|
||||
|
||||
// paint progress
|
||||
int amountFull = 0;
|
||||
if( progressBar.isIndeterminate() ) {
|
||||
boxRect = getBox( boxRect );
|
||||
if( boxRect != null ) {
|
||||
@@ -170,11 +171,8 @@ public class FlatProgressBarUI
|
||||
((Graphics2D)g).fill( new RoundRectangle2D.Float( boxRect.x, boxRect.y,
|
||||
boxRect.width, boxRect.height, arc, arc ) );
|
||||
}
|
||||
|
||||
if( progressBar.isStringPainted() )
|
||||
paintString( g, x, y, width, height, 0, insets );
|
||||
} else {
|
||||
int amountFull = getAmountFull( insets, width, height );
|
||||
amountFull = getAmountFull( insets, width, height );
|
||||
|
||||
RoundRectangle2D.Float progressShape = horizontal
|
||||
? new RoundRectangle2D.Float( c.getComponentOrientation().isLeftToRight() ? x : x + (width - amountFull),
|
||||
@@ -189,10 +187,12 @@ public class FlatProgressBarUI
|
||||
((Graphics2D)g).fill( area );
|
||||
} else
|
||||
((Graphics2D)g).fill( progressShape );
|
||||
|
||||
if( progressBar.isStringPainted() )
|
||||
paintString( g, x, y, width, height, amountFull, insets );
|
||||
}
|
||||
|
||||
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
|
||||
|
||||
if( progressBar.isStringPainted() )
|
||||
paintString( g, x, y, width, height, amountFull, insets );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -60,12 +60,8 @@ public class FlatRadioButtonUI
|
||||
|
||||
private boolean defaults_initialized = false;
|
||||
|
||||
private static ComponentUI instance;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
if( instance == null )
|
||||
instance = new FlatRadioButtonUI();
|
||||
return instance;
|
||||
return FlatUIUtils.createSharedUI( FlatRadioButtonUI.class, FlatRadioButtonUI::new );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -37,6 +37,7 @@ import javax.swing.JMenuBar;
|
||||
import javax.swing.JRootPane;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.plaf.BorderUIResource;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.UIResource;
|
||||
@@ -45,6 +46,7 @@ import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JRootPane}.
|
||||
@@ -54,6 +56,7 @@ import com.formdev.flatlaf.util.SystemInfo;
|
||||
* @uiDefault RootPane.border Border
|
||||
* @uiDefault RootPane.activeBorderColor Color
|
||||
* @uiDefault RootPane.inactiveBorderColor Color
|
||||
* @uiDefault TitlePane.borderColor Color optional
|
||||
*
|
||||
* <!-- FlatWindowResizer -->
|
||||
*
|
||||
@@ -69,7 +72,9 @@ public class FlatRootPaneUI
|
||||
{
|
||||
// check this field before using class JBRCustomDecorations to avoid unnecessary loading of that class
|
||||
static final boolean canUseJBRCustomDecorations
|
||||
= SystemInfo.IS_JETBRAINS_JVM_11_OR_LATER && SystemInfo.IS_WINDOWS_10_OR_LATER;
|
||||
= SystemInfo.isJetBrainsJVM_11_orLater && SystemInfo.isWindows_10_orLater;
|
||||
|
||||
protected final Color borderColor = UIManager.getColor( "TitlePane.borderColor" );
|
||||
|
||||
protected JRootPane rootPane;
|
||||
protected FlatTitlePane titlePane;
|
||||
@@ -89,11 +94,21 @@ public class FlatRootPaneUI
|
||||
|
||||
if( rootPane.getWindowDecorationStyle() != JRootPane.NONE )
|
||||
installClientDecorations();
|
||||
else
|
||||
installBorder();
|
||||
|
||||
if( canUseJBRCustomDecorations )
|
||||
JBRCustomDecorations.install( rootPane );
|
||||
}
|
||||
|
||||
protected void installBorder() {
|
||||
if( borderColor != null ) {
|
||||
Border b = rootPane.getBorder();
|
||||
if( b == null || b instanceof UIResource )
|
||||
rootPane.setBorder( new FlatWindowTitleBorder( borderColor ) );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uninstallUI( JComponent c ) {
|
||||
super.uninstallUI( c );
|
||||
@@ -119,11 +134,8 @@ public class FlatRootPaneUI
|
||||
}
|
||||
|
||||
// enable dark window appearance on macOS when running in JetBrains Runtime
|
||||
if( SystemInfo.IS_JETBRAINS_JVM && SystemInfo.IS_MAC_OS_10_14_MOJAVE ) {
|
||||
LookAndFeel laf = UIManager.getLookAndFeel();
|
||||
boolean isDark = laf instanceof FlatLaf && ((FlatLaf)laf).isDark();
|
||||
c.putClientProperty( "jetbrains.awt.windowDarkAppearance", isDark );
|
||||
}
|
||||
if( SystemInfo.isJetBrainsJVM && SystemInfo.isMacOS_10_14_Mojave_orLater )
|
||||
c.putClientProperty( "jetbrains.awt.windowDarkAppearance", FlatLaf.isLafDark() );
|
||||
}
|
||||
|
||||
protected void installClientDecorations() {
|
||||
@@ -172,7 +184,7 @@ public class FlatRootPaneUI
|
||||
}
|
||||
|
||||
protected FlatWindowResizer createWindowResizer() {
|
||||
return new FlatWindowResizer( rootPane );
|
||||
return new FlatWindowResizer.WindowResizer( rootPane );
|
||||
}
|
||||
|
||||
protected FlatTitlePane createTitlePane() {
|
||||
@@ -203,6 +215,8 @@ public class FlatRootPaneUI
|
||||
uninstallClientDecorations();
|
||||
if( rootPane.getWindowDecorationStyle() != JRootPane.NONE )
|
||||
installClientDecorations();
|
||||
else
|
||||
installBorder();
|
||||
break;
|
||||
|
||||
case FlatClientProperties.MENU_BAR_EMBEDDED:
|
||||
@@ -252,8 +266,9 @@ public class FlatRootPaneUI
|
||||
int width = Math.max( titlePaneSize.width, contentSize.width );
|
||||
int height = titlePaneSize.height + contentSize.height;
|
||||
if( titlePane == null || !titlePane.isMenuBarEmbedded() ) {
|
||||
Dimension menuBarSize = (rootPane.getJMenuBar() != null)
|
||||
? getSizeFunc.apply( rootPane.getJMenuBar() )
|
||||
JMenuBar menuBar = rootPane.getJMenuBar();
|
||||
Dimension menuBarSize = (menuBar != null && menuBar.isVisible())
|
||||
? getSizeFunc.apply( menuBar )
|
||||
: new Dimension();
|
||||
|
||||
width = Math.max( width, menuBarSize.width );
|
||||
@@ -270,6 +285,7 @@ public class FlatRootPaneUI
|
||||
@Override
|
||||
public void layoutContainer( Container parent ) {
|
||||
JRootPane rootPane = (JRootPane) parent;
|
||||
boolean isFullScreen = FlatUIUtils.isFullScreen( rootPane );
|
||||
|
||||
Insets insets = rootPane.getInsets();
|
||||
int x = insets.left;
|
||||
@@ -283,15 +299,15 @@ public class FlatRootPaneUI
|
||||
rootPane.getGlassPane().setBounds( x, y, width, height );
|
||||
|
||||
int nextY = 0;
|
||||
if( titlePane != null ) {
|
||||
if( !isFullScreen && titlePane != null ) {
|
||||
Dimension prefSize = titlePane.getPreferredSize();
|
||||
titlePane.setBounds( 0, 0, width, prefSize.height );
|
||||
nextY += prefSize.height;
|
||||
}
|
||||
|
||||
JMenuBar menuBar = rootPane.getJMenuBar();
|
||||
if( menuBar != null ) {
|
||||
if( titlePane != null && titlePane.isMenuBarEmbedded() ) {
|
||||
if( menuBar != null && menuBar.isVisible() ) {
|
||||
if( !isFullScreen && titlePane != null && titlePane.isMenuBarEmbedded() ) {
|
||||
titlePane.validate();
|
||||
menuBar.setBounds( titlePane.getMenuBarBounds() );
|
||||
} else {
|
||||
@@ -304,6 +320,9 @@ public class FlatRootPaneUI
|
||||
Container contentPane = rootPane.getContentPane();
|
||||
if( contentPane != null )
|
||||
contentPane.setBounds( 0, nextY, width, Math.max( height - nextY, 0 ) );
|
||||
|
||||
if( titlePane != null )
|
||||
titlePane.menuBarLayouted();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -338,7 +357,7 @@ public class FlatRootPaneUI
|
||||
|
||||
@Override
|
||||
public Insets getBorderInsets( Component c, Insets insets ) {
|
||||
if( isWindowMaximized( c ) ) {
|
||||
if( isWindowMaximized( c ) || FlatUIUtils.isFullScreen( c ) ) {
|
||||
// hide border if window is maximized
|
||||
insets.top = insets.left = insets.bottom = insets.right = 0;
|
||||
return insets;
|
||||
@@ -348,7 +367,7 @@ public class FlatRootPaneUI
|
||||
|
||||
@Override
|
||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||
if( isWindowMaximized( c ) )
|
||||
if( isWindowMaximized( c ) || FlatUIUtils.isFullScreen( c ) )
|
||||
return;
|
||||
|
||||
Container parent = c.getParent();
|
||||
@@ -369,4 +388,40 @@ public class FlatRootPaneUI
|
||||
: false;
|
||||
}
|
||||
}
|
||||
|
||||
//---- class FlatWindowTitleBorder ----------------------------------------
|
||||
|
||||
private static class FlatWindowTitleBorder
|
||||
extends BorderUIResource.EmptyBorderUIResource
|
||||
{
|
||||
private final Color borderColor;
|
||||
|
||||
FlatWindowTitleBorder( Color borderColor ) {
|
||||
super( 0, 0, 0, 0 );
|
||||
this.borderColor = borderColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||
if( showBorder( c ) ) {
|
||||
float lineHeight = UIScale.scale( (float) 1 );
|
||||
FlatUIUtils.paintFilledRectangle( g, borderColor, x, y, width, lineHeight );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Insets getBorderInsets( Component c, Insets insets ) {
|
||||
insets.set( showBorder( c ) ? 1 : 0, 0, 0, 0 );
|
||||
return insets;
|
||||
}
|
||||
|
||||
private boolean showBorder( Component c ) {
|
||||
Container parent = c.getParent();
|
||||
return
|
||||
(parent instanceof JFrame &&
|
||||
(((JFrame)parent).getJMenuBar() == null ||
|
||||
!((JFrame)parent).getJMenuBar().isVisible())) ||
|
||||
parent instanceof JDialog;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,10 @@ public class FlatRoundBorder
|
||||
|
||||
@Override
|
||||
protected int getArc( Component c ) {
|
||||
return FlatUIUtils.isRoundRect( c ) ? Short.MAX_VALUE : arc;
|
||||
if( isCellEditor( c ) )
|
||||
return 0;
|
||||
|
||||
Boolean roundRect = FlatUIUtils.isRoundRect( c );
|
||||
return roundRect != null ? (roundRect ? Short.MAX_VALUE : 0) : arc;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ package com.formdev.flatlaf.ui;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.MouseAdapter;
|
||||
@@ -65,7 +64,7 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault ScrollBar.pressedTrackColor Color optional
|
||||
* @uiDefault ScrollBar.pressedThumbColor Color optional
|
||||
* @uiDefault ScrollBar.pressedThumbWithTrack boolean
|
||||
* @uiDefault Component.arrowType String triangle (default) or chevron
|
||||
* @uiDefault Component.arrowType String chevron (default) or triangle
|
||||
* @uiDefault ScrollBar.showButtons boolean
|
||||
* @uiDefault ScrollBar.buttonArrowColor Color
|
||||
* @uiDefault ScrollBar.buttonDisabledArrowColor Color
|
||||
@@ -142,6 +141,12 @@ public class FlatScrollBarUI
|
||||
buttonDisabledArrowColor = UIManager.getColor( "ScrollBar.buttonDisabledArrowColor" );
|
||||
hoverButtonBackground = UIManager.getColor( "ScrollBar.hoverButtonBackground" );
|
||||
pressedButtonBackground = UIManager.getColor( "ScrollBar.pressedButtonBackground" );
|
||||
|
||||
// fallback (e.g. when used in NetBeans GUI builder)
|
||||
if( trackInsets == null )
|
||||
trackInsets = new Insets( 0, 0, 0, 0 );
|
||||
if( thumbInsets == null )
|
||||
thumbInsets = new Insets( 0, 0, 0, 0 );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -215,8 +220,9 @@ public class FlatScrollBarUI
|
||||
|
||||
@Override
|
||||
public void paint( Graphics g, JComponent c ) {
|
||||
FlatUIUtils.setRenderingHints( (Graphics2D) g );
|
||||
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g );
|
||||
super.paint( g, c );
|
||||
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -284,12 +290,12 @@ public class FlatScrollBarUI
|
||||
|
||||
@Override
|
||||
protected Dimension getMinimumThumbSize() {
|
||||
return UIScale.scale( super.getMinimumThumbSize() );
|
||||
return UIScale.scale( FlatUIUtils.addInsets( super.getMinimumThumbSize(), thumbInsets ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dimension getMaximumThumbSize() {
|
||||
return UIScale.scale( super.getMaximumThumbSize() );
|
||||
return UIScale.scale( FlatUIUtils.addInsets( super.getMaximumThumbSize(), thumbInsets ) );
|
||||
}
|
||||
|
||||
//---- class ScrollBarHoverListener ---------------------------------------
|
||||
|
||||
@@ -114,10 +114,7 @@ public class FlatScrollPaneUI
|
||||
return new BasicScrollPaneUI.MouseWheelHandler() {
|
||||
@Override
|
||||
public void mouseWheelMoved( MouseWheelEvent e ) {
|
||||
// Note: Getting UI value "ScrollPane.smoothScrolling" here to allow
|
||||
// applications to turn smooth scrolling on or off at any time
|
||||
// (e.g. in application options dialog).
|
||||
if( UIManager.getBoolean( "ScrollPane.smoothScrolling" ) &&
|
||||
if( isSmoothScrollingEnabled() &&
|
||||
scrollpane.isWheelScrollingEnabled() &&
|
||||
e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL &&
|
||||
e.getPreciseWheelRotation() != 0 &&
|
||||
@@ -130,6 +127,17 @@ public class FlatScrollPaneUI
|
||||
};
|
||||
}
|
||||
|
||||
protected boolean isSmoothScrollingEnabled() {
|
||||
Object smoothScrolling = scrollpane.getClientProperty( FlatClientProperties.SCROLL_PANE_SMOOTH_SCROLLING );
|
||||
if( smoothScrolling instanceof Boolean )
|
||||
return (Boolean) smoothScrolling;
|
||||
|
||||
// Note: Getting UI value "ScrollPane.smoothScrolling" here to allow
|
||||
// applications to turn smooth scrolling on or off at any time
|
||||
// (e.g. in application options dialog).
|
||||
return UIManager.getBoolean( "ScrollPane.smoothScrolling" );
|
||||
}
|
||||
|
||||
private static final double EPSILON = 1e-5d;
|
||||
|
||||
private void mouseWheelMovedSmooth( MouseWheelEvent e ) {
|
||||
|
||||
@@ -52,12 +52,8 @@ public class FlatSeparatorUI
|
||||
|
||||
private boolean defaults_initialized = false;
|
||||
|
||||
private static ComponentUI instance;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
if( instance == null )
|
||||
instance = new FlatSeparatorUI();
|
||||
return instance;
|
||||
return FlatUIUtils.createSharedUI( FlatSeparatorUI.class, FlatSeparatorUI::new );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,17 +18,23 @@ package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Shape;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JSlider;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicSliderUI;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
@@ -49,29 +55,46 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* <!-- FlatSliderUI -->
|
||||
*
|
||||
* @uiDefault Slider.trackWidth int
|
||||
* @uiDefault Slider.thumbWidth int
|
||||
* @uiDefault Slider.thumbSize Dimension
|
||||
* @uiDefault Slider.focusWidth int
|
||||
* @uiDefault Slider.trackValueColor Color optional; defaults to Slider.thumbColor
|
||||
* @uiDefault Slider.trackColor Color
|
||||
* @uiDefault Slider.thumbColor Color
|
||||
* @uiDefault Slider.thumbBorderColor Color optional; if null, no border is painted
|
||||
* @uiDefault Slider.focusedColor Color optional; defaults to Component.focusColor
|
||||
* @uiDefault Slider.hoverColor Color optional; defaults to Slider.focusedColor
|
||||
* @uiDefault Slider.disabledForeground Color used for track and thumb is disabled
|
||||
* @uiDefault Slider.focusedThumbBorderColor Color optional; defaults to Component.focusedBorderColor
|
||||
* @uiDefault Slider.hoverThumbColor Color optional
|
||||
* @uiDefault Slider.pressedThumbColor Color optional
|
||||
* @uiDefault Slider.disabledTrackColor Color
|
||||
* @uiDefault Slider.disabledThumbColor Color
|
||||
* @uiDefault Slider.disabledThumbBorderColor Color optional; defaults to Component.disabledBorderColor
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatSliderUI
|
||||
extends BasicSliderUI
|
||||
{
|
||||
private int trackWidth;
|
||||
private int thumbWidth;
|
||||
protected int trackWidth;
|
||||
protected Dimension thumbSize;
|
||||
protected int focusWidth;
|
||||
|
||||
private Color trackColor;
|
||||
private Color thumbColor;
|
||||
private Color focusColor;
|
||||
private Color hoverColor;
|
||||
private Color disabledForeground;
|
||||
protected Color trackValueColor;
|
||||
protected Color trackColor;
|
||||
protected Color thumbColor;
|
||||
protected Color thumbBorderColor;
|
||||
protected Color focusBaseColor;
|
||||
protected Color focusedColor;
|
||||
protected Color focusedThumbBorderColor;
|
||||
protected Color hoverThumbColor;
|
||||
protected Color pressedThumbColor;
|
||||
protected Color disabledTrackColor;
|
||||
protected Color disabledThumbColor;
|
||||
protected Color disabledThumbBorderColor;
|
||||
|
||||
private MouseListener hoverListener;
|
||||
private boolean hover;
|
||||
protected boolean thumbHover;
|
||||
protected boolean thumbPressed;
|
||||
|
||||
private Object[] oldRenderingHints;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatSliderUI();
|
||||
@@ -81,24 +104,6 @@ public class FlatSliderUI
|
||||
super( null );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installListeners( JSlider slider ) {
|
||||
super.installListeners( slider );
|
||||
|
||||
hoverListener = new FlatUIUtils.HoverListener( slider, h -> {
|
||||
hover = h;
|
||||
} );
|
||||
slider.addMouseListener( hoverListener );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void uninstallListeners( JSlider slider ) {
|
||||
super.uninstallListeners( slider );
|
||||
|
||||
slider.removeMouseListener( hoverListener );
|
||||
hoverListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installDefaults( JSlider slider ) {
|
||||
super.installDefaults( slider );
|
||||
@@ -106,24 +111,65 @@ public class FlatSliderUI
|
||||
LookAndFeel.installProperty( slider, "opaque", false );
|
||||
|
||||
trackWidth = UIManager.getInt( "Slider.trackWidth" );
|
||||
thumbWidth = UIManager.getInt( "Slider.thumbWidth" );
|
||||
thumbSize = UIManager.getDimension( "Slider.thumbSize" );
|
||||
if( thumbSize == null ) {
|
||||
// fallback for compatibility with old versions
|
||||
int thumbWidth = UIManager.getInt( "Slider.thumbWidth" );
|
||||
thumbSize = new Dimension( thumbWidth, thumbWidth );
|
||||
}
|
||||
focusWidth = FlatUIUtils.getUIInt( "Slider.focusWidth", 4 );
|
||||
|
||||
trackValueColor = FlatUIUtils.getUIColor( "Slider.trackValueColor", "Slider.thumbColor" );
|
||||
trackColor = UIManager.getColor( "Slider.trackColor" );
|
||||
thumbColor = UIManager.getColor( "Slider.thumbColor" );
|
||||
focusColor = FlatUIUtils.getUIColor( "Slider.focusedColor", "Component.focusColor" );
|
||||
hoverColor = FlatUIUtils.getUIColor( "Slider.hoverColor", focusColor );
|
||||
disabledForeground = UIManager.getColor( "Slider.disabledForeground" );
|
||||
thumbBorderColor = UIManager.getColor( "Slider.thumbBorderColor" );
|
||||
focusBaseColor = UIManager.getColor( "Component.focusColor" );
|
||||
focusedColor = FlatUIUtils.getUIColor( "Slider.focusedColor", focusBaseColor );
|
||||
focusedThumbBorderColor = FlatUIUtils.getUIColor( "Slider.focusedThumbBorderColor", "Component.focusedBorderColor" );
|
||||
hoverThumbColor = UIManager.getColor( "Slider.hoverThumbColor" );
|
||||
pressedThumbColor = UIManager.getColor( "Slider.pressedThumbColor" );
|
||||
disabledTrackColor = UIManager.getColor( "Slider.disabledTrackColor" );
|
||||
disabledThumbColor = UIManager.getColor( "Slider.disabledThumbColor" );
|
||||
disabledThumbBorderColor = FlatUIUtils.getUIColor( "Slider.disabledThumbBorderColor", "Component.disabledBorderColor" );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void uninstallDefaults( JSlider slider ) {
|
||||
super.uninstallDefaults( slider );
|
||||
|
||||
trackValueColor = null;
|
||||
trackColor = null;
|
||||
thumbColor = null;
|
||||
focusColor = null;
|
||||
hoverColor = null;
|
||||
disabledForeground = null;
|
||||
thumbBorderColor = null;
|
||||
focusBaseColor = null;
|
||||
focusedColor = null;
|
||||
focusedThumbBorderColor = null;
|
||||
hoverThumbColor = null;
|
||||
pressedThumbColor = null;
|
||||
disabledTrackColor = null;
|
||||
disabledThumbColor = null;
|
||||
disabledThumbBorderColor = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TrackListener createTrackListener( JSlider slider ) {
|
||||
return new FlatTrackListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBaseline( JComponent c, int width, int height ) {
|
||||
if( c == null )
|
||||
throw new NullPointerException();
|
||||
if( width < 0 || height < 0 )
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
// no baseline for vertical orientation
|
||||
if( slider.getOrientation() == JSlider.VERTICAL )
|
||||
return -1;
|
||||
|
||||
// compute a baseline so that the track is vertically centered
|
||||
FontMetrics fm = slider.getFontMetrics( slider.getFont() );
|
||||
return trackRect.y + Math.round( (trackRect.height - fm.getHeight()) / 2f ) + fm.getAscent() - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -153,14 +199,50 @@ public class FlatSliderUI
|
||||
|
||||
@Override
|
||||
protected Dimension getThumbSize() {
|
||||
return new Dimension( UIScale.scale( thumbWidth ), UIScale.scale( thumbWidth ) );
|
||||
return calcThumbSize( slider, thumbSize, focusWidth );
|
||||
}
|
||||
|
||||
public static Dimension calcThumbSize( JSlider slider, Dimension thumbSize, int focusWidth ) {
|
||||
int fw = UIScale.scale( focusWidth );
|
||||
int w = UIScale.scale( thumbSize.width ) + fw + fw;
|
||||
int h = UIScale.scale( thumbSize.height ) + fw + fw;
|
||||
return (slider.getOrientation() == JSlider.HORIZONTAL)
|
||||
? new Dimension( w, h )
|
||||
: new Dimension( h, w );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint( Graphics g, JComponent c ) {
|
||||
FlatUIUtils.setRenderingHints( (Graphics2D) g );
|
||||
oldRenderingHints = FlatUIUtils.setRenderingHints( g );
|
||||
|
||||
/*debug
|
||||
g.setColor( Color.gray );
|
||||
g.drawRect( 0, 0, c.getWidth() - 1, c.getHeight() - 1 );
|
||||
g.setColor( Color.orange );
|
||||
g.drawRect( focusRect.x, focusRect.y, focusRect.width - 1, focusRect.height - 1 );
|
||||
g.setColor( Color.magenta );
|
||||
g.drawRect( contentRect.x, contentRect.y, contentRect.width - 1, contentRect.height - 1 );
|
||||
g.setColor( Color.blue );
|
||||
g.drawRect( trackRect.x, trackRect.y, trackRect.width - 1, trackRect.height - 1 );
|
||||
g.setColor( Color.red );
|
||||
g.drawRect( thumbRect.x, thumbRect.y, thumbRect.width - 1, thumbRect.height - 1 );
|
||||
g.setColor( Color.green );
|
||||
g.drawRect( tickRect.x, tickRect.y, tickRect.width - 1, tickRect.height - 1 );
|
||||
g.setColor( Color.red );
|
||||
g.drawRect( labelRect.x, labelRect.y, labelRect.width - 1, labelRect.height - 1 );
|
||||
debug*/
|
||||
|
||||
super.paint( g, c );
|
||||
|
||||
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
|
||||
oldRenderingHints = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintLabels( Graphics g ) {
|
||||
FlatUIUtils.runWithoutRenderingHints( g, oldRenderingHints, () -> {
|
||||
super.paintLabels( g );
|
||||
} );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -201,50 +283,308 @@ public class FlatSliderUI
|
||||
}
|
||||
|
||||
if( coloredTrack != null ) {
|
||||
g.setColor( FlatUIUtils.deriveColor( FlatUIUtils.isPermanentFocusOwner( slider ) ? focusColor : (hover ? hoverColor : thumbColor), thumbColor ) );
|
||||
if( slider.getInverted() ) {
|
||||
RoundRectangle2D temp = track;
|
||||
track = coloredTrack;
|
||||
coloredTrack = temp;
|
||||
}
|
||||
|
||||
g.setColor( trackValueColor );
|
||||
((Graphics2D)g).fill( coloredTrack );
|
||||
}
|
||||
|
||||
g.setColor( enabled ? trackColor : disabledForeground );
|
||||
g.setColor( enabled ? trackColor : disabledTrackColor );
|
||||
((Graphics2D)g).fill( track );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintThumb( Graphics g ) {
|
||||
g.setColor( FlatUIUtils.deriveColor( slider.isEnabled()
|
||||
? (FlatUIUtils.isPermanentFocusOwner( slider ) ? focusColor : (hover ? hoverColor : thumbColor))
|
||||
: disabledForeground,
|
||||
thumbColor ) );
|
||||
Color color = stateColor( slider, thumbHover, thumbPressed,
|
||||
thumbColor, disabledThumbColor, null, hoverThumbColor, pressedThumbColor );
|
||||
color = FlatUIUtils.deriveColor( color, thumbColor );
|
||||
|
||||
if( isRoundThumb() )
|
||||
g.fillOval( thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height );
|
||||
else {
|
||||
double w = thumbRect.width;
|
||||
double h = thumbRect.height;
|
||||
double wh = w / 2;
|
||||
Color borderColor = (thumbBorderColor != null)
|
||||
? stateColor( slider, false, false, thumbBorderColor, disabledThumbBorderColor, focusedThumbBorderColor, null, null )
|
||||
: null;
|
||||
|
||||
Path2D thumb = FlatUIUtils.createPath( 0,0, w,0, w,(h - wh), wh,h, 0,(h - wh) );
|
||||
Color focusedColor = FlatUIUtils.deriveColor( this.focusedColor, focusBaseColor );
|
||||
|
||||
paintThumb( g, slider, thumbRect, isRoundThumb(), color, borderColor, focusedColor, focusWidth );
|
||||
}
|
||||
|
||||
public static void paintThumb( Graphics g, JSlider slider, Rectangle thumbRect, boolean roundThumb,
|
||||
Color thumbColor, Color thumbBorderColor, Color focusedColor, int focusWidth )
|
||||
{
|
||||
double systemScaleFactor = UIScale.getSystemScaleFactor( (Graphics2D) g );
|
||||
if( systemScaleFactor != 1 && systemScaleFactor != 2 ) {
|
||||
// paint at scale 1x to avoid clipping on right and bottom edges at 125%, 150% or 175%
|
||||
HiDPIUtils.paintAtScale1x( (Graphics2D) g, thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height,
|
||||
(g2d, x2, y2, width2, height2, scaleFactor) -> {
|
||||
paintThumbImpl( g, slider, x2, y2, width2, height2,
|
||||
roundThumb, thumbColor, thumbBorderColor, focusedColor,
|
||||
(float) (focusWidth * scaleFactor) );
|
||||
} );
|
||||
return;
|
||||
}
|
||||
|
||||
paintThumbImpl( g, slider, thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height,
|
||||
roundThumb, thumbColor, thumbBorderColor, focusedColor, focusWidth );
|
||||
|
||||
}
|
||||
|
||||
private static void paintThumbImpl( Graphics g, JSlider slider, int x, int y, int width, int height,
|
||||
boolean roundThumb, Color thumbColor, Color thumbBorderColor, Color focusedColor, float focusWidth )
|
||||
{
|
||||
int fw = Math.round( UIScale.scale( focusWidth ) );
|
||||
int tx = x + fw;
|
||||
int ty = y + fw;
|
||||
int tw = width - fw - fw;
|
||||
int th = height - fw - fw;
|
||||
boolean focused = FlatUIUtils.isPermanentFocusOwner( slider );
|
||||
|
||||
if( roundThumb ) {
|
||||
// paint thumb focus border
|
||||
if( focused ) {
|
||||
g.setColor( focusedColor );
|
||||
((Graphics2D)g).fill( createRoundThumbShape( x, y, width, height ) );
|
||||
}
|
||||
|
||||
if( thumbBorderColor != null ) {
|
||||
// paint thumb border
|
||||
g.setColor( thumbBorderColor );
|
||||
((Graphics2D)g).fill( createRoundThumbShape( tx, ty, tw, th ) );
|
||||
|
||||
// paint thumb background
|
||||
float lw = UIScale.scale( 1f );
|
||||
g.setColor( thumbColor );
|
||||
((Graphics2D)g).fill( createRoundThumbShape( tx + lw, ty + lw,
|
||||
tw - lw - lw, th - lw - lw ) );
|
||||
} else {
|
||||
// paint thumb background
|
||||
g.setColor( thumbColor );
|
||||
((Graphics2D)g).fill( createRoundThumbShape( tx, ty, tw, th ) );
|
||||
}
|
||||
} else {
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
try {
|
||||
g2.translate( thumbRect.x, thumbRect.y );
|
||||
g2.translate( x, y );
|
||||
if( slider.getOrientation() == JSlider.VERTICAL ) {
|
||||
if( slider.getComponentOrientation().isLeftToRight() ) {
|
||||
g2.translate( 0, thumbRect.height );
|
||||
g2.translate( 0, height );
|
||||
g2.rotate( Math.toRadians( 270 ) );
|
||||
} else {
|
||||
g2.translate( thumbRect.width, 0 );
|
||||
g2.translate( width, 0 );
|
||||
g2.rotate( Math.toRadians( 90 ) );
|
||||
}
|
||||
|
||||
// rotate thumb width/height
|
||||
int temp = tw;
|
||||
tw = th;
|
||||
th = temp;
|
||||
}
|
||||
|
||||
// paint thumb focus border
|
||||
if( focused ) {
|
||||
g2.setColor( focusedColor );
|
||||
g2.fill( createDirectionalThumbShape( 0, 0,
|
||||
tw + fw + fw, th + fw + fw + (fw * 0.4142f), fw ) );
|
||||
}
|
||||
|
||||
if( thumbBorderColor != null ) {
|
||||
// paint thumb border
|
||||
g2.setColor( thumbBorderColor );
|
||||
g2.fill( createDirectionalThumbShape( fw, fw, tw, th, 0 ) );
|
||||
|
||||
// paint thumb background
|
||||
float lw = UIScale.scale( 1f );
|
||||
g2.setColor( thumbColor );
|
||||
g2.fill( createDirectionalThumbShape( fw + lw, fw + lw,
|
||||
tw - lw - lw, th - lw - lw - (lw * 0.4142f), 0 ) );
|
||||
} else {
|
||||
// paint thumb background
|
||||
g2.setColor( thumbColor );
|
||||
g2.fill( createDirectionalThumbShape( fw, fw, tw, th, 0 ) );
|
||||
}
|
||||
g2.fill( thumb );
|
||||
} finally {
|
||||
g2.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isRoundThumb() {
|
||||
public static Shape createRoundThumbShape( float x, float y, float w, float h ) {
|
||||
if( w == h )
|
||||
return new Ellipse2D.Float( x, y, w, h );
|
||||
else {
|
||||
float arc = Math.min( w, h );
|
||||
return new RoundRectangle2D.Float( x, y, w, h, arc, arc );
|
||||
}
|
||||
}
|
||||
|
||||
public static Shape createDirectionalThumbShape( float x, float y, float w, float h, float arc ) {
|
||||
float wh = w / 2;
|
||||
|
||||
Path2D path = new Path2D.Float();
|
||||
path.moveTo( x + wh, y + h );
|
||||
path.lineTo( x, y + (h - wh) );
|
||||
path.lineTo( x, y + arc );
|
||||
path.quadTo( x, y, x + arc, y );
|
||||
path.lineTo( x + (w - arc), y );
|
||||
path.quadTo( x + w, y, x + w, y + arc );
|
||||
path.lineTo( x + w, y + (h - wh) );
|
||||
path.closePath();
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
public static Color stateColor( JSlider slider, boolean hover, boolean pressed,
|
||||
Color enabledColor, Color disabledColor, Color focusedColor, Color hoverColor, Color pressedColor )
|
||||
{
|
||||
if( disabledColor != null && !slider.isEnabled() )
|
||||
return disabledColor;
|
||||
if( pressedColor != null && pressed )
|
||||
return pressedColor;
|
||||
if( hoverColor != null && hover )
|
||||
return hoverColor;
|
||||
if( focusedColor != null && FlatUIUtils.isPermanentFocusOwner( slider ) )
|
||||
return focusedColor;
|
||||
return enabledColor;
|
||||
}
|
||||
|
||||
protected boolean isRoundThumb() {
|
||||
return !slider.getPaintTicks() && !slider.getPaintLabels();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setThumbLocation( int x, int y ) {
|
||||
if( !isRoundThumb() ) {
|
||||
// the needle of the directional thumb is painted outside of thumbRect
|
||||
// --> must increase repaint rectangle
|
||||
|
||||
// set new thumb location and compute union of old and new thumb bounds
|
||||
Rectangle r = new Rectangle( thumbRect );
|
||||
thumbRect.setLocation( x, y );
|
||||
SwingUtilities.computeUnion( thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height, r );
|
||||
|
||||
// increase union rectangle for repaint
|
||||
int extra = (int) Math.ceil( UIScale.scale( focusWidth ) * 0.4142f );
|
||||
if( slider.getOrientation() == JSlider.HORIZONTAL )
|
||||
r.height += extra;
|
||||
else {
|
||||
r.width += extra;
|
||||
if( !slider.getComponentOrientation().isLeftToRight() )
|
||||
r.x -= extra;
|
||||
}
|
||||
|
||||
slider.repaint( r );
|
||||
} else
|
||||
super.setThumbLocation( x, y );
|
||||
}
|
||||
|
||||
//---- class FlatTrackListener --------------------------------------------
|
||||
|
||||
protected class FlatTrackListener
|
||||
extends TrackListener
|
||||
{
|
||||
@Override
|
||||
public void mouseEntered( MouseEvent e ) {
|
||||
setThumbHover( isOverThumb( e ) );
|
||||
super.mouseEntered( e );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited( MouseEvent e ) {
|
||||
setThumbHover( false );
|
||||
super.mouseExited( e );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseMoved( MouseEvent e ) {
|
||||
setThumbHover( isOverThumb( e ) );
|
||||
super.mouseMoved( e );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed( MouseEvent e ) {
|
||||
setThumbPressed( isOverThumb( e ) );
|
||||
|
||||
if( !slider.isEnabled() )
|
||||
return;
|
||||
|
||||
// use "old" behavior when clicking on track
|
||||
if( UIManager.getBoolean( "Slider.scrollOnTrackClick" ) ) {
|
||||
super.mousePressed( e );
|
||||
return;
|
||||
}
|
||||
|
||||
// "new" behavior set thumb to mouse location when clicking on track
|
||||
|
||||
int x = e.getX();
|
||||
int y = e.getY();
|
||||
|
||||
// clicked on thumb --> let super class do the work
|
||||
calculateGeometry();
|
||||
if( thumbRect.contains( x, y ) ) {
|
||||
super.mousePressed( e );
|
||||
return;
|
||||
}
|
||||
|
||||
if( UIManager.getBoolean( "Slider.onlyLeftMouseButtonDrag" ) &&
|
||||
!SwingUtilities.isLeftMouseButton( e ) )
|
||||
return;
|
||||
|
||||
// move the mouse event coordinates to the center of the thumb
|
||||
int tx = thumbRect.x + (thumbRect.width / 2) - x;
|
||||
int ty = thumbRect.y + (thumbRect.height / 2) - y;
|
||||
e.translatePoint( tx, ty );
|
||||
|
||||
// invoke super mousePressed() to start dragging thumb
|
||||
super.mousePressed( e );
|
||||
|
||||
// move the mouse event coordinates back to current mouse location
|
||||
e.translatePoint( -tx, -ty );
|
||||
|
||||
// invoke mouseDragged() to update thumb location
|
||||
mouseDragged( e );
|
||||
|
||||
setThumbPressed( true );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased( MouseEvent e ) {
|
||||
setThumbPressed( false );
|
||||
super.mouseReleased( e );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDragged( MouseEvent e ) {
|
||||
super.mouseDragged( e );
|
||||
|
||||
if( isDragging() &&
|
||||
slider.getSnapToTicks() &&
|
||||
slider.isEnabled() &&
|
||||
!UIManager.getBoolean( "Slider.snapToTicksOnReleased" ) )
|
||||
{
|
||||
calculateThumbLocation();
|
||||
slider.repaint();
|
||||
}
|
||||
}
|
||||
|
||||
protected void setThumbHover( boolean hover ) {
|
||||
if( hover != thumbHover ) {
|
||||
thumbHover = hover;
|
||||
slider.repaint( thumbRect );
|
||||
}
|
||||
}
|
||||
|
||||
protected void setThumbPressed( boolean pressed ) {
|
||||
if( pressed != thumbPressed ) {
|
||||
thumbPressed = pressed;
|
||||
slider.repaint( thumbRect );
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isOverThumb( MouseEvent e ) {
|
||||
return e != null && slider.isEnabled() && thumbRect.contains( e.getX(), e.getY() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ import com.formdev.flatlaf.FlatClientProperties;
|
||||
*
|
||||
* @uiDefault Component.minimumWidth int
|
||||
* @uiDefault Spinner.buttonStyle String button (default) or none
|
||||
* @uiDefault Component.arrowType String triangle (default) or chevron
|
||||
* @uiDefault Component.arrowType String chevron (default) or triangle
|
||||
* @uiDefault Component.isIntelliJTheme boolean
|
||||
* @uiDefault Component.borderColor Color
|
||||
* @uiDefault Component.disabledBorderColor Color
|
||||
@@ -264,35 +264,38 @@ public class FlatSpinnerUI
|
||||
FlatUIUtils.paintParentBackground( g, c );
|
||||
|
||||
Graphics2D g2 = (Graphics2D) g;
|
||||
FlatUIUtils.setRenderingHints( g2 );
|
||||
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g2 );
|
||||
|
||||
int width = c.getWidth();
|
||||
int height = c.getHeight();
|
||||
Component nextButton = getHandler().nextButton;
|
||||
int arrowX = nextButton.getX();
|
||||
int arrowWidth = nextButton.getWidth();
|
||||
boolean paintButton = !"none".equals( buttonStyle );
|
||||
boolean enabled = spinner.isEnabled();
|
||||
boolean isLeftToRight = spinner.getComponentOrientation().isLeftToRight();
|
||||
|
||||
// paint background
|
||||
g2.setColor( getBackground( enabled ) );
|
||||
FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc );
|
||||
|
||||
// paint arrow buttons background
|
||||
if( paintButton && enabled ) {
|
||||
g2.setColor( buttonBackground );
|
||||
Shape oldClip = g2.getClip();
|
||||
if( isLeftToRight )
|
||||
g2.clipRect( arrowX, 0, width - arrowX, height );
|
||||
else
|
||||
g2.clipRect( 0, 0, arrowX + arrowWidth, height );
|
||||
FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc );
|
||||
g2.setClip( oldClip );
|
||||
}
|
||||
// paint button background and separator
|
||||
boolean paintButton = !"none".equals( buttonStyle );
|
||||
Handler handler = getHandler();
|
||||
if( paintButton && (handler.nextButton != null || handler.previousButton != null) ) {
|
||||
Component button = (handler.nextButton != null) ? handler.nextButton : handler.previousButton;
|
||||
int arrowX = button.getX();
|
||||
int arrowWidth = button.getWidth();
|
||||
boolean isLeftToRight = spinner.getComponentOrientation().isLeftToRight();
|
||||
|
||||
// paint vertical line between value and arrow buttons
|
||||
if( paintButton ) {
|
||||
// paint arrow buttons background
|
||||
if( enabled ) {
|
||||
g2.setColor( buttonBackground );
|
||||
Shape oldClip = g2.getClip();
|
||||
if( isLeftToRight )
|
||||
g2.clipRect( arrowX, 0, width - arrowX, height );
|
||||
else
|
||||
g2.clipRect( 0, 0, arrowX + arrowWidth, height );
|
||||
FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc );
|
||||
g2.setClip( oldClip );
|
||||
}
|
||||
|
||||
// paint vertical line between value and arrow buttons
|
||||
g2.setColor( enabled ? borderColor : disabledBorderColor );
|
||||
float lw = scale( 1f );
|
||||
float lx = isLeftToRight ? arrowX : arrowX + arrowWidth - lw;
|
||||
@@ -300,6 +303,8 @@ public class FlatSpinnerUI
|
||||
}
|
||||
|
||||
paint( g, c );
|
||||
|
||||
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
|
||||
}
|
||||
|
||||
//---- class Handler ------------------------------------------------------
|
||||
@@ -359,7 +364,7 @@ public class FlatSpinnerUI
|
||||
|
||||
if( nextButton == null && previousButton == null ) {
|
||||
if( editor != null )
|
||||
editor.setBounds( r );
|
||||
editor.setBounds( FlatUIUtils.subtractInsets( r, padding ) );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,11 +17,17 @@
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Container;
|
||||
import java.awt.Cursor;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Insets;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JSplitPane;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.ToolTipManager;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicSplitPaneDivider;
|
||||
@@ -42,10 +48,15 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
*
|
||||
* <!-- FlatSplitPaneUI -->
|
||||
*
|
||||
* @uiDefault Component.arrowType String triangle (default) or chevron
|
||||
* @uiDefault Component.arrowType String chevron (default) or triangle
|
||||
* @uiDefault SplitPane.continuousLayout boolean
|
||||
* @uiDefault SplitPaneDivider.oneTouchArrowColor Color
|
||||
* @uiDefault SplitPaneDivider.oneTouchHoverArrowColor Color
|
||||
* @uiDefault SplitPaneDivider.style String grip (default) or plain
|
||||
* @uiDefault SplitPaneDivider.gripColor Color
|
||||
* @uiDefault SplitPaneDivider.gripDotCount int
|
||||
* @uiDefault SplitPaneDivider.gripDotSize int
|
||||
* @uiDefault SplitPaneDivider.gripGap int
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
@@ -54,8 +65,8 @@ public class FlatSplitPaneUI
|
||||
{
|
||||
protected String arrowType;
|
||||
private Boolean continuousLayout;
|
||||
private Color oneTouchArrowColor;
|
||||
private Color oneTouchHoverArrowColor;
|
||||
protected Color oneTouchArrowColor;
|
||||
protected Color oneTouchHoverArrowColor;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatSplitPaneUI();
|
||||
@@ -90,8 +101,16 @@ public class FlatSplitPaneUI
|
||||
protected class FlatSplitPaneDivider
|
||||
extends BasicSplitPaneDivider
|
||||
{
|
||||
protected final String style = UIManager.getString( "SplitPaneDivider.style" );
|
||||
protected final Color gripColor = UIManager.getColor( "SplitPaneDivider.gripColor" );
|
||||
protected final int gripDotCount = FlatUIUtils.getUIInt( "SplitPaneDivider.gripDotCount", 3 );
|
||||
protected final int gripDotSize = FlatUIUtils.getUIInt( "SplitPaneDivider.gripDotSize", 3 );
|
||||
protected final int gripGap = FlatUIUtils.getUIInt( "SplitPaneDivider.gripGap", 2 );
|
||||
|
||||
protected FlatSplitPaneDivider( BasicSplitPaneUI ui ) {
|
||||
super( ui );
|
||||
|
||||
setLayout( new FlatDividerLayout() );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -109,16 +128,66 @@ public class FlatSplitPaneUI
|
||||
return new FlatOneTouchButton( false );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void propertyChange( PropertyChangeEvent e ) {
|
||||
super.propertyChange( e );
|
||||
|
||||
switch( e.getPropertyName() ) {
|
||||
case JSplitPane.DIVIDER_LOCATION_PROPERTY:
|
||||
// necessary to show/hide one-touch buttons on expand/collapse
|
||||
revalidate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint( Graphics g ) {
|
||||
super.paint( g );
|
||||
|
||||
if( "plain".equals( style ) )
|
||||
return;
|
||||
|
||||
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g );
|
||||
|
||||
g.setColor( gripColor );
|
||||
paintGrip( g, 0, 0, getWidth(), getHeight() );
|
||||
|
||||
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
|
||||
}
|
||||
|
||||
protected void paintGrip( Graphics g, int x, int y, int width, int height ) {
|
||||
FlatUIUtils.paintGrip( g, x, y, width, height,
|
||||
splitPane.getOrientation() == JSplitPane.VERTICAL_SPLIT,
|
||||
gripDotCount, gripDotSize, gripGap, true );
|
||||
}
|
||||
|
||||
protected boolean isLeftCollapsed() {
|
||||
int location = splitPane.getDividerLocation();
|
||||
Insets insets = splitPane.getInsets();
|
||||
return (orientation == JSplitPane.VERTICAL_SPLIT)
|
||||
? location == insets.top
|
||||
: location == insets.left;
|
||||
}
|
||||
|
||||
protected boolean isRightCollapsed() {
|
||||
int location = splitPane.getDividerLocation();
|
||||
Insets insets = splitPane.getInsets();
|
||||
return (orientation == JSplitPane.VERTICAL_SPLIT)
|
||||
? location == (splitPane.getHeight() - getHeight() - insets.bottom)
|
||||
: location == (splitPane.getWidth() - getWidth() - insets.right);
|
||||
}
|
||||
|
||||
//---- class FlatOneTouchButton ---------------------------------------
|
||||
|
||||
private class FlatOneTouchButton
|
||||
protected class FlatOneTouchButton
|
||||
extends FlatArrowButton
|
||||
{
|
||||
private final boolean left;
|
||||
protected final boolean left;
|
||||
|
||||
public FlatOneTouchButton( boolean left ) {
|
||||
protected FlatOneTouchButton( boolean left ) {
|
||||
super( SwingConstants.NORTH, arrowType, oneTouchArrowColor, null, oneTouchHoverArrowColor, null );
|
||||
setCursor( Cursor.getPredefinedCursor( Cursor.DEFAULT_CURSOR ) );
|
||||
ToolTipManager.sharedInstance().registerComponent( this );
|
||||
|
||||
this.left = left;
|
||||
}
|
||||
@@ -129,7 +198,67 @@ public class FlatSplitPaneUI
|
||||
? (left ? SwingConstants.NORTH : SwingConstants.SOUTH)
|
||||
: (left ? SwingConstants.WEST : SwingConstants.EAST);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getToolTipText( MouseEvent e ) {
|
||||
String key = (orientation == JSplitPane.VERTICAL_SPLIT)
|
||||
? (left
|
||||
? (isRightCollapsed()
|
||||
? "SplitPaneDivider.expandBottomToolTipText"
|
||||
: "SplitPaneDivider.collapseTopToolTipText")
|
||||
: (isLeftCollapsed()
|
||||
? "SplitPaneDivider.expandTopToolTipText"
|
||||
: "SplitPaneDivider.collapseBottomToolTipText"))
|
||||
: (left
|
||||
? (isRightCollapsed()
|
||||
? "SplitPaneDivider.expandRightToolTipText"
|
||||
: "SplitPaneDivider.collapseLeftToolTipText")
|
||||
: (isLeftCollapsed()
|
||||
? "SplitPaneDivider.expandLeftToolTipText"
|
||||
: "SplitPaneDivider.collapseRightToolTipText"));
|
||||
|
||||
// get text from client property
|
||||
Object value = splitPane.getClientProperty( key );
|
||||
if( value instanceof String )
|
||||
return (String) value;
|
||||
|
||||
// get text from bundle
|
||||
return UIManager.getString( key, getLocale() );
|
||||
}
|
||||
}
|
||||
|
||||
//---- class FlatDividerLayout ----------------------------------------
|
||||
|
||||
protected class FlatDividerLayout
|
||||
extends DividerLayout
|
||||
{
|
||||
@Override
|
||||
public void layoutContainer( Container c ) {
|
||||
super.layoutContainer( c );
|
||||
|
||||
if( leftButton == null || rightButton == null || !splitPane.isOneTouchExpandable() )
|
||||
return;
|
||||
|
||||
// increase side of buttons, which makes them easier to hit by the user
|
||||
// and avoids cut arrows at small divider sizes
|
||||
int extraSize = UIScale.scale( 4 );
|
||||
if( orientation == JSplitPane.VERTICAL_SPLIT ) {
|
||||
leftButton.setSize( leftButton.getWidth() + extraSize, leftButton.getHeight() );
|
||||
rightButton.setBounds( leftButton.getX() + leftButton.getWidth(), rightButton.getY(),
|
||||
rightButton.getWidth() + extraSize, rightButton.getHeight() );
|
||||
} else {
|
||||
leftButton.setSize( leftButton.getWidth(), leftButton.getHeight() + extraSize );
|
||||
rightButton.setBounds( rightButton.getX(), leftButton.getY() + leftButton.getHeight(),
|
||||
rightButton.getWidth(), rightButton.getHeight() + extraSize );
|
||||
}
|
||||
|
||||
// hide buttons if not applicable
|
||||
boolean leftCollapsed = isLeftCollapsed();
|
||||
if( leftCollapsed )
|
||||
rightButton.setLocation( leftButton.getLocation() );
|
||||
leftButton.setVisible( !leftCollapsed );
|
||||
rightButton.setVisible( !isRightCollapsed() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -31,6 +31,7 @@ import javax.swing.JComponent;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.ScrollPaneConstants;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.Border;
|
||||
@@ -98,10 +99,13 @@ public class FlatTableHeaderUI
|
||||
|
||||
@Override
|
||||
public void paint( Graphics g, JComponent c ) {
|
||||
if( header.getColumnModel().getColumnCount() <= 0 )
|
||||
return;
|
||||
|
||||
// do not paint borders if JTableHeader.setDefaultRenderer() was used
|
||||
TableCellRenderer defaultRenderer = header.getDefaultRenderer();
|
||||
boolean paintBorders = isSystemDefaultRenderer( defaultRenderer );
|
||||
if( !paintBorders && header.getColumnModel().getColumnCount() > 0 ) {
|
||||
if( !paintBorders ) {
|
||||
// check whether the renderer delegates to the system default renderer
|
||||
Component rendererComponent = defaultRenderer.getTableCellRendererComponent(
|
||||
header.getTable(), "", false, false, -1, 0 );
|
||||
@@ -145,6 +149,9 @@ public class FlatTableHeaderUI
|
||||
float bottomLineIndent = lineWidth * 3;
|
||||
TableColumnModel columnModel = header.getColumnModel();
|
||||
int columnCount = columnModel.getColumnCount();
|
||||
int sepCount = columnCount;
|
||||
if( hideLastVerticalLine() )
|
||||
sepCount--;
|
||||
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
try {
|
||||
@@ -157,23 +164,30 @@ public class FlatTableHeaderUI
|
||||
// paint column separator lines
|
||||
g2.setColor( separatorColor );
|
||||
|
||||
int sepCount = columnCount;
|
||||
if( header.getTable().getAutoResizeMode() != JTable.AUTO_RESIZE_OFF && !isVerticalScrollBarVisible() )
|
||||
sepCount--;
|
||||
float y = topLineIndent;
|
||||
float h = height - bottomLineIndent;
|
||||
|
||||
if( header.getComponentOrientation().isLeftToRight() ) {
|
||||
int x = 0;
|
||||
for( int i = 0; i < sepCount; i++ ) {
|
||||
x += columnModel.getColumn( i ).getWidth();
|
||||
g2.fill( new Rectangle2D.Float( x - lineWidth, topLineIndent, lineWidth, height - bottomLineIndent ) );
|
||||
g2.fill( new Rectangle2D.Float( x - lineWidth, y, lineWidth, h ) );
|
||||
}
|
||||
|
||||
// paint trailing separator (on right side)
|
||||
if( !hideTrailingVerticalLine() )
|
||||
g2.fill( new Rectangle2D.Float( header.getWidth() - lineWidth, y, lineWidth, h ) );
|
||||
} else {
|
||||
int x = width;
|
||||
Rectangle cellRect = header.getHeaderRect( 0 );
|
||||
int x = cellRect.x + cellRect.width;
|
||||
for( int i = 0; i < sepCount; i++ ) {
|
||||
x -= columnModel.getColumn( i ).getWidth();
|
||||
g2.fill( new Rectangle2D.Float( x - (i < sepCount - 1 ? lineWidth : 0),
|
||||
topLineIndent, lineWidth, height - bottomLineIndent ) );
|
||||
g2.fill( new Rectangle2D.Float( x - (i < sepCount - 1 ? lineWidth : 0), y, lineWidth, h ) );
|
||||
}
|
||||
|
||||
// paint trailing separator (on left side)
|
||||
if( !hideTrailingVerticalLine() )
|
||||
g2.fill( new Rectangle2D.Float( 0, y, lineWidth, h ) );
|
||||
}
|
||||
} finally {
|
||||
g2.dispose();
|
||||
@@ -230,20 +244,30 @@ public class FlatTableHeaderUI
|
||||
return size;
|
||||
}
|
||||
|
||||
private boolean isVerticalScrollBarVisible() {
|
||||
JScrollPane scrollPane = getScrollPane();
|
||||
return (scrollPane != null && scrollPane.getVerticalScrollBar() != null)
|
||||
? scrollPane.getVerticalScrollBar().isVisible()
|
||||
: false;
|
||||
protected boolean hideLastVerticalLine() {
|
||||
Container viewport = header.getParent();
|
||||
Container viewportParent = (viewport != null) ? viewport.getParent() : null;
|
||||
if( !(viewportParent instanceof JScrollPane) )
|
||||
return false;
|
||||
|
||||
Rectangle cellRect = header.getHeaderRect( header.getColumnModel().getColumnCount() - 1 );
|
||||
|
||||
// using component orientation of scroll pane here because it is also used in FlatTableUI
|
||||
JScrollPane scrollPane = (JScrollPane) viewportParent;
|
||||
return scrollPane.getComponentOrientation().isLeftToRight()
|
||||
? cellRect.x + cellRect.width >= viewport.getWidth()
|
||||
: cellRect.x <= 0;
|
||||
}
|
||||
|
||||
private JScrollPane getScrollPane() {
|
||||
Container parent = header.getParent();
|
||||
if( parent == null )
|
||||
return null;
|
||||
protected boolean hideTrailingVerticalLine() {
|
||||
Container viewport = header.getParent();
|
||||
Container viewportParent = (viewport != null) ? viewport.getParent() : null;
|
||||
if( !(viewportParent instanceof JScrollPane) )
|
||||
return false;
|
||||
|
||||
parent = parent.getParent();
|
||||
return (parent instanceof JScrollPane) ? (JScrollPane) parent : null;
|
||||
JScrollPane scrollPane = (JScrollPane) viewportParent;
|
||||
return viewport == scrollPane.getColumnHeader() &&
|
||||
scrollPane.getCorner( ScrollPaneConstants.UPPER_TRAILING_CORNER ) == null;
|
||||
}
|
||||
|
||||
//---- class FlatTableCellHeaderRenderer ----------------------------------
|
||||
|
||||
@@ -17,17 +17,25 @@
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JViewport;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicTableUI;
|
||||
import javax.swing.table.TableCellRenderer;
|
||||
import com.formdev.flatlaf.util.Graphics2DProxy;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
@@ -71,6 +79,10 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault Table.cellFocusColor Color
|
||||
* @uiDefault Table.showCellFocusIndicator boolean
|
||||
*
|
||||
* <!-- FlatInputMaps -->
|
||||
*
|
||||
* @uiDefault Table.consistentHomeEndKeyBehavior boolean
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatTableUI
|
||||
@@ -93,16 +105,6 @@ public class FlatTableUI
|
||||
return new FlatTableUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uninstallUI( JComponent c ) {
|
||||
super.uninstallUI( c );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
@@ -194,6 +196,9 @@ public class FlatTableUI
|
||||
* or the application has to be changed to extend a FlatLaf renderer.
|
||||
*/
|
||||
private void toggleSelectionColors() {
|
||||
if( table == null )
|
||||
return;
|
||||
|
||||
if( FlatUIUtils.isPermanentFocusOwner( table ) ) {
|
||||
if( table.getSelectionBackground() == selectionInactiveBackground )
|
||||
table.setSelectionBackground( selectionBackground );
|
||||
@@ -206,4 +211,94 @@ public class FlatTableUI
|
||||
table.setSelectionForeground( selectionInactiveForeground );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint( Graphics g, JComponent c ) {
|
||||
boolean horizontalLines = table.getShowHorizontalLines();
|
||||
boolean verticalLines = table.getShowVerticalLines();
|
||||
if( horizontalLines || verticalLines ) {
|
||||
// fix grid painting issues in BasicTableUI
|
||||
// - do not paint last vertical grid line if line is on right edge of scroll pane
|
||||
// - fix unstable grid line thickness when scaled at 125%, 150%, 175%, 225%, ...
|
||||
// which paints either 1px or 2px lines depending on location
|
||||
|
||||
boolean hideLastVerticalLine = hideLastVerticalLine();
|
||||
int tableWidth = table.getWidth();
|
||||
|
||||
double systemScaleFactor = UIScale.getSystemScaleFactor( (Graphics2D) g );
|
||||
double lineThickness = (1. / systemScaleFactor) * (int) systemScaleFactor;
|
||||
|
||||
// Java 8 uses drawLine() to paint grid lines
|
||||
// Java 9+ uses fillRect() to paint grid lines
|
||||
g = new Graphics2DProxy( (Graphics2D) g ) {
|
||||
@Override
|
||||
public void drawLine( int x1, int y1, int x2, int y2 ) {
|
||||
// do not paint last vertical line
|
||||
if( hideLastVerticalLine && verticalLines &&
|
||||
x1 == x2 && y1 == 0 && x1 == tableWidth - 1 &&
|
||||
wasInvokedFromPaintGrid() )
|
||||
return;
|
||||
|
||||
super.drawLine( x1, y1, x2, y2 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillRect( int x, int y, int width, int height ) {
|
||||
// do not paint last vertical line
|
||||
if( hideLastVerticalLine && verticalLines &&
|
||||
width == 1 && y == 0 && x == tableWidth - 1 &&
|
||||
wasInvokedFromPaintGrid() )
|
||||
return;
|
||||
|
||||
// reduce line thickness to avoid unstable painted line thickness
|
||||
if( lineThickness != 1 ) {
|
||||
if( horizontalLines && height == 1 && wasInvokedFromPaintGrid() ) {
|
||||
super.fill( new Rectangle2D.Double( x, y, width, lineThickness ) );
|
||||
return;
|
||||
}
|
||||
if( verticalLines && width == 1 && y == 0 && wasInvokedFromPaintGrid() ) {
|
||||
super.fill( new Rectangle2D.Double( x, y, lineThickness, height ) );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
super.fillRect( x, y, width, height );
|
||||
}
|
||||
|
||||
private boolean wasInvokedFromPaintGrid() {
|
||||
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
|
||||
for( int i = 0; i < 10 || i < stackTrace.length; i++ ) {
|
||||
if( "javax.swing.plaf.basic.BasicTableUI".equals( stackTrace[i].getClassName() ) &&
|
||||
"paintGrid".equals( stackTrace[i].getMethodName() ) )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
super.paint( g, c );
|
||||
}
|
||||
|
||||
protected boolean hideLastVerticalLine() {
|
||||
Container viewport = SwingUtilities.getUnwrappedParent( table );
|
||||
Container viewportParent = (viewport != null) ? viewport.getParent() : null;
|
||||
if( !(viewportParent instanceof JScrollPane) )
|
||||
return false;
|
||||
|
||||
// do not hide last vertical line if table is smaller than viewport
|
||||
if( table.getX() + table.getWidth() < viewport.getWidth() )
|
||||
return false;
|
||||
|
||||
// in left-to-right:
|
||||
// - do not hide last vertical line if table used as row header in scroll pane
|
||||
// in right-to-left:
|
||||
// - hide last vertical line if table used as row header in scroll pane
|
||||
// - do not hide last vertical line if table is in center and scroll pane has row header
|
||||
JScrollPane scrollPane = (JScrollPane) viewportParent;
|
||||
JViewport rowHeader = scrollPane.getRowHeader();
|
||||
return scrollPane.getComponentOrientation().isLeftToRight()
|
||||
? (viewport != rowHeader)
|
||||
: (viewport == rowHeader || rowHeader == null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +60,7 @@ public class FlatTextAreaUI
|
||||
{
|
||||
protected int minimumWidth;
|
||||
protected boolean isIntelliJTheme;
|
||||
protected Color background;
|
||||
protected Color disabledBackground;
|
||||
protected Color inactiveBackground;
|
||||
|
||||
@@ -67,12 +68,20 @@ public class FlatTextAreaUI
|
||||
return new FlatTextAreaUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
updateBackground();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
|
||||
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
||||
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
||||
background = UIManager.getColor( "TextArea.background" );
|
||||
disabledBackground = UIManager.getColor( "TextArea.disabledBackground" );
|
||||
inactiveBackground = UIManager.getColor( "TextArea.inactiveBackground" );
|
||||
}
|
||||
@@ -81,6 +90,7 @@ public class FlatTextAreaUI
|
||||
protected void uninstallDefaults() {
|
||||
super.uninstallDefaults();
|
||||
|
||||
background = null;
|
||||
disabledBackground = null;
|
||||
inactiveBackground = null;
|
||||
}
|
||||
@@ -89,26 +99,36 @@ public class FlatTextAreaUI
|
||||
protected void propertyChange( PropertyChangeEvent e ) {
|
||||
super.propertyChange( e );
|
||||
FlatEditorPaneUI.propertyChange( getComponent(), e );
|
||||
|
||||
switch( e.getPropertyName() ) {
|
||||
case "editable":
|
||||
case "enabled":
|
||||
updateBackground();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintSafely( Graphics g ) {
|
||||
super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintBackground( Graphics g ) {
|
||||
private void updateBackground() {
|
||||
JTextComponent c = getComponent();
|
||||
|
||||
Color background = c.getBackground();
|
||||
g.setColor( !(background instanceof UIResource)
|
||||
? background
|
||||
: (isIntelliJTheme && (!c.isEnabled() || !c.isEditable())
|
||||
? FlatUIUtils.getParentBackground( c )
|
||||
: (!c.isEnabled()
|
||||
? disabledBackground
|
||||
: (!c.isEditable() ? inactiveBackground : background))) );
|
||||
g.fillRect( 0, 0, c.getWidth(), c.getHeight() );
|
||||
if( !(background instanceof UIResource) )
|
||||
return;
|
||||
|
||||
// do not update background if it currently has a unknown color (assigned from outside)
|
||||
if( background != this.background &&
|
||||
background != disabledBackground &&
|
||||
background != inactiveBackground )
|
||||
return;
|
||||
|
||||
Color newBackground = !c.isEnabled()
|
||||
? disabledBackground
|
||||
: (!c.isEditable()
|
||||
? inactiveBackground
|
||||
: this.background);
|
||||
|
||||
if( newBackground != background )
|
||||
c.setBackground( newBackground );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -128,4 +148,22 @@ public class FlatTextAreaUI
|
||||
|
||||
return FlatEditorPaneUI.applyMinimumWidth( c, size, minimumWidth );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintSafely( Graphics g ) {
|
||||
super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintBackground( Graphics g ) {
|
||||
JTextComponent c = getComponent();
|
||||
|
||||
// for compatibility with IntelliJ themes
|
||||
if( isIntelliJTheme && (!c.isEnabled() || !c.isEditable()) && (c.getBackground() instanceof UIResource) ) {
|
||||
FlatUIUtils.paintParentBackground( g, c );
|
||||
return;
|
||||
}
|
||||
|
||||
super.paintBackground( g );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,10 @@ public class FlatTextBorder
|
||||
|
||||
@Override
|
||||
protected int getArc( Component c ) {
|
||||
return FlatUIUtils.isRoundRect( c ) ? Short.MAX_VALUE : arc;
|
||||
if( isCellEditor( c ) )
|
||||
return 0;
|
||||
|
||||
Boolean roundRect = FlatUIUtils.isRoundRect( c );
|
||||
return roundRect != null ? (roundRect ? Short.MAX_VALUE : 0) : arc;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,6 +64,7 @@ import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
* @uiDefault Component.isIntelliJTheme boolean
|
||||
* @uiDefault TextField.placeholderForeground Color
|
||||
* @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always
|
||||
* @uiDefault TextComponent.selectAllOnMouseClick boolean
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
@@ -121,7 +122,8 @@ public class FlatTextFieldUI
|
||||
|
||||
@Override
|
||||
protected Caret createCaret() {
|
||||
return new FlatCaret( UIManager.getString( "TextComponent.selectAllOnFocusPolicy" ) );
|
||||
return new FlatCaret( UIManager.getString( "TextComponent.selectAllOnFocusPolicy"),
|
||||
UIManager.getBoolean( "TextComponent.selectAllOnMouseClick" ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.formdev.flatlaf.ui;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dialog;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.EventQueue;
|
||||
@@ -75,6 +76,7 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault TitlePane.foreground Color
|
||||
* @uiDefault TitlePane.inactiveForeground Color
|
||||
* @uiDefault TitlePane.embeddedForeground Color
|
||||
* @uiDefault TitlePane.borderColor Color optional
|
||||
* @uiDefault TitlePane.iconSize Dimension
|
||||
* @uiDefault TitlePane.iconMargins Insets
|
||||
* @uiDefault TitlePane.titleMargins Insets
|
||||
@@ -96,6 +98,7 @@ public class FlatTitlePane
|
||||
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" );
|
||||
|
||||
protected final Insets menuBarMargins = UIManager.getInsets( "TitlePane.menuBarMargins" );
|
||||
protected final Dimension iconSize = UIManager.getDimension( "TitlePane.iconSize" );
|
||||
@@ -148,10 +151,6 @@ public class FlatTitlePane
|
||||
iconLabel.setBorder( new FlatEmptyBorder( UIManager.getInsets( "TitlePane.iconMargins" ) ) );
|
||||
titleLabel.setBorder( new FlatEmptyBorder( UIManager.getInsets( "TitlePane.titleMargins" ) ) );
|
||||
|
||||
//TODO
|
||||
// titleLabel.setHorizontalAlignment( JLabel.CENTER );
|
||||
// titleLabel.setHorizontalAlignment( JLabel.RIGHT );
|
||||
|
||||
leftPanel.setLayout( new BoxLayout( leftPanel, BoxLayout.LINE_AXIS ) );
|
||||
leftPanel.setOpaque( false );
|
||||
leftPanel.add( iconLabel );
|
||||
@@ -160,7 +159,7 @@ public class FlatTitlePane
|
||||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
JMenuBar menuBar = rootPane.getJMenuBar();
|
||||
return (menuBar != null && isMenuBarEmbedded())
|
||||
return (menuBar != null && menuBar.isVisible() && isMenuBarEmbedded())
|
||||
? FlatUIUtils.addInsets( menuBar.getPreferredSize(), UIScale.scale( menuBarMargins ) )
|
||||
: new Dimension();
|
||||
}
|
||||
@@ -169,7 +168,25 @@ public class FlatTitlePane
|
||||
|
||||
createButtons();
|
||||
|
||||
setLayout( new BorderLayout() );
|
||||
setLayout( new BorderLayout() {
|
||||
@Override
|
||||
public void layoutContainer( Container target ) {
|
||||
super.layoutContainer( target );
|
||||
|
||||
// make left panel (with embedded menu bar) smaller if horizontal space is rare
|
||||
// to avoid that embedded menu bar overlaps button bar
|
||||
Insets insets = target.getInsets();
|
||||
int width = target.getWidth() - insets.left - insets.right;
|
||||
if( leftPanel.getWidth() + buttonPanel.getWidth() > width ) {
|
||||
int oldWidth = leftPanel.getWidth();
|
||||
int newWidth = Math.max( width - buttonPanel.getWidth(), 0 );
|
||||
leftPanel.setSize( newWidth, leftPanel.getHeight() );
|
||||
if( !getComponentOrientation().isLeftToRight() )
|
||||
leftPanel.setLocation( leftPanel.getX() + (oldWidth - newWidth), leftPanel.getY() );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
add( leftPanel, BorderLayout.LINE_START );
|
||||
add( titleLabel, BorderLayout.CENTER );
|
||||
add( buttonPanel, BorderLayout.LINE_END );
|
||||
@@ -223,14 +240,17 @@ public class FlatTitlePane
|
||||
}
|
||||
|
||||
protected void activeChanged( boolean active ) {
|
||||
boolean hasEmbeddedMenuBar = rootPane.getJMenuBar() != null && isMenuBarEmbedded();
|
||||
boolean hasEmbeddedMenuBar = rootPane.getJMenuBar() != null && rootPane.getJMenuBar().isVisible() && isMenuBarEmbedded();
|
||||
Color background = FlatUIUtils.nonUIResource( active ? activeBackground : inactiveBackground );
|
||||
Color foreground = FlatUIUtils.nonUIResource( active
|
||||
? (hasEmbeddedMenuBar ? embeddedForeground : activeForeground)
|
||||
: inactiveForeground );
|
||||
Color foreground = FlatUIUtils.nonUIResource( active ? activeForeground : inactiveForeground );
|
||||
Color titleForeground = (hasEmbeddedMenuBar && active) ? FlatUIUtils.nonUIResource( embeddedForeground ) : foreground;
|
||||
|
||||
setBackground( background );
|
||||
titleLabel.setForeground( foreground );
|
||||
titleLabel.setForeground( titleForeground );
|
||||
iconifyButton.setForeground( foreground );
|
||||
maximizeButton.setForeground( foreground );
|
||||
restoreButton.setForeground( foreground );
|
||||
closeButton.setForeground( foreground );
|
||||
|
||||
titleLabel.setHorizontalAlignment( hasEmbeddedMenuBar ? SwingConstants.CENTER : SwingConstants.LEADING );
|
||||
|
||||
@@ -253,6 +273,26 @@ public class FlatTitlePane
|
||||
iconifyButton.setVisible( true );
|
||||
maximizeButton.setVisible( resizable && !maximized );
|
||||
restoreButton.setVisible( resizable && maximized );
|
||||
|
||||
if( maximized &&
|
||||
rootPane.getClientProperty( "_flatlaf.maximizedBoundsUpToDate" ) == null )
|
||||
{
|
||||
rootPane.putClientProperty( "_flatlaf.maximizedBoundsUpToDate", null );
|
||||
|
||||
// In case that frame was maximized from custom code (e.g. when restoring
|
||||
// window state on application startup), then maximized bounds is not set
|
||||
// and the window would overlap Windows task bar.
|
||||
// To avoid this, update maximized bounds here and if it has changed
|
||||
// re-maximize windows so that maximized bounds are used.
|
||||
Rectangle oldMaximizedBounds = frame.getMaximizedBounds();
|
||||
updateMaximizedBounds();
|
||||
Rectangle newMaximizedBounds = frame.getMaximizedBounds();
|
||||
if( newMaximizedBounds != null && !newMaximizedBounds.equals( oldMaximizedBounds ) ) {
|
||||
int oldExtendedState = frame.getExtendedState();
|
||||
frame.setExtendedState( oldExtendedState & ~Frame.MAXIMIZED_BOTH );
|
||||
frame.setExtendedState( oldExtendedState );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// hide buttons because they are only supported in frames
|
||||
iconifyButton.setVisible( false );
|
||||
@@ -375,21 +415,46 @@ public class FlatTitlePane
|
||||
return FlatUIUtils.subtractInsets( bounds, UIScale.scale( getMenuBarMargins() ) );
|
||||
}
|
||||
|
||||
protected Insets getMenuBarMargins() {
|
||||
return getComponentOrientation().isLeftToRight()
|
||||
? menuBarMargins
|
||||
: new Insets( menuBarMargins.top, menuBarMargins.right, menuBarMargins.bottom, menuBarMargins.left );
|
||||
}
|
||||
|
||||
protected void menuBarChanged() {
|
||||
menuBarPlaceholder.invalidate();
|
||||
|
||||
// necessary for the case that an embedded menu bar is made invisible
|
||||
// and a border color is specified
|
||||
repaint();
|
||||
|
||||
// update title foreground color
|
||||
EventQueue.invokeLater( () -> {
|
||||
activeChanged( window == null || window.isActive() );
|
||||
} );
|
||||
}
|
||||
|
||||
protected Insets getMenuBarMargins() {
|
||||
return getComponentOrientation().isLeftToRight()
|
||||
? menuBarMargins
|
||||
: new Insets( menuBarMargins.top, menuBarMargins.right, menuBarMargins.bottom, menuBarMargins.left );
|
||||
protected void menuBarLayouted() {
|
||||
updateJBRHitTestSpotsAndTitleBarHeightLater();
|
||||
}
|
||||
|
||||
/*debug
|
||||
@Override
|
||||
public void paint( Graphics g ) {
|
||||
super.paint( g );
|
||||
|
||||
if( debugTitleBarHeight > 0 ) {
|
||||
g.setColor( Color.green );
|
||||
g.drawLine( 0, debugTitleBarHeight, getWidth(), debugTitleBarHeight );
|
||||
}
|
||||
if( debugHitTestSpots != null ) {
|
||||
g.setColor( Color.blue );
|
||||
for( Rectangle r : debugHitTestSpots )
|
||||
g.drawRect( r.x, r.y, r.width, r.height );
|
||||
}
|
||||
}
|
||||
debug*/
|
||||
|
||||
@Override
|
||||
protected void paintComponent( Graphics g ) {
|
||||
g.setColor( getBackground() );
|
||||
@@ -425,11 +490,24 @@ public class FlatTitlePane
|
||||
|
||||
Frame frame = (Frame) window;
|
||||
|
||||
updateMaximizedBounds();
|
||||
|
||||
// let our WindowStateListener know that the maximized bounds are up-to-date
|
||||
rootPane.putClientProperty( "_flatlaf.maximizedBoundsUpToDate", true );
|
||||
|
||||
// maximize window
|
||||
frame.setExtendedState( frame.getExtendedState() | Frame.MAXIMIZED_BOTH );
|
||||
}
|
||||
|
||||
protected void updateMaximizedBounds() {
|
||||
Frame frame = (Frame) window;
|
||||
|
||||
// set maximized bounds to avoid that maximized window overlaps Windows task bar
|
||||
// (if not running in JBR and if not modified from the application)
|
||||
Rectangle oldMaximizedBounds = frame.getMaximizedBounds();
|
||||
if( !hasJBRCustomDecoration() &&
|
||||
(frame.getMaximizedBounds() == null ||
|
||||
Objects.equals( frame.getMaximizedBounds(), rootPane.getClientProperty( "_flatlaf.maximizedBounds" ) )) )
|
||||
(oldMaximizedBounds == null ||
|
||||
Objects.equals( oldMaximizedBounds, rootPane.getClientProperty( "_flatlaf.maximizedBounds" ) )) )
|
||||
{
|
||||
GraphicsConfiguration gc = window.getGraphicsConfiguration();
|
||||
|
||||
@@ -450,7 +528,7 @@ public class FlatTitlePane
|
||||
int maximizedWidth = screenBounds.width;
|
||||
int maximizedHeight = screenBounds.height;
|
||||
|
||||
if( !SystemInfo.IS_JAVA_15_OR_LATER ) {
|
||||
if( !isMaximizedBoundsFixed() ) {
|
||||
// on Java 8 to 14, maximized x,y are 0,0 based on all screens in a multi-screen environment
|
||||
maximizedX = 0;
|
||||
maximizedY = 0;
|
||||
@@ -470,22 +548,36 @@ public class FlatTitlePane
|
||||
// (see https://bugs.openjdk.java.net/browse/JDK-8231564 and
|
||||
// https://bugs.openjdk.java.net/browse/JDK-8176359)
|
||||
// and except for Java 8 on secondary screens where primary screen is scaled
|
||||
Rectangle maximizedBounds = new Rectangle(
|
||||
Rectangle newMaximizedBounds = new Rectangle(
|
||||
maximizedX + screenInsets.left,
|
||||
maximizedY + screenInsets.top,
|
||||
maximizedWidth - screenInsets.left - screenInsets.right,
|
||||
maximizedHeight - screenInsets.top - screenInsets.bottom );
|
||||
|
||||
// change maximized bounds
|
||||
frame.setMaximizedBounds( maximizedBounds );
|
||||
if( !Objects.equals( oldMaximizedBounds, newMaximizedBounds ) ) {
|
||||
// change maximized bounds
|
||||
frame.setMaximizedBounds( newMaximizedBounds );
|
||||
|
||||
// remember maximized bounds in client property to be able to detect
|
||||
// whether maximized bounds are modified from the application
|
||||
rootPane.putClientProperty( "_flatlaf.maximizedBounds", maximizedBounds );
|
||||
// remember maximized bounds in client property to be able to detect
|
||||
// whether maximized bounds are modified from the application
|
||||
rootPane.putClientProperty( "_flatlaf.maximizedBounds", newMaximizedBounds );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// maximize window
|
||||
frame.setExtendedState( frame.getExtendedState() | Frame.MAXIMIZED_BOTH );
|
||||
/**
|
||||
* Frame.setMaximizedBounds() behaves different on some Java versions after issues
|
||||
* https://bugs.openjdk.java.net/browse/JDK-8231564 and
|
||||
* https://bugs.openjdk.java.net/browse/JDK-8176359
|
||||
* (see also https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8176359)
|
||||
* were fixed in Java 15 and backported to 11.0.8 and 13.0.4.
|
||||
*/
|
||||
private boolean isMaximizedBoundsFixed() {
|
||||
return SystemInfo.isJava_15_orLater ||
|
||||
(SystemInfo.javaVersion >= SystemInfo.toVersion( 11, 0, 8, 0 ) &&
|
||||
SystemInfo.javaVersion < SystemInfo.toVersion( 12, 0, 0, 0 )) ||
|
||||
(SystemInfo.javaVersion >= SystemInfo.toVersion( 13, 0, 4, 0 ) &&
|
||||
SystemInfo.javaVersion < SystemInfo.toVersion( 14, 0, 0, 0 ));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -540,6 +632,12 @@ public class FlatTitlePane
|
||||
titleBarHeight--;
|
||||
|
||||
JBRCustomDecorations.setHitTestSpotsAndTitleBarHeight( window, hitTestSpots, titleBarHeight );
|
||||
|
||||
/*debug
|
||||
debugHitTestSpots = hitTestSpots;
|
||||
debugTitleBarHeight = titleBarHeight;
|
||||
repaint();
|
||||
debug*/
|
||||
}
|
||||
|
||||
protected void addJBRHitTestSpot( JComponent c, boolean subtractMenuBarMargins, List<Rectangle> hitTestSpots ) {
|
||||
@@ -556,6 +654,11 @@ public class FlatTitlePane
|
||||
hitTestSpots.add( r );
|
||||
}
|
||||
|
||||
/*debug
|
||||
private List<Rectangle> debugHitTestSpots;
|
||||
private int debugTitleBarHeight;
|
||||
debug*/
|
||||
|
||||
//---- class TitlePaneBorder ----------------------------------------------
|
||||
|
||||
protected class FlatTitlePaneBorder
|
||||
@@ -565,12 +668,13 @@ public class FlatTitlePane
|
||||
public Insets getBorderInsets( Component c, Insets insets ) {
|
||||
super.getBorderInsets( c, insets );
|
||||
|
||||
// if menu bar is embedded, add bottom insets of menu bar border
|
||||
Border menuBarBorder = getMenuBarBorder();
|
||||
if( menuBarBorder != null ) {
|
||||
// if menu bar is embedded, add bottom insets of menu bar border
|
||||
Insets menuBarInsets = menuBarBorder.getBorderInsets( c );
|
||||
insets.bottom += menuBarInsets.bottom;
|
||||
}
|
||||
} else if( borderColor != null && (rootPane.getJMenuBar() == null || !rootPane.getJMenuBar().isVisible()) )
|
||||
insets.bottom += UIScale.scale( 1 );
|
||||
|
||||
if( hasJBRCustomDecoration() )
|
||||
insets = FlatUIUtils.addInsets( insets, JBRWindowTopBorder.getInstance().getBorderInsets() );
|
||||
@@ -580,10 +684,16 @@ public class FlatTitlePane
|
||||
|
||||
@Override
|
||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||
// if menu bar is embedded, paint menu bar border
|
||||
// paint bottom border
|
||||
Border menuBarBorder = getMenuBarBorder();
|
||||
if( menuBarBorder != null )
|
||||
if( menuBarBorder != null ) {
|
||||
// if menu bar is embedded, paint menu bar border
|
||||
menuBarBorder.paintBorder( c, g, x, y, width, height );
|
||||
} else if( borderColor != null && (rootPane.getJMenuBar() == null || !rootPane.getJMenuBar().isVisible()) ) {
|
||||
// paint border between title pane and content if border color is specified
|
||||
float lineHeight = UIScale.scale( (float) 1 );
|
||||
FlatUIUtils.paintFilledRectangle( g, borderColor, x, y + height - lineHeight, width, lineHeight );
|
||||
}
|
||||
|
||||
if( hasJBRCustomDecoration() )
|
||||
JBRWindowTopBorder.getInstance().paintBorder( c, g, x, y, width, height );
|
||||
@@ -591,7 +701,7 @@ public class FlatTitlePane
|
||||
|
||||
protected Border getMenuBarBorder() {
|
||||
JMenuBar menuBar = rootPane.getJMenuBar();
|
||||
return (menuBar != null && isMenuBarEmbedded()) ? menuBar.getBorder() : null;
|
||||
return (menuBar != null && menuBar.isVisible() && isMenuBarEmbedded()) ? menuBar.getBorder() : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -657,8 +767,7 @@ public class FlatTitlePane
|
||||
|
||||
//---- interface MouseListener ----
|
||||
|
||||
private int lastXOnScreen;
|
||||
private int lastYOnScreen;
|
||||
private Point dragOffset;
|
||||
|
||||
@Override
|
||||
public void mouseClicked( MouseEvent e ) {
|
||||
@@ -682,8 +791,10 @@ public class FlatTitlePane
|
||||
|
||||
@Override
|
||||
public void mousePressed( MouseEvent e ) {
|
||||
lastXOnScreen = e.getXOnScreen();
|
||||
lastYOnScreen = e.getYOnScreen();
|
||||
if( window == null )
|
||||
return; // should newer occur
|
||||
|
||||
dragOffset = SwingUtilities.convertPoint( FlatTitlePane.this, e.getPoint(), window );
|
||||
}
|
||||
|
||||
@Override public void mouseReleased( MouseEvent e ) {}
|
||||
@@ -694,46 +805,45 @@ public class FlatTitlePane
|
||||
|
||||
@Override
|
||||
public void mouseDragged( MouseEvent e ) {
|
||||
if( window == null )
|
||||
return; // should newer occur
|
||||
|
||||
if( hasJBRCustomDecoration() )
|
||||
return; // do nothing if running in JBR
|
||||
|
||||
int xOnScreen = e.getXOnScreen();
|
||||
int yOnScreen = e.getYOnScreen();
|
||||
if( lastXOnScreen == xOnScreen && lastYOnScreen == yOnScreen )
|
||||
return;
|
||||
|
||||
// restore window if it is maximized
|
||||
if( window instanceof Frame ) {
|
||||
Frame frame = (Frame) window;
|
||||
int state = frame.getExtendedState();
|
||||
if( (state & Frame.MAXIMIZED_BOTH) != 0 ) {
|
||||
int maximizedX = window.getX();
|
||||
int maximizedY = window.getY();
|
||||
int maximizedWidth = window.getWidth();
|
||||
|
||||
// restore window size, which also moves window to pre-maximized location
|
||||
frame.setExtendedState( state & ~Frame.MAXIMIZED_BOTH );
|
||||
|
||||
// fix drag offset to ensure that window remains under mouse position
|
||||
// for the case that dragging starts in the right area of the maximized window
|
||||
int restoredWidth = window.getWidth();
|
||||
int newX = maximizedX;
|
||||
JComponent rightComp = getComponentOrientation().isLeftToRight() ? buttonPanel : leftPanel;
|
||||
if( xOnScreen >= maximizedX + restoredWidth - rightComp.getWidth() - 10 )
|
||||
newX = xOnScreen + rightComp.getWidth() + 10 - restoredWidth;
|
||||
|
||||
// move window near mouse
|
||||
window.setLocation( newX, maximizedY );
|
||||
return;
|
||||
int center = restoredWidth / 2;
|
||||
if( dragOffset.x > center ) {
|
||||
// this is same/similar to what Windows 10 does
|
||||
if( dragOffset.x > maximizedWidth - center )
|
||||
dragOffset.x = restoredWidth - (maximizedWidth - dragOffset.x);
|
||||
else
|
||||
dragOffset.x = center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// compute new window location
|
||||
int newX = window.getX() + (xOnScreen - lastXOnScreen);
|
||||
int newY = window.getY() + (yOnScreen - lastYOnScreen);
|
||||
int newX = e.getXOnScreen() - dragOffset.x;
|
||||
int newY = e.getYOnScreen() - dragOffset.y;
|
||||
|
||||
if( newX == window.getX() && newY == window.getY() )
|
||||
return;
|
||||
|
||||
// move window
|
||||
window.setLocation( newX, newY );
|
||||
|
||||
lastXOnScreen = xOnScreen;
|
||||
lastYOnScreen = yOnScreen;
|
||||
}
|
||||
|
||||
@Override public void mouseMoved( MouseEvent e ) {}
|
||||
@@ -745,8 +855,13 @@ public class FlatTitlePane
|
||||
updateJBRHitTestSpotsAndTitleBarHeightLater();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentShown( ComponentEvent e ) {
|
||||
// necessary for the case that the frame is maximized before it is shown
|
||||
frameStateChanged();
|
||||
}
|
||||
|
||||
@Override public void componentMoved( ComponentEvent e ) {}
|
||||
@Override public void componentShown( ComponentEvent e ) {}
|
||||
@Override public void componentHidden( ComponentEvent e ) {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import javax.swing.AbstractButton;
|
||||
import javax.swing.ButtonModel;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JToggleButton;
|
||||
import javax.swing.UIManager;
|
||||
@@ -50,18 +49,17 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault ToggleButton.startBackground Color optional; if set, a gradient paint is used and ToggleButton.background is ignored
|
||||
* @uiDefault ToggleButton.endBackground Color optional; if set, a gradient paint is used
|
||||
* @uiDefault ToggleButton.pressedBackground Color
|
||||
* @uiDefault ToggleButton.disabledBackground Color optional
|
||||
* @uiDefault ToggleButton.disabledText Color
|
||||
* @uiDefault ToggleButton.toolbar.hoverBackground Color
|
||||
* @uiDefault ToggleButton.toolbar.pressedBackground Color
|
||||
*
|
||||
* <!-- FlatToggleButtonUI -->
|
||||
*
|
||||
* @uiDefault ToggleButton.selectedBackground Color
|
||||
* @uiDefault ToggleButton.selectedForeground Color
|
||||
* @uiDefault ToggleButton.disabledBackground Color optional
|
||||
* @uiDefault ToggleButton.disabledText Color
|
||||
* @uiDefault ToggleButton.disabledSelectedBackground Color
|
||||
* @uiDefault ToggleButton.toolbar.hoverBackground Color
|
||||
* @uiDefault ToggleButton.toolbar.pressedBackground Color
|
||||
* @uiDefault ToggleButton.toolbar.selectedBackground Color
|
||||
*
|
||||
* <!-- FlatToggleButtonUI -->
|
||||
*
|
||||
* @uiDefault ToggleButton.tab.underlineHeight int
|
||||
* @uiDefault ToggleButton.tab.underlineColor Color
|
||||
* @uiDefault ToggleButton.tab.disabledUnderlineColor Color
|
||||
@@ -75,12 +73,6 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
public class FlatToggleButtonUI
|
||||
extends FlatButtonUI
|
||||
{
|
||||
protected Color selectedBackground;
|
||||
protected Color selectedForeground;
|
||||
protected Color disabledSelectedBackground;
|
||||
|
||||
protected Color toolbarSelectedBackground;
|
||||
|
||||
protected int tabUnderlineHeight;
|
||||
protected Color tabUnderlineColor;
|
||||
protected Color tabDisabledUnderlineColor;
|
||||
@@ -90,12 +82,8 @@ public class FlatToggleButtonUI
|
||||
|
||||
private boolean defaults_initialized = false;
|
||||
|
||||
private static ComponentUI instance;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
if( instance == null )
|
||||
instance = new FlatToggleButtonUI();
|
||||
return instance;
|
||||
return FlatUIUtils.createSharedUI( FlatToggleButtonUI.class, FlatToggleButtonUI::new );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -108,12 +96,6 @@ public class FlatToggleButtonUI
|
||||
super.installDefaults( b );
|
||||
|
||||
if( !defaults_initialized ) {
|
||||
selectedBackground = UIManager.getColor( "ToggleButton.selectedBackground" );
|
||||
selectedForeground = UIManager.getColor( "ToggleButton.selectedForeground" );
|
||||
disabledSelectedBackground = UIManager.getColor( "ToggleButton.disabledSelectedBackground" );
|
||||
|
||||
toolbarSelectedBackground = UIManager.getColor( "ToggleButton.toolbar.selectedBackground" );
|
||||
|
||||
tabUnderlineHeight = UIManager.getInt( "ToggleButton.tab.underlineHeight" );
|
||||
tabUnderlineColor = UIManager.getColor( "ToggleButton.tab.underlineColor" );
|
||||
tabDisabledUnderlineColor = UIManager.getColor( "ToggleButton.tab.disabledUnderlineColor" );
|
||||
@@ -185,30 +167,4 @@ public class FlatToggleButtonUI
|
||||
} else
|
||||
super.paintBackground( g, c );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Color getBackground( JComponent c ) {
|
||||
ButtonModel model = ((AbstractButton)c).getModel();
|
||||
|
||||
if( model.isSelected() ) {
|
||||
// in toolbar use same colors for disabled and enabled because
|
||||
// we assume that toolbar icon is shown disabled
|
||||
boolean toolBarButton = isToolBarButton( c );
|
||||
return buttonStateColor( c,
|
||||
toolBarButton ? toolbarSelectedBackground : selectedBackground,
|
||||
toolBarButton ? toolbarSelectedBackground : disabledSelectedBackground,
|
||||
null, null,
|
||||
toolBarButton ? toolbarPressedBackground : pressedBackground );
|
||||
}
|
||||
|
||||
return super.getBackground( c );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Color getForeground( JComponent c ) {
|
||||
if( c.isEnabled() && ((AbstractButton)c).isSelected() && !isToolBarButton( c ) )
|
||||
return selectedForeground;
|
||||
|
||||
return super.getForeground( c );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,15 +16,16 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import static com.formdev.flatlaf.util.UIScale.*;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import javax.swing.JToolBar;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.UIManager;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
* Border for {@link javax.swing.JToolBar}.
|
||||
@@ -39,7 +40,7 @@ public class FlatToolBarBorder
|
||||
{
|
||||
private static final int DOT_COUNT = 4;
|
||||
private static final int DOT_SIZE = 2;
|
||||
private static final int GRIP_WIDTH = DOT_SIZE * 3;
|
||||
private static final int GRIP_SIZE = DOT_SIZE * 3;
|
||||
|
||||
protected final Color gripColor = UIManager.getColor( "ToolBar.gripColor" );
|
||||
|
||||
@@ -64,35 +65,27 @@ public class FlatToolBarBorder
|
||||
}
|
||||
|
||||
protected void paintGrip( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||
int dotSize = scale( DOT_SIZE );
|
||||
int gapSize = dotSize;
|
||||
int gripSize = (dotSize * DOT_COUNT) + ((gapSize * (DOT_COUNT - 1)));
|
||||
Rectangle r = calculateGripBounds( c, x, y, width, height );
|
||||
FlatUIUtils.paintGrip( g, r.x, r.y, r.width, r.height,
|
||||
((JToolBar)c).getOrientation() == SwingConstants.VERTICAL,
|
||||
DOT_COUNT, DOT_SIZE, DOT_SIZE, false );
|
||||
}
|
||||
|
||||
// include toolbar margin in grip position calculation
|
||||
Insets insets = getBorderInsets( c );
|
||||
protected Rectangle calculateGripBounds( Component c, int x, int y, int width, int height ) {
|
||||
// include toolbar margin in grip bounds calculation
|
||||
Insets insets = super.getBorderInsets( c, new Insets( 0, 0, 0, 0 ) );
|
||||
Rectangle r = FlatUIUtils.subtractInsets( new Rectangle( x, y, width, height ), insets );
|
||||
|
||||
// calculate grip position
|
||||
boolean horizontal = ((JToolBar)c).getOrientation() == SwingConstants.HORIZONTAL;
|
||||
if( horizontal ) {
|
||||
if( c.getComponentOrientation().isLeftToRight() )
|
||||
x += insets.left - (dotSize * 2);
|
||||
else
|
||||
x += width - insets.right + dotSize;
|
||||
y += Math.round( (height - gripSize) / 2f );
|
||||
} else {
|
||||
// vertical
|
||||
x += Math.round( (width - gripSize) / 2f );
|
||||
y += insets.top - (dotSize * 2);
|
||||
}
|
||||
// calculate grip bounds
|
||||
int gripSize = UIScale.scale( GRIP_SIZE );
|
||||
if( ((JToolBar)c).getOrientation() == SwingConstants.HORIZONTAL ) {
|
||||
if( !c.getComponentOrientation().isLeftToRight() )
|
||||
r.x = r.x + r.width - gripSize;
|
||||
r.width = gripSize;
|
||||
} else
|
||||
r.height = gripSize;
|
||||
|
||||
// paint dots
|
||||
for( int i = 0; i < DOT_COUNT; i++ ) {
|
||||
g.fillOval( x, y, dotSize, dotSize );
|
||||
if( horizontal )
|
||||
y += dotSize + gapSize;
|
||||
else
|
||||
x += dotSize + gapSize;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -101,7 +94,7 @@ public class FlatToolBarBorder
|
||||
|
||||
// add grip inset if floatable
|
||||
if( c instanceof JToolBar && ((JToolBar)c).isFloatable() ) {
|
||||
int gripInset = scale( GRIP_WIDTH );
|
||||
int gripInset = UIScale.scale( GRIP_SIZE );
|
||||
if( ((JToolBar)c).getOrientation() == SwingConstants.HORIZONTAL ) {
|
||||
if( c.getComponentOrientation().isLeftToRight() )
|
||||
insets.left += gripInset;
|
||||
|
||||
@@ -50,12 +50,8 @@ public class FlatToolBarSeparatorUI
|
||||
|
||||
private boolean defaults_initialized = false;
|
||||
|
||||
private static ComponentUI instance;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
if( instance == null )
|
||||
instance = new FlatToolBarSeparatorUI();
|
||||
return instance;
|
||||
return FlatUIUtils.createSharedUI( FlatToolBarSeparatorUI.class, FlatToolBarSeparatorUI::new );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -110,13 +106,15 @@ public class FlatToolBarSeparatorUI
|
||||
float lineWidth = scale( 1f );
|
||||
float offset = scale( 2f );
|
||||
|
||||
FlatUIUtils.setRenderingHints( (Graphics2D) g );
|
||||
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g );
|
||||
g.setColor( separatorColor );
|
||||
|
||||
if( isVertical( c ) )
|
||||
((Graphics2D)g).fill( new Rectangle2D.Float( Math.round( (width - lineWidth) / 2f ), offset, lineWidth, height - (offset * 2) ) );
|
||||
else
|
||||
((Graphics2D)g).fill( new Rectangle2D.Float( offset, Math.round( (height - lineWidth) / 2f ), width - (offset * 2), lineWidth ) );
|
||||
|
||||
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
|
||||
}
|
||||
|
||||
private boolean isVertical( JComponent c ) {
|
||||
|
||||
@@ -52,12 +52,8 @@ public class FlatToolTipUI
|
||||
{
|
||||
private static PropertyChangeListener sharedPropertyChangedListener;
|
||||
|
||||
private static ComponentUI instance;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
if( instance == null )
|
||||
instance = new FlatToolTipUI();
|
||||
return instance;
|
||||
return FlatUIUtils.createSharedUI( FlatToolTipUI.class, FlatToolTipUI::new );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -94,6 +90,11 @@ public class FlatToolTipUI
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize( JComponent c ) {
|
||||
// do not show tool tip if text is empty
|
||||
String text = ((JToolTip)c).getTipText();
|
||||
if( text == null || text.isEmpty() )
|
||||
return new Dimension();
|
||||
|
||||
if( isMultiLine( c ) ) {
|
||||
FontMetrics fm = c.getFontMetrics( c.getFont() );
|
||||
Insets insets = c.getInsets();
|
||||
@@ -115,7 +116,6 @@ public class FlatToolTipUI
|
||||
FontMetrics fm = c.getFontMetrics( c.getFont() );
|
||||
Insets insets = c.getInsets();
|
||||
|
||||
FlatUIUtils.setRenderingHints( (Graphics2D) g );
|
||||
g.setColor( c.getForeground() );
|
||||
|
||||
List<String> lines = StringUtils.split( ((JToolTip)c).getTipText(), '\n' );
|
||||
|
||||
@@ -23,25 +23,34 @@ import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.GraphicsDevice;
|
||||
import java.awt.Insets;
|
||||
import java.awt.KeyboardFocusManager;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.Shape;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.border.CompoundBorder;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.util.DerivedColor;
|
||||
@@ -58,6 +67,8 @@ public class FlatUIUtils
|
||||
{
|
||||
public static final boolean MAC_USE_QUARTZ = Boolean.getBoolean( "apple.awt.graphics.UseQuartz" );
|
||||
|
||||
private static WeakHashMap<LookAndFeel, IdentityHashMap<Object, ComponentUI>> sharedUIinstances = new WeakHashMap<>();
|
||||
|
||||
public static Rectangle addInsets( Rectangle r, Insets insets ) {
|
||||
return new Rectangle(
|
||||
r.x - insets.left,
|
||||
@@ -120,6 +131,10 @@ public class FlatUIUtils
|
||||
return (value instanceof Number) ? ((Number)value).floatValue() : defaultValue;
|
||||
}
|
||||
|
||||
public static boolean isChevron( String arrowType ) {
|
||||
return !"triangle".equals( arrowType );
|
||||
}
|
||||
|
||||
public static Color nonUIResource( Color c ) {
|
||||
return (c instanceof UIResource) ? new Color( c.getRGB(), true ) : c;
|
||||
}
|
||||
@@ -136,7 +151,26 @@ public class FlatUIUtils
|
||||
return FlatClientProperties.clientPropertyInt( c, FlatClientProperties.MINIMUM_HEIGHT, minimumHeight );
|
||||
}
|
||||
|
||||
public static boolean isTableCellEditor( Component c ) {
|
||||
public static boolean isCellEditor( Component c ) {
|
||||
// check whether used in cell editor (check 3 levels up)
|
||||
Component c2 = c;
|
||||
for( int i = 0; i <= 2 && c2 != null; i++ ) {
|
||||
Container parent = c2.getParent();
|
||||
if( parent instanceof JTable && ((JTable)parent).getEditorComponent() == c2 )
|
||||
return true;
|
||||
|
||||
c2 = parent;
|
||||
}
|
||||
|
||||
// check whether used as cell editor
|
||||
// Table.editor is set in JTable.GenericEditor constructor
|
||||
// Tree.cellEditor is set in sun.swing.FilePane.editFileName()
|
||||
String name = c.getName();
|
||||
if( "Table.editor".equals( name ) || "Tree.cellEditor".equals( name ) )
|
||||
return true;
|
||||
|
||||
// for using combo box as cell editor in table
|
||||
// JComboBox.isTableCellEditor is set in javax.swing.DefaultCellEditor(JComboBox) constructor
|
||||
return c instanceof JComponent && Boolean.TRUE.equals( ((JComponent)c).getClientProperty( "JComboBox.isTableCellEditor" ) );
|
||||
}
|
||||
|
||||
@@ -150,9 +184,21 @@ public class FlatUIUtils
|
||||
keyboardFocusManager.getActiveWindow() == SwingUtilities.windowForComponent( c );
|
||||
}
|
||||
|
||||
public static boolean isRoundRect( Component c ) {
|
||||
return c instanceof JComponent && FlatClientProperties.clientPropertyBoolean(
|
||||
(JComponent) c, FlatClientProperties.COMPONENT_ROUND_RECT, false );
|
||||
/**
|
||||
* Returns whether the given component is in a window that is in full-screen mode.
|
||||
*/
|
||||
public static boolean isFullScreen( Component c ) {
|
||||
GraphicsConfiguration gc = c.getGraphicsConfiguration();
|
||||
GraphicsDevice gd = (gc != null) ? gc.getDevice() : null;
|
||||
Window fullScreenWindow = (gd != null) ? gd.getFullScreenWindow() : null;
|
||||
return (fullScreenWindow != null && fullScreenWindow == SwingUtilities.windowForComponent( c ));
|
||||
}
|
||||
|
||||
public static Boolean isRoundRect( Component c ) {
|
||||
return (c instanceof JComponent)
|
||||
? FlatClientProperties.clientPropertyBooleanStrict(
|
||||
(JComponent) c, FlatClientProperties.COMPONENT_ROUND_RECT, null )
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -194,10 +240,57 @@ public class FlatUIUtils
|
||||
/**
|
||||
* Sets rendering hints used for painting.
|
||||
*/
|
||||
public static void setRenderingHints( Graphics2D g ) {
|
||||
g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
|
||||
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL,
|
||||
public static Object[] setRenderingHints( Graphics g ) {
|
||||
Graphics2D g2 = (Graphics2D) g;
|
||||
Object[] oldRenderingHints = new Object[] {
|
||||
g2.getRenderingHint( RenderingHints.KEY_ANTIALIASING ),
|
||||
g2.getRenderingHint( RenderingHints.KEY_STROKE_CONTROL ),
|
||||
};
|
||||
|
||||
g2.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
|
||||
g2.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL,
|
||||
MAC_USE_QUARTZ ? RenderingHints.VALUE_STROKE_PURE : RenderingHints.VALUE_STROKE_NORMALIZE );
|
||||
|
||||
return oldRenderingHints;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets rendering hints previously set with {@link #setRenderingHints}.
|
||||
*/
|
||||
public static void resetRenderingHints( Graphics g, Object[] oldRenderingHints ) {
|
||||
Graphics2D g2 = (Graphics2D) g;
|
||||
g2.setRenderingHint( RenderingHints.KEY_ANTIALIASING, oldRenderingHints[0] );
|
||||
g2.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, oldRenderingHints[1] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Temporary resets rendering hints set with {@link #setRenderingHints}
|
||||
* and runs the given runnable.
|
||||
* <p>
|
||||
* This is intended for painting text while rendering hints are set.
|
||||
* <p>
|
||||
* If text antialiasing is disabled (in OS system settings or via
|
||||
* {@code -Dawt.useSystemAAFontSettings=off}), but general antialiasing is enabled,
|
||||
* then text is still painted using some kind of "grayscale" antialiasing,
|
||||
* which may make the text look bold (depends on font and font size).
|
||||
* To avoid this, temporary disable general antialiasing.
|
||||
* This does not affect text rendering if text antialiasing is enabled (usually the default).
|
||||
*/
|
||||
public static void runWithoutRenderingHints( Graphics g, Object[] oldRenderingHints, Runnable runnable ) {
|
||||
if( oldRenderingHints == null ) {
|
||||
runnable.run();
|
||||
return;
|
||||
}
|
||||
|
||||
Graphics2D g2 = (Graphics2D) g;
|
||||
Object[] oldRenderingHints2 = new Object[] {
|
||||
g2.getRenderingHint( RenderingHints.KEY_ANTIALIASING ),
|
||||
g2.getRenderingHint( RenderingHints.KEY_STROKE_CONTROL ),
|
||||
};
|
||||
|
||||
resetRenderingHints( g2, oldRenderingHints );
|
||||
runnable.run();
|
||||
resetRenderingHints( g2, oldRenderingHints2 );
|
||||
}
|
||||
|
||||
public static Color deriveColor( Color color, Color baseColor ) {
|
||||
@@ -210,7 +303,7 @@ public class FlatUIUtils
|
||||
* Paints an outer border, which is usually a focus border.
|
||||
* <p>
|
||||
* The outside bounds of the painted border are {@code x,y,width,height}.
|
||||
* The line width of the painted border is {@code focusWidth + lineWidth}.
|
||||
* The line thickness of the painted border is {@code focusWidth + lineWidth}.
|
||||
* The given arc diameter refers to the inner rectangle ({@code x,y,width,height} minus {@code focusWidth}).
|
||||
*
|
||||
* @see #paintComponentBorder
|
||||
@@ -219,6 +312,9 @@ public class FlatUIUtils
|
||||
public static void paintComponentOuterBorder( Graphics2D g, int x, int y, int width, int height,
|
||||
float focusWidth, float lineWidth, float arc )
|
||||
{
|
||||
if( focusWidth + lineWidth == 0 )
|
||||
return; // nothing to paint
|
||||
|
||||
double systemScaleFactor = UIScale.getSystemScaleFactor( g );
|
||||
if( systemScaleFactor != 1 && systemScaleFactor != 2 ) {
|
||||
// paint at scale 1x to avoid clipping on right and bottom edges at 125%, 150% or 175%
|
||||
@@ -255,6 +351,7 @@ public class FlatUIUtils
|
||||
* <p>
|
||||
* The outside bounds of the painted border are
|
||||
* {@code x + focusWidth, y + focusWidth, width - (focusWidth * 2), height - (focusWidth * 2)}.
|
||||
* The line thickness of the painted border is {@code lineWidth}.
|
||||
* The given arc diameter refers to the painted rectangle (and not to {@code x,y,width,height}).
|
||||
*
|
||||
* @see #paintComponentOuterBorder
|
||||
@@ -263,6 +360,9 @@ public class FlatUIUtils
|
||||
public static void paintComponentBorder( Graphics2D g, int x, int y, int width, int height,
|
||||
float focusWidth, float lineWidth, float arc )
|
||||
{
|
||||
if( lineWidth == 0 )
|
||||
return; // nothing to paint
|
||||
|
||||
double systemScaleFactor = UIScale.getSystemScaleFactor( g );
|
||||
if( systemScaleFactor != 1 && systemScaleFactor != 2 ) {
|
||||
// paint at scale 1x to avoid clipping on right and bottom edges at 125%, 150% or 175%
|
||||
@@ -344,6 +444,52 @@ public class FlatUIUtils
|
||||
return new RoundRectangle2D.Float( x, y, w, h, arc, arc );
|
||||
}
|
||||
|
||||
static void paintFilledRectangle( Graphics g, Color color, float x, float y, float w, float h ) {
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
try {
|
||||
FlatUIUtils.setRenderingHints( g2 );
|
||||
g2.setColor( color );
|
||||
g2.fill( new Rectangle2D.Float( x, y, w, h ) );
|
||||
} finally {
|
||||
g2.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public static void paintGrip( Graphics g, int x, int y, int width, int height,
|
||||
boolean horizontal, int dotCount, int dotSize, int gap, boolean centerPrecise )
|
||||
{
|
||||
dotSize = UIScale.scale( dotSize );
|
||||
gap = UIScale.scale( gap );
|
||||
int gripSize = (dotSize * dotCount) + ((gap * (dotCount - 1)));
|
||||
|
||||
// calculate grip position
|
||||
float gx;
|
||||
float gy;
|
||||
if( horizontal ) {
|
||||
gx = x + Math.round( (width - gripSize) / 2f );
|
||||
gy = y + ((height - dotSize) / 2f);
|
||||
|
||||
if( !centerPrecise )
|
||||
gy = Math.round( gy );
|
||||
} else {
|
||||
// vertical
|
||||
gx = x + ((width - dotSize) / 2f);
|
||||
gy = y + Math.round( (height - gripSize) / 2f );
|
||||
|
||||
if( !centerPrecise )
|
||||
gx = Math.round( gx );
|
||||
}
|
||||
|
||||
// paint dots
|
||||
for( int i = 0; i < dotCount; i++ ) {
|
||||
((Graphics2D)g).fill( new Ellipse2D.Float( gx, gy, dotSize, dotSize ) );
|
||||
if( horizontal )
|
||||
gx += dotSize + gap;
|
||||
else
|
||||
gy += dotSize + gap;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill background with parent's background color because the visible component
|
||||
* is smaller than its bounds (for the focus decoration).
|
||||
@@ -420,15 +566,31 @@ public class FlatUIUtils
|
||||
float x2 = x + width;
|
||||
float y2 = y + height;
|
||||
|
||||
// same constant as in java.awt.geom.EllipseIterator.CtrlVal used to paint circles
|
||||
double c = 0.5522847498307933;
|
||||
double ci = 1. - c;
|
||||
double ciTopLeft = arcTopLeft * ci;
|
||||
double ciTopRight = arcTopRight * ci;
|
||||
double ciBottomLeft = arcBottomLeft * ci;
|
||||
double ciBottomRight = arcBottomRight * ci;
|
||||
|
||||
Path2D rect = new Path2D.Float();
|
||||
rect.moveTo( x2 - arcTopRight, y );
|
||||
rect.quadTo( x2, y, x2, y + arcTopRight );
|
||||
rect.lineTo( x2, y2 - arcBottomRight );
|
||||
rect.quadTo( x2, y2, x2 - arcBottomRight, y2 );
|
||||
rect.lineTo( x + arcBottomLeft, y2 );
|
||||
rect.quadTo( x, y2, x, y2 - arcBottomLeft );
|
||||
rect.lineTo( x, y + arcTopLeft );
|
||||
rect.quadTo( x, y, x + arcTopLeft, y );
|
||||
rect.moveTo( x2 - arcTopRight, y );
|
||||
rect.curveTo( x2 - ciTopRight, y,
|
||||
x2, y + ciTopRight,
|
||||
x2, y + arcTopRight );
|
||||
rect.lineTo( x2, y2 - arcBottomRight );
|
||||
rect.curveTo( x2, y2 - ciBottomRight,
|
||||
x2 - ciBottomRight, y2,
|
||||
x2 - arcBottomRight, y2 );
|
||||
rect.lineTo( x + arcBottomLeft, y2 );
|
||||
rect.curveTo( x + ciBottomLeft, y2,
|
||||
x, y2 - ciBottomLeft,
|
||||
x, y2 - arcBottomLeft );
|
||||
rect.lineTo( x, y + arcTopLeft );
|
||||
rect.curveTo( x, y + ciTopLeft,
|
||||
x + ciTopLeft, y,
|
||||
x + arcTopLeft, y );
|
||||
rect.closePath();
|
||||
|
||||
return rect;
|
||||
@@ -505,6 +667,19 @@ public class FlatUIUtils
|
||||
return explicitlySet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a shared component UI for the given key and the current Laf.
|
||||
* Each Laf instance has its own shared component UI instance.
|
||||
* <p>
|
||||
* This is for GUI builders that support Laf switching and
|
||||
* may use multiple Laf instances at the same time.
|
||||
*/
|
||||
public static ComponentUI createSharedUI( Object key, Supplier<ComponentUI> newInstanceSupplier ) {
|
||||
return sharedUIinstances
|
||||
.computeIfAbsent( UIManager.getLookAndFeel(), k -> new IdentityHashMap<>() )
|
||||
.computeIfAbsent( key, k -> newInstanceSupplier.get() );
|
||||
}
|
||||
|
||||
//---- class HoverListener ------------------------------------------------
|
||||
|
||||
public static class HoverListener
|
||||
|
||||
@@ -38,12 +38,8 @@ import javax.swing.plaf.basic.BasicViewportUI;
|
||||
public class FlatViewportUI
|
||||
extends BasicViewportUI
|
||||
{
|
||||
private static ComponentUI instance;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
if( instance == null )
|
||||
instance = new FlatViewportUI();
|
||||
return instance;
|
||||
return FlatUIUtils.createSharedUI( FlatViewportUI.class, FlatViewportUI::new );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -17,11 +17,13 @@
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import static java.awt.Cursor.*;
|
||||
import static javax.swing.SwingConstants.*;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dialog;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Frame;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.Window;
|
||||
@@ -34,54 +36,59 @@ import java.awt.event.WindowEvent;
|
||||
import java.awt.event.WindowStateListener;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.function.Supplier;
|
||||
import javax.swing.DesktopManager;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JInternalFrame;
|
||||
import javax.swing.JLayeredPane;
|
||||
import javax.swing.JRootPane;
|
||||
import javax.swing.UIManager;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
* Resizes frames and dialogs.
|
||||
* Resizes frames, dialogs or internal frames.
|
||||
* <p>
|
||||
* Could also be used to implement resize support for any Swing component
|
||||
* by creating a new subclass.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatWindowResizer
|
||||
implements PropertyChangeListener, WindowStateListener, ComponentListener
|
||||
public abstract class FlatWindowResizer
|
||||
implements PropertyChangeListener, ComponentListener
|
||||
{
|
||||
protected final static Integer WINDOW_RESIZER_LAYER = JLayeredPane.DRAG_LAYER + 1;
|
||||
|
||||
protected final JRootPane rootPane;
|
||||
protected final JComponent resizeComp;
|
||||
|
||||
protected final int borderDragThickness = FlatUIUtils.getUIInt( "RootPane.borderDragThickness", 5 );
|
||||
protected final int cornerDragWidth = FlatUIUtils.getUIInt( "RootPane.cornerDragWidth", 16 );
|
||||
protected final boolean honorFrameMinimumSizeOnResize = UIManager.getBoolean( "RootPane.honorFrameMinimumSizeOnResize" );
|
||||
protected final boolean honorDialogMinimumSizeOnResize = UIManager.getBoolean( "RootPane.honorDialogMinimumSizeOnResize" );
|
||||
|
||||
protected final JComponent north;
|
||||
protected final JComponent south;
|
||||
protected final JComponent west;
|
||||
protected final JComponent east;
|
||||
protected final DragBorderComponent topDragComp;
|
||||
protected final DragBorderComponent bottomDragComp;
|
||||
protected final DragBorderComponent leftDragComp;
|
||||
protected final DragBorderComponent rightDragComp;
|
||||
|
||||
protected Window window;
|
||||
protected FlatWindowResizer( JComponent resizeComp ) {
|
||||
this.resizeComp = resizeComp;
|
||||
|
||||
public FlatWindowResizer( JRootPane rootPane ) {
|
||||
this.rootPane = rootPane;
|
||||
topDragComp = createDragBorderComponent( NW_RESIZE_CURSOR, N_RESIZE_CURSOR, NE_RESIZE_CURSOR );
|
||||
bottomDragComp = createDragBorderComponent( SW_RESIZE_CURSOR, S_RESIZE_CURSOR, SE_RESIZE_CURSOR );
|
||||
leftDragComp = createDragBorderComponent( NW_RESIZE_CURSOR, W_RESIZE_CURSOR, SW_RESIZE_CURSOR );
|
||||
rightDragComp = createDragBorderComponent( NE_RESIZE_CURSOR, E_RESIZE_CURSOR, SE_RESIZE_CURSOR );
|
||||
|
||||
north = createDragBorderComponent( NW_RESIZE_CURSOR, N_RESIZE_CURSOR, NE_RESIZE_CURSOR );
|
||||
south = createDragBorderComponent( SW_RESIZE_CURSOR, S_RESIZE_CURSOR, SE_RESIZE_CURSOR );
|
||||
west = createDragBorderComponent( NW_RESIZE_CURSOR, W_RESIZE_CURSOR, SW_RESIZE_CURSOR );
|
||||
east = createDragBorderComponent( NE_RESIZE_CURSOR, E_RESIZE_CURSOR, SE_RESIZE_CURSOR );
|
||||
Container cont = (resizeComp instanceof JRootPane) ? ((JRootPane)resizeComp).getLayeredPane() : resizeComp;
|
||||
Object cons = (cont instanceof JLayeredPane) ? WINDOW_RESIZER_LAYER : null;
|
||||
cont.add( topDragComp, cons, 0 );
|
||||
cont.add( bottomDragComp, cons, 1 );
|
||||
cont.add( leftDragComp, cons, 2 );
|
||||
cont.add( rightDragComp, cons, 3 );
|
||||
|
||||
JLayeredPane layeredPane = rootPane.getLayeredPane();
|
||||
layeredPane.add( north, WINDOW_RESIZER_LAYER );
|
||||
layeredPane.add( south, WINDOW_RESIZER_LAYER );
|
||||
layeredPane.add( west, WINDOW_RESIZER_LAYER );
|
||||
layeredPane.add( east, WINDOW_RESIZER_LAYER );
|
||||
resizeComp.addComponentListener( this );
|
||||
resizeComp.addPropertyChangeListener( "ancestor", this );
|
||||
|
||||
rootPane.addComponentListener( this );
|
||||
rootPane.addPropertyChangeListener( "ancestor", this );
|
||||
|
||||
if( rootPane.isDisplayable() )
|
||||
if( resizeComp.isDisplayable() )
|
||||
addNotify();
|
||||
}
|
||||
|
||||
@@ -92,85 +99,96 @@ public class FlatWindowResizer
|
||||
public void uninstall() {
|
||||
removeNotify();
|
||||
|
||||
rootPane.removeComponentListener( this );
|
||||
rootPane.removePropertyChangeListener( "ancestor", this );
|
||||
resizeComp.removeComponentListener( this );
|
||||
resizeComp.removePropertyChangeListener( "ancestor", this );
|
||||
|
||||
JLayeredPane layeredPane = rootPane.getLayeredPane();
|
||||
layeredPane.remove( north );
|
||||
layeredPane.remove( south );
|
||||
layeredPane.remove( west );
|
||||
layeredPane.remove( east );
|
||||
Container cont = topDragComp.getParent();
|
||||
cont.remove( topDragComp );
|
||||
cont.remove( bottomDragComp );
|
||||
cont.remove( leftDragComp );
|
||||
cont.remove( rightDragComp );
|
||||
}
|
||||
|
||||
public void doLayout() {
|
||||
if( !north.isVisible() )
|
||||
if( !topDragComp.isVisible() )
|
||||
return;
|
||||
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int width = rootPane.getWidth();
|
||||
int height = rootPane.getHeight();
|
||||
int width = resizeComp.getWidth();
|
||||
int height = resizeComp.getHeight();
|
||||
if( width == 0 || height == 0 )
|
||||
return;
|
||||
|
||||
Insets resizeInsets = getResizeInsets();
|
||||
int thickness = UIScale.scale( borderDragThickness );
|
||||
int y2 = y + thickness;
|
||||
int height2 = height - (thickness * 2);
|
||||
int topThickness = Math.max( resizeInsets.top, thickness );
|
||||
int bottomThickness = Math.max( resizeInsets.bottom, thickness );
|
||||
int leftThickness = Math.max( resizeInsets.left, thickness );
|
||||
int rightThickness = Math.max( resizeInsets.right, thickness );
|
||||
int y2 = y + topThickness;
|
||||
int height2 = height - topThickness - bottomThickness;
|
||||
|
||||
north.setBounds( x, y, width, thickness );
|
||||
south.setBounds( x, y + height - thickness, width, thickness );
|
||||
west.setBounds( x, y2, thickness, height2 );
|
||||
east.setBounds( x + width - thickness, y2, thickness, height2 );
|
||||
// set bounds of drag components
|
||||
topDragComp.setBounds( x, y, width, topThickness );
|
||||
bottomDragComp.setBounds( x, y + height - bottomThickness, width, bottomThickness );
|
||||
leftDragComp.setBounds( x, y2, leftThickness, height2 );
|
||||
rightDragComp.setBounds( x + width - rightThickness, y2, rightThickness, height2 );
|
||||
|
||||
// set corner drag widths
|
||||
int cornerDelta = UIScale.scale( cornerDragWidth - borderDragThickness );
|
||||
topDragComp.setCornerDragWidths( leftThickness + cornerDelta, rightThickness + cornerDelta );
|
||||
bottomDragComp.setCornerDragWidths( leftThickness + cornerDelta, rightThickness + cornerDelta );
|
||||
leftDragComp.setCornerDragWidths( cornerDelta, cornerDelta );
|
||||
rightDragComp.setCornerDragWidths( cornerDelta, cornerDelta );
|
||||
}
|
||||
|
||||
protected Insets getResizeInsets() {
|
||||
return new Insets( 0, 0, 0, 0 );
|
||||
}
|
||||
|
||||
protected void addNotify() {
|
||||
Container parent = rootPane.getParent();
|
||||
window = (parent instanceof Window) ? (Window) parent : null;
|
||||
if( window instanceof Frame ) {
|
||||
window.addPropertyChangeListener( "resizable", this );
|
||||
window.addWindowStateListener( this );
|
||||
}
|
||||
|
||||
updateVisibility();
|
||||
}
|
||||
|
||||
protected void removeNotify() {
|
||||
if( window instanceof Frame ) {
|
||||
window.removePropertyChangeListener( "resizable", this );
|
||||
window.removeWindowStateListener( this );
|
||||
}
|
||||
window = null;
|
||||
|
||||
updateVisibility();
|
||||
}
|
||||
|
||||
protected void updateVisibility() {
|
||||
boolean visible = isWindowResizable();
|
||||
if( visible == north.isVisible() )
|
||||
if( visible == topDragComp.isVisible() )
|
||||
return;
|
||||
|
||||
north.setVisible( visible );
|
||||
south.setVisible( visible );
|
||||
west.setVisible( visible );
|
||||
topDragComp.setVisible( visible );
|
||||
bottomDragComp.setVisible( visible );
|
||||
leftDragComp.setVisible( visible );
|
||||
|
||||
// The east component is not hidden, instead its bounds are set to 0,0,1,1 and
|
||||
// it is disabled. This is necessary so that DragBorderComponent.paintComponent() is invoked.
|
||||
east.setEnabled( visible );
|
||||
rightDragComp.setEnabled( visible );
|
||||
if( visible ) {
|
||||
east.setVisible( true ); // necessary because it is initially invisible
|
||||
rightDragComp.setVisible( true ); // necessary because it is initially invisible
|
||||
doLayout();
|
||||
} else
|
||||
east.setBounds( 0, 0, 1, 1 );
|
||||
rightDragComp.setBounds( 0, 0, 1, 1 );
|
||||
}
|
||||
|
||||
protected boolean isWindowResizable() {
|
||||
if( window instanceof Frame )
|
||||
return ((Frame)window).isResizable() && (((Frame)window).getExtendedState() & Frame.MAXIMIZED_BOTH) == 0;
|
||||
if( window instanceof Dialog )
|
||||
return ((Dialog)window).isResizable();
|
||||
boolean isDialog() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected abstract boolean isWindowResizable();
|
||||
protected abstract Rectangle getWindowBounds();
|
||||
protected abstract void setWindowBounds( Rectangle r );
|
||||
protected abstract boolean honorMinimumSizeOnResize();
|
||||
protected abstract Dimension getWindowMinimumSize();
|
||||
|
||||
protected void beginResizing( int direction ) {}
|
||||
protected void endResizing() {}
|
||||
|
||||
//---- interface PropertyChangeListener ----
|
||||
|
||||
@Override
|
||||
public void propertyChange( PropertyChangeEvent e ) {
|
||||
switch( e.getPropertyName() ) {
|
||||
@@ -187,10 +205,7 @@ public class FlatWindowResizer
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowStateChanged( WindowEvent e ) {
|
||||
updateVisibility();
|
||||
}
|
||||
//---- interface ComponentListener ----
|
||||
|
||||
@Override
|
||||
public void componentResized( ComponentEvent e ) {
|
||||
@@ -201,6 +216,165 @@ public class FlatWindowResizer
|
||||
@Override public void componentShown( ComponentEvent e ) {}
|
||||
@Override public void componentHidden( ComponentEvent e ) {}
|
||||
|
||||
//---- class WindowResizer ------------------------------------------------
|
||||
|
||||
/**
|
||||
* Resizes frames and dialogs.
|
||||
*/
|
||||
public static class WindowResizer
|
||||
extends FlatWindowResizer
|
||||
implements WindowStateListener
|
||||
{
|
||||
protected Window window;
|
||||
|
||||
public WindowResizer( JRootPane rootPane ) {
|
||||
super( rootPane );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addNotify() {
|
||||
Container parent = resizeComp.getParent();
|
||||
window = (parent instanceof Window) ? (Window) parent : null;
|
||||
if( window instanceof Frame ) {
|
||||
window.addPropertyChangeListener( "resizable", this );
|
||||
window.addWindowStateListener( this );
|
||||
}
|
||||
|
||||
super.addNotify();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeNotify() {
|
||||
if( window instanceof Frame ) {
|
||||
window.removePropertyChangeListener( "resizable", this );
|
||||
window.removeWindowStateListener( this );
|
||||
}
|
||||
window = null;
|
||||
|
||||
super.removeNotify();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isWindowResizable() {
|
||||
if( FlatUIUtils.isFullScreen( resizeComp ) )
|
||||
return false;
|
||||
if( window instanceof Frame )
|
||||
return ((Frame)window).isResizable() && (((Frame)window).getExtendedState() & Frame.MAXIMIZED_BOTH) == 0;
|
||||
if( window instanceof Dialog )
|
||||
return ((Dialog)window).isResizable();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Rectangle getWindowBounds() {
|
||||
return window.getBounds();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setWindowBounds( Rectangle r ) {
|
||||
window.setBounds( r );
|
||||
|
||||
// immediately layout drag border components
|
||||
doLayout();
|
||||
|
||||
if( Toolkit.getDefaultToolkit().isDynamicLayoutActive() ) {
|
||||
window.validate();
|
||||
resizeComp.repaint();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean honorMinimumSizeOnResize() {
|
||||
return
|
||||
(honorFrameMinimumSizeOnResize && window instanceof Frame) ||
|
||||
(honorDialogMinimumSizeOnResize && window instanceof Dialog);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dimension getWindowMinimumSize() {
|
||||
return window.getMinimumSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isDialog() {
|
||||
return window instanceof Dialog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowStateChanged( WindowEvent e ) {
|
||||
updateVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
//---- class InternalFrameResizer -----------------------------------------
|
||||
|
||||
/**
|
||||
* Resizes internal frames.
|
||||
*/
|
||||
public static class InternalFrameResizer
|
||||
extends FlatWindowResizer
|
||||
{
|
||||
protected final Supplier<DesktopManager> desktopManager;
|
||||
|
||||
public InternalFrameResizer( JInternalFrame frame, Supplier<DesktopManager> desktopManager ) {
|
||||
super( frame );
|
||||
this.desktopManager = desktopManager;
|
||||
|
||||
frame.addPropertyChangeListener( "resizable", this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uninstall() {
|
||||
getFrame().removePropertyChangeListener( "resizable", this );
|
||||
|
||||
super.uninstall();
|
||||
}
|
||||
|
||||
private JInternalFrame getFrame() {
|
||||
return (JInternalFrame) resizeComp;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Insets getResizeInsets() {
|
||||
return getFrame().getInsets();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isWindowResizable() {
|
||||
return getFrame().isResizable();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Rectangle getWindowBounds() {
|
||||
return getFrame().getBounds();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setWindowBounds( Rectangle r ) {
|
||||
desktopManager.get().resizeFrame( getFrame(), r.x, r.y, r.width, r.height );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean honorMinimumSizeOnResize() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dimension getWindowMinimumSize() {
|
||||
return getFrame().getMinimumSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void beginResizing( int direction ) {
|
||||
desktopManager.get().beginResizingFrame( getFrame(), direction );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void endResizing() {
|
||||
desktopManager.get().endResizingFrame( getFrame() );
|
||||
}
|
||||
}
|
||||
|
||||
//---- class DragBorderComponent ------------------------------------------
|
||||
|
||||
protected class DragBorderComponent
|
||||
@@ -212,9 +386,15 @@ public class FlatWindowResizer
|
||||
private final int trailingResizeDir;
|
||||
|
||||
private int resizeDir = -1;
|
||||
private int dragStartMouseX;
|
||||
private int dragStartMouseY;
|
||||
private Rectangle dragStartWindowBounds;
|
||||
|
||||
private int leadingCornerDragWidth;
|
||||
private int trailingCornerDragWidth;
|
||||
|
||||
// offsets of mouse position to window edges
|
||||
private int dragLeftOffset;
|
||||
private int dragRightOffset;
|
||||
private int dragTopOffset;
|
||||
private int dragBottomOffset;
|
||||
|
||||
protected DragBorderComponent( int leadingResizeDir, int centerResizeDir, int trailingResizeDir ) {
|
||||
this.leadingResizeDir = leadingResizeDir;
|
||||
@@ -228,6 +408,11 @@ public class FlatWindowResizer
|
||||
addMouseMotionListener( this );
|
||||
}
|
||||
|
||||
void setCornerDragWidths( int leading, int trailing ) {
|
||||
leadingCornerDragWidth = leading;
|
||||
trailingCornerDragWidth = trailing;
|
||||
}
|
||||
|
||||
protected void setResizeDir( int resizeDir ) {
|
||||
if( this.resizeDir == resizeDir )
|
||||
return;
|
||||
@@ -246,13 +431,26 @@ public class FlatWindowResizer
|
||||
protected void paintComponent( Graphics g ) {
|
||||
super.paintChildren( g );
|
||||
|
||||
// this is necessary because Dialog.setResizable() does not fire events
|
||||
if( window instanceof Dialog )
|
||||
updateVisibility();
|
||||
// for dialogs: necessary because Dialog.setResizable() does not fire events
|
||||
// for frames: necessary because GraphicsDevice.setFullScreenWindow() does not fire events
|
||||
updateVisibility();
|
||||
|
||||
/*debug
|
||||
int width = getWidth();
|
||||
int height = getHeight();
|
||||
|
||||
g.setColor( java.awt.Color.blue );
|
||||
boolean topOrBottom = (centerResizeDir == N_RESIZE_CURSOR || centerResizeDir == S_RESIZE_CURSOR);
|
||||
if( topOrBottom ) {
|
||||
g.drawLine( leadingCornerDragWidth, 0, leadingCornerDragWidth, height );
|
||||
g.drawLine( width - trailingCornerDragWidth, 0, width - trailingCornerDragWidth, height );
|
||||
} else {
|
||||
g.drawLine( 0, leadingCornerDragWidth, width, leadingCornerDragWidth );
|
||||
g.drawLine( 0, height - trailingCornerDragWidth, width, height - trailingCornerDragWidth );
|
||||
}
|
||||
|
||||
g.setColor( java.awt.Color.red );
|
||||
g.drawRect( 0, 0, getWidth() - 1, getHeight() - 1 );
|
||||
g.drawRect( 0, 0, width - 1, height - 1 );
|
||||
debug*/
|
||||
}
|
||||
|
||||
@@ -262,114 +460,116 @@ debug*/
|
||||
|
||||
@Override
|
||||
public void mousePressed( MouseEvent e ) {
|
||||
if( window == null )
|
||||
if( !isWindowResizable() )
|
||||
return;
|
||||
|
||||
dragStartMouseX = e.getXOnScreen();
|
||||
dragStartMouseY = e.getYOnScreen();
|
||||
dragStartWindowBounds = window.getBounds();
|
||||
int xOnScreen = e.getXOnScreen();
|
||||
int yOnScreen = e.getYOnScreen();
|
||||
Rectangle windowBounds = getWindowBounds();
|
||||
|
||||
// compute offsets of mouse position to window edges
|
||||
dragLeftOffset = xOnScreen - windowBounds.x;
|
||||
dragTopOffset = yOnScreen - windowBounds.y;
|
||||
dragRightOffset = windowBounds.x + windowBounds.width - xOnScreen;
|
||||
dragBottomOffset = windowBounds.y + windowBounds.height - yOnScreen;
|
||||
|
||||
int direction = 0;
|
||||
switch( resizeDir ) {
|
||||
case N_RESIZE_CURSOR: direction = NORTH; break;
|
||||
case S_RESIZE_CURSOR: direction = SOUTH; break;
|
||||
case W_RESIZE_CURSOR: direction = WEST; break;
|
||||
case E_RESIZE_CURSOR: direction = EAST; break;
|
||||
case NW_RESIZE_CURSOR: direction = NORTH_WEST; break;
|
||||
case NE_RESIZE_CURSOR: direction = NORTH_EAST; break;
|
||||
case SW_RESIZE_CURSOR: direction = SOUTH_WEST; break;
|
||||
case SE_RESIZE_CURSOR: direction = SOUTH_EAST; break;
|
||||
}
|
||||
beginResizing( direction );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased( MouseEvent e ) {
|
||||
dragStartWindowBounds = null;
|
||||
if( !isWindowResizable() )
|
||||
return;
|
||||
|
||||
dragLeftOffset = dragRightOffset = dragTopOffset = dragBottomOffset = 0;
|
||||
|
||||
endResizing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseEntered( MouseEvent e ) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited( MouseEvent e ) {
|
||||
}
|
||||
@Override public void mouseEntered( MouseEvent e ) {}
|
||||
@Override public void mouseExited( MouseEvent e ) {}
|
||||
|
||||
@Override
|
||||
public void mouseMoved( MouseEvent e ) {
|
||||
boolean topBottom = (centerResizeDir == N_RESIZE_CURSOR || centerResizeDir == S_RESIZE_CURSOR);
|
||||
int xy = topBottom ? e.getX() : e.getY();
|
||||
int wh = topBottom ? getWidth() : getHeight();
|
||||
int cornerWH = UIScale.scale( cornerDragWidth - (topBottom ? 0 : borderDragThickness) );
|
||||
boolean topOrBottom = (centerResizeDir == N_RESIZE_CURSOR || centerResizeDir == S_RESIZE_CURSOR);
|
||||
int xy = topOrBottom ? e.getX() : e.getY();
|
||||
int wh = topOrBottom ? getWidth() : getHeight();
|
||||
|
||||
setResizeDir( xy <= cornerWH
|
||||
setResizeDir( xy <= leadingCornerDragWidth
|
||||
? leadingResizeDir
|
||||
: (xy >= wh - cornerWH
|
||||
: (xy >= wh - trailingCornerDragWidth
|
||||
? trailingResizeDir
|
||||
: centerResizeDir) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDragged( MouseEvent e ) {
|
||||
if( dragStartWindowBounds == null )
|
||||
return;
|
||||
|
||||
if( !isWindowResizable() )
|
||||
return;
|
||||
|
||||
int mouseDeltaX = e.getXOnScreen() - dragStartMouseX;
|
||||
int mouseDeltaY = e.getYOnScreen() - dragStartMouseY;
|
||||
int xOnScreen = e.getXOnScreen();
|
||||
int yOnScreen = e.getYOnScreen();
|
||||
|
||||
int deltaX = 0;
|
||||
int deltaY = 0;
|
||||
int deltaWidth = 0;
|
||||
int deltaHeight = 0;
|
||||
|
||||
// north
|
||||
if( resizeDir == N_RESIZE_CURSOR || resizeDir == NW_RESIZE_CURSOR || resizeDir == NE_RESIZE_CURSOR ) {
|
||||
deltaY = mouseDeltaY;
|
||||
deltaHeight = -mouseDeltaY;
|
||||
}
|
||||
|
||||
// south
|
||||
if( resizeDir == S_RESIZE_CURSOR || resizeDir == SW_RESIZE_CURSOR || resizeDir == SE_RESIZE_CURSOR )
|
||||
deltaHeight = mouseDeltaY;
|
||||
|
||||
// west
|
||||
if( resizeDir == W_RESIZE_CURSOR || resizeDir == NW_RESIZE_CURSOR || resizeDir == SW_RESIZE_CURSOR ) {
|
||||
deltaX = mouseDeltaX;
|
||||
deltaWidth = -mouseDeltaX;
|
||||
}
|
||||
|
||||
// east
|
||||
if( resizeDir == E_RESIZE_CURSOR || resizeDir == NE_RESIZE_CURSOR || resizeDir == SE_RESIZE_CURSOR )
|
||||
deltaWidth = mouseDeltaX;
|
||||
// Get current window bounds and compute new bounds based them.
|
||||
// This is necessary because window manager may alter window bounds while resizing.
|
||||
// E.g. when having two monitors with different scale factors and resizing
|
||||
// a window on first screen to the second screen, then the window manager may
|
||||
// decide at some point that the window should be only on second screen
|
||||
// and adjusts its bounds.
|
||||
Rectangle oldBounds = getWindowBounds();
|
||||
Rectangle newBounds = new Rectangle( oldBounds );
|
||||
|
||||
// compute new window bounds
|
||||
Rectangle newBounds = new Rectangle( dragStartWindowBounds );
|
||||
newBounds.x += deltaX;
|
||||
newBounds.y += deltaY;
|
||||
newBounds.width += deltaWidth;
|
||||
newBounds.height += deltaHeight;
|
||||
|
||||
// top
|
||||
if( resizeDir == N_RESIZE_CURSOR || resizeDir == NW_RESIZE_CURSOR || resizeDir == NE_RESIZE_CURSOR ) {
|
||||
newBounds.y = yOnScreen - dragTopOffset;
|
||||
newBounds.height += (oldBounds.y - newBounds.y);
|
||||
}
|
||||
|
||||
// bottom
|
||||
if( resizeDir == S_RESIZE_CURSOR || resizeDir == SW_RESIZE_CURSOR || resizeDir == SE_RESIZE_CURSOR )
|
||||
newBounds.height = (yOnScreen + dragBottomOffset) - newBounds.y;
|
||||
|
||||
// left
|
||||
if( resizeDir == W_RESIZE_CURSOR || resizeDir == NW_RESIZE_CURSOR || resizeDir == SW_RESIZE_CURSOR ) {
|
||||
newBounds.x = xOnScreen - dragLeftOffset;
|
||||
newBounds.width += (oldBounds.x - newBounds.x);
|
||||
}
|
||||
|
||||
// right
|
||||
if( resizeDir == E_RESIZE_CURSOR || resizeDir == NE_RESIZE_CURSOR || resizeDir == SE_RESIZE_CURSOR )
|
||||
newBounds.width = (xOnScreen + dragRightOffset) - newBounds.x;
|
||||
|
||||
// apply minimum window size
|
||||
boolean honorMinimumSizeOnResize =
|
||||
(honorFrameMinimumSizeOnResize && window instanceof Frame) ||
|
||||
(honorDialogMinimumSizeOnResize && window instanceof Dialog);
|
||||
Dimension minimumSize = honorMinimumSizeOnResize ? window.getMinimumSize() : null;
|
||||
Dimension minimumSize = honorMinimumSizeOnResize() ? getWindowMinimumSize() : null;
|
||||
if( minimumSize == null )
|
||||
minimumSize = UIScale.scale( new Dimension( 150, 50 ) );
|
||||
if( newBounds.width < minimumSize.width ) {
|
||||
if( deltaX != 0 )
|
||||
if( newBounds.x != oldBounds.x )
|
||||
newBounds.x -= (minimumSize.width - newBounds.width);
|
||||
newBounds.width = minimumSize.width;
|
||||
}
|
||||
if( newBounds.height < minimumSize.height ) {
|
||||
if( deltaY != 0 )
|
||||
if( newBounds.y != oldBounds.y )
|
||||
newBounds.y -= (minimumSize.height - newBounds.height);
|
||||
newBounds.height = minimumSize.height;
|
||||
}
|
||||
|
||||
// set window bounds
|
||||
if( !newBounds.equals( dragStartWindowBounds ) ) {
|
||||
window.setBounds( newBounds );
|
||||
|
||||
// immediately layout drag border components
|
||||
FlatWindowResizer.this.doLayout();
|
||||
|
||||
if( Toolkit.getDefaultToolkit().isDynamicLayoutActive() ) {
|
||||
window.validate();
|
||||
rootPane.repaint();
|
||||
}
|
||||
}
|
||||
if( !newBounds.equals( oldBounds ) )
|
||||
setWindowBounds( newBounds );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,7 +191,7 @@ public class JBRCustomDecorations
|
||||
initialized = true;
|
||||
|
||||
// requires JetBrains Runtime 11 and Windows 10
|
||||
if( !SystemInfo.IS_JETBRAINS_JVM_11_OR_LATER || !SystemInfo.IS_WINDOWS_10_OR_LATER )
|
||||
if( !SystemInfo.isJetBrainsJVM_11_orLater || !SystemInfo.isWindows_10_orLater )
|
||||
return;
|
||||
|
||||
if( !FlatSystemProperties.getBoolean( FlatSystemProperties.USE_JETBRAINS_CUSTOM_DECORATIONS, true ) )
|
||||
|
||||
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.util;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComponent;
|
||||
import com.formdev.flatlaf.util.Animator.Interpolator;
|
||||
|
||||
/**
|
||||
* Icon that automatically animates painting on component value changes.
|
||||
* <p>
|
||||
* {@link #getValue(Component)} returns the value of the component.
|
||||
* If the value changes, then {@link #paintIconAnimated(Component, Graphics, int, int, float)}
|
||||
* is invoked multiple times with animated value (from old value to new value).
|
||||
* <p>
|
||||
* Example for an animated icon:
|
||||
* <pre>
|
||||
* private class AnimatedMinimalTestIcon
|
||||
* implements AnimatedIcon
|
||||
* {
|
||||
* @Override public int getIconWidth() { return 100; }
|
||||
* @Override public int getIconHeight() { return 20; }
|
||||
*
|
||||
* @Override
|
||||
* public void paintIconAnimated( Component c, Graphics g, int x, int y, float animatedValue ) {
|
||||
* int w = getIconWidth();
|
||||
* int h = getIconHeight();
|
||||
*
|
||||
* g.setColor( Color.red );
|
||||
* g.drawRect( x, y, w - 1, h - 1 );
|
||||
* g.fillRect( x, y, Math.round( w * animatedValue ), h );
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public float getValue( Component c ) {
|
||||
* return ((AbstractButton)c).isSelected() ? 1 : 0;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* // sample usage
|
||||
* JCheckBox checkBox = new JCheckBox( "test" );
|
||||
* checkBox.setIcon( new AnimatedMinimalTestIcon() );
|
||||
* </pre>
|
||||
*
|
||||
* Animation works only if the component passed to {@link #paintIcon(Component, Graphics, int, int)}
|
||||
* is a instance of {@link JComponent}.
|
||||
* A client property is set on the component to store the animation state.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public interface AnimatedIcon
|
||||
extends Icon
|
||||
{
|
||||
@Override
|
||||
public default void paintIcon( Component c, Graphics g, int x, int y ) {
|
||||
AnimationSupport.paintIcon( this, c, g, x, y );
|
||||
}
|
||||
|
||||
/**
|
||||
* Paints the icon for the given animated value.
|
||||
*
|
||||
* @param c the component that this icon belongs to
|
||||
* @param g the graphics context
|
||||
* @param x the x coordinate of the icon
|
||||
* @param y the y coordinate of the icon
|
||||
* @param animatedValue the animated value, which is either equal to what {@link #getValue(Component)}
|
||||
* returned, or somewhere between the previous value and the latest value
|
||||
* that {@link #getValue(Component)} returned
|
||||
*/
|
||||
void paintIconAnimated( Component c, Graphics g, int x, int y, float animatedValue );
|
||||
|
||||
/**
|
||||
* Gets the value of the component.
|
||||
* <p>
|
||||
* This can be any value and depends on the component.
|
||||
* If the value changes, then this class animates from the old value to the new one.
|
||||
* <p>
|
||||
* For a toggle button this could be {@code 0} for off and {@code 1} for on.
|
||||
*/
|
||||
float getValue( Component c );
|
||||
|
||||
/**
|
||||
* Returns whether animation is enabled for this icon (default is {@code true}).
|
||||
*/
|
||||
default boolean isAnimationEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the duration of the animation in milliseconds (default is 150).
|
||||
*/
|
||||
default int getAnimationDuration() {
|
||||
return 150;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the resolution of the animation in milliseconds (default is 10).
|
||||
* Resolution is the amount of time between timing events.
|
||||
*/
|
||||
default int getAnimationResolution() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the interpolator for the animation.
|
||||
* Default is {@link CubicBezierEasing#STANDARD_EASING}.
|
||||
*/
|
||||
default Interpolator getAnimationInterpolator() {
|
||||
return CubicBezierEasing.STANDARD_EASING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the client property key used to store the animation support.
|
||||
*/
|
||||
default Object getClientPropertyKey() {
|
||||
return getClass();
|
||||
}
|
||||
|
||||
//---- class AnimationSupport ---------------------------------------------
|
||||
|
||||
/**
|
||||
* Animation support class that stores the animation state and implements the animation.
|
||||
*/
|
||||
class AnimationSupport
|
||||
{
|
||||
private float startValue;
|
||||
private float targetValue;
|
||||
private float animatedValue;
|
||||
private float fraction;
|
||||
|
||||
private Animator animator;
|
||||
|
||||
// last x,y coordinates of the icon needed to repaint while animating
|
||||
private int x;
|
||||
private int y;
|
||||
|
||||
public static void paintIcon( AnimatedIcon icon, Component c, Graphics g, int x, int y ) {
|
||||
if( !isAnimationEnabled( icon, c ) ) {
|
||||
// paint without animation if animation is disabled or
|
||||
// component is not a JComponent and therefore does not support
|
||||
// client properties, which are required to keep animation state
|
||||
paintIconImpl( icon, c, g, x, y, null );
|
||||
return;
|
||||
}
|
||||
|
||||
JComponent jc = (JComponent) c;
|
||||
Object key = icon.getClientPropertyKey();
|
||||
AnimationSupport as = (AnimationSupport) jc.getClientProperty( key );
|
||||
if( as == null ) {
|
||||
// painted first time --> do not animate, but remember current component value
|
||||
as = new AnimationSupport();
|
||||
as.startValue = as.targetValue = as.animatedValue = icon.getValue( c );
|
||||
as.x = x;
|
||||
as.y = y;
|
||||
jc.putClientProperty( key, as );
|
||||
} else {
|
||||
// get component value
|
||||
float value = icon.getValue( c );
|
||||
|
||||
if( value != as.targetValue ) {
|
||||
// value changed --> (re)start animation
|
||||
|
||||
if( as.animator == null ) {
|
||||
// create animator
|
||||
AnimationSupport as2 = as;
|
||||
as.animator = new Animator( icon.getAnimationDuration(), fraction -> {
|
||||
// check whether component was removed while animation is running
|
||||
if( !c.isDisplayable() ) {
|
||||
as2.animator.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
// compute animated value
|
||||
as2.animatedValue = as2.startValue + ((as2.targetValue - as2.startValue) * fraction);
|
||||
as2.fraction = fraction;
|
||||
|
||||
// repaint icon
|
||||
c.repaint( as2.x, as2.y, icon.getIconWidth(), icon.getIconHeight() );
|
||||
}, () -> {
|
||||
as2.startValue = as2.animatedValue = as2.targetValue;
|
||||
as2.animator = null;
|
||||
} );
|
||||
}
|
||||
|
||||
if( as.animator.isRunning() ) {
|
||||
// if animation is still running, restart it from the current
|
||||
// animated value to the new target value with reduced duration
|
||||
as.animator.cancel();
|
||||
int duration2 = (int) (icon.getAnimationDuration() * as.fraction);
|
||||
if( duration2 > 0 )
|
||||
as.animator.setDuration( duration2 );
|
||||
as.startValue = as.animatedValue;
|
||||
} else {
|
||||
// new animation
|
||||
as.animator.setDuration( icon.getAnimationDuration() );
|
||||
as.animator.setResolution( icon.getAnimationResolution() );
|
||||
as.animator.setInterpolator( icon.getAnimationInterpolator() );
|
||||
|
||||
as.animatedValue = as.startValue;
|
||||
}
|
||||
|
||||
as.targetValue = value;
|
||||
as.animator.start();
|
||||
}
|
||||
|
||||
as.x = x;
|
||||
as.y = y;
|
||||
}
|
||||
|
||||
paintIconImpl( icon, c, g, x, y, as );
|
||||
}
|
||||
|
||||
private static void paintIconImpl( AnimatedIcon icon, Component c, Graphics g, int x, int y, AnimationSupport as ) {
|
||||
float value = (as != null) ? as.animatedValue : icon.getValue( c );
|
||||
icon.paintIconAnimated( c, g, x, y, value );
|
||||
}
|
||||
|
||||
private static boolean isAnimationEnabled( AnimatedIcon icon, Component c ) {
|
||||
return Animator.useAnimation() && icon.isAnimationEnabled() && c instanceof JComponent;
|
||||
}
|
||||
|
||||
public static void saveIconLocation( AnimatedIcon icon, Component c, int x, int y ) {
|
||||
if( !isAnimationEnabled( icon, c ) )
|
||||
return;
|
||||
|
||||
AnimationSupport as = (AnimationSupport) ((JComponent)c).getClientProperty( icon.getClientPropertyKey() );
|
||||
if( as != null ) {
|
||||
as.x = x;
|
||||
as.y = y;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,340 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import javax.swing.Timer;
|
||||
import com.formdev.flatlaf.FlatSystemProperties;
|
||||
|
||||
/**
|
||||
* Simple animator based on ideas and concepts from "Filthy Rich Clients" book
|
||||
* and "Timing Framework" library.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class Animator
|
||||
{
|
||||
private int duration;
|
||||
private int resolution = 10;
|
||||
private Interpolator interpolator;
|
||||
private final ArrayList<TimingTarget> targets = new ArrayList<>();
|
||||
private final Runnable endRunnable;
|
||||
|
||||
private boolean running;
|
||||
private boolean hasBegun;
|
||||
private boolean timeToStop;
|
||||
private long startTime;
|
||||
private Timer timer;
|
||||
|
||||
/**
|
||||
* Checks whether animations are enabled (the default) or disabled via
|
||||
* system property {@code flatlaf.animation} set to {@code false}.
|
||||
* This allows disabling all animations at command line with {@code -Dflatlaf.animation=false}.
|
||||
*/
|
||||
public static boolean useAnimation() {
|
||||
return FlatSystemProperties.getBoolean( FlatSystemProperties.ANIMATION, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an animation that runs duration milliseconds.
|
||||
* Use {@link #addTarget(TimingTarget)} to receive timing events
|
||||
* and {@link #start()} to start the animation.
|
||||
*
|
||||
* @param duration the duration of the animation in milliseconds
|
||||
*/
|
||||
public Animator( int duration ) {
|
||||
this( duration, null, null );
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an animation that runs duration milliseconds.
|
||||
* Use {@link #start()} to start the animation.
|
||||
*
|
||||
* @param duration the duration of the animation in milliseconds
|
||||
* @param target the target that receives timing events
|
||||
*/
|
||||
public Animator( int duration, TimingTarget target ) {
|
||||
this( duration, target, null );
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an animation that runs duration milliseconds.
|
||||
* Use {@link #start()} to start the animation.
|
||||
*
|
||||
* @param duration the duration of the animation in milliseconds
|
||||
* @param target the target that receives timing events
|
||||
* @param endRunnable a runnable invoked when the animation ends; or {@code null}
|
||||
*/
|
||||
public Animator( int duration, TimingTarget target, Runnable endRunnable ) {
|
||||
setDuration( duration );
|
||||
addTarget( target );
|
||||
this.endRunnable = endRunnable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the duration of the animation in milliseconds.
|
||||
*/
|
||||
public int getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the duration of the animation in milliseconds.
|
||||
*
|
||||
* @throws IllegalStateException if animation is running
|
||||
* @throws IllegalArgumentException if duration is <= zero
|
||||
*/
|
||||
public void setDuration( int duration ) {
|
||||
throwExceptionIfRunning();
|
||||
if( duration <= 0 )
|
||||
throw new IllegalArgumentException();
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the resolution of the animation in milliseconds (default is 10).
|
||||
* Resolution is the amount of time between timing events.
|
||||
*/
|
||||
public int getResolution() {
|
||||
return resolution;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the resolution of the animation in milliseconds.
|
||||
*
|
||||
* @param resolution the resolution of the animation in milliseconds
|
||||
* @throws IllegalStateException if animation is running
|
||||
* @throws IllegalArgumentException if resolution is <= zero
|
||||
*/
|
||||
public void setResolution( int resolution ) {
|
||||
throwExceptionIfRunning();
|
||||
if( resolution <= 0 )
|
||||
throw new IllegalArgumentException();
|
||||
this.resolution = resolution;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the interpolator for the animation.
|
||||
* Default is {@code null}, which means linear.
|
||||
*/
|
||||
public Interpolator getInterpolator() {
|
||||
return interpolator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the interpolator for the animation.
|
||||
*
|
||||
* @throws IllegalStateException if animation is running
|
||||
*/
|
||||
public void setInterpolator( Interpolator interpolator ) {
|
||||
throwExceptionIfRunning();
|
||||
this.interpolator = interpolator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a target to the animation that receives timing events.
|
||||
*
|
||||
* @param target the target that receives timing events
|
||||
*/
|
||||
public void addTarget( TimingTarget target ) {
|
||||
if( target == null )
|
||||
return;
|
||||
|
||||
synchronized( targets ) {
|
||||
if( !targets.contains( target ) )
|
||||
targets.add( target );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a target from the animation.
|
||||
*
|
||||
* @param target the target that should be removed
|
||||
*/
|
||||
public void removeTarget( TimingTarget target ) {
|
||||
synchronized( targets ) {
|
||||
targets.remove( target );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the animation.
|
||||
*
|
||||
* @throws IllegalStateException if animation is running
|
||||
*/
|
||||
public void start() {
|
||||
throwExceptionIfRunning();
|
||||
|
||||
running = true;
|
||||
hasBegun = false;
|
||||
timeToStop = false;
|
||||
startTime = System.nanoTime() / 1000000;
|
||||
|
||||
if( timer == null ) {
|
||||
timer = new Timer( resolution, e -> {
|
||||
if( !hasBegun ) {
|
||||
begin();
|
||||
hasBegun = true;
|
||||
}
|
||||
|
||||
timingEvent( getTimingFraction() );
|
||||
} );
|
||||
} else
|
||||
timer.setDelay( resolution );
|
||||
timer.setInitialDelay( 0 );
|
||||
timer.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the animation before it normally ends.
|
||||
* Invokes {@link TimingTarget#end()} on timing targets.
|
||||
*/
|
||||
public void stop() {
|
||||
stop( false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels the animation before it normally ends.
|
||||
* Does not invoke {@link TimingTarget#end()} on timing targets.
|
||||
*/
|
||||
public void cancel() {
|
||||
stop( true );
|
||||
}
|
||||
|
||||
private void stop( boolean cancel ) {
|
||||
if( !running )
|
||||
return;
|
||||
|
||||
if( timer != null )
|
||||
timer.stop();
|
||||
|
||||
if( !cancel )
|
||||
end();
|
||||
|
||||
running = false;
|
||||
timeToStop = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restarts the animation.
|
||||
* Invokes {@link #cancel()} and {@link #start()}.
|
||||
*/
|
||||
public void restart() {
|
||||
cancel();
|
||||
start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this animation is running.
|
||||
*/
|
||||
public boolean isRunning() {
|
||||
return running;
|
||||
}
|
||||
|
||||
private float getTimingFraction() {
|
||||
long currentTime = System.nanoTime() / 1000000;
|
||||
long elapsedTime = currentTime - startTime;
|
||||
timeToStop = (elapsedTime >= duration);
|
||||
|
||||
float fraction = clampFraction( (float) elapsedTime / duration );
|
||||
if( interpolator != null )
|
||||
fraction = clampFraction( interpolator.interpolate( fraction ) );
|
||||
return fraction;
|
||||
}
|
||||
|
||||
private float clampFraction( float fraction ) {
|
||||
if( fraction < 0 )
|
||||
return 0;
|
||||
if( fraction > 1 )
|
||||
return 1;
|
||||
return fraction;
|
||||
}
|
||||
|
||||
private void timingEvent( float fraction ) {
|
||||
synchronized( targets ) {
|
||||
for( TimingTarget target : targets )
|
||||
target.timingEvent( fraction );
|
||||
}
|
||||
|
||||
if( timeToStop )
|
||||
stop();
|
||||
}
|
||||
|
||||
private void begin() {
|
||||
synchronized( targets ) {
|
||||
for( TimingTarget target : targets )
|
||||
target.begin();
|
||||
}
|
||||
}
|
||||
|
||||
private void end() {
|
||||
synchronized( targets ) {
|
||||
for( TimingTarget target : targets )
|
||||
target.end();
|
||||
}
|
||||
|
||||
if( endRunnable != null )
|
||||
endRunnable.run();
|
||||
}
|
||||
|
||||
private void throwExceptionIfRunning() {
|
||||
if( isRunning() )
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
//---- interface TimingTarget ---------------------------------------------
|
||||
|
||||
/**
|
||||
* Animation callbacks.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface TimingTarget {
|
||||
/**
|
||||
* Invoked multiple times while animation is running.
|
||||
*
|
||||
* @param fraction the percent (0 to 1) elapsed of the current animation cycle
|
||||
*/
|
||||
void timingEvent( float fraction );
|
||||
|
||||
/**
|
||||
* Invoked when the animation begins.
|
||||
*/
|
||||
default void begin() {}
|
||||
|
||||
/**
|
||||
* Invoked when the animation ends.
|
||||
*/
|
||||
default void end() {}
|
||||
}
|
||||
|
||||
//---- interface Interpolator ---------------------------------------------
|
||||
|
||||
/**
|
||||
* Interpolator used by animation to change timing fraction. E.g. for easing.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface Interpolator {
|
||||
/**
|
||||
* Interpolate the given fraction and returns a new fraction.
|
||||
* Both fractions are in range [0, 1].
|
||||
*
|
||||
* @param fraction the percent (0 to 1) elapsed of the current animation cycle
|
||||
* @return new fraction in range [0, 1]
|
||||
*/
|
||||
float interpolate( float fraction );
|
||||
}
|
||||
}
|
||||
@@ -28,11 +28,12 @@ public class ColorFunctions
|
||||
public static Color applyFunctions( Color color, ColorFunction... functions ) {
|
||||
float[] hsl = HSLColor.fromRGB( color );
|
||||
float alpha = color.getAlpha() / 255f;
|
||||
float[] hsla = { hsl[0], hsl[1], hsl[2], alpha * 100 };
|
||||
|
||||
for( ColorFunction function : functions )
|
||||
function.apply( hsl );
|
||||
function.apply( hsla );
|
||||
|
||||
return HSLColor.toRGB( hsl, alpha );
|
||||
return HSLColor.toRGB( hsla[0], hsla[1], hsla[2], hsla[3] / 100 );
|
||||
}
|
||||
|
||||
public static float clamp( float value ) {
|
||||
@@ -43,16 +44,48 @@ public class ColorFunctions
|
||||
: value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a color that is a mixture of two colors.
|
||||
*
|
||||
* @param color1 first color
|
||||
* @param color2 second color
|
||||
* @param weight the weight (in range 0-1) to mix the two colors.
|
||||
* Larger weight uses more of first color, smaller weight more of second color.
|
||||
* @return mixture of colors
|
||||
*/
|
||||
public static Color mix( Color color1, Color color2, float weight ) {
|
||||
if( weight >= 1 )
|
||||
return color1;
|
||||
if( weight <= 0 )
|
||||
return color2;
|
||||
|
||||
int r1 = color1.getRed();
|
||||
int g1 = color1.getGreen();
|
||||
int b1 = color1.getBlue();
|
||||
int a1 = color1.getAlpha();
|
||||
|
||||
int r2 = color2.getRed();
|
||||
int g2 = color2.getGreen();
|
||||
int b2 = color2.getBlue();
|
||||
int a2 = color2.getAlpha();
|
||||
|
||||
return new Color(
|
||||
Math.round( r2 + ((r1 - r2) * weight) ),
|
||||
Math.round( g2 + ((g1 - g2) * weight) ),
|
||||
Math.round( b2 + ((b1 - b2) * weight) ),
|
||||
Math.round( a2 + ((a1 - a2) * weight) ) );
|
||||
}
|
||||
|
||||
//---- interface ColorFunction --------------------------------------------
|
||||
|
||||
public interface ColorFunction {
|
||||
void apply( float[] hsl );
|
||||
void apply( float[] hsla );
|
||||
}
|
||||
|
||||
//---- class HSLIncreaseDecrease ------------------------------------------
|
||||
|
||||
/**
|
||||
* Increase or decrease hue, saturation or luminance of a color in the HSL color space
|
||||
* Increase or decrease hue, saturation, luminance or alpha of a color in the HSL color space
|
||||
* by an absolute or relative amount.
|
||||
*/
|
||||
public static class HSLIncreaseDecrease
|
||||
@@ -75,18 +108,45 @@ public class ColorFunctions
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply( float[] hsl ) {
|
||||
public void apply( float[] hsla ) {
|
||||
float amount2 = increase ? amount : -amount;
|
||||
amount2 = autoInverse && shouldInverse( hsl ) ? -amount2 : amount2;
|
||||
hsl[hslIndex] = clamp( relative
|
||||
? (hsl[hslIndex] * ((100 + amount2) / 100))
|
||||
: (hsl[hslIndex] + amount2) );
|
||||
|
||||
if( hslIndex == 0 ) {
|
||||
// hue is range 0-360
|
||||
hsla[0] = (hsla[0] + amount2) % 360;
|
||||
return;
|
||||
}
|
||||
|
||||
amount2 = autoInverse && shouldInverse( hsla ) ? -amount2 : amount2;
|
||||
hsla[hslIndex] = clamp( relative
|
||||
? (hsla[hslIndex] * ((100 + amount2) / 100))
|
||||
: (hsla[hslIndex] + amount2) );
|
||||
}
|
||||
|
||||
protected boolean shouldInverse( float[] hsl ) {
|
||||
protected boolean shouldInverse( float[] hsla ) {
|
||||
return increase
|
||||
? hsl[hslIndex] >= 50
|
||||
: hsl[hslIndex] < 50;
|
||||
? hsla[hslIndex] >= 50
|
||||
: hsla[hslIndex] < 50;
|
||||
}
|
||||
}
|
||||
|
||||
//---- class HSLIncreaseDecrease ------------------------------------------
|
||||
|
||||
/**
|
||||
* Set the alpha of a color.
|
||||
*/
|
||||
public static class Fade
|
||||
implements ColorFunction
|
||||
{
|
||||
public final float amount;
|
||||
|
||||
public Fade( float amount ) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply( float[] hsla ) {
|
||||
hsla[3] = clamp( amount );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.util;
|
||||
|
||||
/**
|
||||
* An interpolator for {@link Animator} that uses a cubic bezier curve.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class CubicBezierEasing
|
||||
implements Animator.Interpolator
|
||||
{
|
||||
/**
|
||||
* Standard easing as specified in Material design (0.4, 0, 0.2, 1).
|
||||
*
|
||||
* @see <a href="https://material.io/design/motion/speed.html#easing">https://material.io/design/motion/speed.html#easing</a>
|
||||
*/
|
||||
public static final CubicBezierEasing STANDARD_EASING = new CubicBezierEasing( 0.4f, 0f, 0.2f, 1f );
|
||||
|
||||
// common cubic-bezier easing functions (same as in CSS)
|
||||
// https://developer.mozilla.org/en-US/docs/Web/CSS/easing-function
|
||||
public static final CubicBezierEasing EASE = new CubicBezierEasing( 0.25f, 0.1f, 0.25f, 1f );
|
||||
public static final CubicBezierEasing EASE_IN = new CubicBezierEasing( 0.42f, 0f, 1f, 1f );
|
||||
public static final CubicBezierEasing EASE_IN_OUT = new CubicBezierEasing( 0.42f, 0f, 0.58f, 1f );
|
||||
public static final CubicBezierEasing EASE_OUT = new CubicBezierEasing( 0f, 0f, 0.58f, 1f );
|
||||
|
||||
private final float x1;
|
||||
private final float y1;
|
||||
private final float x2;
|
||||
private final float y2;
|
||||
|
||||
/**
|
||||
* Creates a cubic bezier easing interpolator with the given control points.
|
||||
* The start point of the cubic bezier curve is always 0,0 and the end point 1,1.
|
||||
*
|
||||
* @param x1 the x coordinate of the first control point in range [0, 1]
|
||||
* @param y1 the y coordinate of the first control point in range [0, 1]
|
||||
* @param x2 the x coordinate of the second control point in range [0, 1]
|
||||
* @param y2 the y coordinate of the second control point in range [0, 1]
|
||||
*/
|
||||
public CubicBezierEasing( float x1, float y1, float x2, float y2 ) {
|
||||
if( x1 < 0 || x1 > 1 || y1 < 0 || y1 > 1 ||
|
||||
x2 < 0 || x2 > 1 || y2 < 0 || y2 > 1 )
|
||||
throw new IllegalArgumentException( "control points must be in range [0, 1]");
|
||||
|
||||
this.x1 = x1;
|
||||
this.y1 = y1;
|
||||
this.x2 = x2;
|
||||
this.y2 = y2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float interpolate( float fraction ) {
|
||||
if( fraction <= 0 || fraction >= 1 )
|
||||
return fraction;
|
||||
|
||||
// use binary search
|
||||
float low = 0;
|
||||
float high = 1;
|
||||
while( true ) {
|
||||
float mid = (low + high) / 2;
|
||||
float estimate = cubicBezier( mid, x1, x2 );
|
||||
if( Math.abs( fraction - estimate ) < 0.0005f )
|
||||
return cubicBezier( mid, y1, y2 );
|
||||
if( estimate < fraction )
|
||||
low = mid;
|
||||
else
|
||||
high = mid;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the x or y point on a cubic bezier curve for a given t value.
|
||||
*
|
||||
* https://en.wikipedia.org/wiki/B%C3%A9zier_curve#Cubic_B%C3%A9zier_curves
|
||||
*
|
||||
* The general cubic bezier formula is:
|
||||
* x = b0*x0 + b1*x1 + b2*x2 + b3*x3
|
||||
* y = b0*y0 + b1*y1 + b2*y2 + b3*y3
|
||||
*
|
||||
* where:
|
||||
* b0 = (1-t)^3
|
||||
* b1 = 3 * t * (1-t)^2
|
||||
* b2 = 3 * t^2 * (1-t)
|
||||
* b3 = t^3
|
||||
*
|
||||
* x0,y0 is always 0,0 and x3,y3 is 1,1, so we can simplify to:
|
||||
* x = b1*x1 + b2*x2 + b3
|
||||
* y = b1*x1 + b2*x2 + b3
|
||||
*/
|
||||
private static float cubicBezier( float t, float xy1, float xy2 ) {
|
||||
float invT = (1 - t);
|
||||
float b1 = 3 * t * (invT * invT);
|
||||
float b2 = 3 * (t * t) * invT;
|
||||
float b3 = t * t * t;
|
||||
return (b1 * xy1) + (b2 * xy2) + b3;
|
||||
}
|
||||
}
|
||||
@@ -117,10 +117,10 @@ public class HiDPIUtils
|
||||
* This methods computes a correction value for the Y position.
|
||||
*/
|
||||
public static float computeTextYCorrection( Graphics2D g ) {
|
||||
if( !useTextYCorrection() || !SystemInfo.IS_WINDOWS )
|
||||
if( !useTextYCorrection() || !SystemInfo.isWindows )
|
||||
return 0;
|
||||
|
||||
if( !SystemInfo.IS_JAVA_9_OR_LATER )
|
||||
if( !SystemInfo.isJava_9_orLater )
|
||||
return UIScale.getUserScaleFactor() > 1 ? -UIScale.scale( 0.625f ) : 0;
|
||||
|
||||
AffineTransform t = g.getTransform();
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.formdev.flatlaf.util;
|
||||
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
@@ -27,7 +28,7 @@ import com.formdev.flatlaf.FlatLaf;
|
||||
|
||||
/**
|
||||
* Provides Java version compatibility methods.
|
||||
*
|
||||
* <p>
|
||||
* WARNING: This is private API and may change.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
@@ -35,10 +36,12 @@ import com.formdev.flatlaf.FlatLaf;
|
||||
public class JavaCompatibility
|
||||
{
|
||||
private static Method drawStringUnderlineCharAtMethod;
|
||||
private static Method getClippedStringMethod;
|
||||
|
||||
/**
|
||||
* Java 8: sun.swing.SwingUtilities2.drawStringUnderlineCharAt( JComponent c,
|
||||
* Graphics g, String text, int underlinedIndex, int x, int y )
|
||||
* <br>
|
||||
* Java 9: javax.swing.plaf.basic.BasicGraphicsUtils.drawStringUnderlineCharAt( JComponent c,
|
||||
* Graphics2D g, String string, int underlinedIndex, float x, float y )
|
||||
*/
|
||||
@@ -48,10 +51,10 @@ public class JavaCompatibility
|
||||
synchronized( JavaCompatibility.class ) {
|
||||
if( drawStringUnderlineCharAtMethod == null ) {
|
||||
try {
|
||||
Class<?> cls = Class.forName( SystemInfo.IS_JAVA_9_OR_LATER
|
||||
Class<?> cls = Class.forName( SystemInfo.isJava_9_orLater
|
||||
? "javax.swing.plaf.basic.BasicGraphicsUtils"
|
||||
: "sun.swing.SwingUtilities2" );
|
||||
drawStringUnderlineCharAtMethod = cls.getMethod( "drawStringUnderlineCharAt", SystemInfo.IS_JAVA_9_OR_LATER
|
||||
drawStringUnderlineCharAtMethod = cls.getMethod( "drawStringUnderlineCharAt", SystemInfo.isJava_9_orLater
|
||||
? new Class[] { JComponent.class, Graphics2D.class, String.class, int.class, float.class, float.class }
|
||||
: new Class[] { JComponent.class, Graphics.class, String.class, int.class, int.class, int.class } );
|
||||
} catch( Exception ex ) {
|
||||
@@ -62,7 +65,7 @@ public class JavaCompatibility
|
||||
}
|
||||
|
||||
try {
|
||||
if( SystemInfo.IS_JAVA_9_OR_LATER )
|
||||
if( SystemInfo.isJava_9_orLater )
|
||||
drawStringUnderlineCharAtMethod.invoke( null, c, g, text, underlinedIndex, (float) x, (float) y );
|
||||
else
|
||||
drawStringUnderlineCharAtMethod.invoke( null, c, g, text, underlinedIndex, x, y );
|
||||
@@ -71,4 +74,37 @@ public class JavaCompatibility
|
||||
throw new RuntimeException( ex );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Java 8: sun.swing.SwingUtilities2.clipStringIfNecessary( JComponent c,
|
||||
* FontMetrics fm, String string, int availTextWidth )
|
||||
* <br>
|
||||
* Java 9: javax.swing.plaf.basic.BasicGraphicsUtils.getClippedString( JComponent c,
|
||||
* FontMetrics fm, String string, int availTextWidth )
|
||||
*/
|
||||
public static String getClippedString( JComponent c, FontMetrics fm, String string, int availTextWidth ) {
|
||||
synchronized( JavaCompatibility.class ) {
|
||||
if( getClippedStringMethod == null ) {
|
||||
try {
|
||||
Class<?> cls = Class.forName( SystemInfo.isJava_9_orLater
|
||||
? "javax.swing.plaf.basic.BasicGraphicsUtils"
|
||||
: "sun.swing.SwingUtilities2" );
|
||||
getClippedStringMethod = cls.getMethod( SystemInfo.isJava_9_orLater
|
||||
? "getClippedString"
|
||||
: "clipStringIfNecessary",
|
||||
new Class[] { JComponent.class, FontMetrics.class, String.class, int.class } );
|
||||
} catch( Exception ex ) {
|
||||
Logger.getLogger( FlatLaf.class.getName() ).log( Level.SEVERE, null, ex );
|
||||
throw new RuntimeException( ex );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return (String) getClippedStringMethod.invoke( null, c, fm, string, availTextWidth );
|
||||
} catch( IllegalAccessException | IllegalArgumentException | InvocationTargetException ex ) {
|
||||
Logger.getLogger( FlatLaf.class.getName() ).log( Level.SEVERE, null, ex );
|
||||
throw new RuntimeException( ex );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,11 +16,20 @@
|
||||
|
||||
package com.formdev.flatlaf.util;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Image;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
//
|
||||
// NOTE:
|
||||
// This implementation is for Java 8 only.
|
||||
// There is also a variant for Java 9 and later.
|
||||
//
|
||||
// Make sure that the API is in sync.
|
||||
//
|
||||
|
||||
/**
|
||||
* Support for multi-resolution images available since Java 9.
|
||||
*
|
||||
@@ -28,26 +37,86 @@ import java.util.function.Function;
|
||||
*/
|
||||
public class MultiResolutionImageSupport
|
||||
{
|
||||
/**
|
||||
* Checks whether multi-resolution image support is available.
|
||||
*
|
||||
* @return {@code true} when running on Java 9 or later; {@code false} on Java 8
|
||||
*/
|
||||
public static boolean isAvailable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given image is a multi-resolution image that implements
|
||||
* the interface {@code java.awt.image.MultiResolutionImage}.
|
||||
*/
|
||||
public static boolean isMultiResolutionImage( Image image ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a multi-resolution image from the given resolution variants.
|
||||
*
|
||||
* @param baseImageIndex index of the base image in the resolution variants array
|
||||
* @param resolutionVariants image resolution variants (sorted by size; smallest first)
|
||||
* @return a multi-resolution image on Java 9 or later; the base image on Java 8
|
||||
*/
|
||||
public static Image create( int baseImageIndex, Image... resolutionVariants ) {
|
||||
return resolutionVariants[baseImageIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a multi-resolution image for the given dimensions.
|
||||
* Initially the image does not contain any image data.
|
||||
* The real images are created (and cached) on demand by invoking the given producer function.
|
||||
* <p>
|
||||
* The given dimensions array is only used for {@link #getResolutionVariants(Image)}.
|
||||
* The producer function may be invoked with any dimension (that is not contained in
|
||||
* dimensions array) and is expected to produce a image for the passed in dimension.
|
||||
*
|
||||
* @param baseImageIndex index of the base image in the dimensions array
|
||||
* @param dimensions dimensions of resolution variants (sorted by size; smallest first)
|
||||
* @param producer producer function that creates a real image for the requested size
|
||||
* @return a multi-resolution image on Java 9 or later; the base image on Java 8
|
||||
*/
|
||||
public static Image create( int baseImageIndex, Dimension[] dimensions, Function<Dimension, Image> producer ) {
|
||||
return producer.apply( dimensions[baseImageIndex] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a multi-resolution image that maps images from another multi-resolution image
|
||||
* using the given mapper function.
|
||||
* <p>
|
||||
* Can be used to apply filter to multi-resolution images on demand.
|
||||
* E.g. passed in image is for "enabled" state and mapper function creates images
|
||||
* for "disabled" state.
|
||||
*
|
||||
* @param image a multi-resolution image that is mapped using the given mapper function
|
||||
* @param mapper mapper function that maps a single resolution variant to a new image (e.g. applying an filter)
|
||||
* @return a multi-resolution image on Java 9 or later; a mapped image on Java 8
|
||||
*/
|
||||
public static Image map( Image image, Function<Image, Image> mapper ) {
|
||||
return mapper.apply( image );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the image variant that best matches the given width and height.
|
||||
* <p>
|
||||
* If the given image is a multi-resolution image then invokes
|
||||
* {@code java.awt.image.MultiResolutionImage.getResolutionVariant(destImageWidth, destImageHeight)}.
|
||||
* Otherwise returns the given image.
|
||||
*/
|
||||
public static Image getResolutionVariant( Image image, int destImageWidth, int destImageHeight ) {
|
||||
return image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all resolution variants.
|
||||
* <p>
|
||||
* If the given image is a multi-resolution image then invokes
|
||||
* {@code java.awt.image.MultiResolutionImage.getResolutionVariants()}.
|
||||
* Otherwise returns a list containing only the given image.
|
||||
*/
|
||||
public static List<Image> getResolutionVariants( Image image ) {
|
||||
return Collections.singletonList( image );
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.util;
|
||||
|
||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import java.awt.Component;
|
||||
import java.awt.Insets;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
|
||||
/**
|
||||
* Empty border that scales insets.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class ScaledEmptyBorder
|
||||
extends EmptyBorder
|
||||
{
|
||||
public ScaledEmptyBorder( int top, int left, int bottom, int right ) {
|
||||
super( top, left, bottom, right );
|
||||
}
|
||||
|
||||
public ScaledEmptyBorder( Insets insets ) {
|
||||
super( insets );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Insets getBorderInsets() {
|
||||
return new Insets( scale( top ), scale( left ), scale( bottom ), scale( right ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Insets getBorderInsets( Component c, Insets insets ) {
|
||||
insets.left = scale( left );
|
||||
insets.top = scale( top );
|
||||
insets.right = scale( right );
|
||||
insets.bottom = scale( bottom );
|
||||
return insets;
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,13 @@ import java.util.List;
|
||||
*/
|
||||
public class StringUtils
|
||||
{
|
||||
/**
|
||||
* Returns {@code true} if given string is {@code null} or length is zero.
|
||||
*/
|
||||
public static boolean isEmpty( String string ) {
|
||||
return string == null || string.isEmpty();
|
||||
}
|
||||
|
||||
public static String removeLeading( String string, String leading ) {
|
||||
return string.startsWith( leading )
|
||||
? string.substring( leading.length() )
|
||||
|
||||
@@ -27,55 +27,57 @@ import java.util.StringTokenizer;
|
||||
public class SystemInfo
|
||||
{
|
||||
// platforms
|
||||
public static final boolean IS_WINDOWS;
|
||||
public static final boolean IS_MAC;
|
||||
public static final boolean IS_LINUX;
|
||||
public static final boolean isWindows;
|
||||
public static final boolean isMacOS;
|
||||
public static final boolean isLinux;
|
||||
|
||||
// OS versions
|
||||
public static final boolean IS_WINDOWS_10_OR_LATER;
|
||||
public static final boolean IS_MAC_OS_10_11_EL_CAPITAN_OR_LATER;
|
||||
public static final boolean IS_MAC_OS_10_14_MOJAVE;
|
||||
public static final boolean IS_MAC_OS_10_15_CATALINA_OR_LATER;
|
||||
public static final long osVersion;
|
||||
public static final boolean isWindows_10_orLater;
|
||||
public static final boolean isMacOS_10_11_ElCapitan_orLater;
|
||||
public static final boolean isMacOS_10_14_Mojave_orLater;
|
||||
public static final boolean isMacOS_10_15_Catalina_orLater;
|
||||
|
||||
// Java versions
|
||||
public static final boolean IS_JAVA_9_OR_LATER;
|
||||
public static final boolean IS_JAVA_11_OR_LATER;
|
||||
public static final boolean IS_JAVA_15_OR_LATER;
|
||||
public static final long javaVersion;
|
||||
public static final boolean isJava_9_orLater;
|
||||
public static final boolean isJava_11_orLater;
|
||||
public static final boolean isJava_15_orLater;
|
||||
|
||||
// Java VMs
|
||||
public static final boolean IS_JETBRAINS_JVM;
|
||||
public static final boolean IS_JETBRAINS_JVM_11_OR_LATER;
|
||||
public static final boolean isJetBrainsJVM;
|
||||
public static final boolean isJetBrainsJVM_11_orLater;
|
||||
|
||||
// UI toolkits
|
||||
public static final boolean IS_KDE;
|
||||
public static final boolean isKDE;
|
||||
|
||||
static {
|
||||
// platforms
|
||||
String osName = System.getProperty( "os.name" ).toLowerCase( Locale.ENGLISH );
|
||||
IS_WINDOWS = osName.startsWith( "windows" );
|
||||
IS_MAC = osName.startsWith( "mac" );
|
||||
IS_LINUX = osName.startsWith( "linux" );
|
||||
isWindows = osName.startsWith( "windows" );
|
||||
isMacOS = osName.startsWith( "mac" );
|
||||
isLinux = osName.startsWith( "linux" );
|
||||
|
||||
// OS versions
|
||||
long osVersion = scanVersion( System.getProperty( "os.version" ) );
|
||||
IS_WINDOWS_10_OR_LATER = (IS_WINDOWS && osVersion >= toVersion( 10, 0, 0, 0 ));
|
||||
IS_MAC_OS_10_11_EL_CAPITAN_OR_LATER = (IS_MAC && osVersion >= toVersion( 10, 11, 0, 0 ));
|
||||
IS_MAC_OS_10_14_MOJAVE = (IS_MAC && osVersion >= toVersion( 10, 14, 0, 0 ));
|
||||
IS_MAC_OS_10_15_CATALINA_OR_LATER = (IS_MAC && osVersion >= toVersion( 10, 15, 0, 0 ));
|
||||
osVersion = scanVersion( System.getProperty( "os.version" ) );
|
||||
isWindows_10_orLater = (isWindows && osVersion >= toVersion( 10, 0, 0, 0 ));
|
||||
isMacOS_10_11_ElCapitan_orLater = (isMacOS && osVersion >= toVersion( 10, 11, 0, 0 ));
|
||||
isMacOS_10_14_Mojave_orLater = (isMacOS && osVersion >= toVersion( 10, 14, 0, 0 ));
|
||||
isMacOS_10_15_Catalina_orLater = (isMacOS && osVersion >= toVersion( 10, 15, 0, 0 ));
|
||||
|
||||
// Java versions
|
||||
long javaVersion = scanVersion( System.getProperty( "java.version" ) );
|
||||
IS_JAVA_9_OR_LATER = (javaVersion >= toVersion( 9, 0, 0, 0 ));
|
||||
IS_JAVA_11_OR_LATER = (javaVersion >= toVersion( 11, 0, 0, 0 ));
|
||||
IS_JAVA_15_OR_LATER = (javaVersion >= toVersion( 15, 0, 0, 0 ));
|
||||
javaVersion = scanVersion( System.getProperty( "java.version" ) );
|
||||
isJava_9_orLater = (javaVersion >= toVersion( 9, 0, 0, 0 ));
|
||||
isJava_11_orLater = (javaVersion >= toVersion( 11, 0, 0, 0 ));
|
||||
isJava_15_orLater = (javaVersion >= toVersion( 15, 0, 0, 0 ));
|
||||
|
||||
// Java VMs
|
||||
IS_JETBRAINS_JVM = System.getProperty( "java.vm.vendor", "Unknown" )
|
||||
isJetBrainsJVM = System.getProperty( "java.vm.vendor", "Unknown" )
|
||||
.toLowerCase( Locale.ENGLISH ).contains( "jetbrains" );
|
||||
IS_JETBRAINS_JVM_11_OR_LATER = IS_JETBRAINS_JVM && IS_JAVA_11_OR_LATER;
|
||||
isJetBrainsJVM_11_orLater = isJetBrainsJVM && isJava_11_orLater;
|
||||
|
||||
// UI toolkits
|
||||
IS_KDE = (IS_LINUX && System.getenv( "KDE_FULL_SESSION" ) != null);
|
||||
isKDE = (isLinux && System.getenv( "KDE_FULL_SESSION" ) != null);
|
||||
}
|
||||
|
||||
public static long scanVersion( String version ) {
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.awt.Graphics2D;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Toolkit;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.beans.PropertyChangeSupport;
|
||||
@@ -90,10 +91,10 @@ public class UIScale
|
||||
|
||||
jreHiDPI = false;
|
||||
|
||||
if( SystemInfo.IS_JAVA_9_OR_LATER ) {
|
||||
if( SystemInfo.isJava_9_orLater ) {
|
||||
// Java 9 and later supports per-monitor scaling
|
||||
jreHiDPI = true;
|
||||
} else if( SystemInfo.IS_JETBRAINS_JVM ) {
|
||||
} else if( SystemInfo.isJetBrainsJVM ) {
|
||||
// IntelliJ IDEA ships its own JetBrains Java 8 JRE that may supports per-monitor scaling
|
||||
// see com.intellij.ui.JreHiDpiUtil.isJreHiDPIEnabled()
|
||||
try {
|
||||
@@ -112,7 +113,7 @@ public class UIScale
|
||||
}
|
||||
|
||||
public static double getSystemScaleFactor( Graphics2D g ) {
|
||||
return isSystemScalingEnabled() ? g.getDeviceConfiguration().getDefaultTransform().getScaleX() : 1;
|
||||
return isSystemScalingEnabled() ? getSystemScaleFactor( g.getDeviceConfiguration() ) : 1;
|
||||
}
|
||||
|
||||
public static double getSystemScaleFactor( GraphicsConfiguration gc ) {
|
||||
@@ -162,6 +163,13 @@ public class UIScale
|
||||
if( !isUserScalingEnabled() )
|
||||
return;
|
||||
|
||||
// apply custom scale factor specified in system property "flatlaf.uiScale"
|
||||
float customScaleFactor = getCustomScaleFactor();
|
||||
if( customScaleFactor > 0 ) {
|
||||
setUserScaleFactor( customScaleFactor );
|
||||
return;
|
||||
}
|
||||
|
||||
// use font size to calculate scale factor (instead of DPI)
|
||||
// because even if we are on a HiDPI display it is not sure
|
||||
// that a larger font size is set by the current LaF
|
||||
@@ -170,33 +178,70 @@ public class UIScale
|
||||
if( font == null )
|
||||
font = UIManager.getFont( "Label.font" );
|
||||
|
||||
setUserScaleFactor( computeScaleFactor( font ) );
|
||||
float newScaleFactor;
|
||||
if( SystemInfo.isWindows ) {
|
||||
// Special handling for Windows to be compatible with OS scaling,
|
||||
// which distinguish between "screen scaling" and "text scaling".
|
||||
// - Windows "screen scaling" scales everything (text, icon, gaps, etc)
|
||||
// and may have different scaling factors for each screen.
|
||||
// - Windows "text scaling" increases only the font size, but on all screens.
|
||||
//
|
||||
// Both can be changed by the user in the Windows 10 Settings:
|
||||
// - Settings > Display > Scale and layout
|
||||
// - Settings > Ease of Access > Display > Make text bigger (100% - 225%)
|
||||
if( font instanceof UIResource ) {
|
||||
if( isSystemScalingEnabled() ) {
|
||||
// Do not apply own scaling if the JRE scales using Windows screen scale factor.
|
||||
// If user increases font size in Windows 10 settings, desktop property
|
||||
// "win.messagebox.font" is changed and FlatLaf uses the larger font.
|
||||
newScaleFactor = 1;
|
||||
} else {
|
||||
// If the JRE does not scale (Java 8), the size of the UI font
|
||||
// (usually from desktop property "win.messagebox.font")
|
||||
// combines the Windows screen and text scale factors.
|
||||
// But the font in desktop property "win.defaultGUI.font" is only
|
||||
// scaled with the Windows screen scale factor. So use it to compute
|
||||
// our scale factor that is equal to Windows screen scale factor.
|
||||
Font winFont = (Font) Toolkit.getDefaultToolkit().getDesktopProperty( "win.defaultGUI.font" );
|
||||
newScaleFactor = computeScaleFactor( (winFont != null) ? winFont : font );
|
||||
}
|
||||
} else {
|
||||
// If font was explicitly set from outside (is not a UIResource)
|
||||
// use it to compute scale factor. This allows applications to
|
||||
// use custom fonts (e.g. that the user can change in UI) and
|
||||
// get scaling if a larger font size is used.
|
||||
// E.g. FlatLaf Demo supports increasing font size in "Font" menu and UI scales.
|
||||
newScaleFactor = computeScaleFactor( font );
|
||||
}
|
||||
} else
|
||||
newScaleFactor = computeScaleFactor( font );
|
||||
|
||||
setUserScaleFactor( newScaleFactor );
|
||||
}
|
||||
|
||||
private static float computeScaleFactor( Font font ) {
|
||||
// default font size
|
||||
float fontSizeDivider = 12f;
|
||||
|
||||
if( SystemInfo.IS_WINDOWS ) {
|
||||
if( SystemInfo.isWindows ) {
|
||||
// Windows LaF uses Tahoma font rather than the actual Windows system font (Segoe UI),
|
||||
// and its size is always ca. 10% smaller than the actual system font size.
|
||||
// Tahoma 11 is used at 100%
|
||||
if( "Tahoma".equals( font.getFamily() ) )
|
||||
fontSizeDivider = 11f;
|
||||
} else if( SystemInfo.IS_MAC ) {
|
||||
} else if( SystemInfo.isMacOS ) {
|
||||
// default font size on macOS is 13
|
||||
fontSizeDivider = 13f;
|
||||
} else if( SystemInfo.IS_LINUX ) {
|
||||
} else if( SystemInfo.isLinux ) {
|
||||
// default font size for Unity and Gnome is 15 and for KDE it is 13
|
||||
fontSizeDivider = SystemInfo.IS_KDE ? 13f : 15f;
|
||||
fontSizeDivider = SystemInfo.isKDE ? 13f : 15f;
|
||||
}
|
||||
|
||||
return font.getSize() / fontSizeDivider;
|
||||
}
|
||||
|
||||
private static boolean isUserScalingEnabled() {
|
||||
// same as in IntelliJ IDEA
|
||||
return FlatSystemProperties.getBoolean( "hidpi", true );
|
||||
return FlatSystemProperties.getBoolean( FlatSystemProperties.UI_SCALE_ENABLED, true );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -204,8 +249,10 @@ public class UIScale
|
||||
* to the given font.
|
||||
*/
|
||||
public static FontUIResource applyCustomScaleFactor( FontUIResource font ) {
|
||||
String uiScale = System.getProperty( FlatSystemProperties.UI_SCALE );
|
||||
float scaleFactor = parseScaleFactor( uiScale );
|
||||
if( !isUserScalingEnabled() )
|
||||
return font;
|
||||
|
||||
float scaleFactor = getCustomScaleFactor();
|
||||
if( scaleFactor <= 0 )
|
||||
return font;
|
||||
|
||||
@@ -217,6 +264,13 @@ public class UIScale
|
||||
return new FontUIResource( font.deriveFont( (float) newFontSize ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get custom scale factor specified in system property "flatlaf.uiScale".
|
||||
*/
|
||||
private static float getCustomScaleFactor() {
|
||||
return parseScaleFactor( System.getProperty( FlatSystemProperties.UI_SCALE ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to sun.java2d.SunGraphicsEnvironment.getScaleFactor(String)
|
||||
*/
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.formdev.flatlaf.util;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Image;
|
||||
import java.awt.image.AbstractMultiResolutionImage;
|
||||
import java.awt.image.BaseMultiResolutionImage;
|
||||
@@ -27,6 +28,14 @@ import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import javax.swing.ImageIcon;
|
||||
|
||||
//
|
||||
// NOTE:
|
||||
// This implementation is for Java 9 and later.
|
||||
// There is also a variant for Java 8.
|
||||
//
|
||||
// Make sure that the API is in sync.
|
||||
//
|
||||
|
||||
/**
|
||||
* Support for multi-resolution images available since Java 9.
|
||||
*
|
||||
@@ -46,6 +55,10 @@ public class MultiResolutionImageSupport
|
||||
return new BaseMultiResolutionImage( baseImageIndex, resolutionVariants );
|
||||
}
|
||||
|
||||
public static Image create( int baseImageIndex, Dimension[] dimensions, Function<Dimension, Image> producer ) {
|
||||
return new ProducerMultiResolutionImage( dimensions, producer );
|
||||
}
|
||||
|
||||
public static Image map( Image image, Function<Image, Image> mapper ) {
|
||||
return image instanceof MultiResolutionImage
|
||||
? new MappedMultiResolutionImage( image, mapper )
|
||||
@@ -66,6 +79,9 @@ public class MultiResolutionImageSupport
|
||||
|
||||
//---- class MappedMultiResolutionImage -----------------------------------
|
||||
|
||||
/**
|
||||
* A multi-resolution image implementation that maps images on demand for requested sizes.
|
||||
*/
|
||||
private static class MappedMultiResolutionImage
|
||||
extends AbstractMultiResolutionImage
|
||||
{
|
||||
@@ -102,8 +118,52 @@ public class MultiResolutionImageSupport
|
||||
|
||||
private Image mapAndCacheImage( Image image ) {
|
||||
return cache.computeIfAbsent( image, img -> {
|
||||
// using ImageIcon here makes sure that the image is loaded
|
||||
return new ImageIcon( mapper.apply( img ) ).getImage();
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
//---- class ProducerMultiResolutionImage ---------------------------------
|
||||
|
||||
/**
|
||||
* A multi-resolution image implementation that produces images on demand for requested sizes.
|
||||
*/
|
||||
private static class ProducerMultiResolutionImage
|
||||
extends AbstractMultiResolutionImage
|
||||
{
|
||||
private final Dimension[] dimensions;
|
||||
private final Function<Dimension, Image> producer;
|
||||
private final IdentityHashMap<Dimension, Image> cache = new IdentityHashMap<>();
|
||||
|
||||
ProducerMultiResolutionImage( Dimension[] dimensions, Function<Dimension, Image> producer ) {
|
||||
this.dimensions = dimensions;
|
||||
this.producer = producer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Image getResolutionVariant( double destImageWidth, double destImageHeight ) {
|
||||
return produceAndCacheImage( new Dimension( (int) destImageWidth, (int) destImageHeight ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Image> getResolutionVariants() {
|
||||
List<Image> mappedVariants = new ArrayList<>();
|
||||
for( Dimension size : dimensions )
|
||||
mappedVariants.add( produceAndCacheImage( size ) );
|
||||
return mappedVariants;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Image getBaseImage() {
|
||||
return produceAndCacheImage( dimensions[0] );
|
||||
}
|
||||
|
||||
private Image produceAndCacheImage( Dimension size ) {
|
||||
return cache.computeIfAbsent( size, size2 -> {
|
||||
// using ImageIcon here makes sure that the image is loaded
|
||||
return new ImageIcon( producer.apply( size2 ) ).getImage();
|
||||
} );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,18 +21,19 @@
|
||||
#---- variables ----
|
||||
|
||||
@background=#3c3f41
|
||||
@foreground=#bbbbbb
|
||||
@foreground=#bbb
|
||||
@selectionBackground=#4B6EAF
|
||||
@selectionForeground=@foreground
|
||||
@selectionInactiveBackground=#0D293E
|
||||
@selectionInactiveForeground=@foreground
|
||||
@disabledText=#777777
|
||||
@disabledText=#888
|
||||
@textComponentBackground=#45494A
|
||||
@menuBackground=darken(@background,5%)
|
||||
@menuHoverBackground=lighten(@menuBackground,10%,derived)
|
||||
@menuCheckBackground=lighten(@menuBackground,10%,derived)
|
||||
@menuCheckHoverBackground=lighten(@menuBackground,20%,derived)
|
||||
@cellFocusColor=#000000
|
||||
@menuCheckBackground=darken(@selectionBackground,10%)
|
||||
@menuAcceleratorForeground=darken(@foreground,15%)
|
||||
@menuAcceleratorSelectionForeground=@selectionForeground
|
||||
@cellFocusColor=#000
|
||||
@icon=#adadad
|
||||
|
||||
# Drop (use lazy colors for IntelliJ platform themes, which usually do not specify these colors)
|
||||
@@ -42,24 +43,6 @@
|
||||
@dropLineShortColor=lighten(List.selectionBackground,30%,lazy)
|
||||
|
||||
|
||||
#---- globals ----
|
||||
|
||||
*.background=@background
|
||||
*.foreground=@foreground
|
||||
*.textBackground=@background
|
||||
*.textForeground=@foreground
|
||||
*.caretForeground=@foreground
|
||||
*.inactiveBackground=@background
|
||||
*.inactiveForeground=@foreground
|
||||
*.selectionBackground=@selectionBackground
|
||||
*.selectionForeground=@selectionForeground
|
||||
*.disabledBackground=@background
|
||||
*.disabledForeground=@disabledText
|
||||
*.disabledText=@disabledText
|
||||
*.acceleratorForeground=darken(@foreground,15%)
|
||||
*.acceleratorSelectionForeground=@selectionForeground
|
||||
|
||||
|
||||
#---- system colors ----
|
||||
|
||||
activeCaption=#434E60
|
||||
@@ -74,6 +57,9 @@ controlDkShadow=lighten($controlShadow,10%)
|
||||
Button.background=#4c5052
|
||||
Button.hoverBackground=lighten($Button.background,3%,derived)
|
||||
Button.pressedBackground=lighten($Button.background,6%,derived)
|
||||
Button.selectedBackground=lighten($Button.background,10%,derived)
|
||||
Button.selectedForeground=@foreground
|
||||
Button.disabledSelectedBackground=lighten($Button.background,3%,derived)
|
||||
|
||||
Button.borderColor=#5e6060
|
||||
Button.disabledBorderColor=#5e6060
|
||||
@@ -81,7 +67,7 @@ Button.focusedBorderColor=#466d94
|
||||
Button.hoverBorderColor=$Button.focusedBorderColor
|
||||
|
||||
Button.default.background=#365880
|
||||
Button.default.foreground=#bbbbbb
|
||||
Button.default.foreground=#bbb
|
||||
Button.default.hoverBackground=lighten($Button.default.background,3%,derived)
|
||||
Button.default.pressedBackground=lighten($Button.default.background,6%,derived)
|
||||
Button.default.borderColor=#4c708c
|
||||
@@ -92,6 +78,7 @@ Button.default.boldText=true
|
||||
|
||||
Button.toolbar.hoverBackground=lighten($Button.background,1%,derived)
|
||||
Button.toolbar.pressedBackground=lighten($Button.background,4%,derived)
|
||||
Button.toolbar.selectedBackground=lighten($Button.background,7%,derived)
|
||||
|
||||
|
||||
#---- CheckBox ----
|
||||
@@ -132,12 +119,10 @@ CheckBox.icon[filled].selectedPressedBackground=darken($CheckBox.icon[filled].se
|
||||
|
||||
#---- ComboBox ----
|
||||
|
||||
ComboBox.background=@textComponentBackground
|
||||
ComboBox.buttonBackground=@textComponentBackground
|
||||
ComboBox.buttonEditableBackground=#404445
|
||||
ComboBox.buttonArrowColor=#9A9DA1
|
||||
ComboBox.buttonDisabledArrowColor=#585858
|
||||
ComboBox.buttonHoverArrowColor=#bbbbbb
|
||||
ComboBox.buttonHoverArrowColor=#bbb
|
||||
|
||||
|
||||
#---- Component ----
|
||||
@@ -187,11 +172,6 @@ InternalFrame.activeDropShadowOpacity=0.5
|
||||
InternalFrame.inactiveDropShadowOpacity=0.75
|
||||
|
||||
|
||||
#---- List ----
|
||||
|
||||
List.background=@textComponentBackground
|
||||
|
||||
|
||||
#---- Menu ----
|
||||
|
||||
Menu.icon.arrowColor=#A7A7A7
|
||||
@@ -201,7 +181,6 @@ Menu.icon.disabledArrowColor=#606060
|
||||
#---- MenuBar ----
|
||||
|
||||
MenuBar.borderColor=#515151
|
||||
MenuBar.hoverBackground=@menuHoverBackground
|
||||
|
||||
|
||||
#---- MenuItemCheckBox ----
|
||||
@@ -228,17 +207,12 @@ PopupMenu.borderColor=#5e5e5e
|
||||
|
||||
#---- ProgressBar ----
|
||||
|
||||
ProgressBar.background=#555555
|
||||
ProgressBar.background=#555
|
||||
ProgressBar.foreground=#4A88C7
|
||||
ProgressBar.selectionForeground=@foreground
|
||||
ProgressBar.selectionBackground=@foreground
|
||||
|
||||
|
||||
#---- RadioButton ----
|
||||
|
||||
RadioButton.icon[filled].centerDiameter=5
|
||||
|
||||
|
||||
#---- RootPane ----
|
||||
|
||||
RootPane.activeBorderColor=darken(@background,7%,derived)
|
||||
@@ -263,11 +237,15 @@ Separator.foreground=#515151
|
||||
|
||||
#---- Slider ----
|
||||
|
||||
Slider.trackValueColor=#4A88C7
|
||||
Slider.trackColor=#646464
|
||||
Slider.thumbColor=#A6A6A6
|
||||
Slider.tickColor=#888888
|
||||
Slider.hoverColor=darken($Slider.thumbColor,15%,derived)
|
||||
Slider.disabledForeground=#4c5052
|
||||
Slider.thumbColor=$Slider.trackValueColor
|
||||
Slider.tickColor=#888
|
||||
Slider.focusedColor=fade($Component.focusColor,70%,derived)
|
||||
Slider.hoverThumbColor=darken($Slider.thumbColor,10%,derived)
|
||||
Slider.pressedThumbColor=darken($Slider.thumbColor,15%,derived)
|
||||
Slider.disabledTrackColor=#4c5052
|
||||
Slider.disabledThumbColor=$Slider.disabledTrackColor
|
||||
|
||||
|
||||
#---- SplitPane ----
|
||||
@@ -278,23 +256,30 @@ SplitPaneDivider.oneTouchHoverArrowColor=#7A7D81
|
||||
|
||||
#---- TabbedPane ----
|
||||
|
||||
TabbedPane.disabledForeground=@disabledText
|
||||
TabbedPane.underlineColor=#4A88C7
|
||||
TabbedPane.disabledUnderlineColor=#7a7a7a
|
||||
TabbedPane.hoverColor=#2e3133
|
||||
TabbedPane.hoverColor=darken($TabbedPane.background,5%,derived noAutoInverse)
|
||||
TabbedPane.focusColor=#3d4b5c
|
||||
TabbedPane.contentAreaColor=#323232
|
||||
TabbedPane.contentAreaColor=#646464
|
||||
|
||||
TabbedPane.buttonHoverBackground=darken($TabbedPane.background,5%,derived noAutoInverse)
|
||||
TabbedPane.buttonPressedBackground=darken($TabbedPane.background,8%,derived noAutoInverse)
|
||||
|
||||
TabbedPane.closeBackground=null
|
||||
TabbedPane.closeForeground=@disabledText
|
||||
TabbedPane.closeHoverBackground=lighten($TabbedPane.background,5%,derived)
|
||||
TabbedPane.closeHoverForeground=@foreground
|
||||
TabbedPane.closePressedBackground=lighten($TabbedPane.background,10%,derived)
|
||||
TabbedPane.closePressedForeground=$TabbedPane.closeHoverForeground
|
||||
|
||||
|
||||
#---- Table ----
|
||||
|
||||
Table.background=@textComponentBackground
|
||||
Table.gridColor=lighten($Table.background,3%)
|
||||
Table.gridColor=lighten($Table.background,5%)
|
||||
|
||||
|
||||
#---- TableHeader ----
|
||||
|
||||
TableHeader.background=@textComponentBackground
|
||||
TableHeader.separatorColor=lighten($TableHeader.background,10%)
|
||||
TableHeader.bottomSeparatorColor=$TableHeader.separatorColor
|
||||
|
||||
@@ -309,7 +294,6 @@ TitlePane.buttonPressedBackground=lighten($TitlePane.background,20%,derived)
|
||||
#---- ToggleButton ----
|
||||
|
||||
ToggleButton.selectedBackground=lighten($ToggleButton.background,10%,derived)
|
||||
ToggleButton.selectedForeground=@foreground
|
||||
ToggleButton.disabledSelectedBackground=lighten($ToggleButton.background,3%,derived)
|
||||
|
||||
ToggleButton.toolbar.selectedBackground=lighten($ToggleButton.background,7%,derived)
|
||||
@@ -323,5 +307,4 @@ ToolTip.background=#1e2123
|
||||
|
||||
#---- Tree ----
|
||||
|
||||
Tree.background=@textComponentBackground
|
||||
Tree.hash=#505355
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
Button.focusedBackground=null
|
||||
|
||||
Button.default.background=#4D8AC9
|
||||
Button.default.foreground=#FFFFFF
|
||||
Button.default.foreground=#fff
|
||||
Button.default.focusedBackground=null
|
||||
Button.default.borderColor=#3D75B2
|
||||
Button.default.hoverBorderColor=#A9C9F5
|
||||
|
||||
@@ -67,6 +67,22 @@ ViewportUI=com.formdev.flatlaf.ui.FlatViewportUI
|
||||
@menuItemMargin=3,6,3,6
|
||||
|
||||
|
||||
#---- globals ----
|
||||
|
||||
*.background=@background
|
||||
*.foreground=@foreground
|
||||
*.caretForeground=@foreground
|
||||
*.inactiveBackground=@background
|
||||
*.inactiveForeground=@disabledText
|
||||
*.selectionBackground=@selectionBackground
|
||||
*.selectionForeground=@selectionForeground
|
||||
*.disabledBackground=@background
|
||||
*.disabledForeground=@disabledText
|
||||
*.disabledText=@disabledText
|
||||
*.acceleratorForeground=@menuAcceleratorForeground
|
||||
*.acceleratorSelectionForeground=@menuAcceleratorSelectionForeground
|
||||
|
||||
|
||||
#---- system colors ----
|
||||
|
||||
desktop=@textComponentBackground
|
||||
@@ -135,6 +151,7 @@ Button.rollover=true
|
||||
Button.defaultButtonFollowsFocus=false
|
||||
[win]Button.defaultButtonFollowsFocus=true
|
||||
|
||||
Button.borderWidth=1
|
||||
Button.default.borderWidth=1
|
||||
|
||||
Button.toolbar.margin=3,3,3,3
|
||||
@@ -180,9 +197,12 @@ ComboBox.border=com.formdev.flatlaf.ui.FlatRoundBorder
|
||||
ComboBox.padding=2,6,2,6
|
||||
ComboBox.minimumWidth=72
|
||||
ComboBox.editorColumns=0
|
||||
ComboBox.maximumRowCount=20
|
||||
ComboBox.maximumRowCount=15
|
||||
[mac]ComboBox.showPopupOnNavigation=true
|
||||
# allowed values: auto, button or none
|
||||
ComboBox.buttonStyle=auto
|
||||
ComboBox.background=@textComponentBackground
|
||||
ComboBox.buttonBackground=@textComponentBackground
|
||||
|
||||
|
||||
#---- Component ----
|
||||
@@ -192,6 +212,7 @@ Component.innerFocusWidth={float}0.5
|
||||
Component.innerOutlineWidth={float}1
|
||||
Component.arc=5
|
||||
Component.minimumWidth=64
|
||||
# allowed values: chevron or triangle
|
||||
Component.arrowType=chevron
|
||||
Component.hideMnemonics=true
|
||||
|
||||
@@ -219,6 +240,7 @@ FileChooser.homeFolderIcon=com.formdev.flatlaf.icons.FlatFileChooserHomeFolderIc
|
||||
FileChooser.detailsViewIcon=com.formdev.flatlaf.icons.FlatFileChooserDetailsViewIcon
|
||||
FileChooser.listViewIcon=com.formdev.flatlaf.icons.FlatFileChooserListViewIcon
|
||||
FileChooser.usesSingleFilePane=true
|
||||
[win]FileChooser.useSystemExtensionHiding=true
|
||||
|
||||
|
||||
#---- FileView ----
|
||||
@@ -287,6 +309,7 @@ List.cellFocusColor=@cellFocusColor
|
||||
List.cellNoFocusBorder=com.formdev.flatlaf.ui.FlatListCellBorder$Default
|
||||
List.focusCellHighlightBorder=com.formdev.flatlaf.ui.FlatListCellBorder$Focused
|
||||
List.focusSelectedCellHighlightBorder=com.formdev.flatlaf.ui.FlatListCellBorder$Selected
|
||||
List.background=@textComponentBackground
|
||||
List.selectionInactiveBackground=@selectionInactiveBackground
|
||||
List.selectionInactiveForeground=@selectionInactiveForeground
|
||||
List.dropCellBackground=@dropCellBackground
|
||||
@@ -312,6 +335,7 @@ Menu.background=@menuBackground
|
||||
|
||||
MenuBar.border=com.formdev.flatlaf.ui.FlatMenuBarBorder
|
||||
MenuBar.background=@menuBackground
|
||||
MenuBar.hoverBackground=@menuHoverBackground
|
||||
MenuBar.itemMargins=3,8,3,8
|
||||
|
||||
|
||||
@@ -337,7 +361,7 @@ MenuItem.acceleratorDelimiter=-
|
||||
|
||||
# for MenuItem.selectionType=underline
|
||||
MenuItem.underlineSelectionBackground=@menuHoverBackground
|
||||
MenuItem.underlineSelectionCheckBackground=@menuCheckHoverBackground
|
||||
MenuItem.underlineSelectionCheckBackground=@menuCheckBackground
|
||||
MenuItem.underlineSelectionColor=$TabbedPane.underlineColor
|
||||
MenuItem.underlineSelectionHeight=3
|
||||
|
||||
@@ -372,6 +396,7 @@ PasswordField.margin=@textComponentMargin
|
||||
PasswordField.background=@textComponentBackground
|
||||
PasswordField.placeholderForeground=@disabledText
|
||||
PasswordField.echoChar=\u2022
|
||||
PasswordField.showCapsLock=true
|
||||
PasswordField.capsLockIcon=com.formdev.flatlaf.icons.FlatCapsLockIcon
|
||||
|
||||
|
||||
@@ -410,6 +435,7 @@ ProgressBar.repaintInterval=15
|
||||
RadioButton.border=com.formdev.flatlaf.ui.FlatMarginBorder
|
||||
RadioButton.icon=com.formdev.flatlaf.icons.FlatRadioButtonIcon
|
||||
RadioButton.icon.centerDiameter=8
|
||||
RadioButton.icon[filled].centerDiameter=5
|
||||
RadioButton.margin=2,2,2,2
|
||||
RadioButton.iconTextGap=4
|
||||
RadioButton.rollover=true
|
||||
@@ -438,6 +464,8 @@ RootPane.honorDialogMinimumSizeOnResize=true
|
||||
#---- ScrollBar ----
|
||||
|
||||
ScrollBar.width=10
|
||||
ScrollBar.minimumThumbSize=10,10
|
||||
ScrollBar.maximumThumbSize=100000,100000
|
||||
ScrollBar.trackInsets=0,0,0,0
|
||||
ScrollBar.thumbInsets=0,0,0,0
|
||||
ScrollBar.trackArc=0
|
||||
@@ -450,10 +478,12 @@ ScrollBar.buttonArrowColor=$ComboBox.buttonArrowColor
|
||||
ScrollBar.buttonDisabledArrowColor=$ComboBox.buttonDisabledArrowColor
|
||||
ScrollBar.allowsAbsolutePositioning=true
|
||||
|
||||
[mac]ScrollBar.minimumThumbSize=18,18
|
||||
[mac]ScrollBar.thumbInsets=2,2,2,2
|
||||
[mac]ScrollBar.thumbArc=999
|
||||
[mac]ScrollBar.hoverThumbWithTrack=true
|
||||
|
||||
[linux]ScrollBar.minimumThumbSize=18,18
|
||||
[linux]ScrollBar.thumbInsets=2,2,2,2
|
||||
[linux]ScrollBar.thumbArc=999
|
||||
|
||||
@@ -476,8 +506,9 @@ Separator.stripeIndent=1
|
||||
#---- Slider ----
|
||||
|
||||
Slider.focusInsets=0,0,0,0
|
||||
Slider.trackWidth=3
|
||||
Slider.thumbWidth=11
|
||||
Slider.trackWidth=2
|
||||
Slider.thumbSize=12,12
|
||||
Slider.focusWidth=4
|
||||
|
||||
|
||||
#---- Spinner ----
|
||||
@@ -490,6 +521,7 @@ Spinner.buttonDisabledArrowColor=$ComboBox.buttonDisabledArrowColor
|
||||
Spinner.buttonHoverArrowColor=$ComboBox.buttonHoverArrowColor
|
||||
Spinner.padding=@textComponentMargin
|
||||
Spinner.editorBorderPainted=false
|
||||
# allowed values: button or none
|
||||
Spinner.buttonStyle=button
|
||||
|
||||
|
||||
@@ -504,6 +536,12 @@ SplitPane.oneTouchButtonOffset={scaledInteger}2
|
||||
|
||||
SplitPaneDivider.border=null
|
||||
SplitPaneDivider.oneTouchArrowColor=$ComboBox.buttonArrowColor
|
||||
# allowed values: grip or plain
|
||||
SplitPaneDivider.style=grip
|
||||
SplitPaneDivider.gripColor=@icon
|
||||
SplitPaneDivider.gripDotCount=3
|
||||
SplitPaneDivider.gripDotSize={integer}3
|
||||
SplitPaneDivider.gripGap=2
|
||||
|
||||
|
||||
#---- TabbedPane ----
|
||||
@@ -511,14 +549,46 @@ SplitPaneDivider.oneTouchArrowColor=$ComboBox.buttonArrowColor
|
||||
TabbedPane.tabHeight=32
|
||||
TabbedPane.tabSelectionHeight=3
|
||||
TabbedPane.contentSeparatorHeight=1
|
||||
TabbedPane.showTabSeparators=false
|
||||
TabbedPane.tabSeparatorsFullHeight=false
|
||||
TabbedPane.hasFullBorder=false
|
||||
TabbedPane.tabInsets=0,12,0,12
|
||||
TabbedPane.tabInsets=4,12,4,12
|
||||
TabbedPane.tabAreaInsets=0,0,0,0
|
||||
TabbedPane.selectedTabPadInsets=0,0,0,0
|
||||
TabbedPane.tabRunOverlay=0
|
||||
TabbedPane.tabsOverlapBorder=true
|
||||
TabbedPane.tabsOverlapBorder=false
|
||||
TabbedPane.disabledForeground=@disabledText
|
||||
TabbedPane.shadow=@background
|
||||
TabbedPane.contentBorderInsets=null
|
||||
# allowed values: moreTabsButton or arrowButtons
|
||||
TabbedPane.hiddenTabsNavigation=moreTabsButton
|
||||
# allowed values: leading, trailing, center or fill
|
||||
TabbedPane.tabAreaAlignment=leading
|
||||
# allowed values: leading, trailing or center
|
||||
TabbedPane.tabAlignment=center
|
||||
# allowed values: preferred, equal or compact
|
||||
TabbedPane.tabWidthMode=preferred
|
||||
|
||||
# allowed values: chevron or triangle
|
||||
TabbedPane.arrowType=chevron
|
||||
TabbedPane.buttonInsets=2,1,2,1
|
||||
TabbedPane.buttonArc=$Button.arc
|
||||
|
||||
# allowed values: wrap or scroll
|
||||
#TabbedPane.tabLayoutPolicy=scroll
|
||||
# allowed values: never or asNeeded
|
||||
TabbedPane.tabsPopupPolicy=asNeeded
|
||||
# allowed values: never, asNeeded or asNeededSingle
|
||||
TabbedPane.scrollButtonsPolicy=asNeededSingle
|
||||
# allowed values: both or trailing
|
||||
TabbedPane.scrollButtonsPlacement=both
|
||||
|
||||
TabbedPane.closeIcon=com.formdev.flatlaf.icons.FlatTabbedPaneCloseIcon
|
||||
TabbedPane.closeSize=16,16
|
||||
TabbedPane.closeArc=4
|
||||
TabbedPane.closeCrossPlainSize={float}7.5
|
||||
TabbedPane.closeCrossFilledSize=$TabbedPane.closeCrossPlainSize
|
||||
TabbedPane.closeCrossLineWidth={float}1
|
||||
|
||||
|
||||
#---- Table ----
|
||||
@@ -526,6 +596,7 @@ TabbedPane.contentBorderInsets=null
|
||||
Table.rowHeight=20
|
||||
Table.showHorizontalLines=false
|
||||
Table.showVerticalLines=false
|
||||
Table.consistentHomeEndKeyBehavior=true
|
||||
Table.intercellSpacing={dimension}0,0
|
||||
Table.scrollPaneBorder=com.formdev.flatlaf.ui.FlatBorder
|
||||
Table.ascendingSortIcon=com.formdev.flatlaf.icons.FlatAscendingSortIcon
|
||||
@@ -538,6 +609,7 @@ Table.focusCellHighlightBorder=com.formdev.flatlaf.ui.FlatTableCellBorder$Focuse
|
||||
Table.focusSelectedCellHighlightBorder=com.formdev.flatlaf.ui.FlatTableCellBorder$Selected
|
||||
Table.focusCellBackground=@textComponentBackground
|
||||
Table.focusCellForeground=@foreground
|
||||
Table.background=@textComponentBackground
|
||||
Table.selectionInactiveBackground=@selectionInactiveBackground
|
||||
Table.selectionInactiveForeground=@selectionInactiveForeground
|
||||
Table.dropCellBackground=@dropCellBackground
|
||||
@@ -551,6 +623,7 @@ Table.dropLineShortColor=@dropLineShortColor
|
||||
TableHeader.height=25
|
||||
TableHeader.cellBorder=2,3,2,3
|
||||
TableHeader.focusCellBackground=$TableHeader.background
|
||||
TableHeader.background=@textComponentBackground
|
||||
|
||||
|
||||
#---- TextArea ----
|
||||
@@ -562,8 +635,9 @@ TextArea.background=@textComponentBackground
|
||||
|
||||
#---- TextComponent ----
|
||||
|
||||
# allowed values: "never", "once" (default) or "always"
|
||||
# allowed values: never, once or always
|
||||
TextComponent.selectAllOnFocusPolicy=once
|
||||
TextComponent.selectAllOnMouseClick=false
|
||||
TextComponent.arc=0
|
||||
|
||||
|
||||
@@ -608,7 +682,7 @@ TitlePane.foreground=@foreground
|
||||
TitlePane.inactiveForeground=@disabledText
|
||||
|
||||
TitlePane.closeHoverBackground=#e81123
|
||||
TitlePane.closePressedBackground=rgba($TitlePane.closeHoverBackground,60%)
|
||||
TitlePane.closePressedBackground=fade($TitlePane.closeHoverBackground,60%)
|
||||
TitlePane.closeHoverForeground=#fff
|
||||
TitlePane.closePressedForeground=#fff
|
||||
|
||||
@@ -622,6 +696,7 @@ ToggleButton.rollover=true
|
||||
|
||||
ToggleButton.background=$Button.background
|
||||
ToggleButton.pressedBackground=$Button.pressedBackground
|
||||
ToggleButton.selectedForeground=@foreground
|
||||
|
||||
ToggleButton.toolbar.hoverBackground=$Button.toolbar.hoverBackground
|
||||
ToggleButton.toolbar.pressedBackground=$Button.toolbar.pressedBackground
|
||||
@@ -662,9 +737,11 @@ ToolTipManager.enableToolTipMode=activeApplication
|
||||
|
||||
Tree.border=1,1,1,1
|
||||
Tree.editorBorder=1,1,1,1,@cellFocusColor
|
||||
Tree.background=@textComponentBackground
|
||||
Tree.selectionInactiveBackground=@selectionInactiveBackground
|
||||
Tree.selectionInactiveForeground=@selectionInactiveForeground
|
||||
Tree.textBackground=$Tree.background
|
||||
Tree.textForeground=$Tree.foreground
|
||||
Tree.selectionBorderColor=@cellFocusColor
|
||||
Tree.dropCellBackground=@dropCellBackground
|
||||
Tree.dropCellForeground=@dropCellForeground
|
||||
|
||||
@@ -21,18 +21,19 @@
|
||||
#---- variables ----
|
||||
|
||||
@background=#f2f2f2
|
||||
@foreground=#000000
|
||||
@foreground=#000
|
||||
@selectionBackground=#2675BF
|
||||
@selectionForeground=#ffffff
|
||||
@selectionForeground=#fff
|
||||
@selectionInactiveBackground=#d4d4d4
|
||||
@selectionInactiveForeground=@foreground
|
||||
@disabledText=#8C8C8C
|
||||
@textComponentBackground=#ffffff
|
||||
@textComponentBackground=#fff
|
||||
@menuBackground=#fff
|
||||
@menuHoverBackground=darken(@menuBackground,10%,derived)
|
||||
@menuCheckBackground=darken(@menuBackground,10%,derived)
|
||||
@menuCheckHoverBackground=darken(@menuBackground,20%,derived)
|
||||
@cellFocusColor=#000000
|
||||
@menuCheckBackground=lighten(@selectionBackground,40%)
|
||||
@menuAcceleratorForeground=lighten(@foreground,30%)
|
||||
@menuAcceleratorSelectionForeground=@selectionForeground
|
||||
@cellFocusColor=#000
|
||||
@icon=#afafaf
|
||||
|
||||
# Drop (use lazy colors for IntelliJ platform themes, which usually do not specify these colors)
|
||||
@@ -42,24 +43,6 @@
|
||||
@dropLineShortColor=darken(List.selectionBackground,20%,lazy)
|
||||
|
||||
|
||||
#---- globals ----
|
||||
|
||||
*.background=@background
|
||||
*.foreground=@foreground
|
||||
*.textBackground=#cccccc
|
||||
*.textForeground=@foreground
|
||||
*.caretForeground=@foreground
|
||||
*.inactiveBackground=@background
|
||||
*.inactiveForeground=@disabledText
|
||||
*.selectionBackground=@selectionBackground
|
||||
*.selectionForeground=@selectionForeground
|
||||
*.disabledBackground=@background
|
||||
*.disabledForeground=@disabledText
|
||||
*.disabledText=@disabledText
|
||||
*.acceleratorForeground=lighten(@foreground,30%)
|
||||
*.acceleratorSelectionForeground=@selectionForeground
|
||||
|
||||
|
||||
#---- system colors ----
|
||||
|
||||
activeCaption=#99b4d1
|
||||
@@ -71,10 +54,13 @@ controlDkShadow=darken($controlShadow,15%)
|
||||
|
||||
#---- Button ----
|
||||
|
||||
Button.background=#ffffff
|
||||
Button.background=#fff
|
||||
Button.focusedBackground=#e3f1fa
|
||||
Button.hoverBackground=darken($Button.background,3%,derived)
|
||||
Button.pressedBackground=darken($Button.background,10%,derived)
|
||||
Button.selectedBackground=darken($Button.background,20%,derived)
|
||||
Button.selectedForeground=@foreground
|
||||
Button.disabledSelectedBackground=darken($Button.background,13%,derived)
|
||||
|
||||
Button.borderColor=$Component.borderColor
|
||||
Button.disabledBorderColor=$Component.disabledBorderColor
|
||||
@@ -94,13 +80,14 @@ Button.default.borderWidth=2
|
||||
|
||||
Button.toolbar.hoverBackground=darken($Button.background,12%,derived)
|
||||
Button.toolbar.pressedBackground=darken($Button.background,15%,derived)
|
||||
Button.toolbar.selectedBackground=$Button.selectedBackground
|
||||
|
||||
|
||||
#---- CheckBox ----
|
||||
|
||||
# enabled
|
||||
CheckBox.icon.borderColor=#b0b0b0
|
||||
CheckBox.icon.background=#FFFFFF
|
||||
CheckBox.icon.background=#fff
|
||||
CheckBox.icon.selectedBorderColor=$CheckBox.icon.borderColor
|
||||
CheckBox.icon.selectedBackground=$CheckBox.icon.background
|
||||
CheckBox.icon.checkmarkColor=#4F9EE3
|
||||
@@ -126,25 +113,23 @@ CheckBox.icon.pressedBackground=$Button.pressedBackground
|
||||
# enabled
|
||||
CheckBox.icon[filled].selectedBorderColor=#4B97D9
|
||||
CheckBox.icon[filled].selectedBackground=#4F9EE3
|
||||
CheckBox.icon[filled].checkmarkColor=#FFFFFF
|
||||
CheckBox.icon[filled].checkmarkColor=#fff
|
||||
# focused
|
||||
CheckBox.icon[filled].selectedFocusedBorderColor=#ACCFF7
|
||||
CheckBox.icon[filled].selectedFocusedBackground=$CheckBox.icon[filled].selectedBackground
|
||||
CheckBox.icon[filled].selectedFocusedCheckmarkColor=$CheckBox.icon.focusedBackground
|
||||
# hover
|
||||
CheckBox.icon[filled].selectedHoverBackground=#5E94CE
|
||||
CheckBox.icon[filled].selectedHoverBackground=darken($CheckBox.icon[filled].selectedBackground,5%)
|
||||
# pressed
|
||||
CheckBox.icon[filled].selectedPressedBackground=#72A1D4
|
||||
CheckBox.icon[filled].selectedPressedBackground=darken($CheckBox.icon[filled].selectedBackground,10%)
|
||||
|
||||
|
||||
#---- ComboBox ----
|
||||
|
||||
ComboBox.background=@textComponentBackground
|
||||
ComboBox.buttonBackground=@textComponentBackground
|
||||
ComboBox.buttonEditableBackground=#fafafa
|
||||
ComboBox.buttonArrowColor=#666666
|
||||
ComboBox.buttonArrowColor=#666
|
||||
ComboBox.buttonDisabledArrowColor=#ABABAB
|
||||
ComboBox.buttonHoverArrowColor=#999999
|
||||
ComboBox.buttonHoverArrowColor=#999
|
||||
|
||||
|
||||
#---- Component ----
|
||||
@@ -199,21 +184,15 @@ InternalFrame.activeDropShadowOpacity=0.25
|
||||
InternalFrame.inactiveDropShadowOpacity=0.5
|
||||
|
||||
|
||||
#---- List ----
|
||||
|
||||
List.background=@textComponentBackground
|
||||
|
||||
|
||||
#---- Menu ----
|
||||
|
||||
Menu.icon.arrowColor=#666666
|
||||
Menu.icon.arrowColor=#666
|
||||
Menu.icon.disabledArrowColor=#ABABAB
|
||||
|
||||
|
||||
#---- MenuBar ----
|
||||
|
||||
MenuBar.borderColor=#cdcdcd
|
||||
MenuBar.hoverBackground=@menuHoverBackground
|
||||
|
||||
|
||||
#---- MenuItemCheckBox ----
|
||||
@@ -246,11 +225,6 @@ ProgressBar.selectionForeground=@textComponentBackground
|
||||
ProgressBar.selectionBackground=@foreground
|
||||
|
||||
|
||||
#---- RadioButton ----
|
||||
|
||||
RadioButton.icon[filled].centerDiameter=5
|
||||
|
||||
|
||||
#---- RootPane ----
|
||||
|
||||
RootPane.activeBorderColor=#707070
|
||||
@@ -275,38 +249,49 @@ Separator.foreground=#d1d1d1
|
||||
|
||||
#---- Slider ----
|
||||
|
||||
Slider.trackValueColor=#1E82E6
|
||||
Slider.trackColor=#c4c4c4
|
||||
Slider.thumbColor=#6e6e6e
|
||||
Slider.tickColor=#888888
|
||||
Slider.hoverColor=lighten($Slider.thumbColor,15%,derived)
|
||||
Slider.disabledForeground=#c0c0c0
|
||||
Slider.thumbColor=$Slider.trackValueColor
|
||||
Slider.tickColor=#888
|
||||
Slider.focusedColor=fade($Component.focusColor,50%,derived)
|
||||
Slider.hoverThumbColor=lighten($Slider.thumbColor,10%,derived)
|
||||
Slider.pressedThumbColor=lighten($Slider.thumbColor,15%,derived)
|
||||
Slider.disabledTrackColor=#c0c0c0
|
||||
Slider.disabledThumbColor=$Slider.disabledTrackColor
|
||||
|
||||
|
||||
#---- SplitPane ----
|
||||
|
||||
SplitPaneDivider.draggingColor=#c4c4c4
|
||||
SplitPaneDivider.oneTouchHoverArrowColor=#333333
|
||||
SplitPaneDivider.oneTouchHoverArrowColor=#333
|
||||
|
||||
|
||||
#---- TabbedPane ----
|
||||
|
||||
TabbedPane.disabledForeground=@disabledText
|
||||
TabbedPane.underlineColor=#4083C9
|
||||
TabbedPane.disabledUnderlineColor=#ababab
|
||||
TabbedPane.hoverColor=#d9d9d9
|
||||
TabbedPane.hoverColor=darken($TabbedPane.background,7%,derived)
|
||||
TabbedPane.focusColor=#dae4ed
|
||||
TabbedPane.contentAreaColor=#bfbfbf
|
||||
|
||||
TabbedPane.buttonHoverBackground=darken($TabbedPane.background,7%,derived)
|
||||
TabbedPane.buttonPressedBackground=darken($TabbedPane.background,10%,derived)
|
||||
|
||||
TabbedPane.closeBackground=null
|
||||
TabbedPane.closeForeground=@disabledText
|
||||
TabbedPane.closeHoverBackground=darken($TabbedPane.background,20%,derived)
|
||||
TabbedPane.closeHoverForeground=@foreground
|
||||
TabbedPane.closePressedBackground=darken($TabbedPane.background,25%,derived)
|
||||
TabbedPane.closePressedForeground=$TabbedPane.closeHoverForeground
|
||||
|
||||
|
||||
#---- Table ----
|
||||
|
||||
Table.background=@textComponentBackground
|
||||
Table.gridColor=darken($Table.background,3%)
|
||||
Table.gridColor=darken($Table.background,5%)
|
||||
|
||||
|
||||
#---- TableHeader ----
|
||||
|
||||
TableHeader.background=@textComponentBackground
|
||||
TableHeader.separatorColor=darken($TableHeader.background,10%)
|
||||
TableHeader.bottomSeparatorColor=$TableHeader.separatorColor
|
||||
|
||||
@@ -321,7 +306,6 @@ TitlePane.buttonPressedBackground=darken($TitlePane.background,20%,derived)
|
||||
#---- ToggleButton ----
|
||||
|
||||
ToggleButton.selectedBackground=darken($ToggleButton.background,20%,derived)
|
||||
ToggleButton.selectedForeground=@foreground
|
||||
ToggleButton.disabledSelectedBackground=darken($ToggleButton.background,13%,derived)
|
||||
|
||||
ToggleButton.toolbar.selectedBackground=$ToggleButton.selectedBackground
|
||||
@@ -335,5 +319,4 @@ ToolTip.background=#fafafa
|
||||
|
||||
#---- Tree ----
|
||||
|
||||
Tree.background=@textComponentBackground
|
||||
Tree.hash=#E6E6E6
|
||||
|
||||
@@ -35,6 +35,11 @@ Button.default.hoverBorderColor=null
|
||||
HelpButton.hoverBorderColor=null
|
||||
|
||||
|
||||
#---- Slider ----
|
||||
|
||||
Slider.focusedColor=fade($Component.focusColor,40%,derived)
|
||||
|
||||
|
||||
#---- ToggleButton ----
|
||||
|
||||
ToggleButton.startBackground=$ToggleButton.background
|
||||
@@ -45,6 +50,26 @@ ToggleButton.endBackground=$ToggleButton.background
|
||||
|
||||
#---- theme specific ----
|
||||
|
||||
[Arc_Theme]ProgressBar.selectionBackground=#000
|
||||
[Arc_Theme]ProgressBar.selectionForeground=#fff
|
||||
|
||||
[Arc_Theme_-_Orange]ProgressBar.selectionBackground=#000
|
||||
[Arc_Theme_-_Orange]ProgressBar.selectionForeground=#fff
|
||||
|
||||
[Arc_Theme_Dark]ProgressBar.selectionBackground=#ddd
|
||||
[Arc_Theme_Dark]ProgressBar.selectionForeground=#ddd
|
||||
|
||||
[Arc_Theme_Dark_-_Orange]ProgressBar.selectionBackground=#ddd
|
||||
[Arc_Theme_Dark_-_Orange]ProgressBar.selectionForeground=#fff
|
||||
|
||||
[Cobalt_2]CheckBox.icon.background=#002946
|
||||
[Cobalt_2]CheckBox.icon.checkmarkColor=#002946
|
||||
|
||||
[Dark_purple]Slider.focusedColor=fade($Component.focusColor,70%,derived)
|
||||
|
||||
[Dracula]ProgressBar.selectionBackground=#fff
|
||||
[Dracula]ProgressBar.selectionForeground=#fff
|
||||
|
||||
[Gruvbox_Dark_Hard]ToggleButton.selectedBackground=$ToggleButton.selectedBackground
|
||||
[Gruvbox_Dark_Hard]ToggleButton.toolbar.selectedBackground=$ToggleButton.toolbar.selectedBackground
|
||||
|
||||
@@ -62,3 +87,66 @@ ToggleButton.endBackground=$ToggleButton.background
|
||||
[High_contrast]ToggleButton.selectedForeground=#000
|
||||
[High_contrast]ToggleButton.disabledSelectedBackground=#444
|
||||
[High_contrast]ToggleButton.toolbar.selectedBackground=#fff
|
||||
|
||||
[One_Dark]Slider.focusedColor=fade(#568af2,40%)
|
||||
|
||||
[Solarized_Dark]Slider.focusedColor=fade($Component.focusColor,80%,derived)
|
||||
|
||||
[vuesion-theme]Slider.trackValueColor=#ececee
|
||||
[vuesion-theme]Slider.trackColor=#303a45
|
||||
[vuesion-theme]Slider.thumbColor=#ececee
|
||||
[vuesion-theme]Slider.focusedColor=fade(#ececee,20%)
|
||||
|
||||
|
||||
# Material Theme UI Lite
|
||||
|
||||
[Dracula_Contrast]ProgressBar.selectionBackground=#fff
|
||||
[Dracula_Contrast]ProgressBar.selectionForeground=#fff
|
||||
|
||||
[GitHub]ProgressBar.selectionBackground=#222
|
||||
[GitHub]ProgressBar.selectionForeground=#222
|
||||
|
||||
[GitHub_Contrast]ProgressBar.selectionBackground=#222
|
||||
[GitHub_Contrast]ProgressBar.selectionForeground=#222
|
||||
|
||||
[Light_Owl]ProgressBar.selectionBackground=#111
|
||||
[Light_Owl]ProgressBar.selectionForeground=#fff
|
||||
|
||||
[Light_Owl_Contrast]ProgressBar.selectionBackground=#111
|
||||
[Light_Owl_Contrast]ProgressBar.selectionForeground=#fff
|
||||
|
||||
[Material_Lighter]ProgressBar.selectionBackground=#222
|
||||
[Material_Lighter]ProgressBar.selectionForeground=#fff
|
||||
|
||||
[Material_Lighter_Contrast]ProgressBar.selectionBackground=#222
|
||||
[Material_Lighter_Contrast]ProgressBar.selectionForeground=#fff
|
||||
|
||||
[Material_Oceanic]ProgressBar.selectionBackground=#ddd
|
||||
[Material_Oceanic]ProgressBar.selectionForeground=#ddd
|
||||
|
||||
[Material_Oceanic_Contrast]ProgressBar.selectionBackground=#ddd
|
||||
[Material_Oceanic_Contrast]ProgressBar.selectionForeground=#ddd
|
||||
|
||||
[Material_Palenight]ProgressBar.selectionBackground=#ddd
|
||||
[Material_Palenight]ProgressBar.selectionForeground=#ddd
|
||||
|
||||
[Material_Palenight_Contrast]ProgressBar.selectionBackground=#ddd
|
||||
[Material_Palenight_Contrast]ProgressBar.selectionForeground=#ddd
|
||||
|
||||
[Night_Owl]ProgressBar.selectionBackground=#ddd
|
||||
[Night_Owl]ProgressBar.selectionForeground=#ddd
|
||||
|
||||
[Night_Owl_Contrast]ProgressBar.selectionBackground=#ddd
|
||||
[Night_Owl_Contrast]ProgressBar.selectionForeground=#ddd
|
||||
|
||||
[Solarized_Dark]ProgressBar.selectionBackground=#ccc
|
||||
[Solarized_Dark]ProgressBar.selectionForeground=#ccc
|
||||
|
||||
[Material_Solarized_Dark_Contrast]ProgressBar.selectionBackground=#ccc
|
||||
[Material_Solarized_Dark_Contrast]ProgressBar.selectionForeground=#ccc
|
||||
|
||||
[Solarized_Light]ProgressBar.selectionBackground=#222
|
||||
[Solarized_Light]ProgressBar.selectionForeground=#fff
|
||||
|
||||
[Material_Solarized_Light_Contrast]ProgressBar.selectionBackground=#222
|
||||
[Material_Solarized_Light_Contrast]ProgressBar.selectionForeground=#fff
|
||||
|
||||
@@ -46,3 +46,20 @@ FileChooser.refreshActionLabelText=Refresh
|
||||
FileChooser.newFolderActionLabelText=New Folder
|
||||
FileChooser.listViewActionLabelText=List
|
||||
FileChooser.detailsViewActionLabelText=Details
|
||||
|
||||
|
||||
#---- SplitPaneDivider ----
|
||||
|
||||
SplitPaneDivider.collapseLeftToolTipText=Collapse Left Pane
|
||||
SplitPaneDivider.collapseRightToolTipText=Collapse Right Pane
|
||||
SplitPaneDivider.collapseTopToolTipText=Collapse Top Pane
|
||||
SplitPaneDivider.collapseBottomToolTipText=Collapse Bottom Pane
|
||||
SplitPaneDivider.expandLeftToolTipText=Expand Left Pane
|
||||
SplitPaneDivider.expandRightToolTipText=Expand Right Pane
|
||||
SplitPaneDivider.expandTopToolTipText=Expand Top Pane
|
||||
SplitPaneDivider.expandBottomToolTipText=Expand Bottom Pane
|
||||
|
||||
|
||||
#---- TabbedPane ----
|
||||
|
||||
TabbedPane.moreTabsButtonToolTipText=Show Hidden Tabs
|
||||
|
||||
@@ -46,3 +46,8 @@ FileChooser.refreshActionLabelText=Aktualisieren
|
||||
FileChooser.newFolderActionLabelText=Neuer Ordner
|
||||
FileChooser.listViewActionLabelText=Liste
|
||||
FileChooser.detailsViewActionLabelText=Details
|
||||
|
||||
|
||||
#---- TabbedPane ----
|
||||
|
||||
TabbedPane.moreTabsButtonToolTipText=Verdeckte Tabs anzeigen
|
||||
|
||||
@@ -2,3 +2,12 @@ FlatLaf Demo
|
||||
============
|
||||
|
||||
This sub-project contains the FlatLaf Demo source code.
|
||||
|
||||
|
||||
Download
|
||||
--------
|
||||
|
||||
[](https://download.formdev.com/flatlaf/flatlaf-demo-latest.jar)
|
||||
|
||||
Run demo with `java -jar flatlaf-demo-<version>.jar` (or double-click it).
|
||||
Requires Java 8 or newer.
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.formdev.flatlaf.demo;
|
||||
|
||||
import java.awt.Component;
|
||||
import javax.swing.*;
|
||||
import javax.swing.text.DefaultEditorKit;
|
||||
import net.miginfocom.swing.*;
|
||||
@@ -114,14 +115,14 @@ class BasicComponentsPanel
|
||||
JScrollPane scrollPane12 = new JScrollPane();
|
||||
JTextPane textPane4 = new JTextPane();
|
||||
JTextPane textPane5 = new JTextPane();
|
||||
JLabel label3 = new JLabel();
|
||||
JTextField textField5 = new JTextField();
|
||||
JComboBox<String> comboBox7 = new JComboBox<>();
|
||||
JSpinner spinner3 = new JSpinner();
|
||||
JLabel label4 = new JLabel();
|
||||
JTextField textField7 = new JTextField();
|
||||
JComboBox<String> comboBox8 = new JComboBox<>();
|
||||
JSpinner spinner4 = new JSpinner();
|
||||
JLabel errorHintsLabel = new JLabel();
|
||||
JTextField errorHintsTextField = new JTextField();
|
||||
JComboBox<String> errorHintsComboBox = new JComboBox<>();
|
||||
JSpinner errorHintsSpinner = new JSpinner();
|
||||
JLabel warningHintsLabel = new JLabel();
|
||||
JTextField warningHintsTextField = new JTextField();
|
||||
JComboBox<String> warningHintsComboBox = new JComboBox<>();
|
||||
JSpinner warningHintsSpinner = new JSpinner();
|
||||
JPopupMenu popupMenu1 = new JPopupMenu();
|
||||
JMenuItem cutMenuItem = new JMenuItem();
|
||||
JMenuItem copyMenuItem = new JMenuItem();
|
||||
@@ -129,12 +130,12 @@ class BasicComponentsPanel
|
||||
|
||||
//======== this ========
|
||||
setLayout(new MigLayout(
|
||||
"hidemode 3",
|
||||
"insets dialog,hidemode 3",
|
||||
// columns
|
||||
"[]" +
|
||||
"[]" +
|
||||
"[]" +
|
||||
"[]" +
|
||||
"[sizegroup 1]" +
|
||||
"[sizegroup 1]" +
|
||||
"[sizegroup 1]" +
|
||||
"[sizegroup 1]" +
|
||||
"[]" +
|
||||
"[]",
|
||||
// rows
|
||||
@@ -606,44 +607,44 @@ class BasicComponentsPanel
|
||||
textPane5.setText("No scroll pane");
|
||||
add(textPane5, "cell 5 11,growx");
|
||||
|
||||
//---- label3 ----
|
||||
label3.setText("Error hints:");
|
||||
add(label3, "cell 0 12");
|
||||
//---- errorHintsLabel ----
|
||||
errorHintsLabel.setText("Error hints:");
|
||||
add(errorHintsLabel, "cell 0 12");
|
||||
|
||||
//---- textField5 ----
|
||||
textField5.putClientProperty("JComponent.outline", "error");
|
||||
add(textField5, "cell 1 12,growx");
|
||||
//---- errorHintsTextField ----
|
||||
errorHintsTextField.putClientProperty("JComponent.outline", "error");
|
||||
add(errorHintsTextField, "cell 1 12,growx");
|
||||
|
||||
//---- comboBox7 ----
|
||||
comboBox7.putClientProperty("JComponent.outline", "error");
|
||||
comboBox7.setModel(new DefaultComboBoxModel<>(new String[] {
|
||||
//---- errorHintsComboBox ----
|
||||
errorHintsComboBox.putClientProperty("JComponent.outline", "error");
|
||||
errorHintsComboBox.setModel(new DefaultComboBoxModel<>(new String[] {
|
||||
"Editable"
|
||||
}));
|
||||
comboBox7.setEditable(true);
|
||||
add(comboBox7, "cell 2 12,growx");
|
||||
errorHintsComboBox.setEditable(true);
|
||||
add(errorHintsComboBox, "cell 2 12,growx");
|
||||
|
||||
//---- spinner3 ----
|
||||
spinner3.putClientProperty("JComponent.outline", "error");
|
||||
add(spinner3, "cell 3 12,growx");
|
||||
//---- errorHintsSpinner ----
|
||||
errorHintsSpinner.putClientProperty("JComponent.outline", "error");
|
||||
add(errorHintsSpinner, "cell 3 12,growx");
|
||||
|
||||
//---- label4 ----
|
||||
label4.setText("Warning hints:");
|
||||
add(label4, "cell 0 13");
|
||||
//---- warningHintsLabel ----
|
||||
warningHintsLabel.setText("Warning hints:");
|
||||
add(warningHintsLabel, "cell 0 13");
|
||||
|
||||
//---- textField7 ----
|
||||
textField7.putClientProperty("JComponent.outline", "warning");
|
||||
add(textField7, "cell 1 13,growx");
|
||||
//---- warningHintsTextField ----
|
||||
warningHintsTextField.putClientProperty("JComponent.outline", "warning");
|
||||
add(warningHintsTextField, "cell 1 13,growx");
|
||||
|
||||
//---- comboBox8 ----
|
||||
comboBox8.putClientProperty("JComponent.outline", "warning");
|
||||
comboBox8.setModel(new DefaultComboBoxModel<>(new String[] {
|
||||
//---- warningHintsComboBox ----
|
||||
warningHintsComboBox.putClientProperty("JComponent.outline", "warning");
|
||||
warningHintsComboBox.setModel(new DefaultComboBoxModel<>(new String[] {
|
||||
"Not editable"
|
||||
}));
|
||||
add(comboBox8, "cell 2 13,growx");
|
||||
add(warningHintsComboBox, "cell 2 13,growx");
|
||||
|
||||
//---- spinner4 ----
|
||||
spinner4.putClientProperty("JComponent.outline", "warning");
|
||||
add(spinner4, "cell 3 13,growx");
|
||||
//---- warningHintsSpinner ----
|
||||
warningHintsSpinner.putClientProperty("JComponent.outline", "warning");
|
||||
add(warningHintsSpinner, "cell 3 13,growx");
|
||||
|
||||
//======== popupMenu1 ========
|
||||
{
|
||||
@@ -668,6 +669,33 @@ class BasicComponentsPanel
|
||||
cutMenuItem.addActionListener( new DefaultEditorKit.CutAction() );
|
||||
copyMenuItem.addActionListener( new DefaultEditorKit.CopyAction() );
|
||||
pasteMenuItem.addActionListener( new DefaultEditorKit.PasteAction() );
|
||||
|
||||
if( FlatLafDemo.screenshotsMode ) {
|
||||
Component[] components = {
|
||||
button13, button14, button15, button16, comboBox5, comboBox6,
|
||||
textField6, passwordField5,
|
||||
|
||||
formattedTextFieldLabel, formattedTextField1, formattedTextField2, formattedTextField3, formattedTextField4, formattedTextField5,
|
||||
textAreaLabel, scrollPane1, scrollPane2, scrollPane3, scrollPane4, textArea5,
|
||||
editorPaneLabel, scrollPane5, scrollPane6, scrollPane7, scrollPane8, editorPane5,
|
||||
textPaneLabel, scrollPane9, scrollPane10, scrollPane11, scrollPane12, textPane5,
|
||||
|
||||
errorHintsLabel, errorHintsTextField, errorHintsComboBox, errorHintsSpinner,
|
||||
warningHintsLabel, warningHintsTextField, warningHintsComboBox, warningHintsSpinner,
|
||||
};
|
||||
|
||||
for( Component c : components )
|
||||
c.setVisible( false );
|
||||
|
||||
// move password fields one row up
|
||||
Component[] formattedTextFields = { formattedTextFieldLabel, formattedTextField1, formattedTextField2, formattedTextField3, formattedTextField4 };
|
||||
Component[] passwordFields = { passwordFieldLabel, passwordField1, passwordField2, passwordField3, passwordField4 };
|
||||
MigLayout layout = (MigLayout) getLayout();
|
||||
for( int i = 0; i < passwordFields.length; i++ ) {
|
||||
Object cons = layout.getComponentConstraints( formattedTextFields[i] );
|
||||
layout.setComponentConstraints( passwordFields[i], cons );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
|
||||
|
||||
@@ -7,8 +7,8 @@ new FormModel {
|
||||
"JavaCodeGenerator.defaultVariableLocal": true
|
||||
}
|
||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||
"$layoutConstraints": "hidemode 3"
|
||||
"$columnConstraints": "[][][][][][]"
|
||||
"$layoutConstraints": "insets dialog,hidemode 3"
|
||||
"$columnConstraints": "[sizegroup 1][sizegroup 1][sizegroup 1][sizegroup 1][][]"
|
||||
"$rowConstraints": "[][][][][][][][][][][][]para[][]"
|
||||
} ) {
|
||||
name: "this"
|
||||
@@ -592,19 +592,19 @@ new FormModel {
|
||||
"value": "cell 5 11,growx"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label3"
|
||||
name: "errorHintsLabel"
|
||||
"text": "Error hints:"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 12"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JTextField" ) {
|
||||
name: "textField5"
|
||||
name: "errorHintsTextField"
|
||||
"$client.JComponent.outline": "error"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 12,growx"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JComboBox" ) {
|
||||
name: "comboBox7"
|
||||
name: "errorHintsComboBox"
|
||||
"$client.JComponent.outline": "error"
|
||||
"model": new javax.swing.DefaultComboBoxModel {
|
||||
selectedItem: "Editable"
|
||||
@@ -615,25 +615,25 @@ new FormModel {
|
||||
"value": "cell 2 12,growx"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JSpinner" ) {
|
||||
name: "spinner3"
|
||||
name: "errorHintsSpinner"
|
||||
"$client.JComponent.outline": "error"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 3 12,growx"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label4"
|
||||
name: "warningHintsLabel"
|
||||
"text": "Warning hints:"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 13"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JTextField" ) {
|
||||
name: "textField7"
|
||||
name: "warningHintsTextField"
|
||||
"$client.JComponent.outline": "warning"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 13,growx"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JComboBox" ) {
|
||||
name: "comboBox8"
|
||||
name: "warningHintsComboBox"
|
||||
"$client.JComponent.outline": "warning"
|
||||
"model": new javax.swing.DefaultComboBoxModel {
|
||||
selectedItem: "Not editable"
|
||||
@@ -643,7 +643,7 @@ new FormModel {
|
||||
"value": "cell 2 13,growx"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JSpinner" ) {
|
||||
name: "spinner4"
|
||||
name: "warningHintsSpinner"
|
||||
"$client.JComponent.outline": "warning"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 3 13,growx"
|
||||
|
||||
@@ -27,8 +27,12 @@ import javax.swing.UIManager.LookAndFeelInfo;
|
||||
import javax.swing.plaf.metal.MetalLookAndFeel;
|
||||
import javax.swing.plaf.nimbus.NimbusLookAndFeel;
|
||||
import com.formdev.flatlaf.*;
|
||||
import com.formdev.flatlaf.extras.FlatAnimatedLafChange;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
import net.miginfocom.layout.ConstraintParser;
|
||||
import net.miginfocom.layout.LC;
|
||||
import net.miginfocom.layout.UnitValue;
|
||||
import net.miginfocom.swing.*;
|
||||
|
||||
/**
|
||||
@@ -43,6 +47,18 @@ class ControlBar
|
||||
ControlBar() {
|
||||
initComponents();
|
||||
|
||||
// remove top insets
|
||||
MigLayout layout = (MigLayout) getLayout();
|
||||
LC lc = ConstraintParser.parseLayoutConstraint( (String) layout.getLayoutConstraints() );
|
||||
UnitValue[] insets = lc.getInsets();
|
||||
lc.setInsets( new UnitValue[] {
|
||||
new UnitValue( 0, UnitValue.PIXEL, null ),
|
||||
insets[1],
|
||||
insets[2],
|
||||
insets[3]
|
||||
} );
|
||||
layout.setLayoutConstraints( lc );
|
||||
|
||||
// initialize look and feels combo box
|
||||
DefaultComboBoxModel<LookAndFeelInfo> lafModel = new DefaultComboBoxModel<>();
|
||||
lafModel.addElement( new LookAndFeelInfo( "Flat Light (F1)", FlatLightLaf.class.getName() ) );
|
||||
@@ -58,9 +74,9 @@ class ControlBar
|
||||
className.equals( "com.sun.java.swing.plaf.motif.MotifLookAndFeel" ) )
|
||||
continue;
|
||||
|
||||
if( (SystemInfo.IS_WINDOWS && className.equals( "com.sun.java.swing.plaf.windows.WindowsLookAndFeel" )) ||
|
||||
(SystemInfo.IS_MAC && className.equals( "com.apple.laf.AquaLookAndFeel") ) ||
|
||||
(SystemInfo.IS_LINUX && className.equals( "com.sun.java.swing.plaf.gtk.GTKLookAndFeel") ) )
|
||||
if( (SystemInfo.isWindows && className.equals( "com.sun.java.swing.plaf.windows.WindowsLookAndFeel" )) ||
|
||||
(SystemInfo.isMacOS && className.equals( "com.apple.laf.AquaLookAndFeel") ) ||
|
||||
(SystemInfo.isLinux && className.equals( "com.sun.java.swing.plaf.gtk.GTKLookAndFeel") ) )
|
||||
name += " (F9)";
|
||||
else if( className.equals( MetalLookAndFeel.class.getName() ) )
|
||||
name += " (F12)";
|
||||
@@ -111,15 +127,25 @@ class ControlBar
|
||||
registerSwitchToLookAndFeel( KeyEvent.VK_F3, FlatIntelliJLaf.class.getName() );
|
||||
registerSwitchToLookAndFeel( KeyEvent.VK_F4, FlatDarculaLaf.class.getName() );
|
||||
|
||||
if( SystemInfo.IS_WINDOWS )
|
||||
if( SystemInfo.isWindows )
|
||||
registerSwitchToLookAndFeel( KeyEvent.VK_F9, "com.sun.java.swing.plaf.windows.WindowsLookAndFeel" );
|
||||
else if( SystemInfo.IS_MAC )
|
||||
else if( SystemInfo.isMacOS )
|
||||
registerSwitchToLookAndFeel( KeyEvent.VK_F9, "com.apple.laf.AquaLookAndFeel" );
|
||||
else if( SystemInfo.IS_LINUX )
|
||||
else if( SystemInfo.isLinux )
|
||||
registerSwitchToLookAndFeel( KeyEvent.VK_F9, "com.sun.java.swing.plaf.gtk.GTKLookAndFeel" );
|
||||
registerSwitchToLookAndFeel( KeyEvent.VK_F12, MetalLookAndFeel.class.getName() );
|
||||
registerSwitchToLookAndFeel( KeyEvent.VK_F11, NimbusLookAndFeel.class.getName() );
|
||||
|
||||
// register Alt+UP and Alt+DOWN to switch to previous/next theme
|
||||
((JComponent)frame.getContentPane()).registerKeyboardAction(
|
||||
e -> frame.themesPanel.selectPreviousTheme(),
|
||||
KeyStroke.getKeyStroke( KeyEvent.VK_UP, KeyEvent.ALT_DOWN_MASK ),
|
||||
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT );
|
||||
((JComponent)frame.getContentPane()).registerKeyboardAction(
|
||||
e -> frame.themesPanel.selectNextTheme(),
|
||||
KeyStroke.getKeyStroke( KeyEvent.VK_DOWN, KeyEvent.ALT_DOWN_MASK ),
|
||||
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT );
|
||||
|
||||
// register ESC key to close frame
|
||||
((JComponent)frame.getContentPane()).registerKeyboardAction(
|
||||
e -> {
|
||||
@@ -193,6 +219,8 @@ class ControlBar
|
||||
|
||||
EventQueue.invokeLater( () -> {
|
||||
try {
|
||||
FlatAnimatedLafChange.showSnapshot();
|
||||
|
||||
// change look and feel
|
||||
UIManager.setLookAndFeel( lafClassName );
|
||||
|
||||
@@ -202,6 +230,7 @@ class ControlBar
|
||||
|
||||
// update all components
|
||||
FlatLaf.updateUI();
|
||||
FlatAnimatedLafChange.hideSnapshotWithAnimation();
|
||||
|
||||
// increase size of frame if necessary
|
||||
int width = frame.getWidth();
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
package com.formdev.flatlaf.demo;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.datatransfer.DataFlavor;
|
||||
import java.awt.datatransfer.StringSelection;
|
||||
import java.awt.datatransfer.Transferable;
|
||||
@@ -64,6 +67,41 @@ class DataComponentsPanel
|
||||
}
|
||||
}
|
||||
|
||||
private void rowSelectionChanged() {
|
||||
table1.setRowSelectionAllowed( rowSelectionCheckBox.isSelected() );
|
||||
}
|
||||
|
||||
private void columnSelectionChanged() {
|
||||
table1.setColumnSelectionAllowed( columnSelectionCheckBox.isSelected() );
|
||||
}
|
||||
|
||||
private void showHorizontalLinesChanged() {
|
||||
table1.setShowHorizontalLines( showHorizontalLinesCheckBox.isSelected() );
|
||||
}
|
||||
|
||||
private void showVerticalLinesChanged() {
|
||||
table1.setShowVerticalLines( showVerticalLinesCheckBox.isSelected() );
|
||||
}
|
||||
|
||||
private void intercellSpacingChanged() {
|
||||
table1.setIntercellSpacing( intercellSpacingCheckBox.isSelected() ? new Dimension( 1, 1 ) : new Dimension() );
|
||||
}
|
||||
|
||||
private void redGridColorChanged() {
|
||||
table1.setGridColor( redGridColorCheckBox.isSelected() ? Color.red : UIManager.getColor( "Table.gridColor" ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateUI() {
|
||||
super.updateUI();
|
||||
|
||||
EventQueue.invokeLater( () -> {
|
||||
showHorizontalLinesChanged();
|
||||
showVerticalLinesChanged();
|
||||
intercellSpacingChanged();
|
||||
} );
|
||||
}
|
||||
|
||||
@SuppressWarnings( { "unchecked", "rawtypes" } )
|
||||
private void initComponents() {
|
||||
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
|
||||
@@ -80,6 +118,13 @@ class DataComponentsPanel
|
||||
JLabel tableLabel = new JLabel();
|
||||
JScrollPane scrollPane5 = new JScrollPane();
|
||||
table1 = new JTable();
|
||||
JPanel tableOptionsPanel = new JPanel();
|
||||
showHorizontalLinesCheckBox = new JCheckBox();
|
||||
showVerticalLinesCheckBox = new JCheckBox();
|
||||
intercellSpacingCheckBox = new JCheckBox();
|
||||
redGridColorCheckBox = new JCheckBox();
|
||||
rowSelectionCheckBox = new JCheckBox();
|
||||
columnSelectionCheckBox = new JCheckBox();
|
||||
dndCheckBox = new JCheckBox();
|
||||
JPopupMenu popupMenu2 = new JPopupMenu();
|
||||
JMenuItem menuItem3 = new JMenuItem();
|
||||
@@ -89,20 +134,20 @@ class DataComponentsPanel
|
||||
|
||||
//======== this ========
|
||||
setLayout(new MigLayout(
|
||||
"hidemode 3",
|
||||
"insets dialog,hidemode 3",
|
||||
// columns
|
||||
"[]" +
|
||||
"[200]" +
|
||||
"[200]",
|
||||
"[200,fill]" +
|
||||
"[200,fill]" +
|
||||
"[fill]",
|
||||
// rows
|
||||
"[]" +
|
||||
"[::200]" +
|
||||
"[::150]" +
|
||||
"[]"));
|
||||
"[150,grow,sizegroup 1,fill]" +
|
||||
"[150,grow,sizegroup 1,fill]" +
|
||||
"[150,grow,sizegroup 1,fill]"));
|
||||
|
||||
//---- listLabel ----
|
||||
listLabel.setText("JList:");
|
||||
add(listLabel, "cell 0 0");
|
||||
add(listLabel, "cell 0 0,aligny top,growy 0");
|
||||
|
||||
//======== scrollPane1 ========
|
||||
{
|
||||
@@ -134,7 +179,7 @@ class DataComponentsPanel
|
||||
list1.setComponentPopupMenu(popupMenu2);
|
||||
scrollPane1.setViewportView(list1);
|
||||
}
|
||||
add(scrollPane1, "cell 1 0,growx");
|
||||
add(scrollPane1, "cell 1 0");
|
||||
|
||||
//======== scrollPane2 ========
|
||||
{
|
||||
@@ -166,11 +211,11 @@ class DataComponentsPanel
|
||||
list2.setEnabled(false);
|
||||
scrollPane2.setViewportView(list2);
|
||||
}
|
||||
add(scrollPane2, "cell 2 0,growx");
|
||||
add(scrollPane2, "cell 2 0");
|
||||
|
||||
//---- treeLabel ----
|
||||
treeLabel.setText("JTree:");
|
||||
add(treeLabel, "cell 0 1");
|
||||
add(treeLabel, "cell 0 1,aligny top,growy 0");
|
||||
|
||||
//======== scrollPane3 ========
|
||||
{
|
||||
@@ -207,7 +252,7 @@ class DataComponentsPanel
|
||||
tree1.setComponentPopupMenu(popupMenu2);
|
||||
scrollPane3.setViewportView(tree1);
|
||||
}
|
||||
add(scrollPane3, "cell 1 1,growx");
|
||||
add(scrollPane3, "cell 1 1");
|
||||
|
||||
//======== scrollPane4 ========
|
||||
{
|
||||
@@ -216,11 +261,11 @@ class DataComponentsPanel
|
||||
tree2.setEnabled(false);
|
||||
scrollPane4.setViewportView(tree2);
|
||||
}
|
||||
add(scrollPane4, "cell 2 1,growx");
|
||||
add(scrollPane4, "cell 2 1");
|
||||
|
||||
//---- tableLabel ----
|
||||
tableLabel.setText("JTable:");
|
||||
add(tableLabel, "cell 0 2");
|
||||
add(tableLabel, "cell 0 2,aligny top,growy 0");
|
||||
|
||||
//======== scrollPane5 ========
|
||||
{
|
||||
@@ -297,13 +342,61 @@ class DataComponentsPanel
|
||||
table1.setComponentPopupMenu(popupMenu2);
|
||||
scrollPane5.setViewportView(table1);
|
||||
}
|
||||
add(scrollPane5, "cell 1 2 2 1,growx,width 300");
|
||||
add(scrollPane5, "cell 1 2 2 1,width 300");
|
||||
|
||||
//---- dndCheckBox ----
|
||||
dndCheckBox.setText("enable drag and drop");
|
||||
dndCheckBox.setMnemonic('D');
|
||||
dndCheckBox.addActionListener(e -> dndChanged());
|
||||
add(dndCheckBox, "cell 0 3 3 1");
|
||||
//======== tableOptionsPanel ========
|
||||
{
|
||||
tableOptionsPanel.setLayout(new MigLayout(
|
||||
"insets 0,hidemode 3",
|
||||
// columns
|
||||
"[]",
|
||||
// rows
|
||||
"[]0" +
|
||||
"[]0" +
|
||||
"[]0" +
|
||||
"[]0" +
|
||||
"[]0" +
|
||||
"[]0" +
|
||||
"[]0"));
|
||||
|
||||
//---- showHorizontalLinesCheckBox ----
|
||||
showHorizontalLinesCheckBox.setText("show horizontal lines");
|
||||
showHorizontalLinesCheckBox.addActionListener(e -> showHorizontalLinesChanged());
|
||||
tableOptionsPanel.add(showHorizontalLinesCheckBox, "cell 0 0");
|
||||
|
||||
//---- showVerticalLinesCheckBox ----
|
||||
showVerticalLinesCheckBox.setText("show vertical lines");
|
||||
showVerticalLinesCheckBox.addActionListener(e -> showVerticalLinesChanged());
|
||||
tableOptionsPanel.add(showVerticalLinesCheckBox, "cell 0 1");
|
||||
|
||||
//---- intercellSpacingCheckBox ----
|
||||
intercellSpacingCheckBox.setText("intercell spacing");
|
||||
intercellSpacingCheckBox.addActionListener(e -> intercellSpacingChanged());
|
||||
tableOptionsPanel.add(intercellSpacingCheckBox, "cell 0 2");
|
||||
|
||||
//---- redGridColorCheckBox ----
|
||||
redGridColorCheckBox.setText("red grid color");
|
||||
redGridColorCheckBox.addActionListener(e -> redGridColorChanged());
|
||||
tableOptionsPanel.add(redGridColorCheckBox, "cell 0 3");
|
||||
|
||||
//---- rowSelectionCheckBox ----
|
||||
rowSelectionCheckBox.setText("row selection");
|
||||
rowSelectionCheckBox.setSelected(true);
|
||||
rowSelectionCheckBox.addActionListener(e -> rowSelectionChanged());
|
||||
tableOptionsPanel.add(rowSelectionCheckBox, "cell 0 4");
|
||||
|
||||
//---- columnSelectionCheckBox ----
|
||||
columnSelectionCheckBox.setText("column selection");
|
||||
columnSelectionCheckBox.addActionListener(e -> columnSelectionChanged());
|
||||
tableOptionsPanel.add(columnSelectionCheckBox, "cell 0 5");
|
||||
|
||||
//---- dndCheckBox ----
|
||||
dndCheckBox.setText("enable drag and drop");
|
||||
dndCheckBox.setMnemonic('D');
|
||||
dndCheckBox.addActionListener(e -> dndChanged());
|
||||
tableOptionsPanel.add(dndCheckBox, "cell 0 6");
|
||||
}
|
||||
add(tableOptionsPanel, "cell 3 2");
|
||||
|
||||
//======== popupMenu2 ========
|
||||
{
|
||||
@@ -336,6 +429,12 @@ class DataComponentsPanel
|
||||
private JTree tree1;
|
||||
private JTree tree2;
|
||||
private JTable table1;
|
||||
private JCheckBox showHorizontalLinesCheckBox;
|
||||
private JCheckBox showVerticalLinesCheckBox;
|
||||
private JCheckBox intercellSpacingCheckBox;
|
||||
private JCheckBox redGridColorCheckBox;
|
||||
private JCheckBox rowSelectionCheckBox;
|
||||
private JCheckBox columnSelectionCheckBox;
|
||||
private JCheckBox dndCheckBox;
|
||||
// JFormDesigner - End of variables declaration //GEN-END:variables
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
JFDML JFormDesigner: "7.0.1.0.272" Java: "13.0.2" encoding: "UTF-8"
|
||||
JFDML JFormDesigner: "7.0.2.0.298" Java: "14" encoding: "UTF-8"
|
||||
|
||||
new FormModel {
|
||||
contentType: "form/swing"
|
||||
@@ -7,16 +7,16 @@ new FormModel {
|
||||
"JavaCodeGenerator.defaultVariableLocal": true
|
||||
}
|
||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||
"$layoutConstraints": "hidemode 3"
|
||||
"$columnConstraints": "[][200][200]"
|
||||
"$rowConstraints": "[][::200][::150][]"
|
||||
"$layoutConstraints": "insets dialog,hidemode 3"
|
||||
"$columnConstraints": "[][200,fill][200,fill][fill]"
|
||||
"$rowConstraints": "[150,grow,sizegroup 1,fill][150,grow,sizegroup 1,fill][150,grow,sizegroup 1,fill]"
|
||||
} ) {
|
||||
name: "this"
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "listLabel"
|
||||
"text": "JList:"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 0"
|
||||
"value": "cell 0 0,aligny top,growy 0"
|
||||
} )
|
||||
add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) {
|
||||
name: "scrollPane1"
|
||||
@@ -46,7 +46,7 @@ new FormModel {
|
||||
}
|
||||
} )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 0,growx"
|
||||
"value": "cell 1 0"
|
||||
} )
|
||||
add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) {
|
||||
name: "scrollPane2"
|
||||
@@ -76,13 +76,13 @@ new FormModel {
|
||||
}
|
||||
} )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 2 0,growx"
|
||||
"value": "cell 2 0"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "treeLabel"
|
||||
"text": "JTree:"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 1"
|
||||
"value": "cell 0 1,aligny top,growy 0"
|
||||
} )
|
||||
add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) {
|
||||
name: "scrollPane3"
|
||||
@@ -150,7 +150,7 @@ new FormModel {
|
||||
}
|
||||
} )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 1,growx"
|
||||
"value": "cell 1 1"
|
||||
} )
|
||||
add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) {
|
||||
name: "scrollPane4"
|
||||
@@ -162,13 +162,13 @@ new FormModel {
|
||||
}
|
||||
} )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 2 1,growx"
|
||||
"value": "cell 2 1"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "tableLabel"
|
||||
"text": "JTable:"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 2"
|
||||
"value": "cell 0 2,aligny top,growy 0"
|
||||
} )
|
||||
add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) {
|
||||
name: "scrollPane5"
|
||||
@@ -307,22 +307,92 @@ new FormModel {
|
||||
}
|
||||
} )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 2 2 1,growx,width 300"
|
||||
"value": "cell 1 2 2 1,width 300"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||
name: "dndCheckBox"
|
||||
"text": "enable drag and drop"
|
||||
"mnemonic": 68
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "dndChanged", false ) )
|
||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||
"$layoutConstraints": "insets 0,hidemode 3"
|
||||
"$columnConstraints": "[]"
|
||||
"$rowConstraints": "[]0[]0[]0[]0[]0[]0[]0"
|
||||
} ) {
|
||||
name: "tableOptionsPanel"
|
||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||
name: "showHorizontalLinesCheckBox"
|
||||
"text": "show horizontal lines"
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showHorizontalLinesChanged", false ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 0"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||
name: "showVerticalLinesCheckBox"
|
||||
"text": "show vertical lines"
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showVerticalLinesChanged", false ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 1"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||
name: "intercellSpacingCheckBox"
|
||||
"text": "intercell spacing"
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "intercellSpacingChanged", false ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 2"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||
name: "redGridColorCheckBox"
|
||||
"text": "red grid color"
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "redGridColorChanged", false ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 3"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||
name: "rowSelectionCheckBox"
|
||||
"text": "row selection"
|
||||
"selected": true
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "rowSelectionChanged", false ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 4"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||
name: "columnSelectionCheckBox"
|
||||
"text": "column selection"
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "columnSelectionChanged", false ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 5"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||
name: "dndCheckBox"
|
||||
"text": "enable drag and drop"
|
||||
"mnemonic": 68
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "dndChanged", false ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 6"
|
||||
} )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 3 3 1"
|
||||
"value": "cell 3 2"
|
||||
} )
|
||||
}, new FormLayoutConstraints( null ) {
|
||||
"location": new java.awt.Point( 0, 0 )
|
||||
"size": new java.awt.Dimension( 790, 715 )
|
||||
"size": new java.awt.Dimension( 790, 745 )
|
||||
} )
|
||||
add( new FormContainer( "javax.swing.JPopupMenu", new FormLayoutManager( class javax.swing.JPopupMenu ) ) {
|
||||
name: "popupMenu2"
|
||||
@@ -346,7 +416,7 @@ new FormModel {
|
||||
"text": "Noop Action"
|
||||
} )
|
||||
}, new FormLayoutConstraints( null ) {
|
||||
"location": new java.awt.Point( 0, 740 )
|
||||
"location": new java.awt.Point( 0, 800 )
|
||||
} )
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,16 +20,23 @@ import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.prefs.Preferences;
|
||||
import javax.swing.*;
|
||||
import javax.swing.text.DefaultEditorKit;
|
||||
import javax.swing.text.StyleContext;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.demo.HintManager.Hint;
|
||||
import com.formdev.flatlaf.demo.extras.*;
|
||||
import com.formdev.flatlaf.demo.intellijthemes.*;
|
||||
import com.formdev.flatlaf.extras.FlatAnimatedLafChange;
|
||||
import com.formdev.flatlaf.extras.FlatSVGIcon;
|
||||
import com.formdev.flatlaf.extras.SVGUtils;
|
||||
import com.formdev.flatlaf.extras.FlatUIDefaultsInspector;
|
||||
import com.formdev.flatlaf.extras.FlatSVGUtils;
|
||||
import com.formdev.flatlaf.ui.JBRCustomDecorations;
|
||||
import net.miginfocom.layout.ConstraintParser;
|
||||
import net.miginfocom.layout.LC;
|
||||
import net.miginfocom.layout.UnitValue;
|
||||
import net.miginfocom.swing.*;
|
||||
|
||||
/**
|
||||
@@ -52,10 +59,65 @@ class DemoFrame
|
||||
updateFontMenuItems();
|
||||
controlBar.initialize( this, tabbedPane );
|
||||
|
||||
setIconImages( SVGUtils.createWindowIconImages( "/com/formdev/flatlaf/demo/FlatLaf.svg" ) );
|
||||
setIconImages( FlatSVGUtils.createWindowIconImages( "/com/formdev/flatlaf/demo/FlatLaf.svg" ) );
|
||||
|
||||
if( tabIndex >= 0 && tabIndex < tabbedPane.getTabCount() && tabIndex != tabbedPane.getSelectedIndex() )
|
||||
tabbedPane.setSelectedIndex( tabIndex );
|
||||
|
||||
SwingUtilities.invokeLater( () -> {
|
||||
showHints();
|
||||
} );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
|
||||
FlatUIDefaultsInspector.hide();
|
||||
}
|
||||
|
||||
private void showHints() {
|
||||
Hint fontMenuHint = new Hint(
|
||||
"Use 'Font' menu to increase/decrease font size or try different fonts.",
|
||||
fontMenu, SwingConstants.BOTTOM, "hint.fontMenu", null );
|
||||
|
||||
Hint optionsMenuHint = new Hint(
|
||||
"Use 'Options' menu to try out various FlatLaf options.",
|
||||
optionsMenu, SwingConstants.BOTTOM, "hint.optionsMenu", fontMenuHint );
|
||||
|
||||
Hint themesHint = new Hint(
|
||||
"Use 'Themes' list to try out various themes.",
|
||||
themesPanel, SwingConstants.LEFT, "hint.themesPanel", optionsMenuHint );
|
||||
|
||||
HintManager.showHint( themesHint );
|
||||
}
|
||||
|
||||
private void clearHints() {
|
||||
HintManager.hideAllHints();
|
||||
|
||||
Preferences state = DemoPrefs.getState();
|
||||
state.remove( "hint.fontMenu" );
|
||||
state.remove( "hint.optionsMenu" );
|
||||
state.remove( "hint.themesPanel" );
|
||||
}
|
||||
|
||||
private void showUIDefaultsInspector() {
|
||||
FlatUIDefaultsInspector.show();
|
||||
}
|
||||
|
||||
private void newActionPerformed() {
|
||||
NewDialog newDialog = new NewDialog( this );
|
||||
newDialog.setVisible( true );
|
||||
}
|
||||
|
||||
private void openActionPerformed() {
|
||||
JFileChooser chooser = new JFileChooser();
|
||||
chooser.showOpenDialog( this );
|
||||
}
|
||||
|
||||
private void saveAsActionPerformed() {
|
||||
JFileChooser chooser = new JFileChooser();
|
||||
chooser.showSaveDialog( this );
|
||||
}
|
||||
|
||||
private void exitActionPerformed() {
|
||||
@@ -79,11 +141,16 @@ class DemoFrame
|
||||
private void windowDecorationsChanged() {
|
||||
boolean windowDecorations = windowDecorationsCheckBoxMenuItem.isSelected();
|
||||
|
||||
// change window decoration of demo main frame
|
||||
dispose();
|
||||
setUndecorated( windowDecorations );
|
||||
getRootPane().setWindowDecorationStyle( windowDecorations ? JRootPane.FRAME : JRootPane.NONE );
|
||||
menuBarEmbeddedCheckBoxMenuItem.setEnabled( windowDecorations );
|
||||
setVisible( true );
|
||||
|
||||
// enable/disable window decoration for later created frames/dialogs
|
||||
JFrame.setDefaultLookAndFeelDecorated( windowDecorations );
|
||||
JDialog.setDefaultLookAndFeelDecorated( windowDecorations );
|
||||
}
|
||||
|
||||
private void menuBarEmbeddedChanged() {
|
||||
@@ -105,14 +172,26 @@ class DemoFrame
|
||||
repaint();
|
||||
}
|
||||
|
||||
private void animatedLafChangeChanged() {
|
||||
System.setProperty( "flatlaf.animatedLafChange", String.valueOf( animatedLafChangeMenuItem.isSelected() ) );
|
||||
}
|
||||
|
||||
private void showHintsChanged() {
|
||||
clearHints();
|
||||
showHints();
|
||||
}
|
||||
|
||||
private void fontFamilyChanged( ActionEvent e ) {
|
||||
String fontFamily = e.getActionCommand();
|
||||
|
||||
FlatAnimatedLafChange.showSnapshot();
|
||||
|
||||
Font font = UIManager.getFont( "defaultFont" );
|
||||
Font newFont = StyleContext.getDefaultStyleContext().getFont( fontFamily, font.getStyle(), font.getSize() );
|
||||
UIManager.put( "defaultFont", newFont );
|
||||
|
||||
FlatLaf.updateUI();
|
||||
FlatAnimatedLafChange.hideSnapshotWithAnimation();
|
||||
}
|
||||
|
||||
private void fontSizeChanged( ActionEvent e ) {
|
||||
@@ -216,6 +295,7 @@ class DemoFrame
|
||||
JMenu fileMenu = new JMenu();
|
||||
JMenuItem newMenuItem = new JMenuItem();
|
||||
JMenuItem openMenuItem = new JMenuItem();
|
||||
JMenuItem saveAsMenuItem = new JMenuItem();
|
||||
JMenuItem closeMenuItem = new JMenuItem();
|
||||
JMenuItem exitMenuItem = new JMenuItem();
|
||||
JMenu editMenu = new JMenu();
|
||||
@@ -235,6 +315,7 @@ class DemoFrame
|
||||
JMenuItem projectViewMenuItem = new JMenuItem();
|
||||
JMenuItem structureViewMenuItem = new JMenuItem();
|
||||
JMenuItem propertiesViewMenuItem = new JMenuItem();
|
||||
JMenuItem menuItem2 = new JMenuItem();
|
||||
JMenuItem menuItem1 = new JMenuItem();
|
||||
JRadioButtonMenuItem radioButtonMenuItem1 = new JRadioButtonMenuItem();
|
||||
JRadioButtonMenuItem radioButtonMenuItem2 = new JRadioButtonMenuItem();
|
||||
@@ -243,11 +324,14 @@ class DemoFrame
|
||||
JMenuItem restoreFontMenuItem = new JMenuItem();
|
||||
JMenuItem incrFontMenuItem = new JMenuItem();
|
||||
JMenuItem decrFontMenuItem = new JMenuItem();
|
||||
JMenu optionsMenu = new JMenu();
|
||||
optionsMenu = new JMenu();
|
||||
windowDecorationsCheckBoxMenuItem = new JCheckBoxMenuItem();
|
||||
menuBarEmbeddedCheckBoxMenuItem = new JCheckBoxMenuItem();
|
||||
underlineMenuSelectionMenuItem = new JCheckBoxMenuItem();
|
||||
alwaysShowMnemonicsMenuItem = new JCheckBoxMenuItem();
|
||||
animatedLafChangeMenuItem = new JCheckBoxMenuItem();
|
||||
JMenuItem showHintsMenuItem = new JMenuItem();
|
||||
JMenuItem showUIDefaultsInspectorMenuItem = new JMenuItem();
|
||||
JMenu helpMenu = new JMenu();
|
||||
JMenuItem aboutMenuItem = new JMenuItem();
|
||||
JToolBar toolBar1 = new JToolBar();
|
||||
@@ -267,7 +351,7 @@ class DemoFrame
|
||||
OptionPanePanel optionPanePanel = new OptionPanePanel();
|
||||
ExtrasPanel extrasPanel1 = new ExtrasPanel();
|
||||
controlBar = new ControlBar();
|
||||
IJThemesPanel themesPanel = new IJThemesPanel();
|
||||
themesPanel = new IJThemesPanel();
|
||||
|
||||
//======== this ========
|
||||
setTitle("FlatLaf Demo");
|
||||
@@ -287,15 +371,22 @@ class DemoFrame
|
||||
newMenuItem.setText("New");
|
||||
newMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
|
||||
newMenuItem.setMnemonic('N');
|
||||
newMenuItem.addActionListener(e -> menuItemActionPerformed(e));
|
||||
newMenuItem.addActionListener(e -> newActionPerformed());
|
||||
fileMenu.add(newMenuItem);
|
||||
|
||||
//---- openMenuItem ----
|
||||
openMenuItem.setText("Open");
|
||||
openMenuItem.setText("Open...");
|
||||
openMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
|
||||
openMenuItem.setMnemonic('O');
|
||||
openMenuItem.addActionListener(e -> menuItemActionPerformed(e));
|
||||
openMenuItem.addActionListener(e -> openActionPerformed());
|
||||
fileMenu.add(openMenuItem);
|
||||
|
||||
//---- saveAsMenuItem ----
|
||||
saveAsMenuItem.setText("Save As...");
|
||||
saveAsMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
|
||||
saveAsMenuItem.setMnemonic('S');
|
||||
saveAsMenuItem.addActionListener(e -> saveAsActionPerformed());
|
||||
fileMenu.add(saveAsMenuItem);
|
||||
fileMenu.addSeparator();
|
||||
|
||||
//---- closeMenuItem ----
|
||||
@@ -426,6 +517,11 @@ class DemoFrame
|
||||
}
|
||||
viewMenu.add(menu1);
|
||||
|
||||
//---- menuItem2 ----
|
||||
menuItem2.setText("Disabled Item");
|
||||
menuItem2.setEnabled(false);
|
||||
viewMenu.add(menuItem2);
|
||||
|
||||
//---- menuItem1 ----
|
||||
menuItem1.setText("<html>some <b color=\"red\">HTML</b> <i color=\"blue\">text</i></html>");
|
||||
viewMenu.add(menuItem1);
|
||||
@@ -501,6 +597,22 @@ class DemoFrame
|
||||
alwaysShowMnemonicsMenuItem.setText("Always show mnemonics");
|
||||
alwaysShowMnemonicsMenuItem.addActionListener(e -> alwaysShowMnemonics());
|
||||
optionsMenu.add(alwaysShowMnemonicsMenuItem);
|
||||
|
||||
//---- animatedLafChangeMenuItem ----
|
||||
animatedLafChangeMenuItem.setText("Animated Laf Change");
|
||||
animatedLafChangeMenuItem.setSelected(true);
|
||||
animatedLafChangeMenuItem.addActionListener(e -> animatedLafChangeChanged());
|
||||
optionsMenu.add(animatedLafChangeMenuItem);
|
||||
|
||||
//---- showHintsMenuItem ----
|
||||
showHintsMenuItem.setText("Show hints");
|
||||
showHintsMenuItem.addActionListener(e -> showHintsChanged());
|
||||
optionsMenu.add(showHintsMenuItem);
|
||||
|
||||
//---- showUIDefaultsInspectorMenuItem ----
|
||||
showUIDefaultsInspectorMenuItem.setText("Show UI Defaults Inspector");
|
||||
showUIDefaultsInspectorMenuItem.addActionListener(e -> showUIDefaultsInspector());
|
||||
optionsMenu.add(showUIDefaultsInspectorMenuItem);
|
||||
}
|
||||
menuBar1.add(optionsMenu);
|
||||
|
||||
@@ -568,11 +680,12 @@ class DemoFrame
|
||||
|
||||
//======== tabbedPane ========
|
||||
{
|
||||
tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
|
||||
tabbedPane.addChangeListener(e -> selectedTabChanged());
|
||||
tabbedPane.addTab("Basic Components", basicComponentsPanel);
|
||||
tabbedPane.addTab("More Components", moreComponentsPanel);
|
||||
tabbedPane.addTab("Data Components", dataComponentsPanel);
|
||||
tabbedPane.addTab("SplitPane & Tabs", tabsPanel);
|
||||
tabbedPane.addTab("Tabs", tabsPanel);
|
||||
tabbedPane.addTab("Option Pane", optionPanePanel);
|
||||
tabbedPane.addTab("Extras", extrasPanel1);
|
||||
}
|
||||
@@ -612,15 +725,30 @@ class DemoFrame
|
||||
.getSupportsWindowDecorations() || JBRCustomDecorations.isSupported();
|
||||
windowDecorationsCheckBoxMenuItem.setEnabled( supportsWindowDecorations && !JBRCustomDecorations.isSupported() );
|
||||
menuBarEmbeddedCheckBoxMenuItem.setEnabled( supportsWindowDecorations );
|
||||
|
||||
// remove contentPanel bottom insets
|
||||
MigLayout layout = (MigLayout) contentPanel.getLayout();
|
||||
LC lc = ConstraintParser.parseLayoutConstraint( (String) layout.getLayoutConstraints() );
|
||||
UnitValue[] insets = lc.getInsets();
|
||||
lc.setInsets( new UnitValue[] {
|
||||
insets[0],
|
||||
insets[1],
|
||||
new UnitValue( 0, UnitValue.PIXEL, null ),
|
||||
insets[3]
|
||||
} );
|
||||
layout.setLayoutConstraints( lc );
|
||||
}
|
||||
|
||||
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
|
||||
private JMenu fontMenu;
|
||||
private JMenu optionsMenu;
|
||||
private JCheckBoxMenuItem windowDecorationsCheckBoxMenuItem;
|
||||
private JCheckBoxMenuItem menuBarEmbeddedCheckBoxMenuItem;
|
||||
private JCheckBoxMenuItem underlineMenuSelectionMenuItem;
|
||||
private JCheckBoxMenuItem alwaysShowMnemonicsMenuItem;
|
||||
private JCheckBoxMenuItem animatedLafChangeMenuItem;
|
||||
private JTabbedPane tabbedPane;
|
||||
private ControlBar controlBar;
|
||||
IJThemesPanel themesPanel;
|
||||
// JFormDesigner - End of variables declaration //GEN-END:variables
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
JFDML JFormDesigner: "7.0.1.0.272" Java: "13.0.2" encoding: "UTF-8"
|
||||
JFDML JFormDesigner: "7.0.2.0.298" Java: "15" encoding: "UTF-8"
|
||||
|
||||
new FormModel {
|
||||
contentType: "form/swing"
|
||||
@@ -64,6 +64,7 @@ new FormModel {
|
||||
name: "contentPanel"
|
||||
add( new FormContainer( "javax.swing.JTabbedPane", new FormLayoutManager( class javax.swing.JTabbedPane ) ) {
|
||||
name: "tabbedPane"
|
||||
"tabLayoutPolicy": 1
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
@@ -86,7 +87,7 @@ new FormModel {
|
||||
add( new FormComponent( "com.formdev.flatlaf.demo.TabsPanel" ) {
|
||||
name: "tabsPanel"
|
||||
}, new FormLayoutConstraints( null ) {
|
||||
"title": "SplitPane & Tabs"
|
||||
"title": "Tabs"
|
||||
} )
|
||||
add( new FormComponent( "com.formdev.flatlaf.demo.OptionPanePanel" ) {
|
||||
name: "optionPanePanel"
|
||||
@@ -114,6 +115,10 @@ new FormModel {
|
||||
} )
|
||||
add( new FormComponent( "com.formdev.flatlaf.demo.intellijthemes.IJThemesPanel" ) {
|
||||
name: "themesPanel"
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
"JavaCodeGenerator.variableModifiers": 0
|
||||
}
|
||||
}, new FormLayoutConstraints( class java.lang.String ) {
|
||||
"value": "East"
|
||||
} )
|
||||
@@ -128,14 +133,21 @@ new FormModel {
|
||||
"text": "New"
|
||||
"accelerator": static javax.swing.KeyStroke getKeyStroke( 78, 4226, false )
|
||||
"mnemonic": 78
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "menuItemActionPerformed", true ) )
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "newActionPerformed", false ) )
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JMenuItem" ) {
|
||||
name: "openMenuItem"
|
||||
"text": "Open"
|
||||
"text": "Open..."
|
||||
"accelerator": static javax.swing.KeyStroke getKeyStroke( 79, 4226, false )
|
||||
"mnemonic": 79
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "menuItemActionPerformed", true ) )
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "openActionPerformed", false ) )
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JMenuItem" ) {
|
||||
name: "saveAsMenuItem"
|
||||
"text": "Save As..."
|
||||
"accelerator": static javax.swing.KeyStroke getKeyStroke( 83, 4226, false )
|
||||
"mnemonic": 83
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "saveAsActionPerformed", false ) )
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JPopupMenu$Separator" ) {
|
||||
name: "separator2"
|
||||
@@ -264,6 +276,11 @@ new FormModel {
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "menuItemActionPerformed", true ) )
|
||||
} )
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JMenuItem" ) {
|
||||
name: "menuItem2"
|
||||
"text": "Disabled Item"
|
||||
"enabled": false
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JMenuItem" ) {
|
||||
name: "menuItem1"
|
||||
"text": "<html>some <b color=\"red\">HTML</b> <i color=\"blue\">text</i></html>"
|
||||
@@ -322,6 +339,9 @@ new FormModel {
|
||||
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
|
||||
name: "optionsMenu"
|
||||
"text": "Options"
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
add( new FormComponent( "javax.swing.JCheckBoxMenuItem" ) {
|
||||
name: "windowDecorationsCheckBoxMenuItem"
|
||||
"text": "Window decorations"
|
||||
@@ -356,6 +376,25 @@ new FormModel {
|
||||
}
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "alwaysShowMnemonics", false ) )
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JCheckBoxMenuItem" ) {
|
||||
name: "animatedLafChangeMenuItem"
|
||||
"text": "Animated Laf Change"
|
||||
"selected": true
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "animatedLafChangeChanged", false ) )
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JMenuItem" ) {
|
||||
name: "showHintsMenuItem"
|
||||
"text": "Show hints"
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showHintsChanged", false ) )
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JMenuItem" ) {
|
||||
name: "showUIDefaultsInspectorMenuItem"
|
||||
"text": "Show UI Defaults Inspector"
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showUIDefaultsInspector", false ) )
|
||||
} )
|
||||
} )
|
||||
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
|
||||
name: "helpMenu"
|
||||
|
||||
@@ -16,10 +16,13 @@
|
||||
|
||||
package com.formdev.flatlaf.demo;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.SwingUtilities;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.extras.FlatInspector;
|
||||
import com.formdev.flatlaf.extras.FlatUIDefaultsInspector;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
|
||||
/**
|
||||
@@ -30,9 +33,11 @@ public class FlatLafDemo
|
||||
static final String PREFS_ROOT_PATH = "/flatlaf-demo";
|
||||
static final String KEY_TAB = "tab";
|
||||
|
||||
static boolean screenshotsMode = Boolean.parseBoolean( System.getProperty( "flatlaf.demo.screenshotsMode" ) );
|
||||
|
||||
public static void main( String[] args ) {
|
||||
// on macOS enable screen menu bar
|
||||
if( SystemInfo.IS_MAC && System.getProperty( "apple.laf.useScreenMenuBar" ) == null )
|
||||
if( SystemInfo.isMacOS && System.getProperty( "apple.laf.useScreenMenuBar" ) == null )
|
||||
System.setProperty( "apple.laf.useScreenMenuBar", "true" );
|
||||
|
||||
SwingUtilities.invokeLater( () -> {
|
||||
@@ -42,15 +47,22 @@ public class FlatLafDemo
|
||||
JFrame.setDefaultLookAndFeelDecorated( true );
|
||||
JDialog.setDefaultLookAndFeelDecorated( true );
|
||||
|
||||
// application specific UI defaults
|
||||
FlatLaf.registerCustomDefaultsSource( "com.formdev.flatlaf.demo" );
|
||||
|
||||
// set look and feel
|
||||
DemoPrefs.initLaf( args );
|
||||
|
||||
// install inspector
|
||||
// install inspectors
|
||||
FlatInspector.install( "ctrl shift alt X" );
|
||||
FlatUIDefaultsInspector.install( "ctrl shift alt Y" );
|
||||
|
||||
// create frame
|
||||
DemoFrame frame = new DemoFrame();
|
||||
|
||||
if( FlatLafDemo.screenshotsMode )
|
||||
frame.setPreferredSize( new Dimension( 1280, 620 ) );
|
||||
|
||||
// show frame
|
||||
frame.pack();
|
||||
frame.setLocationRelativeTo( null );
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user