mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2026-02-11 06:27:13 -06:00
Compare commits
203 Commits
fonts/inte
...
3.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
19f27a8d56 | ||
|
|
cf3fa17666 | ||
|
|
6fdc56f2d3 | ||
|
|
9f17a5b26d | ||
|
|
fa53e90847 | ||
|
|
50c630f403 | ||
|
|
5630c161ea | ||
|
|
7d16ff9e79 | ||
|
|
a9ea9daec3 | ||
|
|
45bdd40dce | ||
|
|
a2bca88eec | ||
|
|
c0dd02ee13 | ||
|
|
97495a6093 | ||
|
|
4ad45088c4 | ||
|
|
d6d1d4b1b7 | ||
|
|
6e453c170f | ||
|
|
beb2deee52 | ||
|
|
9c69043b2c | ||
|
|
4df34b3f9d | ||
|
|
ee01756188 | ||
|
|
0386aaa18b | ||
|
|
92c4230cde | ||
|
|
26165999e0 | ||
|
|
38b2641078 | ||
|
|
4e19169312 | ||
|
|
46de81c1c9 | ||
|
|
9bf4da7acf | ||
|
|
6f32236fb7 | ||
|
|
c25d857e78 | ||
|
|
8cc2925fd0 | ||
|
|
2b87d3c4db | ||
|
|
7f6f366744 | ||
|
|
b1fdbde5cd | ||
|
|
417f0f5f1c | ||
|
|
ec7673790c | ||
|
|
7d0bdf3b9e | ||
|
|
2ef5270095 | ||
|
|
61ba011c3b | ||
|
|
8d8b9f3e98 | ||
|
|
69899ec29f | ||
|
|
5063621c95 | ||
|
|
030177f739 | ||
|
|
808f5a6381 | ||
|
|
9602b191a9 | ||
|
|
34bd2d781c | ||
|
|
cf364c1264 | ||
|
|
a997820bb6 | ||
|
|
b8fabd59c0 | ||
|
|
97d290795e | ||
|
|
2a237ff5fc | ||
|
|
13a418f74e | ||
|
|
5c56dbfed6 | ||
|
|
0d2f37e1da | ||
|
|
0494c2161c | ||
|
|
635a620439 | ||
|
|
0a7c76ec72 | ||
|
|
9ad8fb38e8 | ||
|
|
1dbe968952 | ||
|
|
460b6492cb | ||
|
|
67b0faa9ae | ||
|
|
5553425a1a | ||
|
|
8ff516e43a | ||
|
|
b6207bafde | ||
|
|
b9f43fd560 | ||
|
|
c617d9f569 | ||
|
|
9efb9761c6 | ||
|
|
03f9115fbf | ||
|
|
a2859cedb5 | ||
|
|
0c604b1023 | ||
|
|
cdee0594f8 | ||
|
|
808833d749 | ||
|
|
581c64b601 | ||
|
|
40418607e5 | ||
|
|
5436ea88d8 | ||
|
|
7bec5ec6dc | ||
|
|
c953ff84d0 | ||
|
|
96cd207df3 | ||
|
|
7a75f62a6a | ||
|
|
61e5fe58c2 | ||
|
|
1a3baba702 | ||
|
|
58dc14bb46 | ||
|
|
a5b7e04943 | ||
|
|
22f2aa5475 | ||
|
|
d4e9cb12be | ||
|
|
75da361480 | ||
|
|
7488bcb7b0 | ||
|
|
1b1a9be107 | ||
|
|
db2f94aa53 | ||
|
|
810146b993 | ||
|
|
93091662ab | ||
|
|
d349227fbf | ||
|
|
c9423e3aa8 | ||
|
|
b9737ca4f1 | ||
|
|
4b4990635d | ||
|
|
afaa2c8c78 | ||
|
|
f506ef0d4f | ||
|
|
d30fe66cac | ||
|
|
270e998e86 | ||
|
|
c395386c05 | ||
|
|
4f1207b0db | ||
|
|
dc3878e290 | ||
|
|
be2876149d | ||
|
|
52bae9dfb0 | ||
|
|
bb636bac3f | ||
|
|
502b18fa86 | ||
|
|
e0a5450264 | ||
|
|
5ffb23c37f | ||
|
|
b75f22b7bd | ||
|
|
35fa3197c8 | ||
|
|
f03725ae36 | ||
|
|
2b640e2129 | ||
|
|
2a983f5c03 | ||
|
|
cacc5daa14 | ||
|
|
593502287d | ||
|
|
7a9bdf9be0 | ||
|
|
170c22c5ed | ||
|
|
7e8fa58bd7 | ||
|
|
046200625c | ||
|
|
710ed55152 | ||
|
|
ce527329a6 | ||
|
|
b455dd41ab | ||
|
|
b47ed94f40 | ||
|
|
f1351a2093 | ||
|
|
c1c5e81df0 | ||
|
|
8e3c8ba6c5 | ||
|
|
dfe4404a17 | ||
|
|
b3fb63c9f5 | ||
|
|
9db3dfff26 | ||
|
|
3c9051e7de | ||
|
|
798a6d061c | ||
|
|
19afbe99d9 | ||
|
|
4715d8d16c | ||
|
|
193da2bc4d | ||
|
|
799f8efe22 | ||
|
|
f6062e1ec4 | ||
|
|
c790778a46 | ||
|
|
4344f1b3a0 | ||
|
|
d520b30500 | ||
|
|
11c02e5f50 | ||
|
|
aa4c6ee9da | ||
|
|
98f8557392 | ||
|
|
6f6a860887 | ||
|
|
38695e9e16 | ||
|
|
242c478cb3 | ||
|
|
f003e835bd | ||
|
|
267defb321 | ||
|
|
4392c7627b | ||
|
|
fde65b2730 | ||
|
|
e908362f0a | ||
|
|
a40b837634 | ||
|
|
b391465fbf | ||
|
|
bad0428f5b | ||
|
|
97018df2f9 | ||
|
|
9d84501bc8 | ||
|
|
e9fb2b3fdc | ||
|
|
f60250fd8a | ||
|
|
5fc3cae28a | ||
|
|
e7935be85b | ||
|
|
89363b2ea1 | ||
|
|
e84390ee46 | ||
|
|
65a0f467ae | ||
|
|
4afb150106 | ||
|
|
0f6702217e | ||
|
|
13a0097858 | ||
|
|
01c830ad92 | ||
|
|
dce4f4623c | ||
|
|
d530624362 | ||
|
|
2e878b62d1 | ||
|
|
d27a246dfe | ||
|
|
778def118a | ||
|
|
bc5587477b | ||
|
|
03a775cd31 | ||
|
|
875083a924 | ||
|
|
f6fc925c9e | ||
|
|
74e1972781 | ||
|
|
2f5c54bb49 | ||
|
|
465798ee3d | ||
|
|
425f3acced | ||
|
|
546382e471 | ||
|
|
7e91d78633 | ||
|
|
136e1e4e30 | ||
|
|
f5f6850172 | ||
|
|
28cdde3f17 | ||
|
|
29b801e13d | ||
|
|
1435469ee5 | ||
|
|
4a0bd2c09f | ||
|
|
f8d67f863f | ||
|
|
0291dd5416 | ||
|
|
9014435d4d | ||
|
|
07ad467c73 | ||
|
|
35e23574cf | ||
|
|
9b62b8395f | ||
|
|
45e7022deb | ||
|
|
32dce16363 | ||
|
|
e34b5eafe1 | ||
|
|
4e1e749094 | ||
|
|
ede9293377 | ||
|
|
9101324a1f | ||
|
|
4b844353ee | ||
|
|
2134c19c58 | ||
|
|
c974784ebb | ||
|
|
5eb6961023 | ||
|
|
07cbd8b97b |
18
.github/workflows/ci.yml
vendored
18
.github/workflows/ci.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
|||||||
# test against
|
# test against
|
||||||
# - Java 8 (minimum requirement)
|
# - Java 8 (minimum requirement)
|
||||||
# - Java LTS versions (11, 17, ...)
|
# - Java LTS versions (11, 17, ...)
|
||||||
# - lastest Java version(s)
|
# - latest Java version(s)
|
||||||
java:
|
java:
|
||||||
- 8
|
- 8
|
||||||
- 11 # LTS
|
- 11 # LTS
|
||||||
@@ -27,7 +27,7 @@ jobs:
|
|||||||
toolchain: [""]
|
toolchain: [""]
|
||||||
include:
|
include:
|
||||||
- java: 17
|
- java: 17
|
||||||
toolchain: 19 # latest
|
toolchain: 21 # latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
@@ -39,9 +39,13 @@ jobs:
|
|||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v3
|
||||||
with:
|
with:
|
||||||
java-version: ${{ matrix.java }}
|
java-version: ${{ matrix.java }}
|
||||||
distribution: adopt # Java 8 and 11 are pre-installed on ubuntu-latest
|
distribution: temurin # Java 8, 11 and 17 are pre-installed on ubuntu-latest
|
||||||
cache: gradle
|
cache: gradle
|
||||||
|
|
||||||
|
- name: Check with Error Prone
|
||||||
|
if: matrix.java == '11'
|
||||||
|
run: ./gradlew errorprone clean -Dtoolchain=${{ matrix.toolchain }}
|
||||||
|
|
||||||
- name: Build with Gradle
|
- name: Build with Gradle
|
||||||
run: ./gradlew build -Dtoolchain=${{ matrix.toolchain }}
|
run: ./gradlew build -Dtoolchain=${{ matrix.toolchain }}
|
||||||
|
|
||||||
@@ -72,11 +76,11 @@ jobs:
|
|||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v3
|
||||||
with:
|
with:
|
||||||
java-version: 11
|
java-version: 11
|
||||||
distribution: adopt # pre-installed on ubuntu-latest
|
distribution: temurin # pre-installed on ubuntu-latest
|
||||||
cache: gradle
|
cache: gradle
|
||||||
|
|
||||||
- name: Publish snapshot to oss.sonatype.org
|
- name: Publish snapshot to oss.sonatype.org
|
||||||
run: ./gradlew publish :flatlaf-theme-editor:build -PskipFonts -Dorg.gradle.internal.publish.checksums.insecure=true
|
run: ./gradlew publish :flatlaf-theme-editor:build -PskipFonts -Dorg.gradle.internal.publish.checksums.insecure=true -Dorg.gradle.parallel=false
|
||||||
env:
|
env:
|
||||||
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
|
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
|
||||||
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
|
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
|
||||||
@@ -108,11 +112,11 @@ jobs:
|
|||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v3
|
||||||
with:
|
with:
|
||||||
java-version: 11
|
java-version: 11
|
||||||
distribution: adopt # pre-installed on ubuntu-latest
|
distribution: temurin # pre-installed on ubuntu-latest
|
||||||
cache: gradle
|
cache: gradle
|
||||||
|
|
||||||
- name: Release a new stable version to Maven Central
|
- name: Release a new stable version to Maven Central
|
||||||
run: ./gradlew publish :flatlaf-demo:build :flatlaf-theme-editor:build -PskipFonts -Prelease
|
run: ./gradlew publish :flatlaf-demo:build :flatlaf-theme-editor:build -PskipFonts -Prelease -Dorg.gradle.parallel=false
|
||||||
env:
|
env:
|
||||||
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
|
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
|
||||||
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
|
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
|
||||||
|
|||||||
3
.github/workflows/fonts.yml
vendored
3
.github/workflows/fonts.yml
vendored
@@ -22,6 +22,7 @@ jobs:
|
|||||||
- inter
|
- inter
|
||||||
- jetbrains-mono
|
- jetbrains-mono
|
||||||
- roboto
|
- roboto
|
||||||
|
- roboto-mono
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: |
|
if: |
|
||||||
@@ -35,7 +36,7 @@ jobs:
|
|||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v3
|
||||||
with:
|
with:
|
||||||
java-version: 11
|
java-version: 11
|
||||||
distribution: adopt # pre-installed on ubuntu-latest
|
distribution: temurin # pre-installed on ubuntu-latest
|
||||||
cache: gradle
|
cache: gradle
|
||||||
|
|
||||||
- name: Build with Gradle
|
- name: Build with Gradle
|
||||||
|
|||||||
3
.github/workflows/natives.yml
vendored
3
.github/workflows/natives.yml
vendored
@@ -20,6 +20,7 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
os:
|
os:
|
||||||
- windows
|
- windows
|
||||||
|
- macos
|
||||||
- ubuntu
|
- ubuntu
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}-latest
|
runs-on: ${{ matrix.os }}-latest
|
||||||
@@ -33,7 +34,7 @@ jobs:
|
|||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v3
|
||||||
with:
|
with:
|
||||||
java-version: 11
|
java-version: 11
|
||||||
distribution: adopt
|
distribution: temurin
|
||||||
cache: gradle
|
cache: gradle
|
||||||
|
|
||||||
- name: Build with Gradle
|
- name: Build with Gradle
|
||||||
|
|||||||
266
CHANGELOG.md
266
CHANGELOG.md
@@ -1,6 +1,272 @@
|
|||||||
FlatLaf Change Log
|
FlatLaf Change Log
|
||||||
==================
|
==================
|
||||||
|
|
||||||
|
## 3.3
|
||||||
|
|
||||||
|
#### New features and improvements
|
||||||
|
|
||||||
|
- macOS (10.14+): Popups (`JPopupMenu`, `JComboBox`, `JToolTip`, etc.) now use
|
||||||
|
native macOS rounded borders. (PR #772; issue #715)
|
||||||
|
- Native libraries: Added `libflatlaf-macos-arm64.dylib` and
|
||||||
|
`libflatlaf-macos-x86_64.dylib`. See also
|
||||||
|
https://www.formdev.com/flatlaf/native-libraries/.
|
||||||
|
- ScrollPane: Support rounded border. (PR #713)
|
||||||
|
- SplitPane: Support divider hover and pressed background colors. (PR #788)
|
||||||
|
- TabbedPane: Support vertical tabs. (PR #758, issue #633)
|
||||||
|
- TabbedPane: Paint rounded tab area background for rounded cards. (issue #717)
|
||||||
|
- ToolBar: Added styling properties `separatorWidth` and `separatorColor`.
|
||||||
|
|
||||||
|
#### Fixed bugs
|
||||||
|
|
||||||
|
- Button and ToggleButton: Selected buttons did not use explicitly set
|
||||||
|
foreground color. (issue 756)
|
||||||
|
- FileChooser: Catch NPE in Java 21 when getting icon for `.exe` files that use
|
||||||
|
default Windows exe icon. (see
|
||||||
|
[JDK-8320692](https://bugs.openjdk.org/browse/JDK-8320692))
|
||||||
|
- OptionPane: Fixed styling custom panel background in `JOptionPane`. (issue
|
||||||
|
#761)
|
||||||
|
- ScrollPane: Styling ScrollPane border properties did not work if view
|
||||||
|
component is a Table.
|
||||||
|
- Table:
|
||||||
|
- Switching theme looses table grid and intercell spacing. (issues #733 and
|
||||||
|
#750)
|
||||||
|
- Fixed background of `boolean` columns when using alternating row colors.
|
||||||
|
(issue #780)
|
||||||
|
- Fixed border arc of components in complex table cell editors. (issue #786)
|
||||||
|
- TableHeader:
|
||||||
|
- No longer temporary replace header cell renderer while painting. This avoids
|
||||||
|
a `StackOverflowError` in case that custom renderer does this too. (see
|
||||||
|
[NetBeans issue #6835](https://github.com/apache/netbeans/issues/6835)) This
|
||||||
|
also improves compatibility with custom table header implementations.
|
||||||
|
- Header cell renderer background/foreground colors were not restored after
|
||||||
|
hover if renderer uses `null` for background/foreground. (PR #790)
|
||||||
|
- TabbedPane:
|
||||||
|
- Avoid unnecessary repainting whole tabbed pane content area when layouting
|
||||||
|
leading/trailing components.
|
||||||
|
- Avoid unnecessary repainting of selected tab on temporary changes.
|
||||||
|
- Fixed "endless" layouting and repainting when using nested tabbed panes (top
|
||||||
|
and bottom tab placement) and RSyntaxTextArea (with enabled line-wrapping)
|
||||||
|
as tab content. (see
|
||||||
|
[jadx issue #2030](https://github.com/skylot/jadx/issues/2030))
|
||||||
|
- Fixed broken rendering after resizing window to minimum size and then
|
||||||
|
increasing size again. (issue #767)
|
||||||
|
|
||||||
|
#### Incompatibilities
|
||||||
|
|
||||||
|
- Removed support for JetBrains custom decorations, which required
|
||||||
|
[JetBrains Runtime](https://github.com/JetBrains/JetBrainsRuntime/wiki) (JBR)
|
||||||
|
8 or 11. It did not work for JBR 17. System property
|
||||||
|
`flatlaf.useJetBrainsCustomDecorations` is now ignored. **Note**: FlatLaf
|
||||||
|
window decorations continue to work with JBR.
|
||||||
|
|
||||||
|
|
||||||
|
## 3.2.5
|
||||||
|
|
||||||
|
#### Fixed bugs
|
||||||
|
|
||||||
|
- Popup: Fixed NPE if popup invoker is `null` on Windows 10. (issue #753;
|
||||||
|
regression in 3.2.1 in fix for #626)
|
||||||
|
|
||||||
|
|
||||||
|
## 3.2.4
|
||||||
|
|
||||||
|
#### Fixed bugs
|
||||||
|
|
||||||
|
- Popup: Fixed NPE if popup invoker is `null` on Linux with Wayland and Java 21.
|
||||||
|
(issue #752; regression in 3.2.3)
|
||||||
|
|
||||||
|
|
||||||
|
## 3.2.3
|
||||||
|
|
||||||
|
#### Fixed bugs
|
||||||
|
|
||||||
|
- Popup: Popups that request focus were not shown on Linux with Wayland and Java 21.
|
||||||
|
(issue #752)
|
||||||
|
|
||||||
|
|
||||||
|
## 3.2.2
|
||||||
|
|
||||||
|
#### Fixed bugs
|
||||||
|
|
||||||
|
- Button: Fixed painting icon and text at wrong location when using HTML text,
|
||||||
|
left/right vertical alignment and running in Java 19+. (issue #746)
|
||||||
|
- CheckBox and RadioButton: Fixed cut off right side when border is removed and
|
||||||
|
horizontal alignment is set to `right`. (issue #734)
|
||||||
|
- TabbedPane: Fixed NPE when using focusable component as tab component and
|
||||||
|
switching theme. (issue #745)
|
||||||
|
|
||||||
|
|
||||||
|
## 3.2.1
|
||||||
|
|
||||||
|
#### Fixed bugs
|
||||||
|
|
||||||
|
- Fixed memory leak in
|
||||||
|
`MultiResolutionImageSupport.create(int,Dimension[],Function<Dimension,Image>)`,
|
||||||
|
which caches images created by the producer function. Used by
|
||||||
|
`FlatSVGIcon.getImage()` and `FlatSVGUtils.createWindowIconImages()`. If you
|
||||||
|
use one of these methods, it is **strongly recommended** to upgrade to this
|
||||||
|
version, because if the returned image is larger and painted very often it may
|
||||||
|
result in an out-of-memory situation. (issue #726)
|
||||||
|
- FileChooser: Fixed occasional NPE in `FlatShortcutsPanel` on Windows. (issue
|
||||||
|
#718)
|
||||||
|
- TextField: Fixed placeholder text painting, which did not respect horizontal
|
||||||
|
alignment property of `JTextField`. (issue #721)
|
||||||
|
- Popup: Fixed drop shadow if popup overlaps a heavyweight component. (Windows
|
||||||
|
10 only; issue #626)
|
||||||
|
|
||||||
|
|
||||||
|
## 3.2
|
||||||
|
|
||||||
|
#### New features and improvements
|
||||||
|
|
||||||
|
- TabbedPane: Support rounded underline selection and rounded card tabs. (PR
|
||||||
|
#703)
|
||||||
|
- FlatLaf window decorations:
|
||||||
|
- Support for Windows on ARM 64-bit. (issue #443, PR #707)
|
||||||
|
- Support toolbox-style "small" window title bar. (issue #659, PR #702)
|
||||||
|
- Extras: Class `FlatSVGIcon` now uses [JSVG](https://github.com/weisJ/jsvg)
|
||||||
|
library (instead of svgSalamander) for rendering. JSVG provides improved SVG
|
||||||
|
rendering and uses less memory compared to svgSalamander. (PR #684)
|
||||||
|
- ComboBox: Improved location of selected item in popup if list is large and
|
||||||
|
scrollable.
|
||||||
|
- FileChooser: Show localized text for all locales supported by Java's Metal
|
||||||
|
look and feel. (issue #680)
|
||||||
|
- Added system property `flatlaf.useNativeLibrary` to allow disabling loading of
|
||||||
|
FlatLaf native library. (issue #674)
|
||||||
|
- IntelliJ Themes:
|
||||||
|
- Reduced memory footprint by releasing Json data and ignoring IntelliJ UI
|
||||||
|
properties that are not used in FlatLaf.
|
||||||
|
- Updated "Hiberbee Dark" and "Gradianto" themes.
|
||||||
|
|
||||||
|
#### Fixed bugs
|
||||||
|
|
||||||
|
- Styling: Fixed scaling of some styling properties (`rowHeight` for Table and
|
||||||
|
Tree; `iconTextGap` for Button, CheckBox and RadioButton). (issue #682)
|
||||||
|
- Fixed `IllegalComponentStateException` when invoker is not showing in
|
||||||
|
`SubMenuUsabilityHelper`. (issue #692)
|
||||||
|
- macOS themes: Changing `@accentColor` variable in FlatLaf properties files did
|
||||||
|
not change all accent related colors for all components.
|
||||||
|
- IntelliJ Themes:
|
||||||
|
- "Light Owl" theme: Fixed wrong (unreadable) text color in selected menu
|
||||||
|
items, selected text in text components, and selection in ComboBox popup
|
||||||
|
list. (issue #687)
|
||||||
|
- "Gradianto Midnight Blue" theme: Fixed color of ScrollBar track, which was
|
||||||
|
not visible. (issue #686)
|
||||||
|
- "Monocai" theme: Fixed unreadable text color of default buttons. (issue
|
||||||
|
#693)
|
||||||
|
- "Vuesion" theme: Fixed foreground colors of disabled text.
|
||||||
|
- "Material UI Lite" themes: Fixed non-editable ComboBox button background.
|
||||||
|
- CheckBox and RadioButton: Fixed unselected icon colors for themes "Atom One
|
||||||
|
Light", "Cyan Light", "GitHub", "Light Owl", "Material Lighter" and
|
||||||
|
"Solarized Light".
|
||||||
|
- TabbedPane: Fixed focused tab background color for themes "Arc *", "Material
|
||||||
|
Design Dark", "Monocai", "One Dark", "Spacegray" and "Xcode-Dark". (issue
|
||||||
|
#697)
|
||||||
|
- TextComponents, ComboBox and Spinner: Fixed background colors of enabled
|
||||||
|
text components, to distinguish from disabled, for themes "Carbon", "Cobalt
|
||||||
|
2", "Gradianto *", "Gruvbox *", "Monocai", "Spacegray", "Vuesion",
|
||||||
|
"Xcode-Dark", "GitHub", and "Light Owl". (issue #528)
|
||||||
|
- Fixed wrong disabled text colors in "Dark Flat", "Hiberbee Dark", "Light
|
||||||
|
Flat", "Nord", "Solarized Dark" and "Solarized Light" themes.
|
||||||
|
- Fixed colors for selection background/foreground, Separator, Slider track
|
||||||
|
and ProgressBar background in various themes.
|
||||||
|
- Native Windows libraries: Fixed crash when running in Java 8 and newer Java
|
||||||
|
version is installed in `PATH` environment variable and using class
|
||||||
|
`SystemInfo` before AWT initialization. (issue #673)
|
||||||
|
- ComboBox: Fixed search in item list for text with spaces. (issue #691)
|
||||||
|
- FormattedTextField: On Linux, fixed `IllegalArgumentException: Invalid
|
||||||
|
location` if `JFormattedTextField.setDocument()` is invoked in a focus gained
|
||||||
|
listener on that formatted text field. (issue #698)
|
||||||
|
- PopupMenu: Make sure that popup menu does not overlap any operating system
|
||||||
|
task bar. (issue #701)
|
||||||
|
- FileChooser: Use system icons on Windows with Java 17.0.3 (and later) 32-bit.
|
||||||
|
Only Java 17 - 17.0.2 32-bit do not use system icons because of a bug in Java
|
||||||
|
32-bit that crashes the application. (PR #709)
|
||||||
|
- FileChooser: Fixed crash on Windows with Java 17 to 17.0.2 32-bit. Java 17
|
||||||
|
64-bit is not affected. (regression since FlatLaf 2.3; PR #522, see also issue
|
||||||
|
#403)
|
||||||
|
|
||||||
|
#### Incompatibilities
|
||||||
|
|
||||||
|
- Extras: Class `FlatSVGIcon` now uses [JSVG](https://github.com/weisJ/jsvg)
|
||||||
|
library for SVG rendering. You need to replace svgSalamander with JSVG in your
|
||||||
|
build scripts and distribute `jsvg.jar` with your application. Also replace
|
||||||
|
`com.kitfox.svg` with `com.github.weisj.jsvg` in `module-info.java` files.
|
||||||
|
- IntelliJ Themes: Removed all "Contrast" themes from "Material UI Lite".
|
||||||
|
|
||||||
|
|
||||||
|
## 3.1.1
|
||||||
|
|
||||||
|
- IntelliJ Themes:
|
||||||
|
- Fixed too large menu item paddings and too large table/tree row heights (all
|
||||||
|
"Material Theme UI Lite" themes; issue #667; regression in FlatLaf 3.1).
|
||||||
|
- Fixed too large tree row height in "Carbon", "Dark Purple", "Gray",
|
||||||
|
"Material Design Dark", "Monokai Pro", "One Dark" and "Spacegray" themes.
|
||||||
|
- Native libraries: Fixed `IllegalArgumentException: URI scheme is not "file"`
|
||||||
|
when using FlatLaf in WebStart. (issue #668; regression in FlatLaf 3.1)
|
||||||
|
|
||||||
|
|
||||||
|
## 3.1
|
||||||
|
|
||||||
|
#### New features and improvements
|
||||||
|
|
||||||
|
- Windows 11: Popups (`JPopupMenu`, `JComboBox`, `JToolTip`, etc.) now use
|
||||||
|
native Windows 11 rounded borders and drop shadows. (PR #643)
|
||||||
|
- Fonts:
|
||||||
|
- Added **Roboto Mono** (https://fonts.google.com/specimen/Roboto+Mono). (PR
|
||||||
|
#639, issue #638)
|
||||||
|
- Updated **JetBrains Mono** to
|
||||||
|
[v2.304](https://github.com/JetBrains/JetBrainsMono/releases/tag/v2.304).
|
||||||
|
- Theme Editor: Support macOS light and dark themes.
|
||||||
|
- TabbedPane: Support hover and focused tab foreground colors. (issue #627)
|
||||||
|
- TabbedPane: `tabbedPane.getBackgroundAt(tabIndex)` now has higher priority
|
||||||
|
than `TabbedPane.focusColor` and `TabbedPane.selectedBackground`. If
|
||||||
|
`tabbedPane.setBackgroundAt(tabIndex)` is used to set a color for a single
|
||||||
|
tab, then this color is now used even if the tab is focused or selected.
|
||||||
|
- TableHeader: Support column hover and pressed background and foreground
|
||||||
|
colors. (issue #636)
|
||||||
|
- Native libraries: Made it easier to distribute FlatLaf native libraries
|
||||||
|
(Windows `.dll` and Linux `.so`) to avoid problems on operating systems with
|
||||||
|
enabled execution restrictions.
|
||||||
|
See https://www.formdev.com/flatlaf/native-libraries/ for more details. (issue #624)
|
||||||
|
- Published native libraries to Maven Central for easy using them as
|
||||||
|
dependencies in Gradle and Maven.
|
||||||
|
- If available, native libraries are now loaded from same location as
|
||||||
|
`flatlaf.jar`, otherwise they are extract from `flatlaf.jar` to temporary
|
||||||
|
folder and loaded from there.
|
||||||
|
- Windows DLLs are now digitally signed with FormDev Software GmbH
|
||||||
|
certificate.
|
||||||
|
|
||||||
|
#### Fixed bugs
|
||||||
|
|
||||||
|
- FlatLaf window decorations:
|
||||||
|
- Fixed inconsistent size of glass pane depending on whether FlatLaf window
|
||||||
|
decorations are used (e.g. Windows 10/11) or not (e.g. macOS). Now the glass
|
||||||
|
pane no longer overlaps the FlatLaf window title bar. (issue #630)
|
||||||
|
- Linux: Fixed broken window resizing on multi-screen setups. (issue #632)
|
||||||
|
- Linux: Fixed behavior of maximize/restore button when tiling window to left
|
||||||
|
or right half of screen. (issue #647)
|
||||||
|
- IntelliJ Themes:
|
||||||
|
- Fixed default button hover background in "Solarized Light" theme. (issue
|
||||||
|
#628)
|
||||||
|
- Avoid that accent color affect some colors in some IntelliJ themes. (issue
|
||||||
|
#625)
|
||||||
|
- Updated "Hiberbee Dark" and "Material Theme UI Lite" themes.
|
||||||
|
- Styling: Fixed resolving of UI variables in styles that use other variables.
|
||||||
|
- MenuItem: Fixed horizontal alignment of icons. (issue #631)
|
||||||
|
- Table: Fixed potential performance issue with paint cell focus indicator
|
||||||
|
border. (issue #654)
|
||||||
|
- Tree: Fixed missing custom closed/opened/leaf icons of a custom
|
||||||
|
`DefaultTreeCellRenderer`. (issue #653; regression since implementing PR #609
|
||||||
|
in FlatLaf 3.0)
|
||||||
|
- Tree: Fixed truncated node text and too small painted non-wide node background
|
||||||
|
if custom cell renderer sets icon, but not disabled icon, and tree is
|
||||||
|
disabled. (issue #640)
|
||||||
|
- Fixed `HiDPIUtils.paintAtScale1x()`, which painted at wrong location if
|
||||||
|
graphics is rotated, is scaled and `x` or `y` parameters are not zero. (issue
|
||||||
|
#646)
|
||||||
|
|
||||||
|
|
||||||
## 3.0
|
## 3.0
|
||||||
|
|
||||||
#### New features and improvements
|
#### New features and improvements
|
||||||
|
|||||||
286
README.md
286
README.md
@@ -6,7 +6,7 @@ Swing desktop applications.
|
|||||||
|
|
||||||
It looks almost flat (no shadows or gradients), clean, simple and elegant.
|
It looks almost flat (no shadows or gradients), clean, simple and elegant.
|
||||||
FlatLaf comes with **Light**, **Dark**, **IntelliJ** and **Darcula** themes,
|
FlatLaf comes with **Light**, **Dark**, **IntelliJ** and **Darcula** themes,
|
||||||
scales on **HiDPI** displays and runs on Java 8 or newer.
|
scales on **HiDPI** displays and runs on Java 8 or newer (LTS and latest).
|
||||||
|
|
||||||
The look is heavily inspired by **Darcula** and **IntelliJ** themes from
|
The look is heavily inspired by **Darcula** and **IntelliJ** themes from
|
||||||
IntelliJ IDEA 2019.2+ and uses almost the same colors and icons.
|
IntelliJ IDEA 2019.2+ and uses almost the same colors and icons.
|
||||||
@@ -15,6 +15,11 @@ IntelliJ IDEA 2019.2+ and uses almost the same colors and icons.
|
|||||||
|
|
||||||

|

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

|
||||||
|
|
||||||
|
|
||||||
IntelliJ Platform Themes
|
IntelliJ Platform Themes
|
||||||
------------------------
|
------------------------
|
||||||
@@ -57,10 +62,15 @@ build script:
|
|||||||
artifactId: flatlaf
|
artifactId: flatlaf
|
||||||
version: (see button below)
|
version: (see button below)
|
||||||
|
|
||||||
Otherwise download `flatlaf-<version>.jar` here:
|
Otherwise, download `flatlaf-<version>.jar` here:
|
||||||
|
|
||||||
[](https://maven-badges.herokuapp.com/maven-central/com.formdev/flatlaf)
|
[](https://maven-badges.herokuapp.com/maven-central/com.formdev/flatlaf)
|
||||||
|
|
||||||
|
See also
|
||||||
|
[Native Libraries distribution](https://www.formdev.com/flatlaf/native-libraries/)
|
||||||
|
for instructions on how to redistribute FlatLaf native libraries with your
|
||||||
|
application.
|
||||||
|
|
||||||
|
|
||||||
### Snapshots
|
### Snapshots
|
||||||
|
|
||||||
@@ -131,7 +141,7 @@ details and downloads.
|
|||||||
Buzz
|
Buzz
|
||||||
----
|
----
|
||||||
|
|
||||||
- [What others say about FlatLaf on Twitter](https://twitter.com/search?f=live&q=flatlaf)
|
- [FlatLaf 3.1 (and 3.0) announcement on Reddit](https://www.reddit.com/r/java/comments/12xgrsu/flatlaf_31_and_30_swing_look_and_feel/)
|
||||||
- [FlatLaf 1.0 announcement on Reddit](https://www.reddit.com/r/java/comments/lsbcwe/flatlaf_10_swing_look_and_feel/)
|
- [FlatLaf 1.0 announcement on Reddit](https://www.reddit.com/r/java/comments/lsbcwe/flatlaf_10_swing_look_and_feel/)
|
||||||
- [FlatLaf announcement on Reddit](https://www.reddit.com/r/java/comments/dl0hu3/flatlaf_flat_look_and_feel/)
|
- [FlatLaf announcement on Reddit](https://www.reddit.com/r/java/comments/dl0hu3/flatlaf_flat_look_and_feel/)
|
||||||
|
|
||||||
@@ -139,121 +149,193 @@ Buzz
|
|||||||
Applications using FlatLaf
|
Applications using FlatLaf
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
- 
|
### Featured
|
||||||
|
|
||||||
|
-  [JFormDesigner](https://www.formdev.com/)
|
||||||
|
(**commercial**) - Java/Swing GUI Designer (from the FlatLaf creators)
|
||||||
|
- 
|
||||||
[JProfiler](https://www.ej-technologies.com/products/jprofiler/overview.html)
|
[JProfiler](https://www.ej-technologies.com/products/jprofiler/overview.html)
|
||||||
12 (**commercial**) - the award-winning all-in-one Java profiler
|
(**commercial**) - the award-winning all-in-one Java profiler
|
||||||
-  [JFormDesigner](https://www.formdev.com/) 8
|
- 
|
||||||
(**commercial**) - Java/Swing GUI Designer
|
|
||||||
-  [Jeyla Studio](https://www.jeylastudio.com/) - Salon
|
|
||||||
Software
|
|
||||||
-  [Fanurio](https://www.fanuriotimetracking.com/) 3.3.2
|
|
||||||
(**commercial**) - time tracking and billing for freelancers and teams
|
|
||||||
-  [Antares](https://www.antarescircuit.io/) - a free,
|
|
||||||
powerful platform for designing, simulating and explaining digital circuits
|
|
||||||
- 
|
|
||||||
[Logisim-evolution](https://github.com/logisim-evolution/logisim-evolution)
|
|
||||||
3.6 - Digital logic design tool and simulator
|
|
||||||
-  [Cinecred](https://loadingbyte.com/cinecred/) - create
|
|
||||||
beautiful film credit sequences
|
|
||||||
-  [tinyMediaManager](https://www.tinymediamanager.org/)
|
|
||||||
v4 (**commercial**) - a media management tool
|
|
||||||
-  [Weasis](https://nroduit.github.io/) - medical DICOM
|
|
||||||
viewer used in healthcare by hospitals, health networks, etc
|
|
||||||
- 
|
|
||||||
[Makelangelo Software](https://github.com/MarginallyClever/Makelangelo-software)
|
|
||||||
7.3.0 - for plotters, especially the wall-hanging polargraph
|
|
||||||
-  [Ultorg](https://www.ultorg.com/) (**commercial**) - a
|
|
||||||
visual query system for relational databases
|
|
||||||
- [MooInfo](https://github.com/rememberber/MooInfo) - visual implementation of
|
|
||||||
OSHI, to view information about the system and hardware
|
|
||||||
- [Jailer](https://github.com/Wisser/Jailer) 11.2 - database subsetting and
|
|
||||||
relational data browsing tool
|
|
||||||
-  [Apache NetBeans](https://netbeans.apache.org/) 11.3 -
|
|
||||||
IDE for Java, PHP, HTML and much more
|
|
||||||
- [jclasslib bytecode viewer](https://github.com/ingokegel/jclasslib) 5.5
|
|
||||||
- [KeyStore Explorer](https://keystore-explorer.org/) 5.4.3
|
|
||||||
- 
|
|
||||||
[install4j](https://www.ej-technologies.com/products/install4j/overview.html)
|
[install4j](https://www.ej-technologies.com/products/install4j/overview.html)
|
||||||
9.0 (**commercial**) - the powerful multi-platform Java installer builder
|
(**commercial**) - the powerful multi-platform Java installer builder
|
||||||
-  [DbVisualizer](https://www.dbvis.com/) 12.0
|
-  [DbVisualizer](https://www.dbvis.com/)
|
||||||
(**commercial**) - the universal database tool for developers, analysts and
|
(**commercial**) - the universal database tool for developers, analysts and
|
||||||
DBAs
|
DBAs
|
||||||
-  [MagicPlot](https://magicplot.com/) 3.0
|
-  [Apache NetBeans](https://netbeans.apache.org/) - IDE
|
||||||
(**commercial**) - Software for nonlinear fitting, plotting and data analysis
|
for Java, PHP, HTML and much more
|
||||||
- 
|
- 
|
||||||
[Thermo-Calc](https://thermocalc.com/products/thermo-calc/) 2021a
|
[Thermo-Calc](https://thermocalc.com/products/thermo-calc/) (**commercial**) -
|
||||||
(**commercial**) - Thermodynamics and Properties Software
|
Thermodynamics and Properties Software
|
||||||
-  [OWASP ZAP](https://www.zaproxy.org/) 2.10 - the worlds
|
|
||||||
most widely used web app scanner
|
### Data
|
||||||
|
|
||||||
|
-  [Ultorg](https://www.ultorg.com/) (**commercial**) - a
|
||||||
|
visual query system for relational databases
|
||||||
|
- [Jailer](https://github.com/Wisser/Jailer) - database subsetting and
|
||||||
|
relational data browsing tool
|
||||||
|
-  [MagicPlot](https://magicplot.com/) (**commercial**) -
|
||||||
|
Software for nonlinear fitting, plotting and data analysis
|
||||||
|
-  [Constellation](https://www.constellation-app.com/) -
|
||||||
|
Data Visualization and Analytics (based on NetBeans platform)
|
||||||
|
- 
|
||||||
|
[Kafka Visualizer](https://github.com/kumait/kafkavisualizer) - Kafka GUI
|
||||||
|
client
|
||||||
|
|
||||||
|
### Security
|
||||||
|
|
||||||
|
-  [ZAP](https://www.zaproxy.org/) - the world's most
|
||||||
|
widely used web app scanner
|
||||||
- 
|
- 
|
||||||
[Burp Suite Professional and Community Edition](https://portswigger.net/burp/pro)
|
[Burp Suite Professional and Community Edition](https://portswigger.net/burp/pro)
|
||||||
2020.11.2 (**commercial**) - the leading software for web security testing
|
(**commercial**) - the leading software for web security testing
|
||||||
|
- 
|
||||||
|
[Ghidra](https://github.com/NationalSecurityAgency/ghidra) - a software
|
||||||
|
reverse engineering (SRE) framework
|
||||||
|
-  [jadx](https://github.com/skylot/jadx) - Dex to Java
|
||||||
|
decompiler
|
||||||
- [BurpCustomizer](https://github.com/CoreyD97/BurpCustomizer) - adds more
|
- [BurpCustomizer](https://github.com/CoreyD97/BurpCustomizer) - adds more
|
||||||
FlatLaf themes to Burp Suite
|
FlatLaf themes to Burp Suite
|
||||||
|
- [Total Validator](https://www.totalvalidator.com/) (**commercial**) - checks
|
||||||
|
your website
|
||||||
|
- [JPass](https://github.com/gaborbata/jpass) - password manager with strong
|
||||||
|
encryption
|
||||||
|
|
||||||
|
### Software Development
|
||||||
|
|
||||||
|
- [jclasslib bytecode viewer](https://github.com/ingokegel/jclasslib)
|
||||||
|
- [KeyStore Explorer](https://keystore-explorer.org/)
|
||||||
|
- 
|
||||||
|
[muCommander](https://github.com/mucommander/mucommander) - lightweight
|
||||||
|
cross-platform file manager
|
||||||
|
-  [Guiffy](https://www.guiffy.com/) (**commercial**) -
|
||||||
|
advanced cross-platform Diff/Merge
|
||||||
|
-  [HashGarten](https://github.com/jonelo/HashGarten) -
|
||||||
|
cross-platform Swing GUI for Jacksum
|
||||||
|
- [Pseudo Assembler IDE](https://github.com/tomasz-herman/PseudoAssemblerIDE) -
|
||||||
|
IDE for Pseudo-Assembler
|
||||||
|
- [Linotte](https://github.com/cpc6128/LangageLinotte) - French programming
|
||||||
|
language created to learn programming
|
||||||
|
- [lsfusion platform](https://github.com/lsfusion/platform) - information
|
||||||
|
systems development platform
|
||||||
|
|
||||||
|
### Electrical
|
||||||
|
|
||||||
|
- [Antares](https://www.antarescircuit.io/) - a free, powerful platform for
|
||||||
|
designing, simulating and explaining digital circuits
|
||||||
|
- [Logisim-evolution](https://github.com/logisim-evolution/logisim-evolution) -
|
||||||
|
Digital logic design tool and simulator
|
||||||
|
- [Makelangelo Software](https://github.com/MarginallyClever/Makelangelo-software) -
|
||||||
|
for plotters, especially the wall-hanging polargraph
|
||||||
|
- [GUIslice Builder](https://github.com/ImpulseAdventure/GUIslice-Builder) - GUI
|
||||||
|
builder for [GUIslice](https://github.com/ImpulseAdventure/GUIslice), a
|
||||||
|
lightweight GUI framework for embedded displays
|
||||||
|
- [ThunderFocus](https://github.com/marcocipriani01/ThunderFocus) -
|
||||||
|
Arduino-based telescope focuser
|
||||||
|
- [RemoteLight](https://github.com/Drumber/RemoteLight) - multifunctional LED
|
||||||
|
control software
|
||||||
|
|
||||||
|
### Media
|
||||||
|
|
||||||
|
-  [jAlbum](https://jalbum.net/) (**commercial**) -
|
||||||
|
creates photo album websites
|
||||||
|
-  [MediathekView](https://mediathekview.de/) - search in
|
||||||
|
media libraries of various German broadcasters
|
||||||
|
- [Cinecred](https://loadingbyte.com/cinecred/) - create beautiful film credit
|
||||||
|
sequences
|
||||||
|
- [tinyMediaManager](https://www.tinymediamanager.org/) (**commercial**) - a
|
||||||
|
media management tool
|
||||||
|
- [Weasis](https://nroduit.github.io/) - medical DICOM viewer used in healthcare
|
||||||
|
by hospitals, health networks, etc
|
||||||
|
- [Shutter Encoder](https://www.shutterencoder.com/)
|
||||||
|
([source code](https://github.com/paulpacifico/shutter-encoder)) -
|
||||||
|
professional video converter and compression tool
|
||||||
|
- [Sound Analysis](https://github.com/tomasz-herman/SoundAnalysis) - analyze
|
||||||
|
sound files in time or frequency domain
|
||||||
|
- [Novel-Grabber](https://github.com/Flameish/Novel-Grabber) - download novels
|
||||||
|
from any webnovel and lightnovel site
|
||||||
|
- [lectureStudio](https://www.lecturestudio.org/) - digitize your lectures with
|
||||||
|
ease
|
||||||
|
|
||||||
|
### Modelling
|
||||||
|
|
||||||
|
-  [Astah](https://astah.net/) (**commercial**) - create
|
||||||
|
UML, ER Diagram, Flowchart, Data Flow Diagram, Requirement Diagram, SysML
|
||||||
|
diagrams and more
|
||||||
|
- [IGMAS+](https://www.gfz-potsdam.de/igmas) - Interactive Gravity and Magnetic
|
||||||
|
Application System
|
||||||
|
|
||||||
|
### Documents
|
||||||
|
|
||||||
|
-  [Big Faceless (BFO) PDF Viewer](https://bfo.com/)
|
||||||
|
(**commercial**) - Swing PDF Viewer
|
||||||
|
- [PDF Studio](https://www.qoppa.com/pdfstudio/) (**commercial**) - create,
|
||||||
|
review and edit PDF documents
|
||||||
|
- [XMLmind XML Editor](https://www.xmlmind.com/xmleditor/) (**commercial**)
|
||||||
|
|
||||||
|
### Geo
|
||||||
|
|
||||||
-  [JOSM](https://josm.openstreetmap.de/) - an extensible
|
-  [JOSM](https://josm.openstreetmap.de/) - an extensible
|
||||||
editor for [OpenStreetMap](https://www.openstreetmap.org/) (requires FlatLaf
|
editor for [OpenStreetMap](https://www.openstreetmap.org/) (requires FlatLaf
|
||||||
JOSM plugin)
|
JOSM plugin)
|
||||||
-  [jAlbum](https://jalbum.net/) 21 (**commercial**) -
|
- [Mapton](https://mapton.org/)
|
||||||
creates photo album websites
|
([source code](https://github.com/trixon/mapton)) - some kind of map
|
||||||
- [PDF Studio](https://www.qoppa.com/pdfstudio/) 2021 (**commercial**) - create,
|
application (based on NetBeans platform)
|
||||||
review and edit PDF documents
|
- [MeteoInfo](https://github.com/meteoinfo/MeteoInfo) - GIS and scientific
|
||||||
- [XMLmind XML Editor](https://www.xmlmind.com/xmleditor/) 9.3 (**commercial**)
|
computation environment for meteorological community
|
||||||
- [Total Validator](https://www.totalvalidator.com/) 15 (**commercial**) -
|
|
||||||
checks your website
|
### Business / Legal
|
||||||
- [j-lawyer](https://github.com/jlawyerorg/j-lawyer-org) - Kanzleisoftware
|
|
||||||
- [MegaMek](https://github.com/MegaMek/megamek),
|
- 
|
||||||
[MegaMekLab](https://github.com/MegaMek/megameklab) and
|
[j-lawyer](https://github.com/jlawyerorg/j-lawyer-org) - Kanzleisoftware
|
||||||
[MekHQ](https://github.com/MegaMek/mekhq) v0.47.5+ - a sci-fi tabletop
|
-  [Jeyla Studio](https://www.jeylastudio.com/) -
|
||||||
BattleTech simulator suite handling battles, unit building, and campaigns
|
Salon Software
|
||||||
- [GUIslice Builder](https://github.com/ImpulseAdventure/GUIslice-Builder)
|
- [Fanurio](https://www.fanuriotimetracking.com/) (**commercial**) - time
|
||||||
0.13.b024 - GUI builder for
|
tracking and billing for freelancers and teams
|
||||||
[GUIslice](https://github.com/ImpulseAdventure/GUIslice), a lightweight GUI
|
- [Jes](https://www.jes-eur.de) - Die Java-EÜR
|
||||||
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/),
|
- [mendelson AS2](https://sourceforge.net/projects/mec-as2/),
|
||||||
[AS4](https://sourceforge.net/projects/mendelson-as4/) and
|
[AS4](https://sourceforge.net/projects/mendelson-as4/) and
|
||||||
[OFTP2](https://sourceforge.net/projects/mendelson-oftp2/) (open-source) and
|
[OFTP2](https://sourceforge.net/projects/mendelson-oftp2/) (open-source) and
|
||||||
[mendelson AS2](https://mendelson-e-c.com/as2/),
|
[mendelson AS2](https://mendelson-e-c.com/as2/),
|
||||||
[AS4](https://mendelson-e-c.com/as4/) and
|
[AS4](https://mendelson-e-c.com/as4/) and
|
||||||
[OFTP2](https://mendelson-e-c.com/oftp2) (**commercial**)
|
[OFTP2](https://mendelson-e-c.com/oftp2) (**commercial**)
|
||||||
- [IGMAS+](https://www.gfz-potsdam.de/igmas) - Interactive Gravity and Magnetic
|
|
||||||
Application System
|
### Messaging
|
||||||
- [MeteoInfo](https://github.com/meteoinfo/MeteoInfo) 2.2 - GIS and scientific
|
|
||||||
computation environment for meteorological community
|
-  [Spark](https://github.com/igniterealtime/Spark) -
|
||||||
- [lsfusion platform](https://github.com/lsfusion/platform) 4 - information
|
cross-platform IM client optimized for businesses and organizations
|
||||||
systems development platform
|
-  [Chatty](https://github.com/chatty/chatty) - Twitch
|
||||||
- [JPass](https://github.com/gaborbata/jpass) - password manager with strong
|
Chat Client
|
||||||
encryption
|
|
||||||
- [Jes - Die Java-EÜR](https://www.jes-eur.de)
|
### Gaming
|
||||||
- [Mapton](https://mapton.org/) 2.0
|
|
||||||
([source code](https://github.com/trixon/mapton)) - some kind of map
|
-  
|
||||||
application (based on NetBeans platform)
|
[BGBlitz](https://www.bgblitz.com/) (**commercial**) - professional Backgammon
|
||||||
- [Pseudo Assembler IDE](https://github.com/tomasz-herman/PseudoAssemblerIDE) -
|
-  [MapTool](https://github.com/RPTools/maptool) - virtual
|
||||||
IDE for Pseudo-Assembler
|
Tabletop for playing role-playing games
|
||||||
- [Linotte](https://github.com/cpc6128/LangageLinotte) 3.1 - French programming
|
- [MegaMek](https://github.com/MegaMek/megamek),
|
||||||
language created to learn programming
|
[MegaMekLab](https://github.com/MegaMek/megameklab) and
|
||||||
- [MEKA](https://github.com/Waikato/meka) 1.9.3 - multi-label classifiers and
|
[MekHQ](https://github.com/MegaMek/mekhq) - a sci-fi tabletop BattleTech
|
||||||
evaluation procedures using the Weka machine learning framework
|
simulator suite handling battles, unit building, and campaigns
|
||||||
- [Shutter Encoder](https://www.shutterencoder.com/) 14.2
|
- [ControllerBuddy](https://github.com/bwRavencl/ControllerBuddy) - advanced
|
||||||
([source code](https://github.com/paulpacifico/shutter-encoder)) -
|
gamepad mapping software
|
||||||
professional video converter and compression tool (screenshots show **old**
|
|
||||||
look)
|
### Utilities
|
||||||
- [Sound Analysis](https://github.com/tomasz-herman/SoundAnalysis) - analyze
|
|
||||||
sound files in time or frequency domain
|
- [MooInfo](https://github.com/rememberber/MooInfo) - visual implementation of
|
||||||
- [RemoteLight](https://github.com/Drumber/RemoteLight) - multifunctional LED
|
OSHI, to view information about the system and hardware
|
||||||
control software
|
- 
|
||||||
- [ThunderFocus](https://github.com/marcocipriani01/ThunderFocus) -
|
[Linux Task Manager (LTM)](https://github.com/ajee10x/LTM-LinuxTaskManager) -
|
||||||
Arduino-based telescope focuser
|
GUI for monitoring and managing various aspects of a Linux system
|
||||||
- [Novel-Grabber](https://github.com/Flameish/Novel-Grabber) - download novels
|
- [Rest Suite](https://github.com/supanadit/restsuite) - Rest API testing
|
||||||
from any webnovel and lightnovel site
|
- [SpringRemote](https://github.com/HaleyWang/SpringRemote) - remote Linux SSH
|
||||||
- [lectureStudio](https://www.lecturestudio.org/) 4.3.1060 - digitize your
|
connections manager
|
||||||
lectures with ease
|
- [jEnTunnel](https://github.com/ggrandes/jentunnel) - manage SSH Tunnels made
|
||||||
|
easy
|
||||||
- [Android Tool](https://github.com/fast-geek/Android-Tool) - makes popular adb
|
- [Android Tool](https://github.com/fast-geek/Android-Tool) - makes popular adb
|
||||||
and fastboot commands easier to use
|
and fastboot commands easier to use
|
||||||
- and more...
|
|
||||||
|
### Miscellaneous
|
||||||
|
|
||||||
|
- [MEKA](https://github.com/Waikato/meka) - multi-label classifiers and
|
||||||
|
evaluation procedures using the Weka machine learning framework
|
||||||
|
|||||||
@@ -14,10 +14,9 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
val releaseVersion = "3.0"
|
import net.ltgt.gradle.errorprone.errorprone
|
||||||
val developmentVersion = "3.1-SNAPSHOT"
|
|
||||||
|
|
||||||
version = if( rootProject.hasProperty( "release" ) ) releaseVersion else developmentVersion
|
version = property( if( hasProperty( "release" ) ) "flatlaf.releaseVersion" else "flatlaf.developmentVersion" ) as String
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
version = rootProject.version
|
version = rootProject.version
|
||||||
@@ -43,6 +42,10 @@ if( !toolchainJavaVersion.isNullOrEmpty() )
|
|||||||
println()
|
println()
|
||||||
|
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
alias( libs.plugins.errorprone ) apply false
|
||||||
|
}
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
tasks {
|
tasks {
|
||||||
withType<JavaCompile>().configureEach {
|
withType<JavaCompile>().configureEach {
|
||||||
@@ -81,4 +84,56 @@ allprojects {
|
|||||||
isFailOnError = false
|
isFailOnError = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//---- Error Prone ----
|
||||||
|
|
||||||
|
tasks.register( "errorprone" ) {
|
||||||
|
group = "verification"
|
||||||
|
tasks.withType<JavaCompile>().forEach {
|
||||||
|
dependsOn( it )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val useErrorProne = gradle.startParameter.taskNames.contains( "errorprone" )
|
||||||
|
if( useErrorProne ) {
|
||||||
|
plugins.withType<JavaPlugin> {
|
||||||
|
apply( plugin = libs.plugins.errorprone.get().pluginId )
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
"errorprone"( libs.errorprone )
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType<JavaCompile>().configureEach {
|
||||||
|
options.compilerArgs.add( "-Werror" )
|
||||||
|
options.errorprone {
|
||||||
|
disable(
|
||||||
|
"ReferenceEquality", // reports usage of '==' for objects
|
||||||
|
"StringSplitter", // reports String.split()
|
||||||
|
"JavaTimeDefaultTimeZone", // reports Year.now()
|
||||||
|
"MissingSummary", // reports `/** @since 2 */`
|
||||||
|
"InvalidBlockTag", // reports @uiDefault in javadoc
|
||||||
|
"AlreadyChecked", // reports false positives
|
||||||
|
"InlineMeSuggester", // suggests using Error Prone annotations for deprecated methods
|
||||||
|
"TypeParameterUnusedInFormals",
|
||||||
|
"UnsynchronizedOverridesSynchronized",
|
||||||
|
"NonApiType", // reports ArrayList/HashSet in parameter or return type
|
||||||
|
)
|
||||||
|
when( project.name ) {
|
||||||
|
"flatlaf-intellij-themes" -> disable(
|
||||||
|
"MutablePublicArray", // reports FlatAllIJThemes.INFOS
|
||||||
|
)
|
||||||
|
"flatlaf-theme-editor" -> disable(
|
||||||
|
"CatchAndPrintStackTrace",
|
||||||
|
)
|
||||||
|
"flatlaf-testing" -> disable(
|
||||||
|
"CatchAndPrintStackTrace",
|
||||||
|
"JdkObsolete", // reports Hashtable used for JSlider.setLabelTable()
|
||||||
|
"JavaUtilDate", // reports usage of class Date
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ public class ReorderJarEntries
|
|||||||
// 1st pass: copy .properties files
|
// 1st pass: copy .properties files
|
||||||
copyFiles( zipOutStream, jarFile, name -> name.endsWith( ".properties" ) );
|
copyFiles( zipOutStream, jarFile, name -> name.endsWith( ".properties" ) );
|
||||||
|
|
||||||
// 2st pass: copy other files
|
// 2nd pass: copy other files
|
||||||
copyFiles( zipOutStream, jarFile, name -> !name.endsWith( ".properties" ) );
|
copyFiles( zipOutStream, jarFile, name -> !name.endsWith( ".properties" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ tasks {
|
|||||||
// depend on :flatlaf-core:compileJava because it generates the JNI headers
|
// depend on :flatlaf-core:compileJava because it generates the JNI headers
|
||||||
dependsOn( ":flatlaf-core:compileJava" )
|
dependsOn( ":flatlaf-core:compileJava" )
|
||||||
|
|
||||||
from( project( ":flatlaf-core" ).buildDir.resolve( "generated/jni-headers" ) )
|
from( project( ":flatlaf-core" ).layout.buildDirectory.dir( "generated/jni-headers" ) )
|
||||||
into( "src/main/headers" )
|
into( "src/main/headers" )
|
||||||
include( extension.headers )
|
include( extension.headers )
|
||||||
filter<org.apache.tools.ant.filters.FixCrLfFilter>(
|
filter<org.apache.tools.ant.filters.FixCrLfFilter>(
|
||||||
|
|||||||
@@ -15,10 +15,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
open class NativeArtifact( val fileName: String, val classifier: String, val type: String ) {}
|
||||||
|
|
||||||
open class PublishExtension {
|
open class PublishExtension {
|
||||||
var artifactId: String? = null
|
var artifactId: String? = null
|
||||||
var name: String? = null
|
var name: String? = null
|
||||||
var description: String? = null
|
var description: String? = null
|
||||||
|
var nativeArtifacts: List<NativeArtifact>? = null
|
||||||
}
|
}
|
||||||
|
|
||||||
val extension = project.extensions.create<PublishExtension>( "flatlafPublish" )
|
val extension = project.extensions.create<PublishExtension>( "flatlafPublish" )
|
||||||
@@ -71,6 +74,15 @@ publishing {
|
|||||||
url.set( "https://github.com/JFormDesigner/FlatLaf/issues" )
|
url.set( "https://github.com/JFormDesigner/FlatLaf/issues" )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
afterEvaluate {
|
||||||
|
extension.nativeArtifacts?.forEach {
|
||||||
|
artifact( artifacts.add( "archives", file( it.fileName ) ) {
|
||||||
|
classifier = it.classifier
|
||||||
|
type = it.type
|
||||||
|
} )
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,3 +122,11 @@ signing {
|
|||||||
tasks.withType<Sign>().configureEach {
|
tasks.withType<Sign>().configureEach {
|
||||||
onlyIf { rootProject.hasProperty( "release" ) }
|
onlyIf { rootProject.hasProperty( "release" ) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check whether parallel build is enabled
|
||||||
|
tasks.withType<PublishToMavenRepository>().configureEach {
|
||||||
|
doFirst {
|
||||||
|
if( System.getProperty( "org.gradle.parallel" ) == "true" )
|
||||||
|
throw RuntimeException( "Publishing does not work correctly with enabled parallel build. Disable parallel build with VM option '-Dorg.gradle.parallel=false'." )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
2
flatlaf-core/.settings/org.eclipse.core.resources.prefs
Normal file
2
flatlaf-core/.settings/org.eclipse.core.resources.prefs
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
eclipse.preferences.version=1
|
||||||
|
encoding/<project>=ISO-8859-1
|
||||||
@@ -14,6 +14,8 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import Flatlaf_publish_gradle.NativeArtifact
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
`java-library`
|
`java-library`
|
||||||
`flatlaf-toolchain`
|
`flatlaf-toolchain`
|
||||||
@@ -25,12 +27,11 @@ plugins {
|
|||||||
val sigtest = configurations.create( "sigtest" )
|
val sigtest = configurations.create( "sigtest" )
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
testImplementation( "org.junit.jupiter:junit-jupiter-api:5.7.2" )
|
testImplementation( libs.bundles.junit )
|
||||||
testImplementation( "org.junit.jupiter:junit-jupiter-params" )
|
testRuntimeOnly( libs.junit.engine )
|
||||||
testRuntimeOnly( "org.junit.jupiter:junit-jupiter-engine" )
|
|
||||||
|
|
||||||
// https://github.com/jtulach/netbeans-apitest
|
// https://github.com/jtulach/netbeans-apitest
|
||||||
sigtest( "org.netbeans.tools:sigtest-maven-plugin:1.7" )
|
sigtest( libs.sigtest )
|
||||||
}
|
}
|
||||||
|
|
||||||
java {
|
java {
|
||||||
@@ -41,7 +42,7 @@ java {
|
|||||||
tasks {
|
tasks {
|
||||||
compileJava {
|
compileJava {
|
||||||
// generate JNI headers
|
// generate JNI headers
|
||||||
options.headerOutputDirectory.set( buildDir.resolve( "generated/jni-headers" ) )
|
options.headerOutputDirectory.set( layout.buildDirectory.dir( "generated/jni-headers" ) )
|
||||||
}
|
}
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
@@ -123,4 +124,14 @@ flatlafPublish {
|
|||||||
artifactId = "flatlaf"
|
artifactId = "flatlaf"
|
||||||
name = "FlatLaf"
|
name = "FlatLaf"
|
||||||
description = "Flat Look and Feel"
|
description = "Flat Look and Feel"
|
||||||
|
|
||||||
|
val natives = "src/main/resources/com/formdev/flatlaf/natives"
|
||||||
|
nativeArtifacts = listOf(
|
||||||
|
NativeArtifact( "${natives}/flatlaf-windows-x86.dll", "windows-x86", "dll" ),
|
||||||
|
NativeArtifact( "${natives}/flatlaf-windows-x86_64.dll", "windows-x86_64", "dll" ),
|
||||||
|
NativeArtifact( "${natives}/flatlaf-windows-arm64.dll", "windows-arm64", "dll" ),
|
||||||
|
NativeArtifact( "${natives}/libflatlaf-macos-arm64.dylib", "macos-arm64", "dylib" ),
|
||||||
|
NativeArtifact( "${natives}/libflatlaf-macos-x86_64.dylib", "macos-x86_64", "dylib" ),
|
||||||
|
NativeArtifact( "${natives}/libflatlaf-linux-x86_64.so", "linux-x86_64", "so" ),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#Signature file v4.1
|
#Signature file v4.1
|
||||||
#Version 2.6
|
#Version 3.3
|
||||||
|
|
||||||
CLSS public abstract interface com.formdev.flatlaf.FlatClientProperties
|
CLSS public abstract interface com.formdev.flatlaf.FlatClientProperties
|
||||||
fld public final static java.lang.String BUTTON_TYPE = "JButton.buttonType"
|
fld public final static java.lang.String BUTTON_TYPE = "JButton.buttonType"
|
||||||
@@ -12,6 +12,7 @@ fld public final static java.lang.String BUTTON_TYPE_TOOLBAR_BUTTON = "toolBarBu
|
|||||||
fld public final static java.lang.String COMPONENT_FOCUS_OWNER = "JComponent.focusOwner"
|
fld public final static java.lang.String COMPONENT_FOCUS_OWNER = "JComponent.focusOwner"
|
||||||
fld public final static java.lang.String COMPONENT_ROUND_RECT = "JComponent.roundRect"
|
fld public final static java.lang.String COMPONENT_ROUND_RECT = "JComponent.roundRect"
|
||||||
fld public final static java.lang.String COMPONENT_TITLE_BAR_CAPTION = "JComponent.titleBarCaption"
|
fld public final static java.lang.String COMPONENT_TITLE_BAR_CAPTION = "JComponent.titleBarCaption"
|
||||||
|
fld public final static java.lang.String GLASS_PANE_FULL_HEIGHT = "JRootPane.glassPaneFullHeight"
|
||||||
fld public final static java.lang.String MENU_BAR_EMBEDDED = "JRootPane.menuBarEmbedded"
|
fld public final static java.lang.String MENU_BAR_EMBEDDED = "JRootPane.menuBarEmbedded"
|
||||||
fld public final static java.lang.String MINIMUM_HEIGHT = "JComponent.minimumHeight"
|
fld public final static java.lang.String MINIMUM_HEIGHT = "JComponent.minimumHeight"
|
||||||
fld public final static java.lang.String MINIMUM_WIDTH = "JComponent.minimumWidth"
|
fld public final static java.lang.String MINIMUM_WIDTH = "JComponent.minimumWidth"
|
||||||
@@ -19,8 +20,10 @@ fld public final static java.lang.String OUTLINE = "JComponent.outline"
|
|||||||
fld public final static java.lang.String OUTLINE_ERROR = "error"
|
fld public final static java.lang.String OUTLINE_ERROR = "error"
|
||||||
fld public final static java.lang.String OUTLINE_WARNING = "warning"
|
fld public final static java.lang.String OUTLINE_WARNING = "warning"
|
||||||
fld public final static java.lang.String PLACEHOLDER_TEXT = "JTextField.placeholderText"
|
fld public final static java.lang.String PLACEHOLDER_TEXT = "JTextField.placeholderText"
|
||||||
|
fld public final static java.lang.String POPUP_BORDER_CORNER_RADIUS = "Popup.borderCornerRadius"
|
||||||
fld public final static java.lang.String POPUP_DROP_SHADOW_PAINTED = "Popup.dropShadowPainted"
|
fld public final static java.lang.String POPUP_DROP_SHADOW_PAINTED = "Popup.dropShadowPainted"
|
||||||
fld public final static java.lang.String POPUP_FORCE_HEAVY_WEIGHT = "Popup.forceHeavyWeight"
|
fld public final static java.lang.String POPUP_FORCE_HEAVY_WEIGHT = "Popup.forceHeavyWeight"
|
||||||
|
fld public final static java.lang.String POPUP_ROUNDED_BORDER_WIDTH = "Popup.roundedBorderWidth"
|
||||||
fld public final static java.lang.String PROGRESS_BAR_LARGE_HEIGHT = "JProgressBar.largeHeight"
|
fld public final static java.lang.String PROGRESS_BAR_LARGE_HEIGHT = "JProgressBar.largeHeight"
|
||||||
fld public final static java.lang.String PROGRESS_BAR_SQUARE = "JProgressBar.square"
|
fld public final static java.lang.String PROGRESS_BAR_SQUARE = "JProgressBar.square"
|
||||||
fld public final static java.lang.String SCROLL_BAR_SHOW_BUTTONS = "JScrollBar.showButtons"
|
fld public final static java.lang.String SCROLL_BAR_SHOW_BUTTONS = "JScrollBar.showButtons"
|
||||||
@@ -65,6 +68,11 @@ fld public final static java.lang.String TABBED_PANE_TAB_CLOSE_TOOLTIPTEXT = "JT
|
|||||||
fld public final static java.lang.String TABBED_PANE_TAB_HEIGHT = "JTabbedPane.tabHeight"
|
fld public final static java.lang.String TABBED_PANE_TAB_HEIGHT = "JTabbedPane.tabHeight"
|
||||||
fld public final static java.lang.String TABBED_PANE_TAB_ICON_PLACEMENT = "JTabbedPane.tabIconPlacement"
|
fld public final static java.lang.String TABBED_PANE_TAB_ICON_PLACEMENT = "JTabbedPane.tabIconPlacement"
|
||||||
fld public final static java.lang.String TABBED_PANE_TAB_INSETS = "JTabbedPane.tabInsets"
|
fld public final static java.lang.String TABBED_PANE_TAB_INSETS = "JTabbedPane.tabInsets"
|
||||||
|
fld public final static java.lang.String TABBED_PANE_TAB_ROTATION = "JTabbedPane.tabRotation"
|
||||||
|
fld public final static java.lang.String TABBED_PANE_TAB_ROTATION_AUTO = "auto"
|
||||||
|
fld public final static java.lang.String TABBED_PANE_TAB_ROTATION_LEFT = "left"
|
||||||
|
fld public final static java.lang.String TABBED_PANE_TAB_ROTATION_NONE = "none"
|
||||||
|
fld public final static java.lang.String TABBED_PANE_TAB_ROTATION_RIGHT = "right"
|
||||||
fld public final static java.lang.String TABBED_PANE_TAB_TYPE = "JTabbedPane.tabType"
|
fld public final static java.lang.String TABBED_PANE_TAB_TYPE = "JTabbedPane.tabType"
|
||||||
fld public final static java.lang.String TABBED_PANE_TAB_TYPE_CARD = "card"
|
fld public final static java.lang.String TABBED_PANE_TAB_TYPE_CARD = "card"
|
||||||
fld public final static java.lang.String TABBED_PANE_TAB_TYPE_UNDERLINED = "underlined"
|
fld public final static java.lang.String TABBED_PANE_TAB_TYPE_UNDERLINED = "underlined"
|
||||||
@@ -86,10 +94,16 @@ fld public final static java.lang.String TEXT_FIELD_TRAILING_COMPONENT = "JTextF
|
|||||||
fld public final static java.lang.String TEXT_FIELD_TRAILING_ICON = "JTextField.trailingIcon"
|
fld public final static java.lang.String TEXT_FIELD_TRAILING_ICON = "JTextField.trailingIcon"
|
||||||
fld public final static java.lang.String TITLE_BAR_BACKGROUND = "JRootPane.titleBarBackground"
|
fld public final static java.lang.String TITLE_BAR_BACKGROUND = "JRootPane.titleBarBackground"
|
||||||
fld public final static java.lang.String TITLE_BAR_FOREGROUND = "JRootPane.titleBarForeground"
|
fld public final static java.lang.String TITLE_BAR_FOREGROUND = "JRootPane.titleBarForeground"
|
||||||
|
fld public final static java.lang.String TITLE_BAR_SHOW_CLOSE = "JRootPane.titleBarShowClose"
|
||||||
fld public final static java.lang.String TITLE_BAR_SHOW_ICON = "JRootPane.titleBarShowIcon"
|
fld public final static java.lang.String TITLE_BAR_SHOW_ICON = "JRootPane.titleBarShowIcon"
|
||||||
|
fld public final static java.lang.String TITLE_BAR_SHOW_ICONIFFY = "JRootPane.titleBarShowIconify"
|
||||||
|
fld public final static java.lang.String TITLE_BAR_SHOW_MAXIMIZE = "JRootPane.titleBarShowMaximize"
|
||||||
|
fld public final static java.lang.String TITLE_BAR_SHOW_TITLE = "JRootPane.titleBarShowTitle"
|
||||||
fld public final static java.lang.String TREE_PAINT_SELECTION = "JTree.paintSelection"
|
fld public final static java.lang.String TREE_PAINT_SELECTION = "JTree.paintSelection"
|
||||||
fld public final static java.lang.String TREE_WIDE_SELECTION = "JTree.wideSelection"
|
fld public final static java.lang.String TREE_WIDE_SELECTION = "JTree.wideSelection"
|
||||||
fld public final static java.lang.String USE_WINDOW_DECORATIONS = "JRootPane.useWindowDecorations"
|
fld public final static java.lang.String USE_WINDOW_DECORATIONS = "JRootPane.useWindowDecorations"
|
||||||
|
fld public final static java.lang.String WINDOW_STYLE = "Window.style"
|
||||||
|
fld public final static java.lang.String WINDOW_STYLE_SMALL = "small"
|
||||||
meth public static <%0 extends java.lang.Object> {%%0} clientProperty(javax.swing.JComponent,java.lang.String,{%%0},java.lang.Class<{%%0}>)
|
meth public static <%0 extends java.lang.Object> {%%0} clientProperty(javax.swing.JComponent,java.lang.String,{%%0},java.lang.Class<{%%0}>)
|
||||||
meth public static boolean clientPropertyBoolean(javax.swing.JComponent,java.lang.String,boolean)
|
meth public static boolean clientPropertyBoolean(javax.swing.JComponent,java.lang.String,boolean)
|
||||||
meth public static boolean clientPropertyEquals(javax.swing.JComponent,java.lang.String,java.lang.Object)
|
meth public static boolean clientPropertyEquals(javax.swing.JComponent,java.lang.String,java.lang.Object)
|
||||||
@@ -195,8 +209,13 @@ meth public static boolean isUseNativeWindowDecorations()
|
|||||||
meth public static boolean setup(javax.swing.LookAndFeel)
|
meth public static boolean setup(javax.swing.LookAndFeel)
|
||||||
meth public static boolean supportsNativeWindowDecorations()
|
meth public static boolean supportsNativeWindowDecorations()
|
||||||
meth public static java.lang.Object parseDefaultsValue(java.lang.String,java.lang.String,java.lang.Class<?>)
|
meth public static java.lang.Object parseDefaultsValue(java.lang.String,java.lang.String,java.lang.Class<?>)
|
||||||
|
meth public static java.lang.String getPreferredFontFamily()
|
||||||
|
meth public static java.lang.String getPreferredLightFontFamily()
|
||||||
|
meth public static java.lang.String getPreferredMonospacedFontFamily()
|
||||||
|
meth public static java.lang.String getPreferredSemiboldFontFamily()
|
||||||
meth public static java.util.Map<java.lang.String,java.lang.Class<?>> getStyleableInfos(javax.swing.JComponent)
|
meth public static java.util.Map<java.lang.String,java.lang.Class<?>> getStyleableInfos(javax.swing.JComponent)
|
||||||
meth public static java.util.Map<java.lang.String,java.lang.String> getGlobalExtraDefaults()
|
meth public static java.util.Map<java.lang.String,java.lang.String> getGlobalExtraDefaults()
|
||||||
|
meth public static java.util.function.Function<java.lang.String,java.awt.Color> getSystemColorGetter()
|
||||||
meth public static javax.swing.UIDefaults$ActiveValue createActiveFontValue(float)
|
meth public static javax.swing.UIDefaults$ActiveValue createActiveFontValue(float)
|
||||||
meth public static void hideMnemonics()
|
meth public static void hideMnemonics()
|
||||||
meth public static void initIconColors(javax.swing.UIDefaults,boolean)
|
meth public static void initIconColors(javax.swing.UIDefaults,boolean)
|
||||||
@@ -209,6 +228,11 @@ meth public static void repaintAllFramesAndDialogs()
|
|||||||
meth public static void revalidateAndRepaintAllFramesAndDialogs()
|
meth public static void revalidateAndRepaintAllFramesAndDialogs()
|
||||||
meth public static void runWithUIDefaultsGetter(java.util.function.Function<java.lang.Object,java.lang.Object>,java.lang.Runnable)
|
meth public static void runWithUIDefaultsGetter(java.util.function.Function<java.lang.Object,java.lang.Object>,java.lang.Runnable)
|
||||||
meth public static void setGlobalExtraDefaults(java.util.Map<java.lang.String,java.lang.String>)
|
meth public static void setGlobalExtraDefaults(java.util.Map<java.lang.String,java.lang.String>)
|
||||||
|
meth public static void setPreferredFontFamily(java.lang.String)
|
||||||
|
meth public static void setPreferredLightFontFamily(java.lang.String)
|
||||||
|
meth public static void setPreferredMonospacedFontFamily(java.lang.String)
|
||||||
|
meth public static void setPreferredSemiboldFontFamily(java.lang.String)
|
||||||
|
meth public static void setSystemColorGetter(java.util.function.Function<java.lang.String,java.awt.Color>)
|
||||||
meth public static void setUseNativeWindowDecorations(boolean)
|
meth public static void setUseNativeWindowDecorations(boolean)
|
||||||
meth public static void showMnemonics(java.awt.Component)
|
meth public static void showMnemonics(java.awt.Component)
|
||||||
meth public static void unregisterCustomDefaultsSource(java.io.File)
|
meth public static void unregisterCustomDefaultsSource(java.io.File)
|
||||||
@@ -223,7 +247,7 @@ meth public void setExtraDefaults(java.util.Map<java.lang.String,java.lang.Strin
|
|||||||
meth public void uninitialize()
|
meth public void uninitialize()
|
||||||
meth public void unregisterUIDefaultsGetter(java.util.function.Function<java.lang.Object,java.lang.Object>)
|
meth public void unregisterUIDefaultsGetter(java.util.function.Function<java.lang.Object,java.lang.Object>)
|
||||||
supr javax.swing.plaf.basic.BasicLookAndFeel
|
supr javax.swing.plaf.basic.BasicLookAndFeel
|
||||||
hfds DESKTOPFONTHINTS,aquaLoaded,customDefaultsSources,desktopPropertyListener,desktopPropertyName,desktopPropertyName2,extraDefaults,getUIMethod,getUIMethodInitialized,globalExtraDefaults,mnemonicHandler,oldPopupFactory,postInitialization,subMenuUsabilityHelperInstalled,uiDefaultsGetters,updateUIPending
|
hfds DESKTOPFONTHINTS,aquaLoaded,customDefaultsSources,desktopPropertyListener,desktopPropertyName,desktopPropertyName2,extraDefaults,globalExtraDefaults,mnemonicHandler,oldPopupFactory,postInitialization,preferredFontFamily,preferredLightFontFamily,preferredMonospacedFontFamily,preferredSemiboldFontFamily,subMenuUsabilityHelperInstalled,systemColorGetter,uiDefaultsGetters,updateUIPending
|
||||||
hcls ActiveFont,FlatUIDefaults,ImageIconUIResource
|
hcls ActiveFont,FlatUIDefaults,ImageIconUIResource
|
||||||
|
|
||||||
CLSS public abstract interface static com.formdev.flatlaf.FlatLaf$DisabledIconProvider
|
CLSS public abstract interface static com.formdev.flatlaf.FlatLaf$DisabledIconProvider
|
||||||
@@ -264,6 +288,8 @@ fld public final static java.lang.String UI_SCALE_ALLOW_SCALE_DOWN = "flatlaf.ui
|
|||||||
fld public final static java.lang.String UI_SCALE_ENABLED = "flatlaf.uiScale.enabled"
|
fld public final static java.lang.String UI_SCALE_ENABLED = "flatlaf.uiScale.enabled"
|
||||||
fld public final static java.lang.String UPDATE_UI_ON_SYSTEM_FONT_CHANGE = "flatlaf.updateUIOnSystemFontChange"
|
fld public final static java.lang.String UPDATE_UI_ON_SYSTEM_FONT_CHANGE = "flatlaf.updateUIOnSystemFontChange"
|
||||||
fld public final static java.lang.String USE_JETBRAINS_CUSTOM_DECORATIONS = "flatlaf.useJetBrainsCustomDecorations"
|
fld public final static java.lang.String USE_JETBRAINS_CUSTOM_DECORATIONS = "flatlaf.useJetBrainsCustomDecorations"
|
||||||
|
anno 0 java.lang.Deprecated()
|
||||||
|
fld public final static java.lang.String USE_NATIVE_LIBRARY = "flatlaf.useNativeLibrary"
|
||||||
fld public final static java.lang.String USE_TEXT_Y_CORRECTION = "flatlaf.useTextYCorrection"
|
fld public final static java.lang.String USE_TEXT_Y_CORRECTION = "flatlaf.useTextYCorrection"
|
||||||
fld public final static java.lang.String USE_UBUNTU_FONT = "flatlaf.useUbuntuFont"
|
fld public final static java.lang.String USE_UBUNTU_FONT = "flatlaf.useUbuntuFont"
|
||||||
fld public final static java.lang.String USE_WINDOW_DECORATIONS = "flatlaf.useWindowDecorations"
|
fld public final static java.lang.String USE_WINDOW_DECORATIONS = "flatlaf.useWindowDecorations"
|
||||||
@@ -282,7 +308,7 @@ meth public static boolean setup(java.io.InputStream)
|
|||||||
meth public static com.formdev.flatlaf.FlatLaf createLaf(com.formdev.flatlaf.IntelliJTheme)
|
meth public static com.formdev.flatlaf.FlatLaf createLaf(com.formdev.flatlaf.IntelliJTheme)
|
||||||
meth public static com.formdev.flatlaf.FlatLaf createLaf(java.io.InputStream) throws java.io.IOException
|
meth public static com.formdev.flatlaf.FlatLaf createLaf(java.io.InputStream) throws java.io.IOException
|
||||||
supr java.lang.Object
|
supr java.lang.Object
|
||||||
hfds checkboxDuplicateColors,checkboxKeyMapping,colors,icons,isMaterialUILite,namedColors,ui,uiKeyCopying,uiKeyInverseMapping,uiKeyMapping
|
hfds checkboxDuplicateColors,checkboxKeyMapping,colors,icons,isMaterialUILite,namedColors,ui,uiKeyCopying,uiKeyDoNotOverride,uiKeyExcludes,uiKeyInverseMapping,uiKeyMapping
|
||||||
|
|
||||||
CLSS public static com.formdev.flatlaf.IntelliJTheme$ThemeLaf
|
CLSS public static com.formdev.flatlaf.IntelliJTheme$ThemeLaf
|
||||||
outer com.formdev.flatlaf.IntelliJTheme
|
outer com.formdev.flatlaf.IntelliJTheme
|
||||||
@@ -295,6 +321,26 @@ meth public java.lang.String getName()
|
|||||||
supr com.formdev.flatlaf.FlatLaf
|
supr com.formdev.flatlaf.FlatLaf
|
||||||
hfds theme
|
hfds theme
|
||||||
|
|
||||||
|
CLSS public com.formdev.flatlaf.themes.FlatMacDarkLaf
|
||||||
|
cons public init()
|
||||||
|
fld public final static java.lang.String NAME = "FlatLaf macOS Dark"
|
||||||
|
meth public boolean isDark()
|
||||||
|
meth public java.lang.String getDescription()
|
||||||
|
meth public java.lang.String getName()
|
||||||
|
meth public static boolean setup()
|
||||||
|
meth public static void installLafInfo()
|
||||||
|
supr com.formdev.flatlaf.FlatDarkLaf
|
||||||
|
|
||||||
|
CLSS public com.formdev.flatlaf.themes.FlatMacLightLaf
|
||||||
|
cons public init()
|
||||||
|
fld public final static java.lang.String NAME = "FlatLaf macOS Light"
|
||||||
|
meth public boolean isDark()
|
||||||
|
meth public java.lang.String getDescription()
|
||||||
|
meth public java.lang.String getName()
|
||||||
|
meth public static boolean setup()
|
||||||
|
meth public static void installLafInfo()
|
||||||
|
supr com.formdev.flatlaf.FlatLightLaf
|
||||||
|
|
||||||
CLSS public abstract interface com.formdev.flatlaf.util.AnimatedIcon
|
CLSS public abstract interface com.formdev.flatlaf.util.AnimatedIcon
|
||||||
innr public static AnimationSupport
|
innr public static AnimationSupport
|
||||||
intf javax.swing.Icon
|
intf javax.swing.Icon
|
||||||
@@ -362,6 +408,7 @@ meth public static float clamp(float)
|
|||||||
meth public static float luma(java.awt.Color)
|
meth public static float luma(java.awt.Color)
|
||||||
meth public static java.awt.Color darken(java.awt.Color,float)
|
meth public static java.awt.Color darken(java.awt.Color,float)
|
||||||
meth public static java.awt.Color desaturate(java.awt.Color,float)
|
meth public static java.awt.Color desaturate(java.awt.Color,float)
|
||||||
|
meth public static java.awt.Color fade(java.awt.Color,float)
|
||||||
meth public static java.awt.Color lighten(java.awt.Color,float)
|
meth public static java.awt.Color lighten(java.awt.Color,float)
|
||||||
meth public static java.awt.Color mix(java.awt.Color,java.awt.Color,float)
|
meth public static java.awt.Color mix(java.awt.Color,java.awt.Color,float)
|
||||||
meth public static java.awt.Color saturate(java.awt.Color,float)
|
meth public static java.awt.Color saturate(java.awt.Color,float)
|
||||||
@@ -437,6 +484,17 @@ meth public java.lang.String toString()
|
|||||||
supr javax.swing.plaf.ColorUIResource
|
supr javax.swing.plaf.ColorUIResource
|
||||||
hfds baseOfDefaultColorRGB,functions,hasBaseOfDefaultColor
|
hfds baseOfDefaultColorRGB,functions,hasBaseOfDefaultColor
|
||||||
|
|
||||||
|
CLSS public com.formdev.flatlaf.util.FontUtils
|
||||||
|
cons public init()
|
||||||
|
meth public static boolean installFont(java.net.URL)
|
||||||
|
meth public static java.awt.Font getCompositeFont(java.lang.String,int,int)
|
||||||
|
meth public static java.awt.Font[] getAllFonts()
|
||||||
|
meth public static java.lang.String[] getAvailableFontFamilyNames()
|
||||||
|
meth public static void loadFontFamily(java.lang.String)
|
||||||
|
meth public static void registerFontFamilyLoader(java.lang.String,java.lang.Runnable)
|
||||||
|
supr java.lang.Object
|
||||||
|
hfds loadersMap
|
||||||
|
|
||||||
CLSS public com.formdev.flatlaf.util.Graphics2DProxy
|
CLSS public com.formdev.flatlaf.util.Graphics2DProxy
|
||||||
cons public init(java.awt.Graphics2D)
|
cons public init(java.awt.Graphics2D)
|
||||||
meth public boolean drawImage(java.awt.Image,int,int,int,int,int,int,int,int,java.awt.Color,java.awt.image.ImageObserver)
|
meth public boolean drawImage(java.awt.Image,int,int,int,int,int,int,int,int,java.awt.Color,java.awt.image.ImageObserver)
|
||||||
@@ -573,7 +631,7 @@ meth public static void drawStringWithYCorrection(javax.swing.JComponent,java.aw
|
|||||||
meth public static void paintAtScale1x(java.awt.Graphics2D,int,int,int,int,com.formdev.flatlaf.util.HiDPIUtils$Painter)
|
meth public static void paintAtScale1x(java.awt.Graphics2D,int,int,int,int,com.formdev.flatlaf.util.HiDPIUtils$Painter)
|
||||||
meth public static void paintAtScale1x(java.awt.Graphics2D,javax.swing.JComponent,com.formdev.flatlaf.util.HiDPIUtils$Painter)
|
meth public static void paintAtScale1x(java.awt.Graphics2D,javax.swing.JComponent,com.formdev.flatlaf.util.HiDPIUtils$Painter)
|
||||||
supr java.lang.Object
|
supr java.lang.Object
|
||||||
hfds useTextYCorrection
|
hfds CORRECTION_INTER,CORRECTION_OPEN_SANS,CORRECTION_SEGOE_UI,CORRECTION_TAHOMA,SCALE_FACTORS,useDebugScaleFactor,useTextYCorrection
|
||||||
|
|
||||||
CLSS public abstract interface static com.formdev.flatlaf.util.HiDPIUtils$Painter
|
CLSS public abstract interface static com.formdev.flatlaf.util.HiDPIUtils$Painter
|
||||||
outer com.formdev.flatlaf.util.HiDPIUtils
|
outer com.formdev.flatlaf.util.HiDPIUtils
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
package com.formdev.flatlaf;
|
package com.formdev.flatlaf;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
import java.awt.IllegalComponentStateException;
|
||||||
|
import java.awt.Window;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.SwingConstants;
|
import javax.swing.SwingConstants;
|
||||||
@@ -31,7 +33,7 @@ public interface FlatClientProperties
|
|||||||
//---- JButton ------------------------------------------------------------
|
//---- JButton ------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies type of a button.
|
* Specifies type of button.
|
||||||
* <p>
|
* <p>
|
||||||
* <strong>Components</strong> {@link javax.swing.JButton} and {@link javax.swing.JToggleButton}<br>
|
* <strong>Components</strong> {@link javax.swing.JButton} and {@link javax.swing.JToggleButton}<br>
|
||||||
* <strong>Value type</strong> {@link java.lang.String}<br>
|
* <strong>Value type</strong> {@link java.lang.String}<br>
|
||||||
@@ -124,6 +126,7 @@ public interface FlatClientProperties
|
|||||||
*/
|
*/
|
||||||
String SQUARE_SIZE = "JButton.squareSize";
|
String SQUARE_SIZE = "JButton.squareSize";
|
||||||
|
|
||||||
|
|
||||||
//---- JComponent ---------------------------------------------------------
|
//---- JComponent ---------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -266,8 +269,47 @@ public interface FlatClientProperties
|
|||||||
*/
|
*/
|
||||||
String COMPONENT_TITLE_BAR_CAPTION = "JComponent.titleBarCaption";
|
String COMPONENT_TITLE_BAR_CAPTION = "JComponent.titleBarCaption";
|
||||||
|
|
||||||
|
|
||||||
//---- Popup --------------------------------------------------------------
|
//---- Popup --------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the popup border corner radius if the component is shown in a popup
|
||||||
|
* or if the component is the owner of another component that is shown in a popup.
|
||||||
|
* <p>
|
||||||
|
* Note that this is not available on all platforms since it requires special support.
|
||||||
|
* Supported platforms:
|
||||||
|
* <ul>
|
||||||
|
* <li><strong>Windows 11</strong>: Only two corner radiuses are supported
|
||||||
|
* by the OS: {@code DWMWCP_ROUND} is 8px and {@code DWMWCP_ROUNDSMALL} is 4px.
|
||||||
|
* If this value is {@code 1 - 4}, then {@code DWMWCP_ROUNDSMALL} is used.
|
||||||
|
* If it is {@code >= 5}, then {@code DWMWCP_ROUND} is used.
|
||||||
|
* <li><strong>macOS</strong> (10.14 and later): Any corner radius is supported.
|
||||||
|
* </ul>
|
||||||
|
* <strong>Component</strong> {@link javax.swing.JComponent}<br>
|
||||||
|
* <strong>Value type</strong> {@link java.lang.Integer}<br>
|
||||||
|
*
|
||||||
|
* @since 3.1
|
||||||
|
*/
|
||||||
|
String POPUP_BORDER_CORNER_RADIUS = "Popup.borderCornerRadius";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the popup rounded border width if the component is shown in a popup
|
||||||
|
* or if the component is the owner of another component that is shown in a popup.
|
||||||
|
* <p>
|
||||||
|
* Only used if popup uses rounded border.
|
||||||
|
* <p>
|
||||||
|
* Note that this is not available on all platforms since it requires special support.
|
||||||
|
* Supported platforms:
|
||||||
|
* <ul>
|
||||||
|
* <li><strong>macOS</strong> (10.14 and later)
|
||||||
|
* </ul>
|
||||||
|
* <strong>Component</strong> {@link javax.swing.JComponent}<br>
|
||||||
|
* <strong>Value type</strong> {@link java.lang.Integer} or {@link java.lang.Float}<br>
|
||||||
|
*
|
||||||
|
* @since 3.3
|
||||||
|
*/
|
||||||
|
String POPUP_ROUNDED_BORDER_WIDTH = "Popup.roundedBorderWidth";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies whether a drop shadow is painted if the component is shown in a popup
|
* Specifies whether a drop shadow is painted if the component is shown in a popup
|
||||||
* or if the component is the owner of another component that is shown in a popup.
|
* or if the component is the owner of another component that is shown in a popup.
|
||||||
@@ -286,6 +328,7 @@ public interface FlatClientProperties
|
|||||||
*/
|
*/
|
||||||
String POPUP_FORCE_HEAVY_WEIGHT = "Popup.forceHeavyWeight";
|
String POPUP_FORCE_HEAVY_WEIGHT = "Popup.forceHeavyWeight";
|
||||||
|
|
||||||
|
|
||||||
//---- JProgressBar -------------------------------------------------------
|
//---- JProgressBar -------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -304,6 +347,7 @@ public interface FlatClientProperties
|
|||||||
*/
|
*/
|
||||||
String PROGRESS_BAR_SQUARE = "JProgressBar.square";
|
String PROGRESS_BAR_SQUARE = "JProgressBar.square";
|
||||||
|
|
||||||
|
|
||||||
//---- JRootPane ----------------------------------------------------------
|
//---- JRootPane ----------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -377,10 +421,10 @@ public interface FlatClientProperties
|
|||||||
String TITLE_BAR_SHOW_TITLE = "JRootPane.titleBarShowTitle";
|
String TITLE_BAR_SHOW_TITLE = "JRootPane.titleBarShowTitle";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies whether the "iconfify" button should be shown in the window title bar
|
* Specifies whether the "iconify" button should be shown in the window title bar
|
||||||
* (requires enabled window decorations). Default is {@code true}.
|
* (requires enabled window decorations). Default is {@code true}.
|
||||||
* <p>
|
* <p>
|
||||||
* Setting this shows/hides the "iconfify" button
|
* Setting this shows/hides the "iconify" button
|
||||||
* for the {@code JFrame} that contains the root pane.
|
* for the {@code JFrame} that contains the root pane.
|
||||||
* <p>
|
* <p>
|
||||||
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||||
@@ -442,6 +486,48 @@ public interface FlatClientProperties
|
|||||||
*/
|
*/
|
||||||
String TITLE_BAR_FOREGROUND = "JRootPane.titleBarForeground";
|
String TITLE_BAR_FOREGROUND = "JRootPane.titleBarForeground";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies whether the glass pane should have full height and overlap the title bar,
|
||||||
|
* if FlatLaf window decorations are enabled. Default is {@code false}.
|
||||||
|
* <p>
|
||||||
|
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||||
|
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||||
|
*
|
||||||
|
* @since 3.1
|
||||||
|
*/
|
||||||
|
String GLASS_PANE_FULL_HEIGHT = "JRootPane.glassPaneFullHeight";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the style of the window title bar.
|
||||||
|
* Besides the default title bar style, you can use a Utility-style title bar,
|
||||||
|
* which is smaller than the default title bar.
|
||||||
|
* <p>
|
||||||
|
* On Windows 10/11, this requires FlatLaf window decorations.
|
||||||
|
* On macOS, Java supports this out of the box.
|
||||||
|
* <p>
|
||||||
|
* Note that this client property must be set before the window becomes displayable.
|
||||||
|
* Otherwise, an {@link IllegalComponentStateException} is thrown.
|
||||||
|
* <p>
|
||||||
|
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||||
|
* <strong>Value type</strong> {@link java.lang.String}<br>
|
||||||
|
* <strong>Allowed Values</strong>
|
||||||
|
* {@link #WINDOW_STYLE_SMALL}
|
||||||
|
*
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
String WINDOW_STYLE = "Window.style";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The window has Utility-style title bar, which is smaller than default title bar.
|
||||||
|
* <p>
|
||||||
|
* This is the same as using {@link Window#setType}( {@link Window.Type#UTILITY} ).
|
||||||
|
*
|
||||||
|
* @see #WINDOW_STYLE
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
String WINDOW_STYLE_SMALL = "small";
|
||||||
|
|
||||||
|
|
||||||
//---- JScrollBar / JScrollPane -------------------------------------------
|
//---- JScrollBar / JScrollPane -------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -460,6 +546,7 @@ public interface FlatClientProperties
|
|||||||
*/
|
*/
|
||||||
String SCROLL_PANE_SMOOTH_SCROLLING = "JScrollPane.smoothScrolling";
|
String SCROLL_PANE_SMOOTH_SCROLLING = "JScrollPane.smoothScrolling";
|
||||||
|
|
||||||
|
|
||||||
//---- JSplitPane ---------------------------------------------------------
|
//---- JSplitPane ---------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -494,6 +581,7 @@ public interface FlatClientProperties
|
|||||||
*/
|
*/
|
||||||
String SPLIT_PANE_EXPANDABLE_SIDE_RIGHT = "right";
|
String SPLIT_PANE_EXPANDABLE_SIDE_RIGHT = "right";
|
||||||
|
|
||||||
|
|
||||||
//---- JTabbedPane --------------------------------------------------------
|
//---- JTabbedPane --------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -863,6 +951,59 @@ public interface FlatClientProperties
|
|||||||
*/
|
*/
|
||||||
String TABBED_PANE_TAB_ICON_PLACEMENT = "JTabbedPane.tabIconPlacement";
|
String TABBED_PANE_TAB_ICON_PLACEMENT = "JTabbedPane.tabIconPlacement";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the rotation of the tabs (title, icon, etc.).
|
||||||
|
* <p>
|
||||||
|
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
|
||||||
|
* <strong>Value type</strong> {@link java.lang.Integer} or {@link java.lang.String}<br>
|
||||||
|
* <strong>Allowed Values</strong>
|
||||||
|
* {@link SwingConstants#LEFT},
|
||||||
|
* {@link SwingConstants#RIGHT},
|
||||||
|
* {@link #TABBED_PANE_TAB_ROTATION_NONE}, (default)
|
||||||
|
* {@link #TABBED_PANE_TAB_ROTATION_AUTO},
|
||||||
|
* {@link #TABBED_PANE_TAB_ROTATION_LEFT} or
|
||||||
|
* {@link #TABBED_PANE_TAB_ROTATION_RIGHT}
|
||||||
|
*
|
||||||
|
* @since 3.3
|
||||||
|
*/
|
||||||
|
String TABBED_PANE_TAB_ROTATION = "JTabbedPane.tabRotation";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tabs are not rotated.
|
||||||
|
*
|
||||||
|
* @see #TABBED_PANE_TAB_ROTATION
|
||||||
|
* @since 3.3
|
||||||
|
*/
|
||||||
|
String TABBED_PANE_TAB_ROTATION_NONE = "none";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tabs are rotated depending on tab placement.
|
||||||
|
* <p>
|
||||||
|
* For top and bottom tab placement, the tabs are not rotated.<br>
|
||||||
|
* For left tab placement, the tabs are rotated counter-clockwise.<br>
|
||||||
|
* For right tab placement, the tabs are rotated clockwise.
|
||||||
|
*
|
||||||
|
* @see #TABBED_PANE_TAB_ROTATION
|
||||||
|
* @since 3.3
|
||||||
|
*/
|
||||||
|
String TABBED_PANE_TAB_ROTATION_AUTO = "auto";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tabs are rotated counter-clockwise.
|
||||||
|
*
|
||||||
|
* @see #TABBED_PANE_TAB_ROTATION
|
||||||
|
* @since 3.3
|
||||||
|
*/
|
||||||
|
String TABBED_PANE_TAB_ROTATION_LEFT = "left";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tabs are rotated clockwise.
|
||||||
|
*
|
||||||
|
* @see #TABBED_PANE_TAB_ROTATION
|
||||||
|
* @since 3.3
|
||||||
|
*/
|
||||||
|
String TABBED_PANE_TAB_ROTATION_RIGHT = "right";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies a component that will be placed at the leading edge of the tabs area.
|
* Specifies a component that will be placed at the leading edge of the tabs area.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -889,6 +1030,7 @@ public interface FlatClientProperties
|
|||||||
*/
|
*/
|
||||||
String TABBED_PANE_TRAILING_COMPONENT = "JTabbedPane.trailingComponent";
|
String TABBED_PANE_TRAILING_COMPONENT = "JTabbedPane.trailingComponent";
|
||||||
|
|
||||||
|
|
||||||
//---- JTextField ---------------------------------------------------------
|
//---- JTextField ---------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1058,6 +1200,7 @@ public interface FlatClientProperties
|
|||||||
*/
|
*/
|
||||||
String TEXT_FIELD_CLEAR_CALLBACK = "JTextField.clearCallback";
|
String TEXT_FIELD_CLEAR_CALLBACK = "JTextField.clearCallback";
|
||||||
|
|
||||||
|
|
||||||
//---- JToggleButton ------------------------------------------------------
|
//---- JToggleButton ------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1099,6 +1242,7 @@ public interface FlatClientProperties
|
|||||||
*/
|
*/
|
||||||
String TAB_BUTTON_SELECTED_BACKGROUND = "JToggleButton.tab.selectedBackground";
|
String TAB_BUTTON_SELECTED_BACKGROUND = "JToggleButton.tab.selectedBackground";
|
||||||
|
|
||||||
|
|
||||||
//---- JTree --------------------------------------------------------------
|
//---- JTree --------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1118,6 +1262,7 @@ public interface FlatClientProperties
|
|||||||
*/
|
*/
|
||||||
String TREE_PAINT_SELECTION = "JTree.paintSelection";
|
String TREE_PAINT_SELECTION = "JTree.paintSelection";
|
||||||
|
|
||||||
|
|
||||||
//---- helper methods -----------------------------------------------------
|
//---- helper methods -----------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -50,7 +50,8 @@ class FlatInputMaps
|
|||||||
}
|
}
|
||||||
|
|
||||||
modifyInputMap( defaults, "ComboBox.ancestorInputMap",
|
modifyInputMap( defaults, "ComboBox.ancestorInputMap",
|
||||||
"SPACE", "spacePopup",
|
// Space key still shows popup, but from FlatComboBoxUI.FlatKeySelectionManager
|
||||||
|
// "SPACE", "spacePopup",
|
||||||
|
|
||||||
"UP", mac( "selectPrevious2", "selectPrevious" ),
|
"UP", mac( "selectPrevious2", "selectPrevious" ),
|
||||||
"DOWN", mac( "selectNext2", "selectNext" ),
|
"DOWN", mac( "selectNext2", "selectNext" ),
|
||||||
@@ -70,7 +71,7 @@ class FlatInputMaps
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// join ltr and rtl bindings to fix up/down/etc keys in right-to-left component orientation
|
// join ltr and rtl bindings to fix up/down/etc. keys in right-to-left component orientation
|
||||||
Object[] bindings = (Object[]) defaults.get( "PopupMenu.selectedWindowInputMapBindings" );
|
Object[] bindings = (Object[]) defaults.get( "PopupMenu.selectedWindowInputMapBindings" );
|
||||||
Object[] rtlBindings = (Object[]) defaults.get( "PopupMenu.selectedWindowInputMapBindings.RightToLeft" );
|
Object[] rtlBindings = (Object[]) defaults.get( "PopupMenu.selectedWindowInputMapBindings.RightToLeft" );
|
||||||
if( bindings != null && rtlBindings != null ) {
|
if( bindings != null && rtlBindings != null ) {
|
||||||
|
|||||||
@@ -30,9 +30,6 @@ import java.awt.image.ImageProducer;
|
|||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.lang.invoke.MethodHandle;
|
|
||||||
import java.lang.invoke.MethodHandles;
|
|
||||||
import java.lang.invoke.MethodType;
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -71,12 +68,14 @@ import javax.swing.plaf.FontUIResource;
|
|||||||
import javax.swing.plaf.IconUIResource;
|
import javax.swing.plaf.IconUIResource;
|
||||||
import javax.swing.plaf.UIResource;
|
import javax.swing.plaf.UIResource;
|
||||||
import javax.swing.plaf.basic.BasicLookAndFeel;
|
import javax.swing.plaf.basic.BasicLookAndFeel;
|
||||||
|
import javax.swing.plaf.metal.MetalLookAndFeel;
|
||||||
import javax.swing.text.StyleContext;
|
import javax.swing.text.StyleContext;
|
||||||
import javax.swing.text.html.HTMLEditorKit;
|
import javax.swing.text.html.HTMLEditorKit;
|
||||||
import com.formdev.flatlaf.ui.FlatNativeWindowBorder;
|
import com.formdev.flatlaf.ui.FlatNativeWindowBorder;
|
||||||
import com.formdev.flatlaf.ui.FlatPopupFactory;
|
import com.formdev.flatlaf.ui.FlatPopupFactory;
|
||||||
import com.formdev.flatlaf.ui.FlatRootPaneUI;
|
import com.formdev.flatlaf.ui.FlatRootPaneUI;
|
||||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||||
|
import com.formdev.flatlaf.ui.JavaCompatibility2;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||||
import com.formdev.flatlaf.util.FontUtils;
|
import com.formdev.flatlaf.util.FontUtils;
|
||||||
import com.formdev.flatlaf.util.GrayFilter;
|
import com.formdev.flatlaf.util.GrayFilter;
|
||||||
@@ -182,17 +181,11 @@ public abstract class FlatLaf
|
|||||||
* This depends on the operating system and on the used Java runtime.
|
* This depends on the operating system and on the used Java runtime.
|
||||||
* <p>
|
* <p>
|
||||||
* This method returns {@code true} on Windows 10/11 (see exception below)
|
* This method returns {@code true} on Windows 10/11 (see exception below)
|
||||||
* and on Linux, {@code false} otherwise.
|
* and on Linux, otherwise returns {@code false}.
|
||||||
|
* <p>
|
||||||
|
* Returns also {@code false} on Windows 10/11 if
|
||||||
|
* FlatLaf native window border support is available (requires Windows 10/11).
|
||||||
* <p>
|
* <p>
|
||||||
* Returns also {@code false} on Windows 10/11 if:
|
|
||||||
* <ul>
|
|
||||||
* <li>FlatLaf native window border support is available (requires Windows 10/11)</li>
|
|
||||||
* <li>running in
|
|
||||||
* <a href="https://confluence.jetbrains.com/display/JBR/JetBrains+Runtime">JetBrains Runtime 11 (or later)</a>
|
|
||||||
* (<a href="https://github.com/JetBrains/JetBrainsRuntime">source code on github</a>)
|
|
||||||
* and JBR supports custom window decorations
|
|
||||||
* </li>
|
|
||||||
* </ul>
|
|
||||||
* In these cases, custom decorations are enabled by the root pane.
|
* In these cases, custom decorations are enabled by the root pane.
|
||||||
* Usage of {@link JFrame#setDefaultLookAndFeelDecorated(boolean)} or
|
* Usage of {@link JFrame#setDefaultLookAndFeelDecorated(boolean)} or
|
||||||
* {@link JDialog#setDefaultLookAndFeelDecorated(boolean)} is not necessary.
|
* {@link JDialog#setDefaultLookAndFeelDecorated(boolean)} is not necessary.
|
||||||
@@ -391,7 +384,7 @@ public abstract class FlatLaf
|
|||||||
Method m = UIManager.class.getMethod( "createLookAndFeel", String.class );
|
Method m = UIManager.class.getMethod( "createLookAndFeel", String.class );
|
||||||
aquaLaf = (BasicLookAndFeel) m.invoke( null, "Mac OS X" );
|
aquaLaf = (BasicLookAndFeel) m.invoke( null, "Mac OS X" );
|
||||||
} else
|
} else
|
||||||
aquaLaf = (BasicLookAndFeel) Class.forName( aquaLafClassName ).getDeclaredConstructor().newInstance();
|
aquaLaf = Class.forName( aquaLafClassName ).asSubclass( BasicLookAndFeel.class ).getDeclaredConstructor().newInstance();
|
||||||
} catch( Exception ex ) {
|
} catch( Exception ex ) {
|
||||||
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to initialize Aqua look and feel '" + aquaLafClassName + "'.", ex );
|
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to initialize Aqua look and feel '" + aquaLafClassName + "'.", ex );
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
@@ -543,7 +536,7 @@ public abstract class FlatLaf
|
|||||||
// which can happen in applications that use some plugin system
|
// which can happen in applications that use some plugin system
|
||||||
// and load FlatLaf in a plugin that uses its own classloader.
|
// and load FlatLaf in a plugin that uses its own classloader.
|
||||||
// (e.g. Apache NetBeans)
|
// (e.g. Apache NetBeans)
|
||||||
if( defaults.get( "FileChooser.fileNameHeaderText" ) != null )
|
if( defaults.get( "TabbedPane.moreTabsButtonToolTipText" ) != null )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// load FlatLaf resource bundle and add content to defaults
|
// load FlatLaf resource bundle and add content to defaults
|
||||||
@@ -581,10 +574,13 @@ public abstract class FlatLaf
|
|||||||
Object activeFont = new ActiveFont( null, null, -1, 0, 0, 0, 0 );
|
Object activeFont = new ActiveFont( null, null, -1, 0, 0, 0, 0 );
|
||||||
|
|
||||||
// override fonts
|
// override fonts
|
||||||
|
List<String> fontKeys = new ArrayList<>( 50 );
|
||||||
for( Object key : defaults.keySet() ) {
|
for( Object key : defaults.keySet() ) {
|
||||||
if( key instanceof String && (((String)key).endsWith( ".font" ) || ((String)key).endsWith( "Font" )) )
|
if( key instanceof String && (((String)key).endsWith( ".font" ) || ((String)key).endsWith( "Font" )) )
|
||||||
defaults.put( key, activeFont );
|
fontKeys.add( (String) key );
|
||||||
}
|
}
|
||||||
|
for( String key : fontKeys )
|
||||||
|
defaults.put( key, activeFont );
|
||||||
|
|
||||||
// add fonts that are not set in BasicLookAndFeel
|
// add fonts that are not set in BasicLookAndFeel
|
||||||
defaults.put( "RootPane.font", activeFont );
|
defaults.put( "RootPane.font", activeFont );
|
||||||
@@ -1291,8 +1287,8 @@ public abstract class FlatLaf
|
|||||||
* @since 2.5
|
* @since 2.5
|
||||||
*/
|
*/
|
||||||
public static Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
public static Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||||
StyleableUI ui = getStyleableUI( c );
|
ComponentUI ui = JavaCompatibility2.getUI( c );
|
||||||
return (ui != null) ? ui.getStyleableInfos( c ) : null;
|
return (ui instanceof StyleableUI) ? ((StyleableUI)ui).getStyleableInfos( c ) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1304,41 +1300,10 @@ public abstract class FlatLaf
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings( "unchecked" )
|
@SuppressWarnings( "unchecked" )
|
||||||
public static <T> T getStyleableValue( JComponent c, String key ) {
|
public static <T> T getStyleableValue( JComponent c, String key ) {
|
||||||
StyleableUI ui = getStyleableUI( c );
|
ComponentUI ui = JavaCompatibility2.getUI( c );
|
||||||
return (ui != null) ? (T) ui.getStyleableValue( c, key ) : null;
|
return (ui instanceof StyleableUI) ? (T) ((StyleableUI)ui).getStyleableValue( c, key ) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static StyleableUI getStyleableUI( JComponent c ) {
|
|
||||||
if( !getUIMethodInitialized ) {
|
|
||||||
getUIMethodInitialized = true;
|
|
||||||
|
|
||||||
if( SystemInfo.isJava_9_orLater ) {
|
|
||||||
try {
|
|
||||||
// JComponent.getUI() is available since Java 9
|
|
||||||
getUIMethod = MethodHandles.lookup().findVirtual( JComponent.class, "getUI",
|
|
||||||
MethodType.methodType( ComponentUI.class ) );
|
|
||||||
} catch( Exception ex ) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
Object ui;
|
|
||||||
if( getUIMethod != null )
|
|
||||||
ui = getUIMethod.invoke( c );
|
|
||||||
else
|
|
||||||
ui = c.getClass().getMethod( "getUI" ).invoke( c );
|
|
||||||
return (ui instanceof StyleableUI) ? (StyleableUI) ui : null;
|
|
||||||
} catch( Throwable ex ) {
|
|
||||||
// ignore
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean getUIMethodInitialized;
|
|
||||||
private static MethodHandle getUIMethod;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the preferred font family to be used for (nearly) all fonts; or {@code null}.
|
* Returns the preferred font family to be used for (nearly) all fonts; or {@code null}.
|
||||||
*
|
*
|
||||||
@@ -1428,26 +1393,36 @@ public abstract class FlatLaf
|
|||||||
private class FlatUIDefaults
|
private class FlatUIDefaults
|
||||||
extends UIDefaults
|
extends UIDefaults
|
||||||
{
|
{
|
||||||
|
private UIDefaults metalDefaults;
|
||||||
|
|
||||||
FlatUIDefaults( int initialCapacity, float loadFactor ) {
|
FlatUIDefaults( int initialCapacity, float loadFactor ) {
|
||||||
super( initialCapacity, loadFactor );
|
super( initialCapacity, loadFactor );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object get( Object key ) {
|
public Object get( Object key ) {
|
||||||
Object value = getValue( key );
|
return get( key, null );
|
||||||
return (value != null) ? (value != NULL_VALUE ? value : null) : super.get( key );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object get( Object key, Locale l ) {
|
public Object get( Object key, Locale l ) {
|
||||||
Object value = getValue( key );
|
Object value = getFromUIDefaultsGetters( key );
|
||||||
return (value != null) ? (value != NULL_VALUE ? value : null) : super.get( key, l );
|
if( value != null )
|
||||||
|
return (value != NULL_VALUE) ? value : null;
|
||||||
|
|
||||||
|
value = super.get( key, l );
|
||||||
|
if( value != null )
|
||||||
|
return value;
|
||||||
|
|
||||||
|
// get file chooser texts from Metal
|
||||||
|
return (key instanceof String && ((String)key).startsWith( "FileChooser." ))
|
||||||
|
? getFromMetal( (String) key, l )
|
||||||
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object getValue( Object key ) {
|
private Object getFromUIDefaultsGetters( Object key ) {
|
||||||
// use local variable for getters to avoid potential multi-threading issues
|
// use local variable for getters to avoid potential multi-threading issues
|
||||||
List<Function<Object, Object>> uiDefaultsGetters = FlatLaf.this.uiDefaultsGetters;
|
List<Function<Object, Object>> uiDefaultsGetters = FlatLaf.this.uiDefaultsGetters;
|
||||||
|
|
||||||
if( uiDefaultsGetters == null )
|
if( uiDefaultsGetters == null )
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@@ -1459,6 +1434,22 @@ public abstract class FlatLaf
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private synchronized Object getFromMetal( String key, Locale l ) {
|
||||||
|
if( metalDefaults == null ) {
|
||||||
|
metalDefaults = new MetalLookAndFeel() {
|
||||||
|
// avoid unnecessary initialization
|
||||||
|
@Override protected void initClassDefaults( UIDefaults table ) {}
|
||||||
|
@Override protected void initSystemColorDefaults( UIDefaults table ) {}
|
||||||
|
}.getDefaults();
|
||||||
|
|
||||||
|
// empty not needed defaults (to save memory) because we're only interested
|
||||||
|
// in resource bundle strings, which are stored in another internal map
|
||||||
|
metalDefaults.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
return metalDefaults.get( key, l );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//---- class ActiveFont ---------------------------------------------------
|
//---- class ActiveFont ---------------------------------------------------
|
||||||
@@ -1541,7 +1532,7 @@ public abstract class FlatLaf
|
|||||||
int newStyle = (style != -1)
|
int newStyle = (style != -1)
|
||||||
? style
|
? style
|
||||||
: (styleChange != 0)
|
: (styleChange != 0)
|
||||||
? baseStyle & ~((styleChange >> 16) & 0xffff) | (styleChange & 0xffff)
|
? (baseStyle & ~((styleChange >> 16) & 0xffff)) | (styleChange & 0xffff)
|
||||||
: baseStyle;
|
: baseStyle;
|
||||||
|
|
||||||
// new size
|
// new size
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import java.io.FileInputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -96,7 +97,7 @@ public class FlatPropertiesLaf
|
|||||||
protected ArrayList<Class<?>> getLafClassesForDefaultsLoading() {
|
protected ArrayList<Class<?>> getLafClassesForDefaultsLoading() {
|
||||||
ArrayList<Class<?>> lafClasses = new ArrayList<>();
|
ArrayList<Class<?>> lafClasses = new ArrayList<>();
|
||||||
lafClasses.add( FlatLaf.class );
|
lafClasses.add( FlatLaf.class );
|
||||||
switch( baseTheme.toLowerCase() ) {
|
switch( baseTheme.toLowerCase( Locale.ENGLISH ) ) {
|
||||||
default:
|
default:
|
||||||
case "light":
|
case "light":
|
||||||
lafClasses.add( FlatLightLaf.class );
|
lafClasses.add( FlatLightLaf.class );
|
||||||
|
|||||||
@@ -103,7 +103,10 @@ public interface FlatSystemProperties
|
|||||||
* <p>
|
* <p>
|
||||||
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
||||||
* <strong>Default</strong> {@code false} (since v2; was {@code true} in v1)
|
* <strong>Default</strong> {@code false} (since v2; was {@code true} in v1)
|
||||||
|
*
|
||||||
|
* @deprecated No longer used since FlatLaf 3.3. Retained for API compatibility.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
String USE_JETBRAINS_CUSTOM_DECORATIONS = "flatlaf.useJetBrainsCustomDecorations";
|
String USE_JETBRAINS_CUSTOM_DECORATIONS = "flatlaf.useJetBrainsCustomDecorations";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -150,10 +153,24 @@ public interface FlatSystemProperties
|
|||||||
* <p>
|
* <p>
|
||||||
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
||||||
* <strong>Default</strong> {@code true}
|
* <strong>Default</strong> {@code true}
|
||||||
|
*
|
||||||
* @since 2.5
|
* @since 2.5
|
||||||
*/
|
*/
|
||||||
String UPDATE_UI_ON_SYSTEM_FONT_CHANGE = "flatlaf.updateUIOnSystemFontChange";
|
String UPDATE_UI_ON_SYSTEM_FONT_CHANGE = "flatlaf.updateUIOnSystemFontChange";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies whether FlatLaf native library should be used.
|
||||||
|
* <p>
|
||||||
|
* Setting this to {@code false} disables loading native library,
|
||||||
|
* which also disables some features that depend on the native library.
|
||||||
|
* <p>
|
||||||
|
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
||||||
|
* <strong>Default</strong> {@code true}
|
||||||
|
*
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
String USE_NATIVE_LIBRARY = "flatlaf.useNativeLibrary";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies a directory in which the native FlatLaf libraries have been extracted.
|
* Specifies a directory in which the native FlatLaf libraries have been extracted.
|
||||||
* The path can be absolute or relative to current application working directory.
|
* The path can be absolute or relative to current application working directory.
|
||||||
@@ -166,7 +183,7 @@ public interface FlatSystemProperties
|
|||||||
* in system properties {@code sun.boot.library.path} and {@code java.library.path}.
|
* in system properties {@code sun.boot.library.path} and {@code java.library.path}.
|
||||||
* (supported since FlatLaf 2.6)
|
* (supported since FlatLaf 2.6)
|
||||||
* <p>
|
* <p>
|
||||||
* If the native library can not loaded from the given path (or via {@link System#loadLibrary(String)}),
|
* If the native library can not be loaded from the given path (or via {@link System#loadLibrary(String)}),
|
||||||
* then the embedded native library is extracted to the temporary directory and loaded from there.
|
* then the embedded native library is extracted to the temporary directory and loaded from there.
|
||||||
*
|
*
|
||||||
* @since 2
|
* @since 2
|
||||||
|
|||||||
@@ -23,13 +23,17 @@ import java.io.InputStreamReader;
|
|||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import javax.swing.UIDefaults;
|
import javax.swing.UIDefaults;
|
||||||
import javax.swing.plaf.ColorUIResource;
|
import javax.swing.plaf.ColorUIResource;
|
||||||
import com.formdev.flatlaf.json.Json;
|
import com.formdev.flatlaf.json.Json;
|
||||||
@@ -61,9 +65,9 @@ public class IntelliJTheme
|
|||||||
|
|
||||||
private final boolean isMaterialUILite;
|
private final boolean isMaterialUILite;
|
||||||
|
|
||||||
private final Map<String, String> colors;
|
private Map<String, String> colors;
|
||||||
private final Map<String, Object> ui;
|
private Map<String, Object> ui;
|
||||||
private final Map<String, Object> icons;
|
private Map<String, Object> icons;
|
||||||
|
|
||||||
private Map<String, ColorUIResource> namedColors = Collections.emptyMap();
|
private Map<String, ColorUIResource> namedColors = Collections.emptyMap();
|
||||||
|
|
||||||
@@ -196,8 +200,9 @@ public class IntelliJTheme
|
|||||||
defaults.put( "HelpButton.focusedBackground", defaults.get( "Button.focusedBackground" ) );
|
defaults.put( "HelpButton.focusedBackground", defaults.get( "Button.focusedBackground" ) );
|
||||||
|
|
||||||
// IDEA uses TextField.background for editable ComboBox and Spinner
|
// IDEA uses TextField.background for editable ComboBox and Spinner
|
||||||
defaults.put( "ComboBox.editableBackground", defaults.get( "TextField.background" ) );
|
Object textFieldBackground = get( defaults, themeSpecificDefaults, "TextField.background" );
|
||||||
defaults.put( "Spinner.background", defaults.get( "TextField.background" ) );
|
defaults.put( "ComboBox.editableBackground", textFieldBackground );
|
||||||
|
defaults.put( "Spinner.background", textFieldBackground );
|
||||||
|
|
||||||
// Spinner arrow button always has same colors as ComboBox arrow button
|
// Spinner arrow button always has same colors as ComboBox arrow button
|
||||||
defaults.put( "Spinner.buttonBackground", defaults.get( "ComboBox.buttonEditableBackground" ) );
|
defaults.put( "Spinner.buttonBackground", defaults.get( "ComboBox.buttonEditableBackground" ) );
|
||||||
@@ -205,22 +210,41 @@ public class IntelliJTheme
|
|||||||
defaults.put( "Spinner.buttonDisabledArrowColor", defaults.get( "ComboBox.buttonDisabledArrowColor" ) );
|
defaults.put( "Spinner.buttonDisabledArrowColor", defaults.get( "ComboBox.buttonDisabledArrowColor" ) );
|
||||||
|
|
||||||
// some themes specify colors for TextField.background, but forget to specify it for other components
|
// some themes specify colors for TextField.background, but forget to specify it for other components
|
||||||
// (probably because those components are not used in IntelliJ)
|
// (probably because those components are not used in IntelliJ IDEA)
|
||||||
if( uiKeys.contains( "TextField.background" ) ) {
|
putAll( defaults, textFieldBackground,
|
||||||
Object textFieldBackground = defaults.get( "TextField.background" );
|
"EditorPane.background",
|
||||||
if( !uiKeys.contains( "FormattedTextField.background" ) )
|
"FormattedTextField.background",
|
||||||
defaults.put( "FormattedTextField.background", textFieldBackground );
|
"PasswordField.background",
|
||||||
if( !uiKeys.contains( "PasswordField.background" ) )
|
"TextArea.background",
|
||||||
defaults.put( "PasswordField.background", textFieldBackground );
|
"TextPane.background"
|
||||||
if( !uiKeys.contains( "EditorPane.background" ) )
|
);
|
||||||
defaults.put( "EditorPane.background", textFieldBackground );
|
putAll( defaults, get( defaults, themeSpecificDefaults, "TextField.selectionBackground" ),
|
||||||
if( !uiKeys.contains( "TextArea.background" ) )
|
"EditorPane.selectionBackground",
|
||||||
defaults.put( "TextArea.background", textFieldBackground );
|
"FormattedTextField.selectionBackground",
|
||||||
if( !uiKeys.contains( "TextPane.background" ) )
|
"PasswordField.selectionBackground",
|
||||||
defaults.put( "TextPane.background", textFieldBackground );
|
"TextArea.selectionBackground",
|
||||||
if( !uiKeys.contains( "Spinner.background" ) )
|
"TextPane.selectionBackground"
|
||||||
defaults.put( "Spinner.background", textFieldBackground );
|
);
|
||||||
}
|
putAll( defaults, get( defaults, themeSpecificDefaults, "TextField.selectionForeground" ),
|
||||||
|
"EditorPane.selectionForeground",
|
||||||
|
"FormattedTextField.selectionForeground",
|
||||||
|
"PasswordField.selectionForeground",
|
||||||
|
"TextArea.selectionForeground",
|
||||||
|
"TextPane.selectionForeground"
|
||||||
|
);
|
||||||
|
|
||||||
|
// fix disabled and not-editable backgrounds for text components, combobox and spinner
|
||||||
|
// (IntelliJ IDEA does not use those colors; instead it used background color of parent)
|
||||||
|
putAll( defaults, panelBackground,
|
||||||
|
"ComboBox.disabledBackground",
|
||||||
|
"EditorPane.disabledBackground", "EditorPane.inactiveBackground",
|
||||||
|
"FormattedTextField.disabledBackground", "FormattedTextField.inactiveBackground",
|
||||||
|
"PasswordField.disabledBackground", "PasswordField.inactiveBackground",
|
||||||
|
"Spinner.disabledBackground",
|
||||||
|
"TextArea.disabledBackground", "TextArea.inactiveBackground",
|
||||||
|
"TextField.disabledBackground", "TextField.inactiveBackground",
|
||||||
|
"TextPane.disabledBackground", "TextPane.inactiveBackground"
|
||||||
|
);
|
||||||
|
|
||||||
// fix ToggleButton
|
// fix ToggleButton
|
||||||
if( !uiKeys.contains( "ToggleButton.startBackground" ) && !uiKeys.contains( "*.startBackground" ) )
|
if( !uiKeys.contains( "ToggleButton.startBackground" ) && !uiKeys.contains( "*.startBackground" ) )
|
||||||
@@ -247,6 +271,33 @@ public class IntelliJTheme
|
|||||||
if( rowHeight > 22 )
|
if( rowHeight > 22 )
|
||||||
defaults.put( "Tree.rowHeight", 22 );
|
defaults.put( "Tree.rowHeight", 22 );
|
||||||
|
|
||||||
|
// get (and remove) theme specific wildcard replacements, which override all other defaults that end with same suffix
|
||||||
|
HashMap<String, Object> wildcards = new HashMap<>();
|
||||||
|
Iterator<Entry<Object, Object>> it = themeSpecificDefaults.entrySet().iterator();
|
||||||
|
while( it.hasNext() ) {
|
||||||
|
Entry<Object, Object> e = it.next();
|
||||||
|
String key = (String) e.getKey();
|
||||||
|
if( key.startsWith( "*." ) ) {
|
||||||
|
wildcards.put( key.substring( "*.".length() ), e.getValue() );
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// override UI defaults with theme specific wildcard replacements
|
||||||
|
if( !wildcards.isEmpty() ) {
|
||||||
|
for( Object key : defaults.keySet().toArray() ) {
|
||||||
|
int dot;
|
||||||
|
if( !(key instanceof String) ||
|
||||||
|
(dot = ((String)key).lastIndexOf( '.' )) < 0 )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
String wildcardKey = ((String)key).substring( dot + 1 );
|
||||||
|
Object wildcardValue = wildcards.get( wildcardKey );
|
||||||
|
if( wildcardValue != null )
|
||||||
|
defaults.put( key, wildcardValue );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// apply theme specific UI defaults at the end to allow overwriting
|
// apply theme specific UI defaults at the end to allow overwriting
|
||||||
for( Map.Entry<Object, Object> e : themeSpecificDefaults.entrySet() ) {
|
for( Map.Entry<Object, Object> e : themeSpecificDefaults.entrySet() ) {
|
||||||
Object key = e.getKey();
|
Object key = e.getKey();
|
||||||
@@ -261,6 +312,20 @@ public class IntelliJTheme
|
|||||||
|
|
||||||
defaults.put( key, value );
|
defaults.put( key, value );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// let Java release memory
|
||||||
|
colors = null;
|
||||||
|
ui = null;
|
||||||
|
icons = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object get( UIDefaults defaults, Map<Object, Object> themeSpecificDefaults, String key ) {
|
||||||
|
return themeSpecificDefaults.getOrDefault( key, defaults.get( key ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void putAll( UIDefaults defaults, Object value, String... keys ) {
|
||||||
|
for( String key : keys )
|
||||||
|
defaults.put( key, value );
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<Object, Object> removeThemeSpecificDefaults( UIDefaults defaults ) {
|
private Map<Object, Object> removeThemeSpecificDefaults( UIDefaults defaults ) {
|
||||||
@@ -334,17 +399,30 @@ public class IntelliJTheme
|
|||||||
if( "".equals( value ) )
|
if( "".equals( value ) )
|
||||||
return; // ignore empty value
|
return; // ignore empty value
|
||||||
|
|
||||||
uiKeys.add( key );
|
// ignore some properties that affect sizes
|
||||||
|
if( key.endsWith( ".border" ) ||
|
||||||
// fix ComboBox size and Spinner border in all Material UI Lite themes
|
key.endsWith( ".rowHeight" ) ||
|
||||||
if( isMaterialUILite && (key.equals( "ComboBox.padding" ) || key.equals( "Spinner.border" )) )
|
key.equals( "ComboBox.padding" ) ||
|
||||||
return; // ignore
|
key.equals( "Spinner.padding" ) ||
|
||||||
|
key.equals( "Tree.leftChildIndent" ) ||
|
||||||
|
key.equals( "Tree.rightChildIndent" ) )
|
||||||
|
return; // ignore
|
||||||
|
|
||||||
// map keys
|
// map keys
|
||||||
key = uiKeyMapping.getOrDefault( key, key );
|
key = uiKeyMapping.getOrDefault( key, key );
|
||||||
if( key.isEmpty() )
|
if( key.isEmpty() )
|
||||||
return; // ignore key
|
return; // ignore key
|
||||||
|
|
||||||
|
// exclude properties
|
||||||
|
int dot = key.indexOf( '.' );
|
||||||
|
if( dot > 0 && uiKeyExcludes.contains( key.substring( 0, dot + 1 ) ) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( uiKeyDoNotOverride.contains( key ) && uiKeys.contains( key ) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
uiKeys.add( key );
|
||||||
|
|
||||||
String valueStr = value.toString();
|
String valueStr = value.toString();
|
||||||
|
|
||||||
// map named colors
|
// map named colors
|
||||||
@@ -390,7 +468,8 @@ public class IntelliJTheme
|
|||||||
// replace all values in UI defaults that match the wildcard key
|
// replace all values in UI defaults that match the wildcard key
|
||||||
for( Object k : defaultsKeysCache ) {
|
for( Object k : defaultsKeysCache ) {
|
||||||
if( k.equals( "Desktop.background" ) ||
|
if( k.equals( "Desktop.background" ) ||
|
||||||
k.equals( "DesktopIcon.background" ) )
|
k.equals( "DesktopIcon.background" ) ||
|
||||||
|
k.equals( "TabbedPane.focusColor" ) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if( k instanceof String ) {
|
if( k instanceof String ) {
|
||||||
@@ -461,7 +540,7 @@ public class IntelliJTheme
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Because IDEA uses SVGs for check boxes and radio buttons, the colors for
|
* Because IDEA uses SVGs for check boxes and radio buttons, the colors for
|
||||||
* this two components are specified in "icons > ColorPalette".
|
* these two components are specified in "icons > ColorPalette".
|
||||||
* FlatLaf uses vector icons and expects colors for the two components in UI defaults.
|
* FlatLaf uses vector icons and expects colors for the two components in UI defaults.
|
||||||
*/
|
*/
|
||||||
private void applyCheckBoxColors( UIDefaults defaults ) {
|
private void applyCheckBoxColors( UIDefaults defaults ) {
|
||||||
@@ -481,18 +560,6 @@ public class IntelliJTheme
|
|||||||
if( !key.startsWith( "Checkbox." ) || !(value instanceof String) )
|
if( !key.startsWith( "Checkbox." ) || !(value instanceof String) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if( key.equals( "Checkbox.Background.Default" ) ||
|
|
||||||
key.equals( "Checkbox.Foreground.Selected" ) )
|
|
||||||
{
|
|
||||||
// This two keys do not work correctly in IDEA because they
|
|
||||||
// map SVG color "#ffffff" to another color, but checkBox.svg and
|
|
||||||
// radio.svg (in package com.intellij.ide.ui.laf.icons.intellij)
|
|
||||||
// use "#fff". So use white to get same appearance as in IDEA.
|
|
||||||
value = "#ffffff";
|
|
||||||
}
|
|
||||||
|
|
||||||
String key2 = checkboxDuplicateColors.get( key );
|
|
||||||
|
|
||||||
if( dark )
|
if( dark )
|
||||||
key = StringUtils.removeTrailing( key, ".Dark" );
|
key = StringUtils.removeTrailing( key, ".Dark" );
|
||||||
|
|
||||||
@@ -506,6 +573,7 @@ public class IntelliJTheme
|
|||||||
if( color != null ) {
|
if( color != null ) {
|
||||||
defaults.put( newKey, color );
|
defaults.put( newKey, color );
|
||||||
|
|
||||||
|
String key2 = checkboxDuplicateColors.get( key + ".Dark");
|
||||||
if( key2 != null ) {
|
if( key2 != null ) {
|
||||||
// When IDEA replaces colors in SVGs it uses color values and not the keys
|
// When IDEA replaces colors in SVGs it uses color values and not the keys
|
||||||
// from com.intellij.ide.ui.UITheme.colorPalette, but there are some keys that
|
// from com.intellij.ide.ui.UITheme.colorPalette, but there are some keys that
|
||||||
@@ -570,17 +638,59 @@ public class IntelliJTheme
|
|||||||
defaults.put( destKey, defaults.get( srcKey ) );
|
defaults.put( destKey, defaults.get( srcKey ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final Set<String> uiKeyExcludes;
|
||||||
|
private static final Set<String> uiKeyDoNotOverride;
|
||||||
/** Rename UI default keys (key --> value). */
|
/** Rename UI default keys (key --> value). */
|
||||||
private static final Map<String, String> uiKeyMapping = new HashMap<>();
|
private static final Map<String, String> uiKeyMapping = new HashMap<>();
|
||||||
/** Copy UI default keys (value --> key). */
|
/** Copy UI default keys (value --> key). */
|
||||||
private static final Map<String, String> uiKeyCopying = new HashMap<>();
|
private static final Map<String, String> uiKeyCopying = new LinkedHashMap<>();
|
||||||
private static final Map<String, String> uiKeyInverseMapping = new HashMap<>();
|
private static final Map<String, String> uiKeyInverseMapping = new HashMap<>();
|
||||||
private static final Map<String, String> checkboxKeyMapping = new HashMap<>();
|
private static final Map<String, String> checkboxKeyMapping = new HashMap<>();
|
||||||
private static final Map<String, String> checkboxDuplicateColors = new HashMap<>();
|
private static final Map<String, String> checkboxDuplicateColors = new HashMap<>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
// IntelliJ UI properties that are not used in FlatLaf
|
||||||
|
uiKeyExcludes = new HashSet<>( Arrays.asList(
|
||||||
|
"ActionButton.", "ActionToolbar.", "ActionsList.", "AppInspector.", "AssignedMnemonic.", "Autocomplete.",
|
||||||
|
"AvailableMnemonic.",
|
||||||
|
"BigSpinner.", "Bookmark.", "BookmarkIcon.", "BookmarkMnemonicAssigned.", "BookmarkMnemonicAvailable.",
|
||||||
|
"BookmarkMnemonicCurrent.", "BookmarkMnemonicIcon.", "Borders.", "Breakpoint.",
|
||||||
|
"Canvas.", "CodeWithMe.", "ComboBoxButton.", "CompletionPopup.", "ComplexPopup.", "Content.",
|
||||||
|
"CurrentMnemonic.", "Counter.",
|
||||||
|
"Debugger.", "DebuggerPopup.", "DebuggerTabs.", "DefaultTabs.", "Dialog.", "DialogWrapper.", "DragAndDrop.",
|
||||||
|
"Editor.", "EditorGroupsTabs.", "EditorTabs.",
|
||||||
|
"FileColor.", "FlameGraph.", "Focus.",
|
||||||
|
"Git.", "Github.", "GotItTooltip.", "Group.", "Gutter.", "GutterTooltip.",
|
||||||
|
"HeaderColor.", "HelpTooltip.", "Hg.",
|
||||||
|
"IconBadge.", "InformationHint.", "InplaceRefactoringPopup.",
|
||||||
|
"Lesson.", "Link.", "LiveIndicator.",
|
||||||
|
"MainMenu.", "MainToolbar.", "MemoryIndicator.", "MlModelBinding.", "MnemonicIcon.",
|
||||||
|
"NavBar.", "NewClass.", "NewPSD.", "Notification.", "Notifications.", "NotificationsToolwindow.",
|
||||||
|
"OnePixelDivider.", "OptionButton.", "Outline.",
|
||||||
|
"ParameterInfo.", "Plugins.", "ProgressIcon.", "PsiViewer.",
|
||||||
|
"ReviewList.", "RunWidget.",
|
||||||
|
"ScreenView.", "SearchEverywhere.", "SearchFieldWithExtension.", "SearchMatch.", "SearchOption.",
|
||||||
|
"SearchResults.", "SegmentedButton.", "Settings.", "SidePanel.", "Space.", "SpeedSearch.", "StateWidget.",
|
||||||
|
"StatusBar.",
|
||||||
|
"Tag.", "TipOfTheDay.", "ToolbarComboWidget.", "ToolWindow.",
|
||||||
|
"UIDesigner.", "UnattendedHostStatus.",
|
||||||
|
"ValidationTooltip.", "VersionControl.",
|
||||||
|
"WelcomeScreen.",
|
||||||
|
|
||||||
|
// lower case
|
||||||
|
"darcula.", "dropArea.", "icons.", "intellijlaf.", "macOSWindow.", "material.", "tooltips.",
|
||||||
|
|
||||||
|
// possible typos in .theme.json files
|
||||||
|
"Checkbox.", "Toolbar.", "Tooltip.", "UiDesigner.", "link."
|
||||||
|
) );
|
||||||
|
|
||||||
|
uiKeyDoNotOverride = new HashSet<>( Arrays.asList(
|
||||||
|
"TabbedPane.selectedForeground"
|
||||||
|
) );
|
||||||
|
|
||||||
// ComboBox
|
// ComboBox
|
||||||
uiKeyMapping.put( "ComboBox.background", "" ); // ignore
|
uiKeyMapping.put( "ComboBox.background", "" ); // ignore
|
||||||
|
uiKeyMapping.put( "ComboBox.buttonBackground", "" ); // ignore
|
||||||
uiKeyMapping.put( "ComboBox.nonEditableBackground", "ComboBox.background" );
|
uiKeyMapping.put( "ComboBox.nonEditableBackground", "ComboBox.background" );
|
||||||
uiKeyMapping.put( "ComboBox.ArrowButton.background", "ComboBox.buttonEditableBackground" );
|
uiKeyMapping.put( "ComboBox.ArrowButton.background", "ComboBox.buttonEditableBackground" );
|
||||||
uiKeyMapping.put( "ComboBox.ArrowButton.disabledIconColor", "ComboBox.buttonDisabledArrowColor" );
|
uiKeyMapping.put( "ComboBox.ArrowButton.disabledIconColor", "ComboBox.buttonDisabledArrowColor" );
|
||||||
@@ -638,9 +748,9 @@ public class IntelliJTheme
|
|||||||
uiKeyCopying.put( "Spinner.buttonDisabledSeparatorColor", "Component.disabledBorderColor" );
|
uiKeyCopying.put( "Spinner.buttonDisabledSeparatorColor", "Component.disabledBorderColor" );
|
||||||
|
|
||||||
// TabbedPane
|
// TabbedPane
|
||||||
uiKeyCopying.put( "TabbedPane.selectedBackground", "DefaultTabs.underlinedTabBackground" );
|
uiKeyMapping.put( "DefaultTabs.underlinedTabBackground", "TabbedPane.selectedBackground" );
|
||||||
uiKeyCopying.put( "TabbedPane.selectedForeground", "DefaultTabs.underlinedTabForeground" );
|
uiKeyMapping.put( "DefaultTabs.underlinedTabForeground", "TabbedPane.selectedForeground" );
|
||||||
uiKeyCopying.put( "TabbedPane.inactiveUnderlineColor", "DefaultTabs.inactiveUnderlineColor" );
|
uiKeyMapping.put( "DefaultTabs.inactiveUnderlineColor", "TabbedPane.inactiveUnderlineColor" );
|
||||||
|
|
||||||
// TitlePane
|
// TitlePane
|
||||||
uiKeyCopying.put( "TitlePane.inactiveBackground", "TitlePane.background" );
|
uiKeyCopying.put( "TitlePane.inactiveBackground", "TitlePane.background" );
|
||||||
|
|||||||
@@ -23,11 +23,14 @@ import java.awt.GraphicsEnvironment;
|
|||||||
import java.awt.Toolkit;
|
import java.awt.Toolkit;
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileReader;
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import javax.swing.text.StyleContext;
|
import javax.swing.text.StyleContext;
|
||||||
import com.formdev.flatlaf.util.LoggingFacade;
|
import com.formdev.flatlaf.util.LoggingFacade;
|
||||||
@@ -68,7 +71,7 @@ class LinuxFontPolicy
|
|||||||
if( word.endsWith( "," ) )
|
if( word.endsWith( "," ) )
|
||||||
word = word.substring( 0, word.length() - 1 ).trim();
|
word = word.substring( 0, word.length() - 1 ).trim();
|
||||||
|
|
||||||
String lword = word.toLowerCase();
|
String lword = word.toLowerCase( Locale.ENGLISH );
|
||||||
if( lword.equals( "italic" ) || lword.equals( "oblique" ) )
|
if( lword.equals( "italic" ) || lword.equals( "oblique" ) )
|
||||||
style |= Font.ITALIC;
|
style |= Font.ITALIC;
|
||||||
else if( lword.equals( "bold" ) )
|
else if( lword.equals( "bold" ) )
|
||||||
@@ -104,7 +107,7 @@ class LinuxFontPolicy
|
|||||||
size = 1;
|
size = 1;
|
||||||
|
|
||||||
// handle logical font names
|
// handle logical font names
|
||||||
String logicalFamily = mapFcName( family.toLowerCase() );
|
String logicalFamily = mapFcName( family.toLowerCase( Locale.ENGLISH ) );
|
||||||
if( logicalFamily != null )
|
if( logicalFamily != null )
|
||||||
family = logicalFamily;
|
family = logicalFamily;
|
||||||
|
|
||||||
@@ -143,7 +146,7 @@ class LinuxFontPolicy
|
|||||||
return createFont( Font.DIALOG, style, size, dsize );
|
return createFont( Font.DIALOG, style, size, dsize );
|
||||||
|
|
||||||
// check whether last work contains some font weight (e.g. Ultra-Bold or Heavy)
|
// check whether last work contains some font weight (e.g. Ultra-Bold or Heavy)
|
||||||
String lastWord = family.substring( index + 1 ).toLowerCase();
|
String lastWord = family.substring( index + 1 ).toLowerCase( Locale.ENGLISH );
|
||||||
if( lastWord.contains( "bold" ) || lastWord.contains( "heavy" ) || lastWord.contains( "black" ) )
|
if( lastWord.contains( "bold" ) || lastWord.contains( "heavy" ) || lastWord.contains( "black" ) )
|
||||||
style |= Font.BOLD;
|
style |= Font.BOLD;
|
||||||
|
|
||||||
@@ -200,7 +203,7 @@ class LinuxFontPolicy
|
|||||||
* Gets the default font for KDE from KDE configuration files.
|
* Gets the default font for KDE from KDE configuration files.
|
||||||
*
|
*
|
||||||
* The Swing fonts are not updated when the user changes system font size
|
* The Swing fonts are not updated when the user changes system font size
|
||||||
* (System Settings > Fonts > Force Font DPI). A application restart is necessary.
|
* (System Settings > Fonts > Force Font DPI). An application restart is necessary.
|
||||||
* This is the same behavior as in native KDE applications.
|
* This is the same behavior as in native KDE applications.
|
||||||
*
|
*
|
||||||
* The "display scale factor" (kdeglobals: [KScreen] > ScaleFactor) is not used
|
* The "display scale factor" (kdeglobals: [KScreen] > ScaleFactor) is not used
|
||||||
@@ -257,6 +260,7 @@ class LinuxFontPolicy
|
|||||||
return createFont( family, style, size, dsize );
|
return createFont( family, style, size, dsize );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings( "MixedMutabilityReturnType" ) // Error Prone
|
||||||
private static List<String> readConfig( String filename ) {
|
private static List<String> readConfig( String filename ) {
|
||||||
File userHome = new File( System.getProperty( "user.home" ) );
|
File userHome = new File( System.getProperty( "user.home" ) );
|
||||||
|
|
||||||
@@ -277,7 +281,9 @@ class LinuxFontPolicy
|
|||||||
|
|
||||||
// read config file
|
// read config file
|
||||||
ArrayList<String> lines = new ArrayList<>( 200 );
|
ArrayList<String> lines = new ArrayList<>( 200 );
|
||||||
try( BufferedReader reader = new BufferedReader( new FileReader( file ) ) ) {
|
try( BufferedReader reader = new BufferedReader( new InputStreamReader(
|
||||||
|
new FileInputStream( file ), StandardCharsets.US_ASCII ) ) )
|
||||||
|
{
|
||||||
String line;
|
String line;
|
||||||
while( (line = reader.readLine()) != null )
|
while( (line = reader.readLine()) != null )
|
||||||
lines.add( line );
|
lines.add( line );
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ debug*/
|
|||||||
|
|
||||||
// get invoker screen bounds
|
// get invoker screen bounds
|
||||||
Component invoker = popup.getInvoker();
|
Component invoker = popup.getInvoker();
|
||||||
invokerBounds = (invoker != null)
|
invokerBounds = (invoker != null && invoker.isShowing())
|
||||||
? new Rectangle( invoker.getLocationOnScreen(), invoker.getSize() )
|
? new Rectangle( invoker.getLocationOnScreen(), invoker.getSize() )
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
@@ -172,7 +172,7 @@ debug*/
|
|||||||
targetTopY = popupLocation.y;
|
targetTopY = popupLocation.y;
|
||||||
targetBottomY = popupLocation.y + popupSize.height;
|
targetBottomY = popupLocation.y + popupSize.height;
|
||||||
|
|
||||||
// install own event queue to supress mouse events when mouse is moved within safe triangle
|
// install own event queue to suppress mouse events when mouse is moved within safe triangle
|
||||||
if( subMenuEventQueue == null )
|
if( subMenuEventQueue == null )
|
||||||
subMenuEventQueue = new SubMenuEventQueue();
|
subMenuEventQueue = new SubMenuEventQueue();
|
||||||
|
|
||||||
|
|||||||
@@ -27,8 +27,12 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.StreamTokenizer;
|
import java.io.StreamTokenizer;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.Executable;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
@@ -271,8 +275,9 @@ class UIDefaultsLoader
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
String value = resolveValue( (String) e.getValue(), propertiesGetter );
|
String value = (String) e.getValue();
|
||||||
try {
|
try {
|
||||||
|
value = resolveValue( value, propertiesGetter );
|
||||||
defaults.put( key, parseValue( key, value, null, null, resolver, addonClassLoaders ) );
|
defaults.put( key, parseValue( key, value, null, null, resolver, addonClassLoaders ) );
|
||||||
} catch( RuntimeException ex ) {
|
} catch( RuntimeException ex ) {
|
||||||
logParseError( key, value, ex, true );
|
logParseError( key, value, ex, true );
|
||||||
@@ -297,7 +302,9 @@ class UIDefaultsLoader
|
|||||||
LoggingFacade.INSTANCE.logConfig( message, ex );
|
LoggingFacade.INSTANCE.logConfig( message, ex );
|
||||||
}
|
}
|
||||||
|
|
||||||
static String resolveValue( String value, Function<String, String> propertiesGetter ) {
|
static String resolveValue( String value, Function<String, String> propertiesGetter )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
value = value.trim();
|
value = value.trim();
|
||||||
String value0 = value;
|
String value0 = value;
|
||||||
|
|
||||||
@@ -326,7 +333,9 @@ class UIDefaultsLoader
|
|||||||
return resolveValue( newValue, propertiesGetter );
|
return resolveValue( newValue, propertiesGetter );
|
||||||
}
|
}
|
||||||
|
|
||||||
static String resolveValueFromUIManager( String value ) {
|
static String resolveValueFromUIManager( String value )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
if( value.startsWith( VARIABLE_PREFIX ) ) {
|
if( value.startsWith( VARIABLE_PREFIX ) ) {
|
||||||
@SuppressWarnings( "unchecked" )
|
@SuppressWarnings( "unchecked" )
|
||||||
Map<String, String> variables = (Map<String, String>) UIManager.get( KEY_VARIABLES );
|
Map<String, String> variables = (Map<String, String>) UIManager.get( KEY_VARIABLES );
|
||||||
@@ -334,7 +343,7 @@ class UIDefaultsLoader
|
|||||||
if( newValue == null )
|
if( newValue == null )
|
||||||
throw new IllegalArgumentException( "variable '" + value + "' not found" );
|
throw new IllegalArgumentException( "variable '" + value + "' not found" );
|
||||||
|
|
||||||
return newValue;
|
return resolveValueFromUIManager( newValue );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !value.startsWith( PROPERTY_PREFIX ) )
|
if( !value.startsWith( PROPERTY_PREFIX ) )
|
||||||
@@ -348,8 +357,11 @@ class UIDefaultsLoader
|
|||||||
// convert binary color to string
|
// convert binary color to string
|
||||||
if( newValue instanceof Color ) {
|
if( newValue instanceof Color ) {
|
||||||
Color color = (Color) newValue;
|
Color color = (Color) newValue;
|
||||||
|
int rgb = color.getRGB() & 0xffffff;
|
||||||
int alpha = color.getAlpha();
|
int alpha = color.getAlpha();
|
||||||
return String.format( (alpha != 255) ? "#%06x%02x" : "#%06x", color.getRGB() & 0xffffff, alpha );
|
return (alpha != 255)
|
||||||
|
? String.format( "#%06x%02x", rgb, alpha )
|
||||||
|
: String.format( "#%06x", rgb );
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new IllegalArgumentException( "property value type '" + newValue.getClass().getName() + "' not supported in references" );
|
throw new IllegalArgumentException( "property value type '" + newValue.getClass().getName() + "' not supported in references" );
|
||||||
@@ -362,12 +374,15 @@ class UIDefaultsLoader
|
|||||||
private static Map<Class<?>, ValueType> javaValueTypes;
|
private static Map<Class<?>, ValueType> javaValueTypes;
|
||||||
private static Map<String, ValueType> knownValueTypes;
|
private static Map<String, ValueType> knownValueTypes;
|
||||||
|
|
||||||
static Object parseValue( String key, String value, Class<?> valueType ) {
|
static Object parseValue( String key, String value, Class<?> valueType )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
return parseValue( key, value, valueType, null, v -> v, Collections.emptyList() );
|
return parseValue( key, value, valueType, null, v -> v, Collections.emptyList() );
|
||||||
}
|
}
|
||||||
|
|
||||||
static Object parseValue( String key, String value, Class<?> javaValueType, ValueType[] resultValueType,
|
static Object parseValue( String key, String value, Class<?> javaValueType, ValueType[] resultValueType,
|
||||||
Function<String, String> resolver, List<ClassLoader> addonClassLoaders )
|
Function<String, String> resolver, List<ClassLoader> addonClassLoaders )
|
||||||
|
throws IllegalArgumentException
|
||||||
{
|
{
|
||||||
if( resultValueType == null )
|
if( resultValueType == null )
|
||||||
resultValueType = tempResultValueType;
|
resultValueType = tempResultValueType;
|
||||||
@@ -397,7 +412,7 @@ class UIDefaultsLoader
|
|||||||
if( value.startsWith( "if(" ) && value.endsWith( ")" ) ) {
|
if( value.startsWith( "if(" ) && value.endsWith( ")" ) ) {
|
||||||
List<String> params = splitFunctionParams( value.substring( 3, value.length() - 1 ), ',' );
|
List<String> params = splitFunctionParams( value.substring( 3, value.length() - 1 ), ',' );
|
||||||
if( params.size() != 3 )
|
if( params.size() != 3 )
|
||||||
throwMissingParametersException( value );
|
throw newMissingParametersException( value );
|
||||||
|
|
||||||
boolean ifCondition = parseCondition( params.get( 0 ), resolver, addonClassLoaders );
|
boolean ifCondition = parseCondition( params.get( 0 ), resolver, addonClassLoaders );
|
||||||
String ifValue = params.get( ifCondition ? 1 : 2 );
|
String ifValue = params.get( ifCondition ? 1 : 2 );
|
||||||
@@ -537,7 +552,7 @@ class UIDefaultsLoader
|
|||||||
case INTEGERORFLOAT:return parseIntegerOrFloat( value );
|
case INTEGERORFLOAT:return parseIntegerOrFloat( value );
|
||||||
case FLOAT: return parseFloat( value );
|
case FLOAT: return parseFloat( value );
|
||||||
case BORDER: return parseBorder( value, resolver, addonClassLoaders );
|
case BORDER: return parseBorder( value, resolver, addonClassLoaders );
|
||||||
case ICON: return parseInstance( value, addonClassLoaders );
|
case ICON: return parseInstance( value, resolver, addonClassLoaders );
|
||||||
case INSETS: return parseInsets( value );
|
case INSETS: return parseInsets( value );
|
||||||
case DIMENSION: return parseDimension( value );
|
case DIMENSION: return parseDimension( value );
|
||||||
case COLOR: return parseColorOrFunction( value, resolver );
|
case COLOR: return parseColorOrFunction( value, resolver );
|
||||||
@@ -546,7 +561,7 @@ class UIDefaultsLoader
|
|||||||
case SCALEDFLOAT: return parseScaledFloat( value );
|
case SCALEDFLOAT: return parseScaledFloat( value );
|
||||||
case SCALEDINSETS: return parseScaledInsets( value );
|
case SCALEDINSETS: return parseScaledInsets( value );
|
||||||
case SCALEDDIMENSION:return parseScaledDimension( value );
|
case SCALEDDIMENSION:return parseScaledDimension( value );
|
||||||
case INSTANCE: return parseInstance( value, addonClassLoaders );
|
case INSTANCE: return parseInstance( value, resolver, addonClassLoaders );
|
||||||
case CLASS: return parseClass( value, addonClassLoaders );
|
case CLASS: return parseClass( value, addonClassLoaders );
|
||||||
case GRAYFILTER: return parseGrayFilter( value );
|
case GRAYFILTER: return parseGrayFilter( value );
|
||||||
case UNKNOWN:
|
case UNKNOWN:
|
||||||
@@ -608,9 +623,11 @@ class UIDefaultsLoader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object parseBorder( String value, Function<String, String> resolver, List<ClassLoader> addonClassLoaders ) {
|
private static Object parseBorder( String value, Function<String, String> resolver, List<ClassLoader> addonClassLoaders )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
if( value.indexOf( ',' ) >= 0 ) {
|
if( value.indexOf( ',' ) >= 0 ) {
|
||||||
// top,left,bottom,right[,lineColor[,lineThickness[,arc]]]
|
// Syntax: top,left,bottom,right[,lineColor[,lineThickness[,arc]]]
|
||||||
List<String> parts = splitFunctionParams( value, ',' );
|
List<String> parts = splitFunctionParams( value, ',' );
|
||||||
Insets insets = parseInsets( value );
|
Insets insets = parseInsets( value );
|
||||||
ColorUIResource lineColor = (parts.size() >= 5)
|
ColorUIResource lineColor = (parts.size() >= 5)
|
||||||
@@ -625,13 +642,29 @@ class UIDefaultsLoader
|
|||||||
: new FlatEmptyBorder( insets );
|
: new FlatEmptyBorder( insets );
|
||||||
};
|
};
|
||||||
} else
|
} else
|
||||||
return parseInstance( value, addonClassLoaders );
|
return parseInstance( value, resolver, addonClassLoaders );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object parseInstance( String value, List<ClassLoader> addonClassLoaders ) {
|
private static Object parseInstance( String value, Function<String, String> resolver, List<ClassLoader> addonClassLoaders ) {
|
||||||
return (LazyValue) t -> {
|
return (LazyValue) t -> {
|
||||||
try {
|
try {
|
||||||
return findClass( value, addonClassLoaders ).getDeclaredConstructor().newInstance();
|
if( value.indexOf( ',' ) >= 0 ) {
|
||||||
|
// Syntax: className,param1,param2,...
|
||||||
|
List<String> parts = splitFunctionParams( value, ',' );
|
||||||
|
String className = parts.get( 0 );
|
||||||
|
Class<?> cls = findClass( className, addonClassLoaders );
|
||||||
|
|
||||||
|
Constructor<?>[] constructors = cls.getDeclaredConstructors();
|
||||||
|
Object result = invokeConstructorOrStaticMethod( constructors, parts, resolver );
|
||||||
|
if( result != null )
|
||||||
|
return result;
|
||||||
|
|
||||||
|
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to instantiate '" + className
|
||||||
|
+ "': no constructor found for parameters '"
|
||||||
|
+ value.substring( value.indexOf( ',' + 1 ) ) + "'.", null );
|
||||||
|
return null;
|
||||||
|
} else
|
||||||
|
return findClass( value, addonClassLoaders ).getDeclaredConstructor().newInstance();
|
||||||
} catch( Exception ex ) {
|
} catch( Exception ex ) {
|
||||||
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to instantiate '" + value + "'.", ex );
|
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to instantiate '" + value + "'.", ex );
|
||||||
return null;
|
return null;
|
||||||
@@ -668,7 +701,9 @@ class UIDefaultsLoader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Insets parseInsets( String value ) {
|
private static Insets parseInsets( String value )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
List<String> numbers = StringUtils.split( value, ',', true, false );
|
List<String> numbers = StringUtils.split( value, ',', true, false );
|
||||||
try {
|
try {
|
||||||
return new InsetsUIResource(
|
return new InsetsUIResource(
|
||||||
@@ -681,7 +716,9 @@ class UIDefaultsLoader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Dimension parseDimension( String value ) {
|
private static Dimension parseDimension( String value )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
List<String> numbers = StringUtils.split( value, ',', true, false );
|
List<String> numbers = StringUtils.split( value, ',', true, false );
|
||||||
try {
|
try {
|
||||||
return new DimensionUIResource(
|
return new DimensionUIResource(
|
||||||
@@ -692,7 +729,9 @@ class UIDefaultsLoader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object parseColorOrFunction( String value, Function<String, String> resolver ) {
|
private static Object parseColorOrFunction( String value, Function<String, String> resolver )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
if( value.endsWith( ")" ) )
|
if( value.endsWith( ")" ) )
|
||||||
return parseColorFunctions( value, resolver );
|
return parseColorFunctions( value, resolver );
|
||||||
|
|
||||||
@@ -702,10 +741,10 @@ class UIDefaultsLoader
|
|||||||
/**
|
/**
|
||||||
* Parses a hex color in {@code #RGB}, {@code #RGBA}, {@code #RRGGBB} or {@code #RRGGBBAA}
|
* Parses a hex color in {@code #RGB}, {@code #RGBA}, {@code #RRGGBB} or {@code #RRGGBBAA}
|
||||||
* format and returns it as color object.
|
* format and returns it as color object.
|
||||||
*
|
|
||||||
* @throws IllegalArgumentException
|
|
||||||
*/
|
*/
|
||||||
static ColorUIResource parseColor( String value ) {
|
static ColorUIResource parseColor( String value )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
int rgba = parseColorRGBA( value );
|
int rgba = parseColorRGBA( value );
|
||||||
return ((rgba & 0xff000000) == 0xff000000)
|
return ((rgba & 0xff000000) == 0xff000000)
|
||||||
? new ColorUIResource( rgba )
|
? new ColorUIResource( rgba )
|
||||||
@@ -716,10 +755,10 @@ class UIDefaultsLoader
|
|||||||
* Parses a hex color in {@code #RGB}, {@code #RGBA}, {@code #RRGGBB} or {@code #RRGGBBAA}
|
* Parses a hex color in {@code #RGB}, {@code #RGBA}, {@code #RRGGBB} or {@code #RRGGBBAA}
|
||||||
* format and returns it as {@code rgba} integer suitable for {@link java.awt.Color},
|
* format and returns it as {@code rgba} integer suitable for {@link java.awt.Color},
|
||||||
* which includes alpha component in bits 24-31.
|
* which includes alpha component in bits 24-31.
|
||||||
*
|
|
||||||
* @throws IllegalArgumentException
|
|
||||||
*/
|
*/
|
||||||
static int parseColorRGBA( String value ) {
|
static int parseColorRGBA( String value )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
int len = value.length();
|
int len = value.length();
|
||||||
if( (len != 4 && len != 5 && len != 7 && len != 9) || value.charAt( 0 ) != '#' )
|
if( (len != 4 && len != 5 && len != 7 && len != 9) || value.charAt( 0 ) != '#' )
|
||||||
throw newInvalidColorException( value );
|
throw newInvalidColorException( value );
|
||||||
@@ -760,7 +799,9 @@ class UIDefaultsLoader
|
|||||||
return new IllegalArgumentException( "invalid color '" + value + "'" );
|
return new IllegalArgumentException( "invalid color '" + value + "'" );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object parseColorFunctions( String value, Function<String, String> resolver ) {
|
private static Object parseColorFunctions( String value, Function<String, String> resolver )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
int paramsStart = value.indexOf( '(' );
|
int paramsStart = value.indexOf( '(' );
|
||||||
if( paramsStart < 0 )
|
if( paramsStart < 0 )
|
||||||
throw new IllegalArgumentException( "missing opening parenthesis in function '" + value + "'" );
|
throw new IllegalArgumentException( "missing opening parenthesis in function '" + value + "'" );
|
||||||
@@ -768,7 +809,7 @@ class UIDefaultsLoader
|
|||||||
String function = StringUtils.substringTrimmed( value, 0, paramsStart );
|
String function = StringUtils.substringTrimmed( value, 0, paramsStart );
|
||||||
List<String> params = splitFunctionParams( value.substring( paramsStart + 1, value.length() - 1 ), ',' );
|
List<String> params = splitFunctionParams( value.substring( paramsStart + 1, value.length() - 1 ), ',' );
|
||||||
if( params.isEmpty() )
|
if( params.isEmpty() )
|
||||||
throwMissingParametersException( value );
|
throw newMissingParametersException( value );
|
||||||
|
|
||||||
if( parseColorDepth > 100 )
|
if( parseColorDepth > 100 )
|
||||||
throw new IllegalArgumentException( "endless recursion in color function '" + value + "'" );
|
throw new IllegalArgumentException( "endless recursion in color function '" + value + "'" );
|
||||||
@@ -813,9 +854,11 @@ class UIDefaultsLoader
|
|||||||
* This "if" function is only used if the "if" is passed as parameter to another
|
* This "if" function is only used if the "if" is passed as parameter to another
|
||||||
* color function. Otherwise, the general "if" function is used.
|
* color function. Otherwise, the general "if" function is used.
|
||||||
*/
|
*/
|
||||||
private static Object parseColorIf( String value, List<String> params, Function<String, String> resolver ) {
|
private static Object parseColorIf( String value, List<String> params, Function<String, String> resolver )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
if( params.size() != 3 )
|
if( params.size() != 3 )
|
||||||
throwMissingParametersException( value );
|
throw newMissingParametersException( value );
|
||||||
|
|
||||||
boolean ifCondition = parseCondition( params.get( 0 ), resolver, Collections.emptyList() );
|
boolean ifCondition = parseCondition( params.get( 0 ), resolver, Collections.emptyList() );
|
||||||
String ifValue = params.get( ifCondition ? 1 : 2 );
|
String ifValue = params.get( ifCondition ? 1 : 2 );
|
||||||
@@ -827,9 +870,11 @@ class UIDefaultsLoader
|
|||||||
* - name: system color name
|
* - name: system color name
|
||||||
* - defaultValue: default color value used if system color is not available
|
* - defaultValue: default color value used if system color is not available
|
||||||
*/
|
*/
|
||||||
private static Object parseColorSystemColor( String value, List<String> params, Function<String, String> resolver ) {
|
private static Object parseColorSystemColor( String value, List<String> params, Function<String, String> resolver )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
if( params.size() < 1 )
|
if( params.size() < 1 )
|
||||||
throwMissingParametersException( value );
|
throw newMissingParametersException( value );
|
||||||
|
|
||||||
ColorUIResource systemColor = getSystemColor( params.get( 0 ) );
|
ColorUIResource systemColor = getSystemColor( params.get( 0 ) );
|
||||||
if( systemColor != null )
|
if( systemColor != null )
|
||||||
@@ -869,6 +914,7 @@ class UIDefaultsLoader
|
|||||||
*/
|
*/
|
||||||
private static ColorUIResource parseColorRgbOrRgba( boolean hasAlpha, List<String> params,
|
private static ColorUIResource parseColorRgbOrRgba( boolean hasAlpha, List<String> params,
|
||||||
Function<String, String> resolver )
|
Function<String, String> resolver )
|
||||||
|
throws IllegalArgumentException
|
||||||
{
|
{
|
||||||
if( hasAlpha && params.size() == 2 ) {
|
if( hasAlpha && params.size() == 2 ) {
|
||||||
// syntax rgba(color,alpha), which allows adding alpha to any color
|
// syntax rgba(color,alpha), which allows adding alpha to any color
|
||||||
@@ -898,7 +944,9 @@ class UIDefaultsLoader
|
|||||||
* - lightness: a percentage 0-100%
|
* - lightness: a percentage 0-100%
|
||||||
* - alpha: a percentage 0-100%
|
* - alpha: a percentage 0-100%
|
||||||
*/
|
*/
|
||||||
private static ColorUIResource parseColorHslOrHsla( boolean hasAlpha, List<String> params ) {
|
private static ColorUIResource parseColorHslOrHsla( boolean hasAlpha, List<String> params )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
int hue = parseInteger( params.get( 0 ), 0, 360, false );
|
int hue = parseInteger( params.get( 0 ), 0, 360, false );
|
||||||
int saturation = parsePercentage( params.get( 1 ) );
|
int saturation = parsePercentage( params.get( 1 ) );
|
||||||
int lightness = parsePercentage( params.get( 2 ) );
|
int lightness = parsePercentage( params.get( 2 ) );
|
||||||
@@ -918,6 +966,7 @@ class UIDefaultsLoader
|
|||||||
*/
|
*/
|
||||||
private static Object parseColorHSLIncreaseDecrease( int hslIndex, boolean increase,
|
private static Object parseColorHSLIncreaseDecrease( int hslIndex, boolean increase,
|
||||||
List<String> params, Function<String, String> resolver )
|
List<String> params, Function<String, String> resolver )
|
||||||
|
throws IllegalArgumentException
|
||||||
{
|
{
|
||||||
String colorStr = params.get( 0 );
|
String colorStr = params.get( 0 );
|
||||||
int amount = parsePercentage( params.get( 1 ) );
|
int amount = parsePercentage( params.get( 1 ) );
|
||||||
@@ -961,7 +1010,9 @@ class UIDefaultsLoader
|
|||||||
* - amount: percentage 0-100%
|
* - amount: percentage 0-100%
|
||||||
* - options: [derived] [lazy]
|
* - options: [derived] [lazy]
|
||||||
*/
|
*/
|
||||||
private static Object parseColorFade( List<String> params, Function<String, String> resolver ) {
|
private static Object parseColorFade( List<String> params, Function<String, String> resolver )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
String colorStr = params.get( 0 );
|
String colorStr = params.get( 0 );
|
||||||
int amount = parsePercentage( params.get( 1 ) );
|
int amount = parsePercentage( params.get( 1 ) );
|
||||||
boolean derived = false;
|
boolean derived = false;
|
||||||
@@ -995,7 +1046,9 @@ class UIDefaultsLoader
|
|||||||
* - angle: number of degrees to rotate
|
* - angle: number of degrees to rotate
|
||||||
* - options: [derived]
|
* - options: [derived]
|
||||||
*/
|
*/
|
||||||
private static Object parseColorSpin( List<String> params, Function<String, String> resolver ) {
|
private static Object parseColorSpin( List<String> params, Function<String, String> resolver )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
String colorStr = params.get( 0 );
|
String colorStr = params.get( 0 );
|
||||||
int amount = parseInteger( params.get( 1 ) );
|
int amount = parseInteger( params.get( 1 ) );
|
||||||
boolean derived = false;
|
boolean derived = false;
|
||||||
@@ -1023,6 +1076,7 @@ class UIDefaultsLoader
|
|||||||
*/
|
*/
|
||||||
private static Object parseColorChange( int hslIndex,
|
private static Object parseColorChange( int hslIndex,
|
||||||
List<String> params, Function<String, String> resolver )
|
List<String> params, Function<String, String> resolver )
|
||||||
|
throws IllegalArgumentException
|
||||||
{
|
{
|
||||||
String colorStr = params.get( 0 );
|
String colorStr = params.get( 0 );
|
||||||
int value = (hslIndex == 0)
|
int value = (hslIndex == 0)
|
||||||
@@ -1051,7 +1105,9 @@ class UIDefaultsLoader
|
|||||||
* - weight: the weight (in range 0-100%) to mix the two colors
|
* - weight: the weight (in range 0-100%) to mix the two colors
|
||||||
* larger weight uses more of first color, smaller weight more of second color
|
* larger weight uses more of first color, smaller weight more of second color
|
||||||
*/
|
*/
|
||||||
private static Object parseColorMix( String color1Str, List<String> params, Function<String, String> resolver ) {
|
private static Object parseColorMix( String color1Str, List<String> params, Function<String, String> resolver )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
if( color1Str == null )
|
if( color1Str == null )
|
||||||
color1Str = params.get( i++ );
|
color1Str = params.get( i++ );
|
||||||
@@ -1078,7 +1134,9 @@ class UIDefaultsLoader
|
|||||||
* - threshold: the threshold (in range 0-100%) to specify where the transition
|
* - threshold: the threshold (in range 0-100%) to specify where the transition
|
||||||
* from "dark" to "light" is (default is 43%)
|
* from "dark" to "light" is (default is 43%)
|
||||||
*/
|
*/
|
||||||
private static Object parseColorContrast( List<String> params, Function<String, String> resolver ) {
|
private static Object parseColorContrast( List<String> params, Function<String, String> resolver )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
String colorStr = params.get( 0 );
|
String colorStr = params.get( 0 );
|
||||||
String darkStr = params.get( 1 );
|
String darkStr = params.get( 1 );
|
||||||
String lightStr = params.get( 2 );
|
String lightStr = params.get( 2 );
|
||||||
@@ -1104,7 +1162,9 @@ class UIDefaultsLoader
|
|||||||
* the alpha of this color is used as weight to mix the two colors
|
* the alpha of this color is used as weight to mix the two colors
|
||||||
* - background: a background color (e.g. #f00) or a color function
|
* - background: a background color (e.g. #f00) or a color function
|
||||||
*/
|
*/
|
||||||
private static ColorUIResource parseColorOver( List<String> params, Function<String, String> resolver ) {
|
private static ColorUIResource parseColorOver( List<String> params, Function<String, String> resolver )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
String foregroundStr = params.get( 0 );
|
String foregroundStr = params.get( 0 );
|
||||||
String backgroundStr = params.get( 1 );
|
String backgroundStr = params.get( 1 );
|
||||||
|
|
||||||
@@ -1128,6 +1188,7 @@ class UIDefaultsLoader
|
|||||||
|
|
||||||
private static Object parseFunctionBaseColor( String colorStr, ColorFunction function,
|
private static Object parseFunctionBaseColor( String colorStr, ColorFunction function,
|
||||||
boolean derived, Function<String, String> resolver )
|
boolean derived, Function<String, String> resolver )
|
||||||
|
throws IllegalArgumentException
|
||||||
{
|
{
|
||||||
// parse base color
|
// parse base color
|
||||||
String resolvedColorStr = resolver.apply( colorStr );
|
String resolvedColorStr = resolver.apply( colorStr );
|
||||||
@@ -1159,7 +1220,9 @@ class UIDefaultsLoader
|
|||||||
/**
|
/**
|
||||||
* Syntax: [normal] [bold|+bold|-bold] [italic|+italic|-italic] [<size>|+<incr>|-<decr>|<percent>%] [family[, family]] [$baseFontKey]
|
* Syntax: [normal] [bold|+bold|-bold] [italic|+italic|-italic] [<size>|+<incr>|-<decr>|<percent>%] [family[, family]] [$baseFontKey]
|
||||||
*/
|
*/
|
||||||
private static Object parseFont( String value ) {
|
private static Object parseFont( String value )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
Object font = fontCache.get( value );
|
Object font = fontCache.get( value );
|
||||||
if( font != null )
|
if( font != null )
|
||||||
return font;
|
return font;
|
||||||
@@ -1257,7 +1320,9 @@ class UIDefaultsLoader
|
|||||||
return font;
|
return font;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int parsePercentage( String value ) {
|
private static int parsePercentage( String value )
|
||||||
|
throws IllegalArgumentException, NumberFormatException
|
||||||
|
{
|
||||||
if( !value.endsWith( "%" ) )
|
if( !value.endsWith( "%" ) )
|
||||||
throw new NumberFormatException( "invalid percentage '" + value + "'" );
|
throw new NumberFormatException( "invalid percentage '" + value + "'" );
|
||||||
|
|
||||||
@@ -1273,7 +1338,9 @@ class UIDefaultsLoader
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Boolean parseBoolean( String value ) {
|
private static Boolean parseBoolean( String value )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
switch( value ) {
|
switch( value ) {
|
||||||
case "false": return false;
|
case "false": return false;
|
||||||
case "true": return true;
|
case "true": return true;
|
||||||
@@ -1281,13 +1348,17 @@ class UIDefaultsLoader
|
|||||||
throw new IllegalArgumentException( "invalid boolean '" + value + "'" );
|
throw new IllegalArgumentException( "invalid boolean '" + value + "'" );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Character parseCharacter( String value ) {
|
private static Character parseCharacter( String value )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
if( value.length() != 1 )
|
if( value.length() != 1 )
|
||||||
throw new IllegalArgumentException( "invalid character '" + value + "'" );
|
throw new IllegalArgumentException( "invalid character '" + value + "'" );
|
||||||
return value.charAt( 0 );
|
return value.charAt( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Integer parseInteger( String value, int min, int max, boolean allowPercentage ) {
|
private static Integer parseInteger( String value, int min, int max, boolean allowPercentage )
|
||||||
|
throws IllegalArgumentException, NumberFormatException
|
||||||
|
{
|
||||||
if( allowPercentage && value.endsWith( "%" ) ) {
|
if( allowPercentage && value.endsWith( "%" ) ) {
|
||||||
int percent = parsePercentage( value );
|
int percent = parsePercentage( value );
|
||||||
return (max * percent) / 100;
|
return (max * percent) / 100;
|
||||||
@@ -1299,7 +1370,9 @@ class UIDefaultsLoader
|
|||||||
return integer;
|
return integer;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Integer parseInteger( String value ) {
|
private static Integer parseInteger( String value )
|
||||||
|
throws NumberFormatException
|
||||||
|
{
|
||||||
try {
|
try {
|
||||||
return Integer.parseInt( value );
|
return Integer.parseInt( value );
|
||||||
} catch( NumberFormatException ex ) {
|
} catch( NumberFormatException ex ) {
|
||||||
@@ -1307,7 +1380,9 @@ class UIDefaultsLoader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Number parseIntegerOrFloat( String value ) {
|
private static Number parseIntegerOrFloat( String value )
|
||||||
|
throws NumberFormatException
|
||||||
|
{
|
||||||
try {
|
try {
|
||||||
return Integer.parseInt( value );
|
return Integer.parseInt( value );
|
||||||
} catch( NumberFormatException ex ) {
|
} catch( NumberFormatException ex ) {
|
||||||
@@ -1319,7 +1394,9 @@ class UIDefaultsLoader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Float parseFloat( String value ) {
|
private static Float parseFloat( String value )
|
||||||
|
throws NumberFormatException
|
||||||
|
{
|
||||||
try {
|
try {
|
||||||
return Float.parseFloat( value );
|
return Float.parseFloat( value );
|
||||||
} catch( NumberFormatException ex ) {
|
} catch( NumberFormatException ex ) {
|
||||||
@@ -1327,35 +1404,45 @@ class UIDefaultsLoader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ActiveValue parseScaledInteger( String value ) {
|
private static ActiveValue parseScaledInteger( String value )
|
||||||
|
throws NumberFormatException
|
||||||
|
{
|
||||||
int val = parseInteger( value );
|
int val = parseInteger( value );
|
||||||
return t -> {
|
return t -> {
|
||||||
return UIScale.scale( val );
|
return UIScale.scale( val );
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ActiveValue parseScaledFloat( String value ) {
|
private static ActiveValue parseScaledFloat( String value )
|
||||||
|
throws NumberFormatException
|
||||||
|
{
|
||||||
float val = parseFloat( value );
|
float val = parseFloat( value );
|
||||||
return t -> {
|
return t -> {
|
||||||
return UIScale.scale( val );
|
return UIScale.scale( val );
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ActiveValue parseScaledInsets( String value ) {
|
private static ActiveValue parseScaledInsets( String value )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
Insets insets = parseInsets( value );
|
Insets insets = parseInsets( value );
|
||||||
return t -> {
|
return t -> {
|
||||||
return UIScale.scale( insets );
|
return UIScale.scale( insets );
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ActiveValue parseScaledDimension( String value ) {
|
private static ActiveValue parseScaledDimension( String value )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
Dimension dimension = parseDimension( value );
|
Dimension dimension = parseDimension( value );
|
||||||
return t -> {
|
return t -> {
|
||||||
return UIScale.scale( dimension );
|
return UIScale.scale( dimension );
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object parseGrayFilter( String value ) {
|
private static Object parseGrayFilter( String value )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
List<String> numbers = StringUtils.split( value, ',', true, false );
|
List<String> numbers = StringUtils.split( value, ',', true, false );
|
||||||
try {
|
try {
|
||||||
int brightness = Integer.parseInt( numbers.get( 0 ) );
|
int brightness = Integer.parseInt( numbers.get( 0 ) );
|
||||||
@@ -1399,6 +1486,86 @@ class UIDefaultsLoader
|
|||||||
return strs;
|
return strs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Object invokeConstructorOrStaticMethod( Executable[] constructorsOrMethods,
|
||||||
|
List<String> parts, Function<String, String> resolver )
|
||||||
|
throws Exception
|
||||||
|
{
|
||||||
|
// order constructors/methods by parameter types:
|
||||||
|
// - String parameters to the end
|
||||||
|
// - int before float parameters
|
||||||
|
constructorsOrMethods = constructorsOrMethods.clone();
|
||||||
|
Arrays.sort( constructorsOrMethods, (c1, c2) -> {
|
||||||
|
Class<?>[] ptypes1 = c1.getParameterTypes();
|
||||||
|
Class<?>[] ptypes2 = c2.getParameterTypes();
|
||||||
|
if( ptypes1.length != ptypes2.length )
|
||||||
|
return ptypes1.length - ptypes2.length;
|
||||||
|
|
||||||
|
for( int i = 0; i < ptypes1.length; i++ ) {
|
||||||
|
Class<?> pt1 = ptypes1[i];
|
||||||
|
Class<?> pt2 = ptypes2[i];
|
||||||
|
|
||||||
|
if( pt1 == pt2 )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// order methods with String parameters to the end
|
||||||
|
if( pt1 == String.class )
|
||||||
|
return 2;
|
||||||
|
if( pt2 == String.class )
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
// order int before float
|
||||||
|
if( pt1 == int.class )
|
||||||
|
return -1;
|
||||||
|
if( pt2 == int.class )
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
} );
|
||||||
|
|
||||||
|
// search for best constructor/method for given parameter values
|
||||||
|
for( Executable cm : constructorsOrMethods ) {
|
||||||
|
if( cm.getParameterCount() != parts.size() - 1 )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Object[] params = parseMethodParams( cm.getParameterTypes(), parts, resolver );
|
||||||
|
if( params == null )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// invoke constructor or static method
|
||||||
|
if( cm instanceof Constructor )
|
||||||
|
return ((Constructor<?>)cm).newInstance( params );
|
||||||
|
else
|
||||||
|
return ((Method)cm).invoke( null, params );
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Object[] parseMethodParams( Class<?>[] paramTypes, List<String> parts, Function<String, String> resolver ) {
|
||||||
|
Object[] params = new Object[paramTypes.length];
|
||||||
|
try {
|
||||||
|
for( int i = 0; i < params.length; i++ ) {
|
||||||
|
Class<?> paramType = paramTypes[i];
|
||||||
|
String paramValue = parts.get( i + 1 );
|
||||||
|
if( paramType == String.class )
|
||||||
|
params[i] = paramValue;
|
||||||
|
else if( paramType == boolean.class )
|
||||||
|
params[i] = parseBoolean( paramValue );
|
||||||
|
else if( paramType == int.class )
|
||||||
|
params[i] = parseInteger( paramValue );
|
||||||
|
else if( paramType == float.class )
|
||||||
|
params[i] = parseFloat( paramValue );
|
||||||
|
else if( paramType == Color.class )
|
||||||
|
params[i] = parseColorOrFunction( resolver.apply( paramValue ), resolver );
|
||||||
|
else
|
||||||
|
return null; // unsupported parameter type
|
||||||
|
}
|
||||||
|
} catch( IllegalArgumentException ex ) {
|
||||||
|
return null; // failed to parse parameter for expected parameter type
|
||||||
|
}
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For use in LazyValue to get value for given key from UIManager and report error
|
* For use in LazyValue to get value for given key from UIManager and report error
|
||||||
* if not found. If key is prefixed by '?', then no error is reported.
|
* if not found. If key is prefixed by '?', then no error is reported.
|
||||||
@@ -1416,7 +1583,7 @@ class UIDefaultsLoader
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void throwMissingParametersException( String value ) {
|
private static IllegalArgumentException newMissingParametersException( String value ) {
|
||||||
throw new IllegalArgumentException( "missing parameters in function '" + value + "'" );
|
return new IllegalArgumentException( "missing parameters in function '" + value + "'" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,8 +53,8 @@ public class FlatInternalFrameCloseIcon
|
|||||||
|
|
||||||
g.setColor( FlatButtonUI.buttonStateColor( c, c.getForeground(), null, null, hoverForeground, pressedForeground ) );
|
g.setColor( FlatButtonUI.buttonStateColor( c, c.getForeground(), null, null, hoverForeground, pressedForeground ) );
|
||||||
|
|
||||||
float mx = width / 2;
|
float mx = width / 2f;
|
||||||
float my = height / 2;
|
float my = height / 2f;
|
||||||
float r = 3.25f;
|
float r = 3.25f;
|
||||||
|
|
||||||
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD, 4 );
|
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD, 4 );
|
||||||
|
|||||||
@@ -90,12 +90,12 @@ public class FlatTabbedPaneCloseIcon
|
|||||||
closeSize.width, closeSize.height, closeArc, closeArc );
|
closeSize.width, closeSize.height, closeArc, closeArc );
|
||||||
}
|
}
|
||||||
|
|
||||||
// set cross color
|
// set color of cross
|
||||||
Color fg = FlatButtonUI.buttonStateColor( c, closeForeground, null, null, closeHoverForeground, closePressedForeground );
|
Color fg = FlatButtonUI.buttonStateColor( c, closeForeground, null, null, closeHoverForeground, closePressedForeground );
|
||||||
g.setColor( FlatUIUtils.deriveColor( fg, c.getForeground() ) );
|
g.setColor( FlatUIUtils.deriveColor( fg, c.getForeground() ) );
|
||||||
|
|
||||||
float mx = width / 2;
|
float mx = width / 2f;
|
||||||
float my = height / 2;
|
float my = height / 2f;
|
||||||
float r = ((bg != null) ? closeCrossFilledSize : closeCrossPlainSize) / 2;
|
float r = ((bg != null) ? closeCrossFilledSize : closeCrossPlainSize) / 2;
|
||||||
|
|
||||||
// paint cross
|
// paint cross
|
||||||
|
|||||||
@@ -57,11 +57,11 @@ public class FlatTreeOpenIcon
|
|||||||
double arc = 1.5;
|
double arc = 1.5;
|
||||||
double arc2 = 0.5;
|
double arc2 = 0.5;
|
||||||
path = FlatUIUtils.createPath( false,
|
path = FlatUIUtils.createPath( false,
|
||||||
// bottom-left of opend part
|
// bottom-left of opened part
|
||||||
2,13.5,
|
2,13.5,
|
||||||
// top-left of opend part
|
// top-left of opened part
|
||||||
FlatUIUtils.ROUNDED, 4.5,7.5, arc,
|
FlatUIUtils.ROUNDED, 4.5,7.5, arc,
|
||||||
// top-right of opend part
|
// top-right of opened part
|
||||||
FlatUIUtils.ROUNDED, 15.5,7.5, arc2,
|
FlatUIUtils.ROUNDED, 15.5,7.5, arc2,
|
||||||
|
|
||||||
// bottom-right
|
// bottom-right
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import java.awt.Component;
|
|||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.RenderingHints;
|
import java.awt.RenderingHints;
|
||||||
import javax.swing.UIManager;
|
|
||||||
import com.formdev.flatlaf.ui.FlatButtonUI;
|
import com.formdev.flatlaf.ui.FlatButtonUI;
|
||||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||||
@@ -30,6 +29,7 @@ import com.formdev.flatlaf.util.HiDPIUtils;
|
|||||||
* Base class for window icons.
|
* Base class for window icons.
|
||||||
*
|
*
|
||||||
* @uiDefault TitlePane.buttonSize Dimension
|
* @uiDefault TitlePane.buttonSize Dimension
|
||||||
|
* @uiDefault TitlePane.buttonSymbolHeight int
|
||||||
* @uiDefault TitlePane.buttonHoverBackground Color
|
* @uiDefault TitlePane.buttonHoverBackground Color
|
||||||
* @uiDefault TitlePane.buttonPressedBackground Color
|
* @uiDefault TitlePane.buttonPressedBackground Color
|
||||||
*
|
*
|
||||||
@@ -38,17 +38,22 @@ import com.formdev.flatlaf.util.HiDPIUtils;
|
|||||||
public abstract class FlatWindowAbstractIcon
|
public abstract class FlatWindowAbstractIcon
|
||||||
extends FlatAbstractIcon
|
extends FlatAbstractIcon
|
||||||
{
|
{
|
||||||
|
private final int symbolHeight;
|
||||||
private final Color hoverBackground;
|
private final Color hoverBackground;
|
||||||
private final Color pressedBackground;
|
private final Color pressedBackground;
|
||||||
|
|
||||||
public FlatWindowAbstractIcon() {
|
/** @since 3.2 */
|
||||||
this( UIManager.getDimension( "TitlePane.buttonSize" ),
|
protected FlatWindowAbstractIcon( String windowStyle ) {
|
||||||
UIManager.getColor( "TitlePane.buttonHoverBackground" ),
|
this( FlatUIUtils.getSubUIDimension( "TitlePane.buttonSize", windowStyle ),
|
||||||
UIManager.getColor( "TitlePane.buttonPressedBackground" ) );
|
FlatUIUtils.getSubUIInt( "TitlePane.buttonSymbolHeight", windowStyle, 10 ),
|
||||||
|
FlatUIUtils.getSubUIColor( "TitlePane.buttonHoverBackground", windowStyle ),
|
||||||
|
FlatUIUtils.getSubUIColor( "TitlePane.buttonPressedBackground", windowStyle ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public FlatWindowAbstractIcon( Dimension size, Color hoverBackground, Color pressedBackground ) {
|
/** @since 3.2 */
|
||||||
|
protected FlatWindowAbstractIcon( Dimension size, int symbolHeight, Color hoverBackground, Color pressedBackground ) {
|
||||||
super( size.width, size.height, null );
|
super( size.width, size.height, null );
|
||||||
|
this.symbolHeight = symbolHeight;
|
||||||
this.hoverBackground = hoverBackground;
|
this.hoverBackground = hoverBackground;
|
||||||
this.pressedBackground = pressedBackground;
|
this.pressedBackground = pressedBackground;
|
||||||
}
|
}
|
||||||
@@ -66,7 +71,7 @@ public abstract class FlatWindowAbstractIcon
|
|||||||
protected void paintBackground( Component c, Graphics2D g ) {
|
protected void paintBackground( Component c, Graphics2D g ) {
|
||||||
Color background = FlatButtonUI.buttonStateColor( c, null, null, null, hoverBackground, pressedBackground );
|
Color background = FlatButtonUI.buttonStateColor( c, null, null, null, hoverBackground, pressedBackground );
|
||||||
if( background != null ) {
|
if( background != null ) {
|
||||||
// disable antialiasing for background rectangle painting to avoid blury edges when scaled (e.g. at 125% or 175%)
|
// disable antialiasing for background rectangle painting to avoid blurry edges when scaled (e.g. at 125% or 175%)
|
||||||
Object oldHint = g.getRenderingHint( RenderingHints.KEY_ANTIALIASING );
|
Object oldHint = g.getRenderingHint( RenderingHints.KEY_ANTIALIASING );
|
||||||
g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF );
|
g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF );
|
||||||
|
|
||||||
@@ -80,4 +85,9 @@ public abstract class FlatWindowAbstractIcon
|
|||||||
protected Color getForeground( Component c ) {
|
protected Color getForeground( Component c ) {
|
||||||
return c.getForeground();
|
return c.getForeground();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @since 3.2 */
|
||||||
|
protected int getSymbolHeight() {
|
||||||
|
return symbolHeight;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ import java.awt.Color;
|
|||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.geom.Path2D;
|
import java.awt.geom.Path2D;
|
||||||
import javax.swing.UIManager;
|
|
||||||
import com.formdev.flatlaf.ui.FlatButtonUI;
|
import com.formdev.flatlaf.ui.FlatButtonUI;
|
||||||
|
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||||
import com.formdev.flatlaf.util.SystemInfo;
|
import com.formdev.flatlaf.util.SystemInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -38,18 +38,27 @@ import com.formdev.flatlaf.util.SystemInfo;
|
|||||||
public class FlatWindowCloseIcon
|
public class FlatWindowCloseIcon
|
||||||
extends FlatWindowAbstractIcon
|
extends FlatWindowAbstractIcon
|
||||||
{
|
{
|
||||||
private final Color hoverForeground = UIManager.getColor( "TitlePane.closeHoverForeground" );
|
private final Color hoverForeground;
|
||||||
private final Color pressedForeground = UIManager.getColor( "TitlePane.closePressedForeground" );
|
private final Color pressedForeground;
|
||||||
|
|
||||||
public FlatWindowCloseIcon() {
|
public FlatWindowCloseIcon() {
|
||||||
super( UIManager.getDimension( "TitlePane.buttonSize" ),
|
this( null );
|
||||||
UIManager.getColor( "TitlePane.closeHoverBackground" ),
|
}
|
||||||
UIManager.getColor( "TitlePane.closePressedBackground" ) );
|
|
||||||
|
/** @since 3.2 */
|
||||||
|
public FlatWindowCloseIcon( String windowStyle ) {
|
||||||
|
super( FlatUIUtils.getSubUIDimension( "TitlePane.buttonSize", windowStyle ),
|
||||||
|
FlatUIUtils.getSubUIInt( "TitlePane.buttonSymbolHeight", windowStyle, 10 ),
|
||||||
|
FlatUIUtils.getSubUIColor( "TitlePane.closeHoverBackground", windowStyle ),
|
||||||
|
FlatUIUtils.getSubUIColor( "TitlePane.closePressedBackground", windowStyle ) );
|
||||||
|
|
||||||
|
hoverForeground = FlatUIUtils.getSubUIColor( "TitlePane.closeHoverForeground", windowStyle );
|
||||||
|
pressedForeground = FlatUIUtils.getSubUIColor( "TitlePane.closePressedForeground", windowStyle );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
|
protected void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
|
||||||
int iwh = (int) (10 * scaleFactor);
|
int iwh = (int) (getSymbolHeight() * scaleFactor);
|
||||||
int ix = x + ((width - iwh) / 2);
|
int ix = x + ((width - iwh) / 2);
|
||||||
int iy = y + ((height - iwh) / 2);
|
int iy = y + ((height - iwh) / 2);
|
||||||
int ix2 = ix + iwh - 1;
|
int ix2 = ix + iwh - 1;
|
||||||
|
|||||||
@@ -27,11 +27,17 @@ public class FlatWindowIconifyIcon
|
|||||||
extends FlatWindowAbstractIcon
|
extends FlatWindowAbstractIcon
|
||||||
{
|
{
|
||||||
public FlatWindowIconifyIcon() {
|
public FlatWindowIconifyIcon() {
|
||||||
|
this( null );
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @since 3.2 */
|
||||||
|
public FlatWindowIconifyIcon( String windowStyle ) {
|
||||||
|
super( windowStyle );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
|
protected void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
|
||||||
int iw = (int) (10 * scaleFactor);
|
int iw = (int) (getSymbolHeight() * scaleFactor);
|
||||||
int ih = (int) scaleFactor;
|
int ih = (int) scaleFactor;
|
||||||
int ix = x + ((width - iw) / 2);
|
int ix = x + ((width - iw) / 2);
|
||||||
int iy = y + ((height - ih) / 2);
|
int iy = y + ((height - ih) / 2);
|
||||||
|
|||||||
@@ -29,11 +29,17 @@ public class FlatWindowMaximizeIcon
|
|||||||
extends FlatWindowAbstractIcon
|
extends FlatWindowAbstractIcon
|
||||||
{
|
{
|
||||||
public FlatWindowMaximizeIcon() {
|
public FlatWindowMaximizeIcon() {
|
||||||
|
this( null );
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @since 3.2 */
|
||||||
|
public FlatWindowMaximizeIcon( String windowStyle ) {
|
||||||
|
super( windowStyle );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
|
protected void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
|
||||||
int iwh = (int) (10 * scaleFactor);
|
int iwh = (int) (getSymbolHeight() * scaleFactor);
|
||||||
int ix = x + ((width - iwh) / 2);
|
int ix = x + ((width - iwh) / 2);
|
||||||
int iy = y + ((height - iwh) / 2);
|
int iy = y + ((height - iwh) / 2);
|
||||||
float thickness = SystemInfo.isWindows_11_orLater ? (float) scaleFactor : (int) scaleFactor;
|
float thickness = SystemInfo.isWindows_11_orLater ? (float) scaleFactor : (int) scaleFactor;
|
||||||
|
|||||||
@@ -32,18 +32,24 @@ public class FlatWindowRestoreIcon
|
|||||||
extends FlatWindowAbstractIcon
|
extends FlatWindowAbstractIcon
|
||||||
{
|
{
|
||||||
public FlatWindowRestoreIcon() {
|
public FlatWindowRestoreIcon() {
|
||||||
|
this( null );
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @since 3.2 */
|
||||||
|
public FlatWindowRestoreIcon( String windowStyle ) {
|
||||||
|
super( windowStyle );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
|
protected void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
|
||||||
int iwh = (int) (10 * scaleFactor);
|
int iwh = (int) (getSymbolHeight() * scaleFactor);
|
||||||
int ix = x + ((width - iwh) / 2);
|
int ix = x + ((width - iwh) / 2);
|
||||||
int iy = y + ((height - iwh) / 2);
|
int iy = y + ((height - iwh) / 2);
|
||||||
float thickness = SystemInfo.isWindows_11_orLater ? (float) scaleFactor : (int) scaleFactor;
|
float thickness = SystemInfo.isWindows_11_orLater ? (float) scaleFactor : (int) scaleFactor;
|
||||||
int arc = Math.max( (int) (1.5 * scaleFactor), 2 );
|
int arc = Math.max( (int) (1.5 * scaleFactor), 2 );
|
||||||
int arcOuter = (int) (arc + (1.5 * scaleFactor));
|
int arcOuter = (int) (arc + (1.5 * scaleFactor));
|
||||||
|
|
||||||
int rwh = (int) (8 * scaleFactor);
|
int rwh = (int) ((getSymbolHeight() - 2) * scaleFactor);
|
||||||
int ro2 = iwh - rwh;
|
int ro2 = iwh - rwh;
|
||||||
|
|
||||||
// upper-right rectangle
|
// upper-right rectangle
|
||||||
|
|||||||
@@ -502,9 +502,9 @@ class JsonParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean isHexDigit() {
|
private boolean isHexDigit() {
|
||||||
return current >= '0' && current <= '9'
|
return (current >= '0' && current <= '9')
|
||||||
|| current >= 'a' && current <= 'f'
|
|| (current >= 'a' && current <= 'f')
|
||||||
|| current >= 'A' && current <= 'F';
|
|| (current >= 'A' && current <= 'F');
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isEndOfText() {
|
private boolean isEndOfText() {
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ public class Location {
|
|||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (getClass() != obj.getClass()) {
|
if (!(obj instanceof Location)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Location other = (Location)obj;
|
Location other = (Location)obj;
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import javax.swing.JComboBox;
|
|||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JScrollPane;
|
import javax.swing.JScrollPane;
|
||||||
import javax.swing.JSpinner;
|
import javax.swing.JSpinner;
|
||||||
import javax.swing.JViewport;
|
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.plaf.basic.BasicBorders;
|
import javax.swing.plaf.basic.BasicBorders;
|
||||||
import com.formdev.flatlaf.FlatClientProperties;
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
@@ -195,8 +194,7 @@ public class FlatBorder
|
|||||||
protected boolean isEnabled( Component c ) {
|
protected boolean isEnabled( Component c ) {
|
||||||
if( c instanceof JScrollPane ) {
|
if( c instanceof JScrollPane ) {
|
||||||
// check whether view component is disabled
|
// check whether view component is disabled
|
||||||
JViewport viewport = ((JScrollPane)c).getViewport();
|
Component view = FlatScrollPaneUI.getView( (JScrollPane) c );
|
||||||
Component view = (viewport != null) ? viewport.getView() : null;
|
|
||||||
if( view != null && !isEnabled( view ) )
|
if( view != null && !isEnabled( view ) )
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,6 +53,8 @@ import javax.swing.plaf.ToolBarUI;
|
|||||||
import javax.swing.plaf.UIResource;
|
import javax.swing.plaf.UIResource;
|
||||||
import javax.swing.plaf.basic.BasicButtonListener;
|
import javax.swing.plaf.basic.BasicButtonListener;
|
||||||
import javax.swing.plaf.basic.BasicButtonUI;
|
import javax.swing.plaf.basic.BasicButtonUI;
|
||||||
|
import javax.swing.plaf.basic.BasicHTML;
|
||||||
|
import javax.swing.text.View;
|
||||||
import com.formdev.flatlaf.FlatClientProperties;
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
import com.formdev.flatlaf.FlatLaf;
|
import com.formdev.flatlaf.FlatLaf;
|
||||||
import com.formdev.flatlaf.icons.FlatHelpButtonIcon;
|
import com.formdev.flatlaf.icons.FlatHelpButtonIcon;
|
||||||
@@ -362,6 +364,9 @@ public class FlatButtonUI
|
|||||||
return ((FlatHelpButtonIcon)helpButtonIcon).applyStyleProperty( key, value );
|
return ((FlatHelpButtonIcon)helpButtonIcon).applyStyleProperty( key, value );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( "iconTextGap".equals( key ) && value instanceof Integer )
|
||||||
|
value = UIScale.scale( (Integer) value );
|
||||||
|
|
||||||
if( borderShared == null )
|
if( borderShared == null )
|
||||||
borderShared = new AtomicBoolean( true );
|
borderShared = new AtomicBoolean( true );
|
||||||
return FlatStylingSupport.applyToAnnotatedObjectOrBorder( this, key, value, b, borderShared );
|
return FlatStylingSupport.applyToAnnotatedObjectOrBorder( this, key, value, b, borderShared );
|
||||||
@@ -548,9 +553,45 @@ public class FlatButtonUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Similar to BasicButtonUI.paint(), but does not use zero insets for HTML text,
|
||||||
|
* which is done in BasicButtonUI.layout() since Java 19.
|
||||||
|
* See https://github.com/openjdk/jdk/pull/8407
|
||||||
|
* and https://github.com/openjdk/jdk/pull/8407#issuecomment-1761583430
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void paint( Graphics g, JComponent c ) {
|
public void paint( Graphics g, JComponent c ) {
|
||||||
super.paint( FlatLabelUI.createGraphicsHTMLTextYCorrection( g, c ), c );
|
g = FlatLabelUI.createGraphicsHTMLTextYCorrection( g, c );
|
||||||
|
|
||||||
|
AbstractButton b = (AbstractButton) c;
|
||||||
|
|
||||||
|
// layout
|
||||||
|
String clippedText = layout( b, b.getFontMetrics( b.getFont() ), b.getWidth(), b.getHeight() );
|
||||||
|
|
||||||
|
// not used in FlatLaf, but invoked for compatibility with BasicButtonUI.paint()
|
||||||
|
clearTextShiftOffset();
|
||||||
|
|
||||||
|
// not used in FlatLaf, but invoked for compatibility with BasicButtonUI.paint()
|
||||||
|
ButtonModel model = b.getModel();
|
||||||
|
if( model.isArmed() && model.isPressed() )
|
||||||
|
paintButtonPressed( g, b );
|
||||||
|
|
||||||
|
// paint icon
|
||||||
|
if( b.getIcon() != null )
|
||||||
|
paintIcon( g, b, iconR );
|
||||||
|
|
||||||
|
// paint text
|
||||||
|
if( clippedText != null && !clippedText.isEmpty() ) {
|
||||||
|
View view = (View) b.getClientProperty( BasicHTML.propertyKey );
|
||||||
|
if( view != null )
|
||||||
|
view.paint( g, textR ); // HTML text
|
||||||
|
else
|
||||||
|
paintText( g, b, textR, clippedText );
|
||||||
|
}
|
||||||
|
|
||||||
|
// not used in FlatLaf, but invoked for compatibility with BasicButtonUI.paint()
|
||||||
|
if( b.isFocusPainted() && b.hasFocus() )
|
||||||
|
paintFocus( g, b, viewR, textR, iconR );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -680,14 +721,15 @@ public class FlatButtonUI
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected Color getForeground( JComponent c ) {
|
protected Color getForeground( JComponent c ) {
|
||||||
|
Color fg = c.getForeground();
|
||||||
boolean toolBarButton = isToolBarButton( c ) || isBorderlessButton( c );
|
boolean toolBarButton = isToolBarButton( c ) || isBorderlessButton( c );
|
||||||
|
|
||||||
// selected state
|
// selected state
|
||||||
if( ((AbstractButton)c).isSelected() ) {
|
if( ((AbstractButton)c).isSelected() ) {
|
||||||
return buttonStateColor( c,
|
return buttonStateColor( c,
|
||||||
toolBarButton
|
toolBarButton
|
||||||
? (toolbarSelectedForeground != null ? toolbarSelectedForeground : c.getForeground())
|
? (toolbarSelectedForeground != null ? toolbarSelectedForeground : fg)
|
||||||
: selectedForeground,
|
: (isCustomForeground( fg ) ? fg : selectedForeground),
|
||||||
toolBarButton
|
toolBarButton
|
||||||
? (toolbarDisabledSelectedForeground != null ? toolbarDisabledSelectedForeground : disabledText)
|
? (toolbarDisabledSelectedForeground != null ? toolbarDisabledSelectedForeground : disabledText)
|
||||||
: (disabledSelectedForeground != null ? disabledSelectedForeground : disabledText),
|
: (disabledSelectedForeground != null ? disabledSelectedForeground : disabledText),
|
||||||
@@ -699,7 +741,7 @@ public class FlatButtonUI
|
|||||||
// toolbar button
|
// toolbar button
|
||||||
if( toolBarButton ) {
|
if( toolBarButton ) {
|
||||||
return buttonStateColor( c,
|
return buttonStateColor( c,
|
||||||
c.getForeground(),
|
fg,
|
||||||
disabledText,
|
disabledText,
|
||||||
null,
|
null,
|
||||||
toolbarHoverForeground,
|
toolbarHoverForeground,
|
||||||
@@ -710,7 +752,7 @@ public class FlatButtonUI
|
|||||||
return buttonStateColor( c,
|
return buttonStateColor( c,
|
||||||
getForegroundBase( c, def ),
|
getForegroundBase( c, def ),
|
||||||
disabledText,
|
disabledText,
|
||||||
isCustomForeground( c.getForeground() ) ? null : (def ? defaultFocusedForeground : focusedForeground),
|
isCustomForeground( fg ) ? null : (def ? defaultFocusedForeground : focusedForeground),
|
||||||
def ? defaultHoverForeground : hoverForeground,
|
def ? defaultHoverForeground : hoverForeground,
|
||||||
def ? defaultPressedForeground : pressedForeground );
|
def ? defaultPressedForeground : pressedForeground );
|
||||||
}
|
}
|
||||||
@@ -783,6 +825,67 @@ public class FlatButtonUI
|
|||||||
return margin instanceof UIResource && Objects.equals( margin, defaultMargin );
|
return margin instanceof UIResource && Objects.equals( margin, defaultMargin );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBaseline( JComponent c, int width, int height ) {
|
||||||
|
return getBaselineImpl( c, width, height );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Similar to BasicButtonUI.getBaseline(), but does not use zero insets for HTML text,
|
||||||
|
* which is done in BasicButtonUI.layout() since Java 19.
|
||||||
|
* See https://github.com/openjdk/jdk/pull/8407
|
||||||
|
* and https://github.com/openjdk/jdk/pull/8407#issuecomment-1761583430
|
||||||
|
*/
|
||||||
|
static int getBaselineImpl( JComponent c, int width, int height ) {
|
||||||
|
if( width < 0 || height < 0 )
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
|
||||||
|
AbstractButton b = (AbstractButton) c;
|
||||||
|
String text = b.getText();
|
||||||
|
if( text == null || text.isEmpty() )
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
FontMetrics fm = b.getFontMetrics( b.getFont() );
|
||||||
|
layout( b, fm, width, height );
|
||||||
|
|
||||||
|
View view = (View) b.getClientProperty( BasicHTML.propertyKey );
|
||||||
|
if( view != null ) {
|
||||||
|
// HTML text
|
||||||
|
int baseline = BasicHTML.getHTMLBaseline( view, textR.width, textR.height );
|
||||||
|
return (baseline >= 0) ? textR.y + baseline : baseline;
|
||||||
|
} else
|
||||||
|
return textR.y + fm.getAscent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Similar to BasicButtonUI.layout(), but does not use zero insets for HTML text,
|
||||||
|
* which is done in BasicButtonUI.layout() since Java 19.
|
||||||
|
* See https://github.com/openjdk/jdk/pull/8407
|
||||||
|
* and https://github.com/openjdk/jdk/pull/8407#issuecomment-1761583430
|
||||||
|
*/
|
||||||
|
private static String layout( AbstractButton b, FontMetrics fm, int width, int height ) {
|
||||||
|
// compute view rectangle
|
||||||
|
Insets insets = b.getInsets();
|
||||||
|
viewR.setBounds( insets.left, insets.top,
|
||||||
|
width - insets.left - insets.right,
|
||||||
|
height - insets.top - insets.bottom );
|
||||||
|
|
||||||
|
// reset rectangles
|
||||||
|
textR.setBounds( 0, 0, 0, 0 );
|
||||||
|
iconR.setBounds( 0, 0, 0, 0 );
|
||||||
|
|
||||||
|
String text = b.getText();
|
||||||
|
return SwingUtilities.layoutCompoundLabel( b, fm, text, b.getIcon(),
|
||||||
|
b.getVerticalAlignment(), b.getHorizontalAlignment(),
|
||||||
|
b.getVerticalTextPosition(), b.getHorizontalTextPosition(),
|
||||||
|
viewR, iconR, textR,
|
||||||
|
(text != null) ? b.getIconTextGap() : 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Rectangle viewR = new Rectangle();
|
||||||
|
private static Rectangle textR = new Rectangle();
|
||||||
|
private static Rectangle iconR = new Rectangle();
|
||||||
|
|
||||||
//---- class FlatButtonListener -------------------------------------------
|
//---- class FlatButtonListener -------------------------------------------
|
||||||
|
|
||||||
protected class FlatButtonListener
|
protected class FlatButtonListener
|
||||||
|
|||||||
@@ -256,10 +256,14 @@ public class FlatCaret
|
|||||||
// select all
|
// select all
|
||||||
if( c instanceof JFormattedTextField ) {
|
if( c instanceof JFormattedTextField ) {
|
||||||
EventQueue.invokeLater( () -> {
|
EventQueue.invokeLater( () -> {
|
||||||
if( getComponent() == null )
|
// Warning: do not use variables from outside of this runnable
|
||||||
|
// because they may be out-of-date when this runnable is executed
|
||||||
|
|
||||||
|
JTextComponent c2 = getComponent();
|
||||||
|
if( c2 == null )
|
||||||
return; // was deinstalled
|
return; // was deinstalled
|
||||||
|
|
||||||
select( 0, doc.getLength() );
|
select( 0, c2.getDocument().getLength() );
|
||||||
} );
|
} );
|
||||||
} else {
|
} else {
|
||||||
select( 0, doc.getLength() );
|
select( 0, doc.getLength() );
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import java.awt.Component;
|
|||||||
import java.awt.ComponentOrientation;
|
import java.awt.ComponentOrientation;
|
||||||
import java.awt.Container;
|
import java.awt.Container;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
|
import java.awt.EventQueue;
|
||||||
import java.awt.FontMetrics;
|
import java.awt.FontMetrics;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
@@ -48,10 +49,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
import javax.swing.AbstractAction;
|
import javax.swing.AbstractAction;
|
||||||
import javax.swing.BorderFactory;
|
import javax.swing.BorderFactory;
|
||||||
import javax.swing.CellRendererPane;
|
import javax.swing.CellRendererPane;
|
||||||
|
import javax.swing.ComboBoxModel;
|
||||||
import javax.swing.DefaultListCellRenderer;
|
import javax.swing.DefaultListCellRenderer;
|
||||||
import javax.swing.InputMap;
|
import javax.swing.InputMap;
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
import javax.swing.JComboBox;
|
import javax.swing.JComboBox;
|
||||||
|
import javax.swing.JComboBox.KeySelectionManager;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JList;
|
import javax.swing.JList;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
@@ -102,7 +105,6 @@ import com.formdev.flatlaf.util.SystemInfo;
|
|||||||
* @uiDefault ComboBox.maximumRowCount int
|
* @uiDefault ComboBox.maximumRowCount int
|
||||||
* @uiDefault ComboBox.buttonStyle String auto (default), button, mac or none
|
* @uiDefault ComboBox.buttonStyle String auto (default), button, mac or none
|
||||||
* @uiDefault Component.arrowType String chevron (default) or triangle
|
* @uiDefault Component.arrowType String chevron (default) or triangle
|
||||||
* @uiDefault Component.isIntelliJTheme boolean
|
|
||||||
* @uiDefault ComboBox.editableBackground Color optional; defaults to ComboBox.background
|
* @uiDefault ComboBox.editableBackground Color optional; defaults to ComboBox.background
|
||||||
* @uiDefault ComboBox.focusedBackground Color optional
|
* @uiDefault ComboBox.focusedBackground Color optional
|
||||||
* @uiDefault ComboBox.disabledBackground Color
|
* @uiDefault ComboBox.disabledBackground Color
|
||||||
@@ -134,7 +136,6 @@ public class FlatComboBoxUI
|
|||||||
@Styleable protected int editorColumns;
|
@Styleable protected int editorColumns;
|
||||||
@Styleable protected String buttonStyle;
|
@Styleable protected String buttonStyle;
|
||||||
@Styleable protected String arrowType;
|
@Styleable protected String arrowType;
|
||||||
protected boolean isIntelliJTheme;
|
|
||||||
|
|
||||||
private Color background;
|
private Color background;
|
||||||
@Styleable protected Color editableBackground;
|
@Styleable protected Color editableBackground;
|
||||||
@@ -182,6 +183,9 @@ public class FlatComboBoxUI
|
|||||||
private void installUIImpl( JComponent c ) {
|
private void installUIImpl( JComponent c ) {
|
||||||
super.installUI( c );
|
super.installUI( c );
|
||||||
|
|
||||||
|
// install key selection manager that shows popup when Space key is pressed
|
||||||
|
comboBox.setKeySelectionManager( new FlatKeySelectionManager( comboBox.getKeySelectionManager() ) );
|
||||||
|
|
||||||
installStyle();
|
installStyle();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,7 +244,6 @@ public class FlatComboBoxUI
|
|||||||
editorColumns = UIManager.getInt( "ComboBox.editorColumns" );
|
editorColumns = UIManager.getInt( "ComboBox.editorColumns" );
|
||||||
buttonStyle = UIManager.getString( "ComboBox.buttonStyle" );
|
buttonStyle = UIManager.getString( "ComboBox.buttonStyle" );
|
||||||
arrowType = UIManager.getString( "Component.arrowType" );
|
arrowType = UIManager.getString( "Component.arrowType" );
|
||||||
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
|
||||||
|
|
||||||
background = UIManager.getColor( "ComboBox.background" );
|
background = UIManager.getColor( "ComboBox.background" );
|
||||||
editableBackground = UIManager.getColor( "ComboBox.editableBackground" );
|
editableBackground = UIManager.getColor( "ComboBox.editableBackground" );
|
||||||
@@ -679,7 +682,7 @@ public class FlatComboBoxUI
|
|||||||
|
|
||||||
return (editableBackground != null && comboBox.isEditable()) ? editableBackground : background;
|
return (editableBackground != null && comboBox.isEditable()) ? editableBackground : background;
|
||||||
} else
|
} else
|
||||||
return isIntelliJTheme ? FlatUIUtils.getParentBackground( comboBox ) : disabledBackground;
|
return disabledBackground;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Color getForeground( boolean enabled ) {
|
protected Color getForeground( boolean enabled ) {
|
||||||
@@ -923,7 +926,7 @@ public class FlatComboBoxUI
|
|||||||
protected void configurePopup() {
|
protected void configurePopup() {
|
||||||
super.configurePopup();
|
super.configurePopup();
|
||||||
|
|
||||||
// make opaque to avoid that background shines thru border (e.g. at 150% scaling)
|
// make opaque to avoid that background shines through border (e.g. at 150% scaling)
|
||||||
setOpaque( true );
|
setOpaque( true );
|
||||||
|
|
||||||
// set popup border
|
// set popup border
|
||||||
@@ -941,7 +944,7 @@ public class FlatComboBoxUI
|
|||||||
if( popupBackground != null )
|
if( popupBackground != null )
|
||||||
list.setBackground( popupBackground );
|
list.setBackground( popupBackground );
|
||||||
|
|
||||||
// set popup background because it may shine thru when scaled (e.g. at 150%)
|
// set popup background because it may shine through when scaled (e.g. at 150%)
|
||||||
// use non-UIResource to avoid that it is overwritten when making
|
// use non-UIResource to avoid that it is overwritten when making
|
||||||
// popup visible (see JPopupMenu.setInvoker()) in theme editor preview
|
// popup visible (see JPopupMenu.setInvoker()) in theme editor preview
|
||||||
setBackground( FlatUIUtils.nonUIResource( list.getBackground() ) );
|
setBackground( FlatUIUtils.nonUIResource( list.getBackground() ) );
|
||||||
@@ -986,6 +989,29 @@ public class FlatComboBoxUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// improve location of selected item in popup if list is large and scrollable
|
||||||
|
if( list.getHeight() == 0 ) {
|
||||||
|
// If popup is shown for the first time (or after a laf switch) and is scrollable,
|
||||||
|
// then BasicComboPopup scrolls the selected item to the top of the visible area.
|
||||||
|
// But for usability it would be better to have selected item somewhere
|
||||||
|
// in the middle of the visible area so that the user can see items above
|
||||||
|
// the selected item, which are usually more "important".
|
||||||
|
|
||||||
|
int selectedIndex = list.getSelectedIndex();
|
||||||
|
if( selectedIndex >= 1 ) {
|
||||||
|
int maximumRowCount = comboBox.getMaximumRowCount();
|
||||||
|
if( selectedIndex < maximumRowCount ) {
|
||||||
|
// selected item is in the first visible items --> scroll to top
|
||||||
|
list.scrollRectToVisible( new Rectangle() );
|
||||||
|
} else {
|
||||||
|
// scroll the selected item to the middle of the visible area
|
||||||
|
int firstVisibleIndex = Math.max( selectedIndex - (maximumRowCount / 2), 0 );
|
||||||
|
if( firstVisibleIndex > 0 )
|
||||||
|
list.ensureIndexIsVisible( firstVisibleIndex );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
super.show( invoker, x, y );
|
super.show( invoker, x, y );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1064,7 +1090,7 @@ public class FlatComboBoxUI
|
|||||||
}
|
}
|
||||||
|
|
||||||
// using synchronized to avoid problems with code that modifies combo box
|
// using synchronized to avoid problems with code that modifies combo box
|
||||||
// (model, selection, etc) not on AWT thread (which should be not done)
|
// (model, selection, etc.) not on AWT thread (which should be not done)
|
||||||
synchronized void install( Component c, int focusWidth ) {
|
synchronized void install( Component c, int focusWidth ) {
|
||||||
if( !(c instanceof JComponent) )
|
if( !(c instanceof JComponent) )
|
||||||
return;
|
return;
|
||||||
@@ -1209,4 +1235,46 @@ public class FlatComboBoxUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---- class FlatKeySelectionManager --------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key selection manager that delegates to the default manager.
|
||||||
|
* Shows the popup if Space key is pressed and "typed characters" buffer is empty.
|
||||||
|
* If items contain spaces (e.g. "a b") it is still possible to select them
|
||||||
|
* by pressing keys 'a', 'Space' and 'b'.
|
||||||
|
*/
|
||||||
|
private class FlatKeySelectionManager
|
||||||
|
implements JComboBox.KeySelectionManager, UIResource
|
||||||
|
{
|
||||||
|
private final KeySelectionManager delegate;
|
||||||
|
private final long timeFactor;
|
||||||
|
private long lastTime;
|
||||||
|
|
||||||
|
FlatKeySelectionManager( JComboBox.KeySelectionManager delegate ) {
|
||||||
|
this.delegate = delegate;
|
||||||
|
|
||||||
|
Long value = (Long) UIManager.get( "ComboBox.timeFactor" );
|
||||||
|
timeFactor = (value != null) ? value : 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings( "rawtypes" )
|
||||||
|
@Override
|
||||||
|
public int selectionForKey( char aKey, ComboBoxModel aModel ) {
|
||||||
|
long time = EventQueue.getMostRecentEventTime();
|
||||||
|
long oldLastTime = lastTime;
|
||||||
|
lastTime = time;
|
||||||
|
|
||||||
|
// SPACE key shows popup if not yet visible
|
||||||
|
if( aKey == ' ' &&
|
||||||
|
time - oldLastTime >= timeFactor &&
|
||||||
|
!comboBox.isPopupVisible() )
|
||||||
|
{
|
||||||
|
comboBox.setPopupVisible( true );
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return delegate.selectionForKey( aKey, aModel );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,6 @@ import com.formdev.flatlaf.util.LoggingFacade;
|
|||||||
* <!-- FlatEditorPaneUI -->
|
* <!-- FlatEditorPaneUI -->
|
||||||
*
|
*
|
||||||
* @uiDefault Component.minimumWidth int
|
* @uiDefault Component.minimumWidth int
|
||||||
* @uiDefault Component.isIntelliJTheme boolean
|
|
||||||
* @uiDefault EditorPane.focusedBackground Color optional
|
* @uiDefault EditorPane.focusedBackground Color optional
|
||||||
*
|
*
|
||||||
* @author Karl Tauber
|
* @author Karl Tauber
|
||||||
@@ -69,7 +68,6 @@ public class FlatEditorPaneUI
|
|||||||
implements StyleableUI
|
implements StyleableUI
|
||||||
{
|
{
|
||||||
@Styleable protected int minimumWidth;
|
@Styleable protected int minimumWidth;
|
||||||
protected boolean isIntelliJTheme;
|
|
||||||
private Color background;
|
private Color background;
|
||||||
@Styleable protected Color disabledBackground;
|
@Styleable protected Color disabledBackground;
|
||||||
@Styleable protected Color inactiveBackground;
|
@Styleable protected Color inactiveBackground;
|
||||||
@@ -101,7 +99,6 @@ public class FlatEditorPaneUI
|
|||||||
|
|
||||||
String prefix = getPropertyPrefix();
|
String prefix = getPropertyPrefix();
|
||||||
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
||||||
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
|
||||||
background = UIManager.getColor( prefix + ".background" );
|
background = UIManager.getColor( prefix + ".background" );
|
||||||
disabledBackground = UIManager.getColor( prefix + ".disabledBackground" );
|
disabledBackground = UIManager.getColor( prefix + ".disabledBackground" );
|
||||||
inactiveBackground = UIManager.getColor( prefix + ".inactiveBackground" );
|
inactiveBackground = UIManager.getColor( prefix + ".inactiveBackground" );
|
||||||
@@ -252,11 +249,11 @@ public class FlatEditorPaneUI
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void paintBackground( Graphics g ) {
|
protected void paintBackground( Graphics g ) {
|
||||||
paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground );
|
paintBackground( g, getComponent(), focusedBackground );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void paintBackground( Graphics g, JTextComponent c, boolean isIntelliJTheme, Color focusedBackground ) {
|
static void paintBackground( Graphics g, JTextComponent c, Color focusedBackground ) {
|
||||||
g.setColor( FlatTextFieldUI.getBackground( c, isIntelliJTheme, focusedBackground ) );
|
g.setColor( FlatTextFieldUI.getBackground( c, focusedBackground ) );
|
||||||
g.fillRect( 0, 0, c.getWidth(), c.getHeight() );
|
g.fillRect( 0, 0, c.getWidth(), c.getHeight() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import java.beans.PropertyChangeEvent;
|
|||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import javax.swing.AbstractButton;
|
import javax.swing.AbstractButton;
|
||||||
import javax.swing.Box;
|
import javax.swing.Box;
|
||||||
@@ -53,6 +54,7 @@ import javax.swing.plaf.ComponentUI;
|
|||||||
import javax.swing.plaf.metal.MetalFileChooserUI;
|
import javax.swing.plaf.metal.MetalFileChooserUI;
|
||||||
import javax.swing.table.TableCellRenderer;
|
import javax.swing.table.TableCellRenderer;
|
||||||
import com.formdev.flatlaf.FlatClientProperties;
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
|
import com.formdev.flatlaf.icons.FlatFileViewDirectoryIcon;
|
||||||
import com.formdev.flatlaf.util.LoggingFacade;
|
import com.formdev.flatlaf.util.LoggingFacade;
|
||||||
import com.formdev.flatlaf.util.ScaledImageIcon;
|
import com.formdev.flatlaf.util.ScaledImageIcon;
|
||||||
import com.formdev.flatlaf.util.SystemInfo;
|
import com.formdev.flatlaf.util.SystemInfo;
|
||||||
@@ -346,12 +348,12 @@ public class FlatFileChooserUI
|
|||||||
fileView.clearIconCache();
|
fileView.clearIconCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean doNotUseSystemIcons() {
|
private static boolean doNotUseSystemIcons() {
|
||||||
// Java 17 32bit craches on Windows when using system icons
|
// Java 17 32bit craches on Windows when using system icons
|
||||||
// fixed in Java 18+ (see https://bugs.openjdk.java.net/browse/JDK-8277299)
|
// fixed in Java 18+, fix backported in Java 17.0.3+ (see https://bugs.openjdk.java.net/browse/JDK-8277299)
|
||||||
return SystemInfo.isWindows &&
|
return SystemInfo.isWindows &&
|
||||||
SystemInfo.isX86 &&
|
SystemInfo.isX86 &&
|
||||||
(SystemInfo.isJava_17_orLater && !SystemInfo.isJava_18_orLater);
|
(SystemInfo.isJava_17_orLater && SystemInfo.javaVersion < SystemInfo.toVersion( 17, 0, 3, 0 ));
|
||||||
}
|
}
|
||||||
|
|
||||||
//---- class FlatFileView -------------------------------------------------
|
//---- class FlatFileView -------------------------------------------------
|
||||||
@@ -368,7 +370,11 @@ public class FlatFileChooserUI
|
|||||||
|
|
||||||
// get system icon
|
// get system icon
|
||||||
if( f != null ) {
|
if( f != null ) {
|
||||||
icon = getFileChooser().getFileSystemView().getSystemIcon( f );
|
try {
|
||||||
|
icon = getFileChooser().getFileSystemView().getSystemIcon( f );
|
||||||
|
} catch( NullPointerException ex ) {
|
||||||
|
// Java 21 may throw a NPE for exe files that use default Windows exe icon
|
||||||
|
}
|
||||||
|
|
||||||
if( icon != null ) {
|
if( icon != null ) {
|
||||||
if( icon instanceof ImageIcon )
|
if( icon instanceof ImageIcon )
|
||||||
@@ -407,7 +413,7 @@ public class FlatFileChooserUI
|
|||||||
|
|
||||||
protected final File[] files;
|
protected final File[] files;
|
||||||
protected final JToggleButton[] buttons;
|
protected final JToggleButton[] buttons;
|
||||||
protected final ButtonGroup buttonGroup;
|
protected final ButtonGroup buttonGroup = new ButtonGroup();
|
||||||
|
|
||||||
@SuppressWarnings( "unchecked" )
|
@SuppressWarnings( "unchecked" )
|
||||||
public FlatShortcutsPanel( JFileChooser fc ) {
|
public FlatShortcutsPanel( JFileChooser fc ) {
|
||||||
@@ -426,19 +432,22 @@ public class FlatFileChooserUI
|
|||||||
File[] files = getChooserShortcutPanelFiles( fsv );
|
File[] files = getChooserShortcutPanelFiles( fsv );
|
||||||
if( filesFunction != null )
|
if( filesFunction != null )
|
||||||
files = filesFunction.apply( files );
|
files = filesFunction.apply( files );
|
||||||
this.files = files;
|
|
||||||
|
|
||||||
// create toolbar buttons
|
// create toolbar buttons
|
||||||
buttons = new JToggleButton[files.length];
|
ArrayList<File> filesList = new ArrayList<>();
|
||||||
buttonGroup = new ButtonGroup();
|
ArrayList<JToggleButton> buttonsList = new ArrayList<>();
|
||||||
for( int i = 0; i < files.length; i++ ) {
|
for( File file : files ) {
|
||||||
// wrap drive path
|
if( file == null )
|
||||||
if( fsv.isFileSystemRoot( files[i] ) )
|
continue;
|
||||||
files[i] = fsv.createFileObject( files[i].getAbsolutePath() );
|
|
||||||
|
// wrap drive path
|
||||||
|
if( fsv.isFileSystemRoot( file ) )
|
||||||
|
file = fsv.createFileObject( file.getAbsolutePath() );
|
||||||
|
|
||||||
File file = files[i];
|
|
||||||
String name = getDisplayName( fsv, file );
|
String name = getDisplayName( fsv, file );
|
||||||
Icon icon = getIcon( fsv, file );
|
Icon icon = getIcon( fsv, file );
|
||||||
|
if( name == null )
|
||||||
|
continue;
|
||||||
|
|
||||||
// remove path from name
|
// remove path from name
|
||||||
int lastSepIndex = name.lastIndexOf( File.separatorChar );
|
int lastSepIndex = name.lastIndexOf( File.separatorChar );
|
||||||
@@ -453,15 +462,21 @@ public class FlatFileChooserUI
|
|||||||
|
|
||||||
// create button
|
// create button
|
||||||
JToggleButton button = createButton( name, icon );
|
JToggleButton button = createButton( name, icon );
|
||||||
|
File f = file;
|
||||||
button.addActionListener( e -> {
|
button.addActionListener( e -> {
|
||||||
fc.setCurrentDirectory( file );
|
fc.setCurrentDirectory( f );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
add( button );
|
add( button );
|
||||||
buttonGroup.add( button );
|
buttonGroup.add( button );
|
||||||
buttons[i] = button;
|
|
||||||
|
filesList.add( file );
|
||||||
|
buttonsList.add( button );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.files = filesList.toArray( new File[filesList.size()] );
|
||||||
|
this.buttons = buttonsList.toArray( new JToggleButton[buttonsList.size()] );
|
||||||
|
|
||||||
directoryChanged( fc.getCurrentDirectory() );
|
directoryChanged( fc.getCurrentDirectory() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -526,29 +541,39 @@ public class FlatFileChooserUI
|
|||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Java 17+ supports getting larger system icons
|
if( doNotUseSystemIcons() )
|
||||||
try {
|
return new FlatFileViewDirectoryIcon();
|
||||||
if( SystemInfo.isJava_17_orLater ) {
|
|
||||||
Method m = fsv.getClass().getMethod( "getSystemIcon", File.class, int.class, int.class );
|
|
||||||
return (Icon) m.invoke( fsv, file, iconSize.width, iconSize.height );
|
|
||||||
} else if( iconSize.width > 16 || iconSize.height > 16 ) {
|
|
||||||
Class<?> cls = Class.forName( "sun.awt.shell.ShellFolder" );
|
|
||||||
if( cls.isInstance( file ) ) {
|
|
||||||
Method m = file.getClass().getMethod( "getIcon", boolean.class );
|
|
||||||
m.setAccessible( true );
|
|
||||||
Image image = (Image) m.invoke( file, true );
|
|
||||||
if( image != null )
|
|
||||||
return new ImageIcon( image );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch( IllegalAccessException ex ) {
|
|
||||||
// do not log because access may be denied via VM option '--illegal-access=deny'
|
|
||||||
} catch( Exception ex ) {
|
|
||||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
|
||||||
}
|
|
||||||
|
|
||||||
// get system icon in default size 16x16
|
try {
|
||||||
return fsv.getSystemIcon( file );
|
// Java 17+ supports getting larger system icons
|
||||||
|
try {
|
||||||
|
if( SystemInfo.isJava_17_orLater ) {
|
||||||
|
Method m = fsv.getClass().getMethod( "getSystemIcon", File.class, int.class, int.class );
|
||||||
|
return (Icon) m.invoke( fsv, file, iconSize.width, iconSize.height );
|
||||||
|
} else if( iconSize.width > 16 || iconSize.height > 16 ) {
|
||||||
|
Class<?> cls = Class.forName( "sun.awt.shell.ShellFolder" );
|
||||||
|
if( cls.isInstance( file ) ) {
|
||||||
|
Method m = file.getClass().getMethod( "getIcon", boolean.class );
|
||||||
|
m.setAccessible( true );
|
||||||
|
Image image = (Image) m.invoke( file, true );
|
||||||
|
if( image != null )
|
||||||
|
return new ImageIcon( image );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch( Exception ex ) {
|
||||||
|
// do not log InaccessibleObjectException because access
|
||||||
|
// may be denied via VM option '--illegal-access=deny' (default in Java 16)
|
||||||
|
// (not catching InaccessibleObjectException here because it is new in Java 9, but FlatLaf also runs on Java 8)
|
||||||
|
if( !"java.lang.reflect.InaccessibleObjectException".equals( ex.getClass().getName() ) )
|
||||||
|
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||||
|
}
|
||||||
|
|
||||||
|
// get system icon in default size 16x16
|
||||||
|
return fsv.getSystemIcon( file );
|
||||||
|
} catch( NullPointerException ex ) {
|
||||||
|
// Java 21 may throw a NPE for exe files that use default Windows exe icon
|
||||||
|
return new FlatFileViewDirectoryIcon();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void directoryChanged( File file ) {
|
protected void directoryChanged( File file ) {
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ import javax.swing.plaf.ComponentUI;
|
|||||||
* <!-- FlatTextFieldUI -->
|
* <!-- FlatTextFieldUI -->
|
||||||
*
|
*
|
||||||
* @uiDefault Component.minimumWidth int
|
* @uiDefault Component.minimumWidth int
|
||||||
* @uiDefault Component.isIntelliJTheme boolean
|
|
||||||
* @uiDefault FormattedTextField.placeholderForeground Color
|
* @uiDefault FormattedTextField.placeholderForeground Color
|
||||||
* @uiDefault FormattedTextField.focusedBackground Color optional
|
* @uiDefault FormattedTextField.focusedBackground Color optional
|
||||||
* @uiDefault FormattedTextField.iconTextGap int optional, default is 4
|
* @uiDefault FormattedTextField.iconTextGap int optional, default is 4
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import java.awt.Rectangle;
|
|||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import javax.swing.Icon;
|
import javax.swing.Icon;
|
||||||
@@ -179,7 +180,7 @@ public class FlatLabelUI
|
|||||||
// BASE_SIZE rule is parsed in javax.swing.text.html.StyleSheet.addRule()
|
// BASE_SIZE rule is parsed in javax.swing.text.html.StyleSheet.addRule()
|
||||||
String style = "<style>BASE_SIZE " + c.getFont().getSize() + "</style>";
|
String style = "<style>BASE_SIZE " + c.getFont().getSize() + "</style>";
|
||||||
|
|
||||||
String lowerText = text.toLowerCase();
|
String lowerText = text.toLowerCase( Locale.ENGLISH );
|
||||||
int headIndex;
|
int headIndex;
|
||||||
int styleIndex;
|
int styleIndex;
|
||||||
|
|
||||||
@@ -228,7 +229,7 @@ public class FlatLabelUI
|
|||||||
int tagBegin = i + 1;
|
int tagBegin = i + 1;
|
||||||
for( i += 2; i < textLength; i++ ) {
|
for( i += 2; i < textLength; i++ ) {
|
||||||
if( !Character.isLetterOrDigit( text.charAt( i ) ) ) {
|
if( !Character.isLetterOrDigit( text.charAt( i ) ) ) {
|
||||||
String tag = text.substring( tagBegin, i ).toLowerCase();
|
String tag = text.substring( tagBegin, i ).toLowerCase( Locale.ENGLISH );
|
||||||
if( tagsUseFontSizeSet.contains( tag ) )
|
if( tagsUseFontSizeSet.contains( tag ) )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import java.awt.Component;
|
|||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.Insets;
|
import java.awt.Insets;
|
||||||
|
import javax.swing.JComponent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Line border for various components.
|
* Line border for various components.
|
||||||
@@ -66,6 +67,9 @@ public class FlatLineBorder
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||||
|
if( c instanceof JComponent && ((JComponent)c).getClientProperty( FlatPopupFactory.KEY_POPUP_USES_NATIVE_BORDER ) != null )
|
||||||
|
return;
|
||||||
|
|
||||||
Graphics2D g2 = (Graphics2D) g.create();
|
Graphics2D g2 = (Graphics2D) g.create();
|
||||||
try {
|
try {
|
||||||
FlatUIUtils.setRenderingHints( g2 );
|
FlatUIUtils.setRenderingHints( g2 );
|
||||||
|
|||||||
@@ -301,7 +301,8 @@ public class FlatListUI
|
|||||||
// get renderer component
|
// get renderer component
|
||||||
@SuppressWarnings( "unchecked" )
|
@SuppressWarnings( "unchecked" )
|
||||||
Component rendererComponent = cellRenderer.getListCellRendererComponent( list,
|
Component rendererComponent = cellRenderer.getListCellRendererComponent( list,
|
||||||
dataModel.getElementAt( row ), row, isSelected, list.hasFocus() && (row == leadIndex) );
|
dataModel.getElementAt( row ), row, isSelected,
|
||||||
|
FlatUIUtils.isPermanentFocusOwner( list ) && (row == leadIndex) );
|
||||||
|
|
||||||
//
|
//
|
||||||
boolean isFileList = Boolean.TRUE.equals( list.getClientProperty( "List.isFileList" ) );
|
boolean isFileList = Boolean.TRUE.equals( list.getClientProperty( "List.isFileList" ) );
|
||||||
@@ -410,7 +411,7 @@ public class FlatListUI
|
|||||||
int leftIndex = locationToIndex( list, new Point( r.x - 1, r.y ) );
|
int leftIndex = locationToIndex( list, new Point( r.x - 1, r.y ) );
|
||||||
int rightIndex = locationToIndex( list, new Point( r.x + r.width, r.y ) );
|
int rightIndex = locationToIndex( list, new Point( r.x + r.width, r.y ) );
|
||||||
|
|
||||||
// special handling for the case that last column contains less cells than the other columns
|
// special handling for the case that last column contains fewer cells than the other columns
|
||||||
boolean ltr = list.getComponentOrientation().isLeftToRight();
|
boolean ltr = list.getComponentOrientation().isLeftToRight();
|
||||||
if( !ltr && leftIndex >= 0 && leftIndex != row && leftIndex == locationToIndex( list, new Point( r.x - 1, r.y - 1 ) ) )
|
if( !ltr && leftIndex >= 0 && leftIndex != row && leftIndex == locationToIndex( list, new Point( r.x - 1, r.y - 1 ) ) )
|
||||||
leftIndex = -1;
|
leftIndex = -1;
|
||||||
|
|||||||
@@ -456,10 +456,11 @@ debug*/
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// center because the real icon may be smaller than dimension in iconRect
|
// center because the real icon may be smaller than dimension in iconRect
|
||||||
|
int x = iconRect.x + centerOffset( iconRect.width, icon.getIconWidth() );
|
||||||
int y = iconRect.y + centerOffset( iconRect.height, icon.getIconHeight() );
|
int y = iconRect.y + centerOffset( iconRect.height, icon.getIconHeight() );
|
||||||
|
|
||||||
// paint
|
// paint
|
||||||
icon.paintIcon( menuItem, g, iconRect.x, y );
|
icon.paintIcon( menuItem, g, x, y );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static void paintText( Graphics g, JMenuItem menuItem,
|
protected static void paintText( Graphics g, JMenuItem menuItem,
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
package com.formdev.flatlaf.ui;
|
package com.formdev.flatlaf.ui;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.security.CodeSource;
|
||||||
import com.formdev.flatlaf.FlatSystemProperties;
|
import com.formdev.flatlaf.FlatSystemProperties;
|
||||||
import com.formdev.flatlaf.util.LoggingFacade;
|
import com.formdev.flatlaf.util.LoggingFacade;
|
||||||
import com.formdev.flatlaf.util.NativeLibrary;
|
import com.formdev.flatlaf.util.NativeLibrary;
|
||||||
@@ -31,6 +33,7 @@ import com.formdev.flatlaf.util.SystemInfo;
|
|||||||
*/
|
*/
|
||||||
class FlatNativeLibrary
|
class FlatNativeLibrary
|
||||||
{
|
{
|
||||||
|
private static boolean initialized;
|
||||||
private static NativeLibrary nativeLibrary;
|
private static NativeLibrary nativeLibrary;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -43,28 +46,52 @@ class FlatNativeLibrary
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void initialize() {
|
private static void initialize() {
|
||||||
if( nativeLibrary != null )
|
if( initialized )
|
||||||
|
return;
|
||||||
|
initialized = true;
|
||||||
|
|
||||||
|
if( !FlatSystemProperties.getBoolean( FlatSystemProperties.USE_NATIVE_LIBRARY, true ) )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
String libraryName;
|
String classifier;
|
||||||
if( SystemInfo.isWindows_10_orLater && (SystemInfo.isX86 || SystemInfo.isX86_64) ) {
|
String ext;
|
||||||
// Windows: requires Windows 10/11 (x86 or x86_64)
|
if( SystemInfo.isWindows_10_orLater && (SystemInfo.isX86 || SystemInfo.isX86_64 || SystemInfo.isAARCH64) ) {
|
||||||
|
// Windows: requires Windows 10/11 (x86, x86_64 or aarch64)
|
||||||
|
|
||||||
libraryName = "flatlaf-windows-x86";
|
if( SystemInfo.isAARCH64 )
|
||||||
if( SystemInfo.isX86_64 )
|
classifier = "windows-arm64";
|
||||||
libraryName += "_64";
|
else if( SystemInfo.isX86_64 )
|
||||||
|
classifier = "windows-x86_64";
|
||||||
|
else
|
||||||
|
classifier = "windows-x86";
|
||||||
|
|
||||||
|
ext = "dll";
|
||||||
|
|
||||||
|
// Do not load jawt.dll (part of JRE) here explicitly because
|
||||||
|
// the FlatLaf native library flatlaf.dll may be loaded very early on Windows
|
||||||
|
// (e.g. from class com.formdev.flatlaf.util.SystemInfo) and before AWT is
|
||||||
|
// initialized (and awt.dll is loaded). Loading jawt.dll also loads awt.dll.
|
||||||
|
// In Java 8, loading jawt.dll before AWT is initialized may load
|
||||||
|
// a wrong version of awt.dll if a newer Java version (e.g. 19)
|
||||||
|
// is in PATH environment variable. Then Java 19 awt.dll and Java 8 awt.dll
|
||||||
|
// are loaded at same time and calling JAWT_GetAWT() crashes the application.
|
||||||
|
//
|
||||||
|
// To avoid this, flatlaf.dll is not linked to jawt.dll,
|
||||||
|
// which avoids loading jawt.dll when flatlaf.dll is loaded.
|
||||||
|
// Instead, flatlaf.dll dynamically loads jawt.dll when first used,
|
||||||
|
// which is guaranteed after AWT initialization.
|
||||||
|
|
||||||
|
} else if( SystemInfo.isMacOS_10_14_Mojave_orLater && (SystemInfo.isAARCH64 || SystemInfo.isX86_64) ) {
|
||||||
|
// macOS: requires macOS 10.14 or later (arm64 or x86_64)
|
||||||
|
|
||||||
|
classifier = SystemInfo.isAARCH64 ? "macos-arm64" : "macos-x86_64";
|
||||||
|
ext = "dylib";
|
||||||
|
|
||||||
// In Java 8, load jawt.dll (part of JRE) explicitly because it
|
|
||||||
// is not found when running application with <jdk>/bin/java.exe.
|
|
||||||
// When using <jdk>/jre/bin/java.exe, it is found.
|
|
||||||
// jawt.dll is located in <jdk>/jre/bin/.
|
|
||||||
// Java 9 and later do not have this problem,
|
|
||||||
// but load jawt.dll anyway to be on the safe side.
|
|
||||||
loadJAWT();
|
|
||||||
} else if( SystemInfo.isLinux && SystemInfo.isX86_64 ) {
|
} else if( SystemInfo.isLinux && SystemInfo.isX86_64 ) {
|
||||||
// Linux: requires x86_64
|
// Linux: requires x86_64
|
||||||
|
|
||||||
libraryName = "flatlaf-linux-x86_64";
|
classifier = "linux-x86_64";
|
||||||
|
ext = "so";
|
||||||
|
|
||||||
// Load libjawt.so (part of JRE) explicitly because it is not found
|
// Load libjawt.so (part of JRE) explicitly because it is not found
|
||||||
// in all Java versions/distributions.
|
// in all Java versions/distributions.
|
||||||
@@ -76,10 +103,13 @@ class FlatNativeLibrary
|
|||||||
return; // no native library available for current OS or CPU architecture
|
return; // no native library available for current OS or CPU architecture
|
||||||
|
|
||||||
// load native library
|
// load native library
|
||||||
nativeLibrary = createNativeLibrary( libraryName );
|
nativeLibrary = createNativeLibrary( classifier, ext );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static NativeLibrary createNativeLibrary( String libraryName ) {
|
private static NativeLibrary createNativeLibrary( String classifier, String ext ) {
|
||||||
|
String libraryName = "flatlaf-" + classifier;
|
||||||
|
|
||||||
|
// load from "java.library.path" or from path specified in system property "flatlaf.nativeLibraryPath"
|
||||||
String libraryPath = System.getProperty( FlatSystemProperties.NATIVE_LIBRARY_PATH );
|
String libraryPath = System.getProperty( FlatSystemProperties.NATIVE_LIBRARY_PATH );
|
||||||
if( libraryPath != null ) {
|
if( libraryPath != null ) {
|
||||||
if( "system".equals( libraryPath ) ) {
|
if( "system".equals( libraryPath ) ) {
|
||||||
@@ -97,9 +127,74 @@ class FlatNativeLibrary
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// load from beside the FlatLaf jar
|
||||||
|
// e.g. for flatlaf-3.1.jar, load flatlaf-3.1-windows-x86_64.dll (from same directory)
|
||||||
|
File libraryFile = findLibraryBesideJar( classifier, ext );
|
||||||
|
if( libraryFile != null )
|
||||||
|
return new NativeLibrary( libraryFile, true );
|
||||||
|
|
||||||
|
// load from FlatLaf jar (extract native library to temp folder)
|
||||||
return new NativeLibrary( "com/formdev/flatlaf/natives/" + libraryName, null, true );
|
return new NativeLibrary( "com/formdev/flatlaf/natives/" + libraryName, null, true );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search for a native library beside the jar that contains this class
|
||||||
|
* (usually the FlatLaf jar).
|
||||||
|
* The native library must be in the same directory (or in "../bin" if jar is in "lib")
|
||||||
|
* as the jar and have the same basename as the jar.
|
||||||
|
* If FlatLaf jar is repackaged into fat/uber application jar, "-flatlaf" is appended to jar basename.
|
||||||
|
* The classifier and the extension are appended to the jar basename.
|
||||||
|
*
|
||||||
|
* E.g.
|
||||||
|
* flatlaf-3.1.jar
|
||||||
|
* flatlaf-3.1-windows-x86_64.dll
|
||||||
|
* flatlaf-3.1-linux-x86_64.so
|
||||||
|
*/
|
||||||
|
private static File findLibraryBesideJar( String classifier, String ext ) {
|
||||||
|
try {
|
||||||
|
// get location of FlatLaf jar
|
||||||
|
CodeSource codeSource = FlatNativeLibrary.class.getProtectionDomain().getCodeSource();
|
||||||
|
URL jarUrl = (codeSource != null) ? codeSource.getLocation() : null;
|
||||||
|
if( jarUrl == null )
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// if url is not a file, then we're running in a special environment (e.g. WebStart)
|
||||||
|
if( !"file".equals( jarUrl.getProtocol() ) )
|
||||||
|
return null;
|
||||||
|
|
||||||
|
File jarFile = new File( jarUrl.toURI() );
|
||||||
|
|
||||||
|
// if jarFile is a directory, then we're in a development environment
|
||||||
|
if( !jarFile.isFile() )
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// build library file
|
||||||
|
String jarName = jarFile.getName();
|
||||||
|
String jarBasename = jarName.substring( 0, jarName.lastIndexOf( '.' ) );
|
||||||
|
File parent = jarFile.getParentFile();
|
||||||
|
String libraryName = jarBasename
|
||||||
|
+ (jarBasename.contains( "flatlaf" ) ? "" : "-flatlaf")
|
||||||
|
+ '-' + classifier + '.' + ext;
|
||||||
|
|
||||||
|
// check whether native library exists in same directory as jar
|
||||||
|
File libraryFile = new File( parent, libraryName );
|
||||||
|
if( libraryFile.isFile() )
|
||||||
|
return libraryFile;
|
||||||
|
|
||||||
|
// if jar is in "lib" directory, then also check whether library exists
|
||||||
|
// in "../bin" directory
|
||||||
|
if( parent.getName().equalsIgnoreCase( "lib" ) ) {
|
||||||
|
libraryFile = new File( parent.getParentFile(), "bin/" + libraryName );
|
||||||
|
if( libraryFile.isFile() )
|
||||||
|
return libraryFile;
|
||||||
|
}
|
||||||
|
} catch( Exception ex ) {
|
||||||
|
LoggingFacade.INSTANCE.logSevere( ex.getMessage(), ex );
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private static void loadJAWT() {
|
private static void loadJAWT() {
|
||||||
try {
|
try {
|
||||||
System.loadLibrary( "jawt" );
|
System.loadLibrary( "jawt" );
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import java.awt.event.MouseEvent;
|
|||||||
import java.awt.geom.AffineTransform;
|
import java.awt.geom.AffineTransform;
|
||||||
import javax.swing.JDialog;
|
import javax.swing.JDialog;
|
||||||
import javax.swing.JFrame;
|
import javax.swing.JFrame;
|
||||||
|
import com.formdev.flatlaf.util.SystemInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Native methods for Linux.
|
* Native methods for Linux.
|
||||||
@@ -34,8 +35,14 @@ import javax.swing.JFrame;
|
|||||||
*/
|
*/
|
||||||
class FlatNativeLinuxLibrary
|
class FlatNativeLinuxLibrary
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Checks whether native library is loaded/available.
|
||||||
|
* <p>
|
||||||
|
* <b>Note</b>: It is required to invoke this method before invoking any other
|
||||||
|
* method of this class. Otherwise, the native library may not be loaded.
|
||||||
|
*/
|
||||||
static boolean isLoaded() {
|
static boolean isLoaded() {
|
||||||
return FlatNativeLibrary.isLoaded();
|
return SystemInfo.isLinux && FlatNativeLibrary.isLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
// direction for _NET_WM_MOVERESIZE message
|
// direction for _NET_WM_MOVERESIZE message
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 FormDev Software GmbH
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.formdev.flatlaf.ui;
|
||||||
|
|
||||||
|
import java.awt.Window;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Native methods for macOS.
|
||||||
|
* <p>
|
||||||
|
* <b>Note</b>: This is private API. Do not use!
|
||||||
|
*
|
||||||
|
* <h2>Methods that use windows as parameter</h2>
|
||||||
|
*
|
||||||
|
* For all methods that accept a {@link java.awt.Window} as parameter,
|
||||||
|
* the underlying macOS window must be already created,
|
||||||
|
* otherwise the method fails. You can use following to ensure this:
|
||||||
|
* <pre>{@code
|
||||||
|
* if( !window.isDisplayable() )
|
||||||
|
* window.addNotify();
|
||||||
|
* }</pre>
|
||||||
|
* or invoke the method after packing the window. E.g.
|
||||||
|
* <pre>{@code
|
||||||
|
* window.pack();
|
||||||
|
* }</pre>
|
||||||
|
*
|
||||||
|
* @author Karl Tauber
|
||||||
|
* @since 3.3
|
||||||
|
*/
|
||||||
|
public class FlatNativeMacLibrary
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Checks whether native library is loaded/available.
|
||||||
|
* <p>
|
||||||
|
* <b>Note</b>: It is required to invoke this method before invoking any other
|
||||||
|
* method of this class. Otherwise, the native library may not be loaded.
|
||||||
|
*/
|
||||||
|
public static boolean isLoaded() {
|
||||||
|
return FlatNativeLibrary.isLoaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
public native static boolean setWindowRoundedBorder( Window window, float radius, float borderWidth, int borderColor );
|
||||||
|
}
|
||||||
@@ -17,20 +17,26 @@
|
|||||||
package com.formdev.flatlaf.ui;
|
package com.formdev.flatlaf.ui;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
import java.awt.Component;
|
||||||
import java.awt.Container;
|
import java.awt.Container;
|
||||||
|
import java.awt.Graphics;
|
||||||
|
import java.awt.Graphics2D;
|
||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
|
import java.awt.Toolkit;
|
||||||
import java.awt.Window;
|
import java.awt.Window;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.swing.JDialog;
|
import javax.swing.JDialog;
|
||||||
import javax.swing.JFrame;
|
import javax.swing.JFrame;
|
||||||
import javax.swing.JRootPane;
|
import javax.swing.JRootPane;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.event.ChangeListener;
|
import javax.swing.event.ChangeListener;
|
||||||
|
import javax.swing.plaf.BorderUIResource;
|
||||||
import com.formdev.flatlaf.FlatClientProperties;
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
import com.formdev.flatlaf.FlatLaf;
|
import com.formdev.flatlaf.FlatLaf;
|
||||||
import com.formdev.flatlaf.FlatSystemProperties;
|
import com.formdev.flatlaf.FlatSystemProperties;
|
||||||
import com.formdev.flatlaf.ui.JBRCustomDecorations.JBRWindowTopBorder;
|
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||||
import com.formdev.flatlaf.util.SystemInfo;
|
import com.formdev.flatlaf.util.SystemInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -54,27 +60,15 @@ public class FlatNativeWindowBorder
|
|||||||
!SystemInfo.isWinPE &&
|
!SystemInfo.isWinPE &&
|
||||||
FlatSystemProperties.getBoolean( FlatSystemProperties.USE_WINDOW_DECORATIONS, true );
|
FlatSystemProperties.getBoolean( FlatSystemProperties.USE_WINDOW_DECORATIONS, true );
|
||||||
|
|
||||||
// check this field before using class JBRCustomDecorations to avoid unnecessary loading of that class
|
|
||||||
private static final boolean canUseJBRCustomDecorations =
|
|
||||||
canUseWindowDecorations &&
|
|
||||||
SystemInfo.isJetBrainsJVM_11_orLater &&
|
|
||||||
FlatSystemProperties.getBoolean( FlatSystemProperties.USE_JETBRAINS_CUSTOM_DECORATIONS, false );
|
|
||||||
|
|
||||||
private static Boolean supported;
|
private static Boolean supported;
|
||||||
private static Provider nativeProvider;
|
private static Provider nativeProvider;
|
||||||
|
|
||||||
public static boolean isSupported() {
|
public static boolean isSupported() {
|
||||||
if( canUseJBRCustomDecorations )
|
|
||||||
return JBRCustomDecorations.isSupported();
|
|
||||||
|
|
||||||
initialize();
|
initialize();
|
||||||
return supported;
|
return supported;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Object install( JRootPane rootPane ) {
|
static Object install( JRootPane rootPane ) {
|
||||||
if( canUseJBRCustomDecorations )
|
|
||||||
return JBRCustomDecorations.install( rootPane );
|
|
||||||
|
|
||||||
if( !isSupported() )
|
if( !isSupported() )
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@@ -163,11 +157,6 @@ public class FlatNativeWindowBorder
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void uninstall( JRootPane rootPane, Object data ) {
|
static void uninstall( JRootPane rootPane, Object data ) {
|
||||||
if( canUseJBRCustomDecorations ) {
|
|
||||||
JBRCustomDecorations.uninstall( rootPane, data );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !isSupported() )
|
if( !isSupported() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -215,9 +204,6 @@ public class FlatNativeWindowBorder
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean hasCustomDecoration( Window window ) {
|
public static boolean hasCustomDecoration( Window window ) {
|
||||||
if( canUseJBRCustomDecorations )
|
|
||||||
return JBRCustomDecorations.hasCustomDecoration( window );
|
|
||||||
|
|
||||||
if( !isSupported() )
|
if( !isSupported() )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -225,11 +211,6 @@ public class FlatNativeWindowBorder
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void setHasCustomDecoration( Window window, boolean hasCustomDecoration ) {
|
public static void setHasCustomDecoration( Window window, boolean hasCustomDecoration ) {
|
||||||
if( canUseJBRCustomDecorations ) {
|
|
||||||
JBRCustomDecorations.setHasCustomDecoration( window, hasCustomDecoration );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !isSupported() )
|
if( !isSupported() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -240,11 +221,6 @@ public class FlatNativeWindowBorder
|
|||||||
List<Rectangle> hitTestSpots, Rectangle appIconBounds, Rectangle minimizeButtonBounds,
|
List<Rectangle> hitTestSpots, Rectangle appIconBounds, Rectangle minimizeButtonBounds,
|
||||||
Rectangle maximizeButtonBounds, Rectangle closeButtonBounds )
|
Rectangle maximizeButtonBounds, Rectangle closeButtonBounds )
|
||||||
{
|
{
|
||||||
if( canUseJBRCustomDecorations ) {
|
|
||||||
JBRCustomDecorations.setTitleBarHeightAndHitTestSpots( window, titleBarHeight, hitTestSpots );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !isSupported() )
|
if( !isSupported() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -253,7 +229,7 @@ public class FlatNativeWindowBorder
|
|||||||
}
|
}
|
||||||
|
|
||||||
static boolean showWindow( Window window, int cmd ) {
|
static boolean showWindow( Window window, int cmd ) {
|
||||||
if( canUseJBRCustomDecorations || !isSupported() )
|
if( !isSupported() )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return nativeProvider.showWindow( window, cmd );
|
return nativeProvider.showWindow( window, cmd );
|
||||||
@@ -320,20 +296,36 @@ public class FlatNativeWindowBorder
|
|||||||
* No longer needed since Windows 11.
|
* No longer needed since Windows 11.
|
||||||
*/
|
*/
|
||||||
static class WindowTopBorder
|
static class WindowTopBorder
|
||||||
extends JBRCustomDecorations.JBRWindowTopBorder
|
extends BorderUIResource.EmptyBorderUIResource
|
||||||
{
|
{
|
||||||
private static WindowTopBorder instance;
|
private static WindowTopBorder instance;
|
||||||
|
|
||||||
static JBRWindowTopBorder getInstance() {
|
private final Color activeLightColor = new Color( 0x707070 );
|
||||||
if( canUseJBRCustomDecorations )
|
private final Color activeDarkColor = new Color( 0x2D2E2F );
|
||||||
return JBRWindowTopBorder.getInstance();
|
private final Color inactiveLightColor = new Color( 0xaaaaaa );
|
||||||
|
private final Color inactiveDarkColor = new Color( 0x494A4B );
|
||||||
|
|
||||||
|
private boolean colorizationAffectsBorders;
|
||||||
|
private Color activeColor;
|
||||||
|
|
||||||
|
static WindowTopBorder getInstance() {
|
||||||
if( instance == null )
|
if( instance == null )
|
||||||
instance = new WindowTopBorder();
|
instance = new WindowTopBorder();
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
WindowTopBorder() {
|
||||||
|
super( 1, 0, 0, 0 );
|
||||||
|
|
||||||
|
update();
|
||||||
|
installListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void update() {
|
||||||
|
colorizationAffectsBorders = isColorizationColorAffectsBorders();
|
||||||
|
activeColor = calculateActiveBorderColor();
|
||||||
|
}
|
||||||
|
|
||||||
void installListeners() {
|
void installListeners() {
|
||||||
nativeProvider.addChangeListener( e -> {
|
nativeProvider.addChangeListener( e -> {
|
||||||
update();
|
update();
|
||||||
@@ -346,19 +338,69 @@ public class FlatNativeWindowBorder
|
|||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
boolean isColorizationColorAffectsBorders() {
|
boolean isColorizationColorAffectsBorders() {
|
||||||
return nativeProvider.isColorizationColorAffectsBorders();
|
return nativeProvider.isColorizationColorAffectsBorders();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
Color getColorizationColor() {
|
Color getColorizationColor() {
|
||||||
return nativeProvider.getColorizationColor();
|
return nativeProvider.getColorizationColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
int getColorizationColorBalance() {
|
int getColorizationColorBalance() {
|
||||||
return nativeProvider.getColorizationColorBalance();
|
return nativeProvider.getColorizationColorBalance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Color calculateActiveBorderColor() {
|
||||||
|
if( !colorizationAffectsBorders )
|
||||||
|
return null;
|
||||||
|
|
||||||
|
Color colorizationColor = getColorizationColor();
|
||||||
|
if( colorizationColor != null ) {
|
||||||
|
int colorizationColorBalance = getColorizationColorBalance();
|
||||||
|
if( colorizationColorBalance < 0 || colorizationColorBalance > 100 )
|
||||||
|
colorizationColorBalance = 100;
|
||||||
|
|
||||||
|
if( colorizationColorBalance == 0 )
|
||||||
|
return new Color( 0xD9D9D9 );
|
||||||
|
if( colorizationColorBalance == 100 )
|
||||||
|
return colorizationColor;
|
||||||
|
|
||||||
|
float alpha = colorizationColorBalance / 100.0f;
|
||||||
|
float remainder = 1 - alpha;
|
||||||
|
int r = Math.round( colorizationColor.getRed() * alpha + 0xD9 * remainder );
|
||||||
|
int g = Math.round( colorizationColor.getGreen() * alpha + 0xD9 * remainder );
|
||||||
|
int b = Math.round( colorizationColor.getBlue() * alpha + 0xD9 * remainder );
|
||||||
|
|
||||||
|
// avoid potential IllegalArgumentException in Color constructor
|
||||||
|
r = Math.min( Math.max( r, 0 ), 255 );
|
||||||
|
g = Math.min( Math.max( g, 0 ), 255 );
|
||||||
|
b = Math.min( Math.max( b, 0 ), 255 );
|
||||||
|
|
||||||
|
return new Color( r, g, b );
|
||||||
|
}
|
||||||
|
|
||||||
|
Color activeBorderColor = (Color) Toolkit.getDefaultToolkit().getDesktopProperty( "win.frame.activeBorderColor" );
|
||||||
|
return (activeBorderColor != null) ? activeBorderColor : UIManager.getColor( "MenuBar.borderColor" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||||
|
Window window = SwingUtilities.windowForComponent( c );
|
||||||
|
boolean active = window != null && window.isActive();
|
||||||
|
boolean dark = FlatLaf.isLafDark();
|
||||||
|
|
||||||
|
g.setColor( active
|
||||||
|
? (activeColor != null ? activeColor : (dark ? activeDarkColor : activeLightColor))
|
||||||
|
: (dark ? inactiveDarkColor : inactiveLightColor) );
|
||||||
|
HiDPIUtils.paintAtScale1x( (Graphics2D) g, x, y, width, height, this::paintImpl );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void paintImpl( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
|
||||||
|
g.fillRect( x, y, width, 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
void repaintBorder( Component c ) {
|
||||||
|
c.repaint( 0, 0, c.getWidth(), 1 );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,159 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022 FormDev Software GmbH
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.formdev.flatlaf.ui;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.Window;
|
||||||
|
import com.formdev.flatlaf.util.SystemInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Native methods for Windows.
|
||||||
|
* <p>
|
||||||
|
* <b>Note</b>: This is private API. Do not use!
|
||||||
|
*
|
||||||
|
* @author Karl Tauber
|
||||||
|
* @since 3.1
|
||||||
|
*/
|
||||||
|
public class FlatNativeWindowsLibrary
|
||||||
|
{
|
||||||
|
private static long osBuildNumber = Long.MIN_VALUE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether native library is loaded/available.
|
||||||
|
* <p>
|
||||||
|
* <b>Note</b>: It is required to invoke this method before invoking any other
|
||||||
|
* method of this class. Otherwise, the native library may not be loaded.
|
||||||
|
*/
|
||||||
|
public static boolean isLoaded() {
|
||||||
|
return SystemInfo.isWindows && FlatNativeLibrary.isLoaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the Windows operating system build number.
|
||||||
|
* <p>
|
||||||
|
* Invokes Win32 API method {@code GetVersionEx()} and returns {@code OSVERSIONINFO.dwBuildNumber}.
|
||||||
|
* See https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getversionexa
|
||||||
|
*/
|
||||||
|
public static long getOSBuildNumber() {
|
||||||
|
if( osBuildNumber == Long.MIN_VALUE )
|
||||||
|
osBuildNumber = getOSBuildNumberImpl();
|
||||||
|
return osBuildNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invokes Win32 API method {@code GetVersionEx()} and returns {@code OSVERSIONINFO.dwBuildNumber}.
|
||||||
|
* See https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getversionexa
|
||||||
|
*/
|
||||||
|
private native static long getOSBuildNumberImpl();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the Windows window handle (HWND) for the given Swing window.
|
||||||
|
* <p>
|
||||||
|
* Note that the underlying Windows window must be already created,
|
||||||
|
* otherwise this method returns zero. Use following to ensure this:
|
||||||
|
* <pre>{@code
|
||||||
|
* if( !window.isDisplayable() )
|
||||||
|
* window.addNotify();
|
||||||
|
* }</pre>
|
||||||
|
* or invoke this method after packing the window. E.g.
|
||||||
|
* <pre>{@code
|
||||||
|
* window.pack();
|
||||||
|
* long hwnd = getHWND( window );
|
||||||
|
* }</pre>
|
||||||
|
*/
|
||||||
|
public native static long getHWND( Window window );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DWM_WINDOW_CORNER_PREFERENCE
|
||||||
|
* see https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwm_window_corner_preference
|
||||||
|
*/
|
||||||
|
public static final int
|
||||||
|
DWMWCP_DEFAULT = 0,
|
||||||
|
DWMWCP_DONOTROUND = 1,
|
||||||
|
DWMWCP_ROUND = 2,
|
||||||
|
DWMWCP_ROUNDSMALL = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the rounded corner preference for the window.
|
||||||
|
* Allowed values are {@link #DWMWCP_DEFAULT}, {@link #DWMWCP_DONOTROUND},
|
||||||
|
* {@link #DWMWCP_ROUND} and {@link #DWMWCP_ROUNDSMALL}.
|
||||||
|
* <p>
|
||||||
|
* Invokes Win32 API method {@code DwmSetWindowAttribute(DWMWA_WINDOW_CORNER_PREFERENCE)}.
|
||||||
|
* See https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/nf-dwmapi-dwmsetwindowattribute
|
||||||
|
* <p>
|
||||||
|
* Supported since Windows 11 Build 22000.
|
||||||
|
*/
|
||||||
|
public native static boolean setWindowCornerPreference( long hwnd, int cornerPreference );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DWMWINDOWATTRIBUTE
|
||||||
|
* see https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute
|
||||||
|
*
|
||||||
|
* @since 3.3
|
||||||
|
*/
|
||||||
|
public static final int
|
||||||
|
DWMWA_USE_IMMERSIVE_DARK_MODE = 20,
|
||||||
|
DWMWA_BORDER_COLOR = 34,
|
||||||
|
DWMWA_CAPTION_COLOR = 35,
|
||||||
|
DWMWA_TEXT_COLOR = 36;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invokes Win32 API method {@code DwmSetWindowAttribute()} with a {@code BOOL} attribute value.
|
||||||
|
* See https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/nf-dwmapi-dwmsetwindowattribute
|
||||||
|
*
|
||||||
|
* @since 3.3
|
||||||
|
*/
|
||||||
|
public native static boolean dwmSetWindowAttributeBOOL( long hwnd, int attribute, boolean value );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invokes Win32 API method {@code DwmSetWindowAttribute()} with a {@code DWORD} attribute value.
|
||||||
|
* See https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/nf-dwmapi-dwmsetwindowattribute
|
||||||
|
*
|
||||||
|
* @since 3.3
|
||||||
|
*/
|
||||||
|
public native static boolean dwmSetWindowAttributeDWORD( long hwnd, int attribute, int value );
|
||||||
|
|
||||||
|
/** @since 3.3 */
|
||||||
|
public static final int
|
||||||
|
// use this constant to reset any window part colors to the system default behavior
|
||||||
|
DWMWA_COLOR_DEFAULT = 0xFFFFFFFF,
|
||||||
|
// use this constant to specify that a window part should not be rendered
|
||||||
|
DWMWA_COLOR_NONE = 0xFFFFFFFE;
|
||||||
|
|
||||||
|
/** @since 3.3 */
|
||||||
|
public static final Color COLOR_NONE = new Color( 0, true );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invokes Win32 API method {@code DwmSetWindowAttribute()} with a {@code COLORREF} attribute value.
|
||||||
|
* See https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/nf-dwmapi-dwmsetwindowattribute
|
||||||
|
* <p>
|
||||||
|
* Supported since Windows 11 Build 22000.
|
||||||
|
*
|
||||||
|
* @since 3.3
|
||||||
|
*/
|
||||||
|
public static boolean dwmSetWindowAttributeCOLORREF( long hwnd, int attribute, Color color ) {
|
||||||
|
// convert color to Windows RGB value
|
||||||
|
int rgb = (color == COLOR_NONE)
|
||||||
|
? DWMWA_COLOR_NONE
|
||||||
|
: (color != null
|
||||||
|
? (color.getRed() | (color.getGreen() << 8) | (color.getBlue() << 16))
|
||||||
|
: DWMWA_COLOR_DEFAULT);
|
||||||
|
|
||||||
|
// DwmSetWindowAttribute() expects COLORREF as attribute value, which is defined as DWORD
|
||||||
|
return dwmSetWindowAttributeDWORD( hwnd, attribute, rgb );
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,9 +30,7 @@ import javax.swing.JPanel;
|
|||||||
import javax.swing.JRootPane;
|
import javax.swing.JRootPane;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.border.Border;
|
|
||||||
import javax.swing.plaf.ComponentUI;
|
import javax.swing.plaf.ComponentUI;
|
||||||
import javax.swing.plaf.UIResource;
|
|
||||||
import javax.swing.plaf.basic.BasicHTML;
|
import javax.swing.plaf.basic.BasicHTML;
|
||||||
import javax.swing.plaf.basic.BasicOptionPaneUI;
|
import javax.swing.plaf.basic.BasicOptionPaneUI;
|
||||||
import com.formdev.flatlaf.FlatClientProperties;
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
@@ -115,13 +113,6 @@ public class FlatOptionPaneUI
|
|||||||
sameSizeButtons = FlatUIUtils.getUIBoolean( "OptionPane.sameSizeButtons", true );
|
sameSizeButtons = FlatUIUtils.getUIBoolean( "OptionPane.sameSizeButtons", true );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void installComponents() {
|
|
||||||
super.installComponents();
|
|
||||||
|
|
||||||
updateChildPanels( optionPane );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected PropertyChangeListener createPropertyChangeListener() {
|
protected PropertyChangeListener createPropertyChangeListener() {
|
||||||
PropertyChangeListener superListener = super.createPropertyChangeListener();
|
PropertyChangeListener superListener = super.createPropertyChangeListener();
|
||||||
@@ -155,6 +146,13 @@ public class FlatOptionPaneUI
|
|||||||
protected Container createMessageArea() {
|
protected Container createMessageArea() {
|
||||||
Container messageArea = super.createMessageArea();
|
Container messageArea = super.createMessageArea();
|
||||||
|
|
||||||
|
// use non-UIResource OptionPane.messageAreaBorder to avoid that it is replaced when switching LaF
|
||||||
|
// and make panel non-opaque for OptionPane.background
|
||||||
|
updateAreaPanel( messageArea );
|
||||||
|
|
||||||
|
// make known sub-panels non-opaque for OptionPane.background
|
||||||
|
updateKnownChildPanels( messageArea );
|
||||||
|
|
||||||
// set icon-message gap
|
// set icon-message gap
|
||||||
if( iconMessageGap > 0 ) {
|
if( iconMessageGap > 0 ) {
|
||||||
Component iconMessageSeparator = SwingUtils.getComponentByName( messageArea, "OptionPane.separator" );
|
Component iconMessageSeparator = SwingUtils.getComponentByName( messageArea, "OptionPane.separator" );
|
||||||
@@ -169,6 +167,10 @@ public class FlatOptionPaneUI
|
|||||||
protected Container createButtonArea() {
|
protected Container createButtonArea() {
|
||||||
Container buttonArea = super.createButtonArea();
|
Container buttonArea = super.createButtonArea();
|
||||||
|
|
||||||
|
// use non-UIResource OptionPane.buttonAreaBorder to avoid that it is replaced when switching LaF
|
||||||
|
// and make panel non-opaque for OptionPane.background
|
||||||
|
updateAreaPanel( buttonArea );
|
||||||
|
|
||||||
// scale button padding and subtract focusWidth
|
// scale button padding and subtract focusWidth
|
||||||
if( buttonArea.getLayout() instanceof ButtonAreaLayout ) {
|
if( buttonArea.getLayout() instanceof ButtonAreaLayout ) {
|
||||||
ButtonAreaLayout layout = (ButtonAreaLayout) buttonArea.getLayout();
|
ButtonAreaLayout layout = (ButtonAreaLayout) buttonArea.getLayout();
|
||||||
@@ -218,22 +220,33 @@ public class FlatOptionPaneUI
|
|||||||
super.addMessageComponents( container, cons, msg, maxll, internallyCreated );
|
super.addMessageComponents( container, cons, msg, maxll, internallyCreated );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateChildPanels( Container c ) {
|
private void updateAreaPanel( Container area ) {
|
||||||
|
if( !(area instanceof JPanel) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// use non-UIResource border to avoid that it is replaced when switching LaF
|
||||||
|
// and make panel non-opaque for OptionPane.background
|
||||||
|
JPanel panel = (JPanel) area;
|
||||||
|
panel.setBorder( FlatUIUtils.nonUIResource( panel.getBorder() ) );
|
||||||
|
panel.setOpaque( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateKnownChildPanels( Container c ) {
|
||||||
for( Component child : c.getComponents() ) {
|
for( Component child : c.getComponents() ) {
|
||||||
if( child.getClass() == JPanel.class ) {
|
if( child instanceof JPanel && child.getName() != null ) {
|
||||||
JPanel panel = (JPanel)child;
|
switch( child.getName() ) {
|
||||||
|
case "OptionPane.realBody":
|
||||||
// make sub-panel non-opaque for OptionPane.background
|
case "OptionPane.body":
|
||||||
panel.setOpaque( false );
|
case "OptionPane.separator":
|
||||||
|
case "OptionPane.break":
|
||||||
// use non-UIResource borders to avoid that they are replaced when switching LaF
|
// make known sub-panels non-opaque for OptionPane.background
|
||||||
Border border = panel.getBorder();
|
((JPanel)child).setOpaque( false );
|
||||||
if( border instanceof UIResource )
|
break;
|
||||||
panel.setBorder( FlatUIUtils.nonUIResource( border ) );
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( child instanceof Container )
|
if( child instanceof Container )
|
||||||
updateChildPanels( (Container) child );
|
updateKnownChildPanels( (Container) child );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,6 @@ import com.formdev.flatlaf.util.UIScale;
|
|||||||
* <!-- FlatTextFieldUI -->
|
* <!-- FlatTextFieldUI -->
|
||||||
*
|
*
|
||||||
* @uiDefault Component.minimumWidth int
|
* @uiDefault Component.minimumWidth int
|
||||||
* @uiDefault Component.isIntelliJTheme boolean
|
|
||||||
* @uiDefault PasswordField.placeholderForeground Color
|
* @uiDefault PasswordField.placeholderForeground Color
|
||||||
* @uiDefault PasswordField.focusedBackground Color optional
|
* @uiDefault PasswordField.focusedBackground Color optional
|
||||||
* @uiDefault PasswordField.iconTextGap int optional, default is 4
|
* @uiDefault PasswordField.iconTextGap int optional, default is 4
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import java.awt.Window;
|
|||||||
import java.awt.event.ComponentEvent;
|
import java.awt.event.ComponentEvent;
|
||||||
import java.awt.event.ComponentListener;
|
import java.awt.event.ComponentListener;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
|
import java.awt.event.WindowFocusListener;
|
||||||
import java.lang.invoke.MethodHandle;
|
import java.lang.invoke.MethodHandle;
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
import java.lang.invoke.MethodType;
|
import java.lang.invoke.MethodType;
|
||||||
@@ -43,6 +44,7 @@ import java.lang.reflect.Method;
|
|||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JLayeredPane;
|
import javax.swing.JLayeredPane;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JPopupMenu;
|
||||||
import javax.swing.JToolTip;
|
import javax.swing.JToolTip;
|
||||||
import javax.swing.JWindow;
|
import javax.swing.JWindow;
|
||||||
import javax.swing.Popup;
|
import javax.swing.Popup;
|
||||||
@@ -52,6 +54,9 @@ import javax.swing.SwingUtilities;
|
|||||||
import javax.swing.ToolTipManager;
|
import javax.swing.ToolTipManager;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.border.Border;
|
import javax.swing.border.Border;
|
||||||
|
import javax.swing.border.EmptyBorder;
|
||||||
|
import javax.swing.border.LineBorder;
|
||||||
|
import javax.swing.plaf.basic.BasicComboPopup;
|
||||||
import com.formdev.flatlaf.FlatClientProperties;
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
import com.formdev.flatlaf.util.SystemInfo;
|
import com.formdev.flatlaf.util.SystemInfo;
|
||||||
import com.formdev.flatlaf.util.UIScale;
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
@@ -66,6 +71,8 @@ import com.formdev.flatlaf.util.UIScale;
|
|||||||
public class FlatPopupFactory
|
public class FlatPopupFactory
|
||||||
extends PopupFactory
|
extends PopupFactory
|
||||||
{
|
{
|
||||||
|
static final String KEY_POPUP_USES_NATIVE_BORDER = "FlatLaf.internal.FlatPopupFactory.popupUsesNativeBorder";
|
||||||
|
|
||||||
private MethodHandle java8getPopupMethod;
|
private MethodHandle java8getPopupMethod;
|
||||||
private MethodHandle java9getPopupMethod;
|
private MethodHandle java9getPopupMethod;
|
||||||
|
|
||||||
@@ -79,14 +86,34 @@ public class FlatPopupFactory
|
|||||||
y = pt.y;
|
y = pt.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fixLinuxWaylandJava21focusIssue( owner );
|
||||||
|
|
||||||
boolean forceHeavyWeight = isOptionEnabled( owner, contents, FlatClientProperties.POPUP_FORCE_HEAVY_WEIGHT, "Popup.forceHeavyWeight" );
|
boolean forceHeavyWeight = isOptionEnabled( owner, contents, FlatClientProperties.POPUP_FORCE_HEAVY_WEIGHT, "Popup.forceHeavyWeight" );
|
||||||
|
|
||||||
if( !isOptionEnabled( owner, contents, FlatClientProperties.POPUP_DROP_SHADOW_PAINTED, "Popup.dropShadowPainted" ) || SystemInfo.isProjector || SystemInfo.isWebswing )
|
if( !isOptionEnabled( owner, contents, FlatClientProperties.POPUP_DROP_SHADOW_PAINTED, "Popup.dropShadowPainted" ) || SystemInfo.isProjector || SystemInfo.isWebswing )
|
||||||
return new NonFlashingPopup( getPopupForScreenOfOwner( owner, contents, x, y, forceHeavyWeight ), contents );
|
return new NonFlashingPopup( getPopupForScreenOfOwner( owner, contents, x, y, forceHeavyWeight ), contents );
|
||||||
|
|
||||||
// macOS and Linux adds drop shadow to heavy weight popups
|
// macOS and Linux adds drop shadow to heavy weight popups
|
||||||
if( SystemInfo.isMacOS || SystemInfo.isLinux )
|
if( SystemInfo.isMacOS || SystemInfo.isLinux ) {
|
||||||
return new NonFlashingPopup( getPopupForScreenOfOwner( owner, contents, x, y, true ), contents );
|
NonFlashingPopup popup = new NonFlashingPopup( getPopupForScreenOfOwner( owner, contents, x, y, true ), contents );
|
||||||
|
if( popup.popupWindow != null && SystemInfo.isMacOS && FlatNativeMacLibrary.isLoaded() )
|
||||||
|
setupRoundedBorder( popup.popupWindow, owner, contents );
|
||||||
|
return popup;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Windows 11 with FlatLaf native library can use rounded corners and shows drop shadow for heavy weight popups
|
||||||
|
if( isWindows11BorderSupported() &&
|
||||||
|
getBorderCornerRadius( owner, contents ) > 0 )
|
||||||
|
{
|
||||||
|
NonFlashingPopup popup = new NonFlashingPopup( getPopupForScreenOfOwner( owner, contents, x, y, true ), contents );
|
||||||
|
if( popup.popupWindow != null )
|
||||||
|
setupRoundedBorder( popup.popupWindow, owner, contents );
|
||||||
|
return popup;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check whether popup overlaps a heavy weight component
|
||||||
|
if( !forceHeavyWeight && overlapsHeavyWeightComponent( owner, contents, x, y ) )
|
||||||
|
forceHeavyWeight = true;
|
||||||
|
|
||||||
// create drop shadow popup
|
// create drop shadow popup
|
||||||
return new DropShadowPopup( getPopupForScreenOfOwner( owner, contents, x, y, forceHeavyWeight ), owner, contents );
|
return new DropShadowPopup( getPopupForScreenOfOwner( owner, contents, x, y, forceHeavyWeight ), owner, contents );
|
||||||
@@ -140,47 +167,6 @@ public class FlatPopupFactory
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows the given popup and, if necessary, fixes the location of a heavy weight popup window.
|
|
||||||
* <p>
|
|
||||||
* On a dual screen setup, where screens use different scale factors, it may happen
|
|
||||||
* that the window location changes when showing a heavy weight popup window.
|
|
||||||
* E.g. when opening a dialog on the secondary screen and making combobox popup visible.
|
|
||||||
* <p>
|
|
||||||
* This is a workaround for https://bugs.openjdk.java.net/browse/JDK-8224608
|
|
||||||
*/
|
|
||||||
private static void showPopupAndFixLocation( Popup popup, Window popupWindow ) {
|
|
||||||
if( popupWindow != null ) {
|
|
||||||
// remember location of heavy weight popup window
|
|
||||||
int x = popupWindow.getX();
|
|
||||||
int y = popupWindow.getY();
|
|
||||||
|
|
||||||
popup.show();
|
|
||||||
|
|
||||||
// restore popup window location if it has changed
|
|
||||||
// (probably scaled when screens use different scale factors)
|
|
||||||
if( popupWindow.getX() != x || popupWindow.getY() != y )
|
|
||||||
popupWindow.setLocation( x, y );
|
|
||||||
} else
|
|
||||||
popup.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isOptionEnabled( Component owner, Component contents, String clientKey, String uiKey ) {
|
|
||||||
if( owner instanceof JComponent ) {
|
|
||||||
Boolean b = FlatClientProperties.clientPropertyBooleanStrict( (JComponent) owner, clientKey, null );
|
|
||||||
if( b != null )
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( contents instanceof JComponent ) {
|
|
||||||
Boolean b = FlatClientProperties.clientPropertyBooleanStrict( (JComponent) contents, clientKey, null );
|
|
||||||
if( b != null )
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
return UIManager.getBoolean( uiKey );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* There is no API in Java 8 to force creation of heavy weight popups,
|
* There is no API in Java 8 to force creation of heavy weight popups,
|
||||||
* but it is possible with reflection. Java 9 provides a new method.
|
* but it is possible with reflection. Java 9 provides a new method.
|
||||||
@@ -216,6 +202,33 @@ public class FlatPopupFactory
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isOptionEnabled( Component owner, Component contents, String clientKey, String uiKey ) {
|
||||||
|
Object value = getOption( owner, contents, clientKey, uiKey );
|
||||||
|
return (value instanceof Boolean) ? (Boolean) value : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get option from:
|
||||||
|
* <ol>
|
||||||
|
* <li>client property {@code clientKey} of {@code owner}
|
||||||
|
* <li>client property {@code clientKey} of {@code contents}
|
||||||
|
* <li>UI property {@code uiKey}
|
||||||
|
* </ol>
|
||||||
|
*/
|
||||||
|
private static Object getOption( Component owner, Component contents, String clientKey, String uiKey ) {
|
||||||
|
for( Component c : new Component[] { owner, contents } ) {
|
||||||
|
if( c instanceof JComponent ) {
|
||||||
|
Object value = ((JComponent)c).getClientProperty( clientKey );
|
||||||
|
if( value != null )
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return UIManager.get( uiKey );
|
||||||
|
}
|
||||||
|
|
||||||
|
//---- tooltips -----------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Usually ToolTipManager places a tooltip at (mouseLocation.x, mouseLocation.y + 20).
|
* Usually ToolTipManager places a tooltip at (mouseLocation.x, mouseLocation.y + 20).
|
||||||
* In case that the tooltip would be partly outside of the screen,
|
* In case that the tooltip would be partly outside of the screen,
|
||||||
@@ -300,9 +313,184 @@ public class FlatPopupFactory
|
|||||||
((JComponent)owner).getToolTipLocation( me ) != null;
|
((JComponent)owner).getToolTipLocation( me ) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---- native rounded border ----------------------------------------------
|
||||||
|
|
||||||
|
private static boolean isWindows11BorderSupported() {
|
||||||
|
return SystemInfo.isWindows_11_orLater && FlatNativeWindowsLibrary.isLoaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void setupRoundedBorder( Window popupWindow, Component owner, Component contents ) {
|
||||||
|
// make sure that the native window is created
|
||||||
|
if( !popupWindow.isDisplayable() )
|
||||||
|
popupWindow.addNotify();
|
||||||
|
|
||||||
|
int borderCornerRadius = getBorderCornerRadius( owner, contents );
|
||||||
|
float borderWidth = getRoundedBorderWidth( owner, contents );
|
||||||
|
|
||||||
|
// get Swing border color
|
||||||
|
Color borderColor = null; // use system default color
|
||||||
|
if( contents instanceof JComponent ) {
|
||||||
|
Border border = ((JComponent)contents).getBorder();
|
||||||
|
border = FlatUIUtils.unwrapNonUIResourceBorder( border );
|
||||||
|
|
||||||
|
// get color from border of contents (e.g. JPopupMenu or JToolTip)
|
||||||
|
if( border instanceof FlatLineBorder )
|
||||||
|
borderColor = ((FlatLineBorder)border).getLineColor();
|
||||||
|
else if( border instanceof LineBorder )
|
||||||
|
borderColor = ((LineBorder)border).getLineColor();
|
||||||
|
else if( border instanceof EmptyBorder )
|
||||||
|
borderColor = FlatNativeWindowsLibrary.COLOR_NONE; // do not paint border
|
||||||
|
|
||||||
|
// avoid that FlatLineBorder paints the Swing border
|
||||||
|
((JComponent)contents).putClientProperty( KEY_POPUP_USES_NATIVE_BORDER, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( SystemInfo.isWindows ) {
|
||||||
|
// get native window handle
|
||||||
|
long hwnd = FlatNativeWindowsLibrary.getHWND( popupWindow );
|
||||||
|
|
||||||
|
// set corner preference
|
||||||
|
int cornerPreference = (borderCornerRadius <= 4)
|
||||||
|
? FlatNativeWindowsLibrary.DWMWCP_ROUNDSMALL // 4px
|
||||||
|
: FlatNativeWindowsLibrary.DWMWCP_ROUND; // 8px
|
||||||
|
FlatNativeWindowsLibrary.setWindowCornerPreference( hwnd, cornerPreference );
|
||||||
|
|
||||||
|
// set border color
|
||||||
|
FlatNativeWindowsLibrary.dwmSetWindowAttributeCOLORREF( hwnd, FlatNativeWindowsLibrary.DWMWA_BORDER_COLOR, borderColor );
|
||||||
|
} else if( SystemInfo.isMacOS ) {
|
||||||
|
if( borderColor == null || borderColor == FlatNativeWindowsLibrary.COLOR_NONE )
|
||||||
|
borderWidth = 0;
|
||||||
|
|
||||||
|
// set corner radius, border width and color
|
||||||
|
FlatNativeMacLibrary.setWindowRoundedBorder( popupWindow, borderCornerRadius,
|
||||||
|
borderWidth, (borderColor != null) ? borderColor.getRGB() : 0 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void resetWindows11Border( Window popupWindow ) {
|
||||||
|
// get window handle
|
||||||
|
long hwnd = FlatNativeWindowsLibrary.getHWND( popupWindow );
|
||||||
|
if( hwnd == 0 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// reset corner preference
|
||||||
|
FlatNativeWindowsLibrary.setWindowCornerPreference( hwnd, FlatNativeWindowsLibrary.DWMWCP_DONOTROUND );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getBorderCornerRadius( Component owner, Component contents ) {
|
||||||
|
String uiKey =
|
||||||
|
(contents instanceof BasicComboPopup) ? "ComboBox.borderCornerRadius" :
|
||||||
|
(contents instanceof JPopupMenu) ? "PopupMenu.borderCornerRadius" :
|
||||||
|
(contents instanceof JToolTip) ? "ToolTip.borderCornerRadius" :
|
||||||
|
"Popup.borderCornerRadius";
|
||||||
|
|
||||||
|
Object value = getOption( owner, contents, FlatClientProperties.POPUP_BORDER_CORNER_RADIUS, uiKey );
|
||||||
|
return (value instanceof Integer) ? (Integer) value : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float getRoundedBorderWidth( Component owner, Component contents ) {
|
||||||
|
String uiKey =
|
||||||
|
(contents instanceof BasicComboPopup) ? "ComboBox.roundedBorderWidth" :
|
||||||
|
(contents instanceof JPopupMenu) ? "PopupMenu.roundedBorderWidth" :
|
||||||
|
(contents instanceof JToolTip) ? "ToolTip.roundedBorderWidth" :
|
||||||
|
"Popup.roundedBorderWidth";
|
||||||
|
|
||||||
|
Object value = getOption( owner, contents, FlatClientProperties.POPUP_ROUNDED_BORDER_WIDTH, uiKey );
|
||||||
|
return (value instanceof Number) ? ((Number)value).floatValue() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---- fixes --------------------------------------------------------------
|
||||||
|
|
||||||
|
private static boolean overlapsHeavyWeightComponent( Component owner, Component contents, int x, int y ) {
|
||||||
|
if( owner == null )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Window window = SwingUtilities.getWindowAncestor( owner );
|
||||||
|
if( window == null )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Rectangle r = new Rectangle( new Point( x, y ), contents.getPreferredSize() );
|
||||||
|
return overlapsHeavyWeightComponent( window, r );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean overlapsHeavyWeightComponent( Component parent, Rectangle r ) {
|
||||||
|
if( !parent.isVisible() || !r.intersects( parent.getBounds() ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( !parent.isLightweight() && !(parent instanceof Window) )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if( parent instanceof Container ) {
|
||||||
|
Rectangle r2 = new Rectangle( r.x - parent.getX(), r.y - parent.getY(), r.width, r.height );
|
||||||
|
for( Component c : ((Container)parent).getComponents() ) {
|
||||||
|
if( overlapsHeavyWeightComponent( c, r2 ) )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On Linux with Wayland, since Java 21, Swing adds a window focus listener to popup owner/invoker window,
|
||||||
|
* which hides the popup as soon as the owner/invoker window looses focus.
|
||||||
|
* This works fine for light-weight popups.
|
||||||
|
* It also works for heavy-weight popups if they do not request focus.
|
||||||
|
* Because FlatLaf always uses heavy-weight popups, all popups that request focus
|
||||||
|
* are broken since Java 21.
|
||||||
|
*
|
||||||
|
* This method removes the problematic window focus listener.
|
||||||
|
*
|
||||||
|
* https://bugs.openjdk.org/browse/JDK-8280993
|
||||||
|
* https://github.com/openjdk/jdk/pull/13830
|
||||||
|
*/
|
||||||
|
private static void fixLinuxWaylandJava21focusIssue( Component owner ) {
|
||||||
|
// only necessary on Linux when running in Java 21+
|
||||||
|
if( owner == null || !SystemInfo.isLinux || SystemInfo.javaVersion < SystemInfo.toVersion( 21, 0, 0, 0 ) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// get window
|
||||||
|
Window window = SwingUtilities.getWindowAncestor( owner );
|
||||||
|
if( window == null )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// remove window focus listener, which was added from class sun.awt.UNIXToolkit since Java 21
|
||||||
|
for( WindowFocusListener l : window.getWindowFocusListeners() ) {
|
||||||
|
if( "sun.awt.UNIXToolkit$1".equals( l.getClass().getName() ) ) {
|
||||||
|
window.removeWindowFocusListener( l );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows the given popup and, if necessary, fixes the location of a heavy weight popup window.
|
||||||
|
* <p>
|
||||||
|
* On a dual screen setup, where screens use different scale factors, it may happen
|
||||||
|
* that the window location changes when showing a heavy weight popup window.
|
||||||
|
* E.g. when opening a dialog on the secondary screen and making combobox popup visible.
|
||||||
|
* <p>
|
||||||
|
* This is a workaround for https://bugs.openjdk.java.net/browse/JDK-8224608
|
||||||
|
*/
|
||||||
|
private static void showPopupAndFixLocation( Popup popup, Window popupWindow ) {
|
||||||
|
if( popupWindow != null ) {
|
||||||
|
// remember location of heavy weight popup window
|
||||||
|
int x = popupWindow.getX();
|
||||||
|
int y = popupWindow.getY();
|
||||||
|
|
||||||
|
popup.show();
|
||||||
|
|
||||||
|
// restore popup window location if it has changed
|
||||||
|
// (probably scaled when screens use different scale factors)
|
||||||
|
if( popupWindow.getX() != x || popupWindow.getY() != y )
|
||||||
|
popupWindow.setLocation( x, y );
|
||||||
|
} else
|
||||||
|
popup.show();
|
||||||
|
}
|
||||||
|
|
||||||
//---- class NonFlashingPopup ---------------------------------------------
|
//---- class NonFlashingPopup ---------------------------------------------
|
||||||
|
|
||||||
private class NonFlashingPopup
|
private static class NonFlashingPopup
|
||||||
extends Popup
|
extends Popup
|
||||||
{
|
{
|
||||||
private Popup delegate;
|
private Popup delegate;
|
||||||
@@ -353,6 +541,9 @@ public class FlatPopupFactory
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void hide() {
|
public void hide() {
|
||||||
|
if( contents instanceof JComponent )
|
||||||
|
((JComponent)contents).putClientProperty( KEY_POPUP_USES_NATIVE_BORDER, null );
|
||||||
|
|
||||||
if( delegate != null ) {
|
if( delegate != null ) {
|
||||||
delegate.hide();
|
delegate.hide();
|
||||||
delegate = null;
|
delegate = null;
|
||||||
@@ -431,6 +622,14 @@ public class FlatPopupFactory
|
|||||||
oldDropShadowWindowBackground = dropShadowWindow.getBackground();
|
oldDropShadowWindowBackground = dropShadowWindow.getBackground();
|
||||||
dropShadowWindow.setBackground( new Color( 0, true ) );
|
dropShadowWindow.setBackground( new Color( 0, true ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Windows 11: reset corner preference on reused heavy weight popups
|
||||||
|
if( isWindows11BorderSupported() ) {
|
||||||
|
resetWindows11Border( popupWindow );
|
||||||
|
if( dropShadowWindow != null )
|
||||||
|
resetWindows11Border( dropShadowWindow );
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
mediumWeightPanel = (Panel) SwingUtilities.getAncestorOfClass( Panel.class, contents );
|
mediumWeightPanel = (Panel) SwingUtilities.getAncestorOfClass( Panel.class, contents );
|
||||||
if( mediumWeightPanel != null ) {
|
if( mediumWeightPanel != null ) {
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ import javax.swing.plaf.basic.BasicComboPopup;
|
|||||||
import javax.swing.plaf.basic.BasicMenuItemUI;
|
import javax.swing.plaf.basic.BasicMenuItemUI;
|
||||||
import javax.swing.plaf.basic.BasicPopupMenuUI;
|
import javax.swing.plaf.basic.BasicPopupMenuUI;
|
||||||
import javax.swing.plaf.basic.DefaultMenuLayout;
|
import javax.swing.plaf.basic.DefaultMenuLayout;
|
||||||
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||||
import com.formdev.flatlaf.util.LoggingFacade;
|
import com.formdev.flatlaf.util.LoggingFacade;
|
||||||
@@ -192,27 +193,38 @@ public class FlatPopupMenuUI
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Popup getPopup( JPopupMenu popup, int x, int y ) {
|
public Popup getPopup( JPopupMenu popup, int x, int y ) {
|
||||||
|
Dimension popupSize = popup.getPreferredSize();
|
||||||
|
Rectangle screenBounds = getScreenBoundsAt( x, y );
|
||||||
|
|
||||||
|
// make sure that popup does not overlap any task/side bar
|
||||||
|
if( x + popupSize.width > screenBounds.x + screenBounds.width )
|
||||||
|
x = screenBounds.x + screenBounds.width - popupSize.width;
|
||||||
|
if( y + popupSize.height > screenBounds.y + screenBounds.height )
|
||||||
|
y = screenBounds.y + screenBounds.height - popupSize.height;
|
||||||
|
if( x < screenBounds.x )
|
||||||
|
x = screenBounds.x;
|
||||||
|
if( y < screenBounds.y )
|
||||||
|
y = screenBounds.y;
|
||||||
|
|
||||||
// do not add scroller to combobox popups or to popups that already have a scroll pane
|
// do not add scroller to combobox popups or to popups that already have a scroll pane
|
||||||
if( popup instanceof BasicComboPopup ||
|
if( popup instanceof BasicComboPopup ||
|
||||||
(popup.getComponentCount() > 0 && popup.getComponent( 0 ) instanceof JScrollPane) )
|
(popup.getComponentCount() > 0 && popup.getComponent( 0 ) instanceof JScrollPane) )
|
||||||
return super.getPopup( popup, x, y );
|
return super.getPopup( popup, x, y );
|
||||||
|
|
||||||
// do not add scroller if popup fits into screen
|
// do not add scroller if popup fits into screen
|
||||||
Dimension prefSize = popup.getPreferredSize();
|
if( popupSize.height <= screenBounds.height )
|
||||||
int screenHeight = getScreenHeightAt( x, y );
|
|
||||||
if( prefSize.height <= screenHeight )
|
|
||||||
return super.getPopup( popup, x, y );
|
return super.getPopup( popup, x, y );
|
||||||
|
|
||||||
// create scroller
|
// create scroller
|
||||||
FlatPopupScroller scroller = new FlatPopupScroller( popup );
|
FlatPopupScroller scroller = new FlatPopupScroller( popup );
|
||||||
scroller.setPreferredSize( new Dimension( prefSize.width, screenHeight ) );
|
scroller.setPreferredSize( new Dimension( popupSize.width, screenBounds.height ) );
|
||||||
|
|
||||||
// create popup
|
// create popup
|
||||||
PopupFactory popupFactory = PopupFactory.getSharedInstance();
|
PopupFactory popupFactory = PopupFactory.getSharedInstance();
|
||||||
return popupFactory.getPopup( popup.getInvoker(), scroller, x, y );
|
return popupFactory.getPopup( popup.getInvoker(), scroller, x, y );
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getScreenHeightAt( int x, int y ) {
|
private Rectangle getScreenBoundsAt( int x, int y ) {
|
||||||
// find GraphicsConfiguration at popup location (similar to JPopupMenu.getCurrentGraphicsConfiguration())
|
// find GraphicsConfiguration at popup location (similar to JPopupMenu.getCurrentGraphicsConfiguration())
|
||||||
GraphicsConfiguration gc = null;
|
GraphicsConfiguration gc = null;
|
||||||
for( GraphicsDevice device : GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices() ) {
|
for( GraphicsDevice device : GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices() ) {
|
||||||
@@ -233,7 +245,7 @@ public class FlatPopupMenuUI
|
|||||||
Toolkit toolkit = Toolkit.getDefaultToolkit();
|
Toolkit toolkit = Toolkit.getDefaultToolkit();
|
||||||
Rectangle screenBounds = (gc != null) ? gc.getBounds() : new Rectangle( toolkit.getScreenSize() );
|
Rectangle screenBounds = (gc != null) ? gc.getBounds() : new Rectangle( toolkit.getScreenSize() );
|
||||||
Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets( gc );
|
Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets( gc );
|
||||||
return screenBounds.height - screenInsets.top - screenInsets.bottom;
|
return FlatUIUtils.subtractInsets( screenBounds, screenInsets );
|
||||||
}
|
}
|
||||||
|
|
||||||
//---- class FlatPopupMenuLayout ------------------------------------------
|
//---- class FlatPopupMenuLayout ------------------------------------------
|
||||||
@@ -297,6 +309,9 @@ public class FlatPopupMenuUI
|
|||||||
popup.addMenuKeyListener( this );
|
popup.addMenuKeyListener( this );
|
||||||
|
|
||||||
updateArrowButtons();
|
updateArrowButtons();
|
||||||
|
|
||||||
|
putClientProperty( FlatClientProperties.POPUP_BORDER_CORNER_RADIUS,
|
||||||
|
UIManager.getInt( "PopupMenu.borderCornerRadius" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void scroll( int unitsToScroll ) {
|
void scroll( int unitsToScroll ) {
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import javax.swing.CellRendererPane;
|
|||||||
import javax.swing.Icon;
|
import javax.swing.Icon;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.LookAndFeel;
|
import javax.swing.LookAndFeel;
|
||||||
|
import javax.swing.SwingConstants;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.plaf.ComponentUI;
|
import javax.swing.plaf.ComponentUI;
|
||||||
@@ -208,6 +209,9 @@ public class FlatRadioButtonUI
|
|||||||
return ((FlatCheckBoxIcon)icon).applyStyleProperty( key, value );
|
return ((FlatCheckBoxIcon)icon).applyStyleProperty( key, value );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( "iconTextGap".equals( key ) && value instanceof Integer )
|
||||||
|
value = UIScale.scale( (Integer) value );
|
||||||
|
|
||||||
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, b, key, value );
|
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, b, key, value );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,7 +263,7 @@ public class FlatRadioButtonUI
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paint( Graphics g, JComponent c ) {
|
public void paint( Graphics g, JComponent c ) {
|
||||||
// fill background even if not opaque if
|
// fill background even if not opaque and if:
|
||||||
// - contentAreaFilled is true and
|
// - contentAreaFilled is true and
|
||||||
// - if background color is different to default background color
|
// - if background color is different to default background color
|
||||||
// (this paints selection if using the component as cell renderer)
|
// (this paints selection if using the component as cell renderer)
|
||||||
@@ -275,20 +279,27 @@ public class FlatRadioButtonUI
|
|||||||
int focusWidth = getIconFocusWidth( c );
|
int focusWidth = getIconFocusWidth( c );
|
||||||
if( focusWidth > 0 ) {
|
if( focusWidth > 0 ) {
|
||||||
boolean ltr = c.getComponentOrientation().isLeftToRight();
|
boolean ltr = c.getComponentOrientation().isLeftToRight();
|
||||||
|
int halign = ((AbstractButton)c).getHorizontalAlignment();
|
||||||
|
if( halign == SwingConstants.LEADING )
|
||||||
|
halign = ltr ? SwingConstants.LEFT : SwingConstants.RIGHT;
|
||||||
|
else if( halign == SwingConstants.TRAILING )
|
||||||
|
halign = ltr ? SwingConstants.RIGHT : SwingConstants.LEFT;
|
||||||
|
|
||||||
Insets insets = c.getInsets( tempInsets );
|
Insets insets = c.getInsets( tempInsets );
|
||||||
int leftOrRightInset = ltr ? insets.left : insets.right;
|
if( (focusWidth > insets.left || focusWidth > insets.right) &&
|
||||||
if( focusWidth > leftOrRightInset ) {
|
(halign == SwingConstants.LEFT || halign == SwingConstants.RIGHT) )
|
||||||
|
{
|
||||||
// The left (or right) inset is smaller than the focus width, which may be
|
// The left (or right) inset is smaller than the focus width, which may be
|
||||||
// the case if insets were explicitly reduced (e.g. with an EmptyBorder).
|
// the case if insets were explicitly reduced (e.g. with an EmptyBorder).
|
||||||
// In this case the width has been increased in getPreferredSize() and
|
// In this case the width has been increased in getPreferredSize() and
|
||||||
// here it is necessary to fix icon and text painting location.
|
// here it is necessary to fix icon and text painting location.
|
||||||
int offset = focusWidth - leftOrRightInset;
|
int offset = (halign == SwingConstants.LEFT)
|
||||||
if( !ltr )
|
? Math.max( focusWidth - insets.left, 0 )
|
||||||
offset = -offset;
|
: -Math.max( focusWidth - insets.right, 0 );
|
||||||
|
|
||||||
// move the graphics origin to the left (or right)
|
// move the graphics origin to the left (or right)
|
||||||
g.translate( offset, 0 );
|
g.translate( offset, 0 );
|
||||||
super.paint( g, c );
|
super.paint( FlatLabelUI.createGraphicsHTMLTextYCorrection( g, c ), c );
|
||||||
g.translate( -offset, 0 );
|
g.translate( -offset, 0 );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -325,6 +336,11 @@ public class FlatRadioButtonUI
|
|||||||
: 0;
|
: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBaseline( JComponent c, int width, int height ) {
|
||||||
|
return FlatButtonUI.getBaselineImpl( c, width, height );
|
||||||
|
}
|
||||||
|
|
||||||
//---- class FlatRadioButtonListener --------------------------------------
|
//---- class FlatRadioButtonListener --------------------------------------
|
||||||
|
|
||||||
/** @since 2 */
|
/** @since 2 */
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import java.awt.Dimension;
|
|||||||
import java.awt.Frame;
|
import java.awt.Frame;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.IllegalComponentStateException;
|
||||||
import java.awt.Insets;
|
import java.awt.Insets;
|
||||||
import java.awt.LayoutManager;
|
import java.awt.LayoutManager;
|
||||||
import java.awt.LayoutManager2;
|
import java.awt.LayoutManager2;
|
||||||
@@ -49,7 +50,6 @@ import javax.swing.plaf.RootPaneUI;
|
|||||||
import javax.swing.plaf.UIResource;
|
import javax.swing.plaf.UIResource;
|
||||||
import javax.swing.plaf.basic.BasicRootPaneUI;
|
import javax.swing.plaf.basic.BasicRootPaneUI;
|
||||||
import com.formdev.flatlaf.FlatClientProperties;
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
import com.formdev.flatlaf.FlatLaf;
|
|
||||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||||
import com.formdev.flatlaf.util.SystemInfo;
|
import com.formdev.flatlaf.util.SystemInfo;
|
||||||
import com.formdev.flatlaf.util.UIScale;
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
@@ -155,10 +155,6 @@ public class FlatRootPaneUI
|
|||||||
if( background == null || background instanceof UIResource )
|
if( background == null || background instanceof UIResource )
|
||||||
parent.setBackground( UIManager.getColor( "control" ) );
|
parent.setBackground( UIManager.getColor( "control" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
// enable dark window appearance on macOS when running in JetBrains Runtime
|
|
||||||
if( SystemInfo.isJetBrainsJVM && SystemInfo.isMacOS_10_14_Mojave_orLater )
|
|
||||||
c.putClientProperty( "jetbrains.awt.windowDarkAppearance", FlatLaf.isLafDark() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -362,6 +358,15 @@ public class FlatRootPaneUI
|
|||||||
if( titlePane != null )
|
if( titlePane != null )
|
||||||
titlePane.titleBarColorsChanged();
|
titlePane.titleBarColorsChanged();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case FlatClientProperties.GLASS_PANE_FULL_HEIGHT:
|
||||||
|
rootPane.revalidate();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FlatClientProperties.WINDOW_STYLE:
|
||||||
|
if( rootPane.isDisplayable() )
|
||||||
|
throw new IllegalComponentStateException( "The client property 'Window.style' must be set before the window becomes displayable." );
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -442,11 +447,11 @@ public class FlatRootPaneUI
|
|||||||
int width = rootPane.getWidth() - insets.left - insets.right;
|
int width = rootPane.getWidth() - insets.left - insets.right;
|
||||||
int height = rootPane.getHeight() - insets.top - insets.bottom;
|
int height = rootPane.getHeight() - insets.top - insets.bottom;
|
||||||
|
|
||||||
|
// layered pane
|
||||||
if( rootPane.getLayeredPane() != null )
|
if( rootPane.getLayeredPane() != null )
|
||||||
rootPane.getLayeredPane().setBounds( x, y, width, height );
|
rootPane.getLayeredPane().setBounds( x, y, width, height );
|
||||||
if( rootPane.getGlassPane() != null )
|
|
||||||
rootPane.getGlassPane().setBounds( x, y, width, height );
|
|
||||||
|
|
||||||
|
// title pane
|
||||||
int nextY = 0;
|
int nextY = 0;
|
||||||
if( titlePane != null ) {
|
if( titlePane != null ) {
|
||||||
int prefHeight = !isFullScreen ? titlePane.getPreferredSize().height : 0;
|
int prefHeight = !isFullScreen ? titlePane.getPreferredSize().height : 0;
|
||||||
@@ -454,6 +459,15 @@ public class FlatRootPaneUI
|
|||||||
nextY += prefHeight;
|
nextY += prefHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// glass pane
|
||||||
|
if( rootPane.getGlassPane() != null ) {
|
||||||
|
boolean fullHeight = FlatClientProperties.clientPropertyBoolean(
|
||||||
|
rootPane, FlatClientProperties.GLASS_PANE_FULL_HEIGHT, false );
|
||||||
|
int offset = fullHeight ? 0 : nextY;
|
||||||
|
rootPane.getGlassPane().setBounds( x, y + offset, width, height - offset );
|
||||||
|
}
|
||||||
|
|
||||||
|
// menu bar
|
||||||
JMenuBar menuBar = rootPane.getJMenuBar();
|
JMenuBar menuBar = rootPane.getJMenuBar();
|
||||||
if( menuBar != null && menuBar.isVisible() ) {
|
if( menuBar != null && menuBar.isVisible() ) {
|
||||||
boolean embedded = !isFullScreen && titlePane != null && titlePane.isMenuBarEmbedded();
|
boolean embedded = !isFullScreen && titlePane != null && titlePane.isMenuBarEmbedded();
|
||||||
@@ -467,10 +481,12 @@ public class FlatRootPaneUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// content pane
|
||||||
Container contentPane = rootPane.getContentPane();
|
Container contentPane = rootPane.getContentPane();
|
||||||
if( contentPane != null )
|
if( contentPane != null )
|
||||||
contentPane.setBounds( 0, nextY, width, Math.max( height - nextY, 0 ) );
|
contentPane.setBounds( 0, nextY, width, Math.max( height - nextY, 0 ) );
|
||||||
|
|
||||||
|
// title pane
|
||||||
if( titlePane != null )
|
if( titlePane != null )
|
||||||
titlePane.menuBarLayouted();
|
titlePane.menuBarLayouted();
|
||||||
}
|
}
|
||||||
@@ -478,7 +494,7 @@ public class FlatRootPaneUI
|
|||||||
@Override
|
@Override
|
||||||
public void invalidateLayout( Container parent ) {
|
public void invalidateLayout( Container parent ) {
|
||||||
if( titlePane != null )
|
if( titlePane != null )
|
||||||
titlePane.menuBarChanged();
|
titlePane.menuBarInvalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -536,7 +552,7 @@ public class FlatRootPaneUI
|
|||||||
|
|
||||||
protected boolean isWindowMaximized( Component c ) {
|
protected boolean isWindowMaximized( Component c ) {
|
||||||
Container parent = c.getParent();
|
Container parent = c.getParent();
|
||||||
return parent instanceof Frame && (((Frame)parent).getExtendedState() & Frame.MAXIMIZED_BOTH) != 0;
|
return parent instanceof Frame && (((Frame)parent).getExtendedState() & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_BOTH;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -245,7 +245,7 @@ public class FlatScrollBarUI
|
|||||||
// because scroll bars do not receive mouse exited event.
|
// because scroll bars do not receive mouse exited event.
|
||||||
// The scroll pane, including its scroll bars, is not part
|
// The scroll pane, including its scroll bars, is not part
|
||||||
// of the component hierarchy and does not receive mouse events
|
// of the component hierarchy and does not receive mouse events
|
||||||
// directly. Instead LWComponentPeer receives mouse events
|
// directly. Instead, LWComponentPeer receives mouse events
|
||||||
// and delegates them to peers, but entered/exited events
|
// and delegates them to peers, but entered/exited events
|
||||||
// are sent only for the whole scroll pane.
|
// are sent only for the whole scroll pane.
|
||||||
// Exited event is only sent when mouse leaves scroll pane.
|
// Exited event is only sent when mouse leaves scroll pane.
|
||||||
|
|||||||
@@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 FormDev Software GmbH
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.formdev.flatlaf.ui;
|
||||||
|
|
||||||
|
import java.awt.Component;
|
||||||
|
import java.awt.Insets;
|
||||||
|
import javax.swing.JList;
|
||||||
|
import javax.swing.JScrollPane;
|
||||||
|
import javax.swing.JTable;
|
||||||
|
import javax.swing.JTree;
|
||||||
|
import javax.swing.UIManager;
|
||||||
|
import javax.swing.text.JTextComponent;
|
||||||
|
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||||
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Border for {@link javax.swing.JScrollPane}.
|
||||||
|
*
|
||||||
|
* @uiDefault ScrollPane.arc int
|
||||||
|
* @uiDefault ScrollPane.List.arc int
|
||||||
|
* @uiDefault ScrollPane.Table.arc int
|
||||||
|
* @uiDefault ScrollPane.TextComponent.arc int
|
||||||
|
* @uiDefault ScrollPane.Tree.arc int
|
||||||
|
|
||||||
|
* @author Karl Tauber
|
||||||
|
* @since 3.3
|
||||||
|
*/
|
||||||
|
public class FlatScrollPaneBorder
|
||||||
|
extends FlatBorder
|
||||||
|
{
|
||||||
|
@Styleable protected int arc = UIManager.getInt( "ScrollPane.arc" );
|
||||||
|
|
||||||
|
private boolean isArcStyled;
|
||||||
|
private final int listArc = FlatUIUtils.getUIInt( "ScrollPane.List.arc", -1 );
|
||||||
|
private final int tableArc = FlatUIUtils.getUIInt( "ScrollPane.Table.arc", -1 );
|
||||||
|
private final int textComponentArc = FlatUIUtils.getUIInt( "ScrollPane.TextComponent.arc", -1 );
|
||||||
|
private final int treeArc = FlatUIUtils.getUIInt( "ScrollPane.Tree.arc", -1 );
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object applyStyleProperty( String key, Object value ) {
|
||||||
|
Object oldValue = super.applyStyleProperty( key, value );
|
||||||
|
|
||||||
|
if( "arc".equals( key ) )
|
||||||
|
isArcStyled = true;
|
||||||
|
|
||||||
|
return oldValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Insets getBorderInsets( Component c, Insets insets ) {
|
||||||
|
insets = super.getBorderInsets( c, insets );
|
||||||
|
|
||||||
|
// if view is rounded, increase left and right insets to avoid that the viewport
|
||||||
|
// is painted over the rounded border on the corners
|
||||||
|
int padding = getLeftRightPadding( c );
|
||||||
|
if( padding > 0 ) {
|
||||||
|
insets.left += padding;
|
||||||
|
insets.right += padding;
|
||||||
|
}
|
||||||
|
|
||||||
|
return insets;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getArc( Component c ) {
|
||||||
|
if( isCellEditor( c ) )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if( isArcStyled )
|
||||||
|
return arc;
|
||||||
|
|
||||||
|
if( c instanceof JScrollPane ) {
|
||||||
|
Component view = FlatScrollPaneUI.getView( (JScrollPane) c );
|
||||||
|
if( listArc >= 0 && view instanceof JList )
|
||||||
|
return listArc;
|
||||||
|
if( tableArc >= 0 && view instanceof JTable )
|
||||||
|
return tableArc;
|
||||||
|
if( textComponentArc >= 0&& view instanceof JTextComponent )
|
||||||
|
return textComponentArc;
|
||||||
|
if( treeArc >= 0 && view instanceof JTree )
|
||||||
|
return treeArc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return arc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the scaled left/right padding used when arc is larger than zero.
|
||||||
|
* <p>
|
||||||
|
* This is the distance from the inside of the left border to the left side of the view component.
|
||||||
|
* On the right side, this is the distance between the right side of the view component and
|
||||||
|
* the vertical scrollbar. Or the inside of the right border if the scrollbar is hidden.
|
||||||
|
*/
|
||||||
|
public int getLeftRightPadding( Component c ) {
|
||||||
|
// Subtract lineWidth from radius because radius is given for the outside
|
||||||
|
// of the painted line, but insets from super already include lineWidth.
|
||||||
|
// Reduce padding by 10% to make padding slightly smaller because it is not recognizable
|
||||||
|
// when the view is minimally painted over the beginning of the border curve.
|
||||||
|
int arc = getArc( c );
|
||||||
|
return (arc > 0)
|
||||||
|
? Math.max( Math.round( UIScale.scale( ((arc / 2f) - getLineWidth( c )) * 0.9f ) ), 0 )
|
||||||
|
: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,9 +17,12 @@
|
|||||||
package com.formdev.flatlaf.ui;
|
package com.formdev.flatlaf.ui;
|
||||||
|
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
|
import java.awt.Container;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
|
import java.awt.Graphics2D;
|
||||||
import java.awt.Insets;
|
import java.awt.Insets;
|
||||||
import java.awt.KeyboardFocusManager;
|
import java.awt.KeyboardFocusManager;
|
||||||
|
import java.awt.LayoutManager;
|
||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
import java.awt.event.ContainerEvent;
|
import java.awt.event.ContainerEvent;
|
||||||
import java.awt.event.ContainerListener;
|
import java.awt.event.ContainerListener;
|
||||||
@@ -41,16 +44,19 @@ import javax.swing.JTree;
|
|||||||
import javax.swing.JViewport;
|
import javax.swing.JViewport;
|
||||||
import javax.swing.LookAndFeel;
|
import javax.swing.LookAndFeel;
|
||||||
import javax.swing.ScrollPaneConstants;
|
import javax.swing.ScrollPaneConstants;
|
||||||
|
import javax.swing.ScrollPaneLayout;
|
||||||
import javax.swing.Scrollable;
|
import javax.swing.Scrollable;
|
||||||
import javax.swing.SwingConstants;
|
import javax.swing.SwingConstants;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
|
import javax.swing.border.Border;
|
||||||
import javax.swing.plaf.ComponentUI;
|
import javax.swing.plaf.ComponentUI;
|
||||||
import javax.swing.plaf.basic.BasicScrollPaneUI;
|
import javax.swing.plaf.basic.BasicScrollPaneUI;
|
||||||
import com.formdev.flatlaf.FlatClientProperties;
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||||
import com.formdev.flatlaf.util.LoggingFacade;
|
import com.formdev.flatlaf.util.LoggingFacade;
|
||||||
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JScrollPane}.
|
* Provides the Flat LaF UI delegate for {@link javax.swing.JScrollPane}.
|
||||||
@@ -97,7 +103,13 @@ public class FlatScrollPaneUI
|
|||||||
super.installUI( c );
|
super.installUI( c );
|
||||||
|
|
||||||
int focusWidth = UIManager.getInt( "Component.focusWidth" );
|
int focusWidth = UIManager.getInt( "Component.focusWidth" );
|
||||||
LookAndFeel.installProperty( c, "opaque", focusWidth == 0 );
|
int arc = UIManager.getInt( "ScrollPane.arc" );
|
||||||
|
LookAndFeel.installProperty( c, "opaque", focusWidth == 0 && arc == 0 );
|
||||||
|
|
||||||
|
// install layout manager
|
||||||
|
LayoutManager layout = c.getLayout();
|
||||||
|
if( layout != null && layout.getClass() == ScrollPaneLayout.UIResource.class )
|
||||||
|
c.setLayout( createScrollPaneLayout() );
|
||||||
|
|
||||||
installStyle();
|
installStyle();
|
||||||
|
|
||||||
@@ -108,6 +120,10 @@ public class FlatScrollPaneUI
|
|||||||
public void uninstallUI( JComponent c ) {
|
public void uninstallUI( JComponent c ) {
|
||||||
MigLayoutVisualPadding.uninstall( scrollpane );
|
MigLayoutVisualPadding.uninstall( scrollpane );
|
||||||
|
|
||||||
|
// uninstall layout manager
|
||||||
|
if( c.getLayout() instanceof FlatScrollPaneLayout )
|
||||||
|
c.setLayout( new ScrollPaneLayout.UIResource() );
|
||||||
|
|
||||||
super.uninstallUI( c );
|
super.uninstallUI( c );
|
||||||
|
|
||||||
oldStyleValues = null;
|
oldStyleValues = null;
|
||||||
@@ -130,6 +146,13 @@ public class FlatScrollPaneUI
|
|||||||
handler = null;
|
handler = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 3.3
|
||||||
|
*/
|
||||||
|
protected FlatScrollPaneLayout createScrollPaneLayout() {
|
||||||
|
return new FlatScrollPaneLayout();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected MouseWheelListener createMouseWheelListener() {
|
protected MouseWheelListener createMouseWheelListener() {
|
||||||
MouseWheelListener superListener = super.createMouseWheelListener();
|
MouseWheelListener superListener = super.createMouseWheelListener();
|
||||||
@@ -290,8 +313,7 @@ public class FlatScrollPaneUI
|
|||||||
Object corner = e.getNewValue();
|
Object corner = e.getNewValue();
|
||||||
if( corner instanceof JButton &&
|
if( corner instanceof JButton &&
|
||||||
((JButton)corner).getBorder() instanceof FlatButtonBorder &&
|
((JButton)corner).getBorder() instanceof FlatButtonBorder &&
|
||||||
scrollpane.getViewport() != null &&
|
getView( scrollpane ) instanceof JTable )
|
||||||
scrollpane.getViewport().getView() instanceof JTable )
|
|
||||||
{
|
{
|
||||||
((JButton)corner).setBorder( BorderFactory.createEmptyBorder() );
|
((JButton)corner).setBorder( BorderFactory.createEmptyBorder() );
|
||||||
((JButton)corner).setFocusable( false );
|
((JButton)corner).setFocusable( false );
|
||||||
@@ -308,6 +330,18 @@ public class FlatScrollPaneUI
|
|||||||
scrollpane.revalidate();
|
scrollpane.revalidate();
|
||||||
scrollpane.repaint();
|
scrollpane.repaint();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "border":
|
||||||
|
Object newBorder = e.getNewValue();
|
||||||
|
if( newBorder != null && newBorder == UIManager.getBorder( "Table.scrollPaneBorder" ) ) {
|
||||||
|
// JTable.configureEnclosingScrollPaneUI() replaces the scrollpane border
|
||||||
|
// with another one --> re-apply style on new border
|
||||||
|
borderShared = null;
|
||||||
|
installStyle();
|
||||||
|
scrollpane.revalidate();
|
||||||
|
scrollpane.repaint();
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -334,9 +368,10 @@ public class FlatScrollPaneUI
|
|||||||
|
|
||||||
/** @since 2 */
|
/** @since 2 */
|
||||||
protected Object applyStyleProperty( String key, Object value ) {
|
protected Object applyStyleProperty( String key, Object value ) {
|
||||||
if( key.equals( "focusWidth" ) ) {
|
if( key.equals( "focusWidth" ) || key.equals( "arc" ) ) {
|
||||||
int focusWidth = (value instanceof Integer) ? (int) value : UIManager.getInt( "Component.focusWidth" );
|
int focusWidth = (value instanceof Integer) ? (int) value : UIManager.getInt( "Component.focusWidth" );
|
||||||
LookAndFeel.installProperty( scrollpane, "opaque", focusWidth == 0 );
|
int arc = (value instanceof Integer) ? (int) value : UIManager.getInt( "ScrollPane.arc" );
|
||||||
|
LookAndFeel.installProperty( scrollpane, "opaque", focusWidth == 0 && arc == 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( borderShared == null )
|
if( borderShared == null )
|
||||||
@@ -360,8 +395,8 @@ public class FlatScrollPaneUI
|
|||||||
protected void updateViewport( PropertyChangeEvent e ) {
|
protected void updateViewport( PropertyChangeEvent e ) {
|
||||||
super.updateViewport( e );
|
super.updateViewport( e );
|
||||||
|
|
||||||
JViewport oldViewport = (JViewport) (e.getOldValue());
|
JViewport oldViewport = (JViewport) e.getOldValue();
|
||||||
JViewport newViewport = (JViewport) (e.getNewValue());
|
JViewport newViewport = (JViewport) e.getNewValue();
|
||||||
|
|
||||||
removeViewportListeners( oldViewport );
|
removeViewportListeners( oldViewport );
|
||||||
addViewportListeners( newViewport );
|
addViewportListeners( newViewport );
|
||||||
@@ -402,13 +437,46 @@ public class FlatScrollPaneUI
|
|||||||
c.getHeight() - insets.top - insets.bottom );
|
c.getHeight() - insets.top - insets.bottom );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if view is rounded, paint rounded background with view background color
|
||||||
|
// to ensure that free areas at left and right have same color as view
|
||||||
|
Component view;
|
||||||
|
float arc = getBorderArc( scrollpane );
|
||||||
|
if( arc > 0 && (view = getView( scrollpane )) != null ) {
|
||||||
|
float focusWidth = FlatUIUtils.getBorderFocusWidth( c );
|
||||||
|
|
||||||
|
g.setColor( view.getBackground() );
|
||||||
|
|
||||||
|
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g );
|
||||||
|
FlatUIUtils.paintComponentBackground( (Graphics2D) g, 0, 0, c.getWidth(), c.getHeight(), focusWidth, arc );
|
||||||
|
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
|
||||||
|
}
|
||||||
|
|
||||||
paint( g, c );
|
paint( g, c );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void paint( Graphics g, JComponent c ) {
|
||||||
|
Border viewportBorder = scrollpane.getViewportBorder();
|
||||||
|
if( viewportBorder != null ) {
|
||||||
|
Rectangle r = scrollpane.getViewportBorderBounds();
|
||||||
|
int padding = getBorderLeftRightPadding( scrollpane );
|
||||||
|
JScrollBar vsb = scrollpane.getVerticalScrollBar();
|
||||||
|
if( padding > 0 &&
|
||||||
|
vsb != null && vsb.isVisible() &&
|
||||||
|
scrollpane.getLayout() instanceof FlatScrollPaneLayout &&
|
||||||
|
((FlatScrollPaneLayout)scrollpane.getLayout()).canIncreaseViewportWidth( scrollpane ) )
|
||||||
|
{
|
||||||
|
boolean ltr = scrollpane.getComponentOrientation().isLeftToRight();
|
||||||
|
int extraWidth = Math.min( padding, vsb.getWidth() );
|
||||||
|
viewportBorder.paintBorder( scrollpane, g, r.x - (ltr ? 0 : extraWidth), r.y, r.width + extraWidth, r.height );
|
||||||
|
} else
|
||||||
|
viewportBorder.paintBorder( scrollpane, g, r.x, r.y, r.width, r.height );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** @since 1.3 */
|
/** @since 1.3 */
|
||||||
public static boolean isPermanentFocusOwner( JScrollPane scrollPane ) {
|
public static boolean isPermanentFocusOwner( JScrollPane scrollPane ) {
|
||||||
JViewport viewport = scrollPane.getViewport();
|
Component view = getView( scrollPane );
|
||||||
Component view = (viewport != null) ? viewport.getView() : null;
|
|
||||||
if( view == null )
|
if( view == null )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -428,6 +496,25 @@ public class FlatScrollPaneUI
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Component getView( JScrollPane scrollPane ) {
|
||||||
|
JViewport viewport = scrollPane.getViewport();
|
||||||
|
return (viewport != null) ? viewport.getView() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float getBorderArc( JScrollPane scrollPane ) {
|
||||||
|
Border border = scrollPane.getBorder();
|
||||||
|
return (border instanceof FlatScrollPaneBorder)
|
||||||
|
? UIScale.scale( (float) ((FlatScrollPaneBorder)border).getArc( scrollPane ) )
|
||||||
|
: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getBorderLeftRightPadding( JScrollPane scrollPane ) {
|
||||||
|
Border border = scrollPane.getBorder();
|
||||||
|
return (border instanceof FlatScrollPaneBorder)
|
||||||
|
? ((FlatScrollPaneBorder)border).getLeftRightPadding( scrollPane )
|
||||||
|
: 0;
|
||||||
|
}
|
||||||
|
|
||||||
//---- class Handler ------------------------------------------------------
|
//---- class Handler ------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -450,13 +537,71 @@ public class FlatScrollPaneUI
|
|||||||
@Override
|
@Override
|
||||||
public void focusGained( FocusEvent e ) {
|
public void focusGained( FocusEvent e ) {
|
||||||
// necessary to update focus border
|
// necessary to update focus border
|
||||||
scrollpane.repaint();
|
if( scrollpane.getBorder() instanceof FlatBorder )
|
||||||
|
scrollpane.repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void focusLost( FocusEvent e ) {
|
public void focusLost( FocusEvent e ) {
|
||||||
// necessary to update focus border
|
// necessary to update focus border
|
||||||
scrollpane.repaint();
|
if( scrollpane.getBorder() instanceof FlatBorder )
|
||||||
|
scrollpane.repaint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---- class FlatScrollPaneLayout -----------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 3.3
|
||||||
|
*/
|
||||||
|
protected static class FlatScrollPaneLayout
|
||||||
|
extends ScrollPaneLayout.UIResource
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void layoutContainer( Container parent ) {
|
||||||
|
super.layoutContainer( parent );
|
||||||
|
|
||||||
|
JScrollPane scrollPane = (JScrollPane) parent;
|
||||||
|
int padding = getBorderLeftRightPadding( scrollPane );
|
||||||
|
if( padding > 0 && vsb != null && vsb.isVisible() ) {
|
||||||
|
// move vertical scrollbar to trailing edge
|
||||||
|
Insets insets = scrollPane.getInsets();
|
||||||
|
Rectangle r = vsb.getBounds();
|
||||||
|
int y = Math.max( r.y, insets.top + padding );
|
||||||
|
int y2 = Math.min( r.y + r.height, scrollPane.getHeight() - insets.bottom - padding );
|
||||||
|
boolean ltr = scrollPane.getComponentOrientation().isLeftToRight();
|
||||||
|
|
||||||
|
vsb.setBounds( r.x + (ltr ? padding : -padding), y, r.width, y2 - y );
|
||||||
|
|
||||||
|
// increase width of viewport, column header and horizontal scrollbar
|
||||||
|
if( canIncreaseViewportWidth( scrollPane ) ) {
|
||||||
|
int extraWidth = Math.min( padding, vsb.getWidth() );
|
||||||
|
resizeViewport( viewport, extraWidth, ltr );
|
||||||
|
resizeViewport( colHead, extraWidth, ltr );
|
||||||
|
resizeViewport( hsb, extraWidth, ltr );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean canIncreaseViewportWidth( JScrollPane scrollPane ) {
|
||||||
|
return scrollPane.getComponentOrientation().isLeftToRight()
|
||||||
|
? !isCornerVisible( upperRight ) && !isCornerVisible( lowerRight )
|
||||||
|
: !isCornerVisible( upperLeft ) && !isCornerVisible( lowerLeft );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isCornerVisible( Component corner ) {
|
||||||
|
return corner != null &&
|
||||||
|
corner.getWidth() > 0 &&
|
||||||
|
corner.getHeight() > 0 &&
|
||||||
|
corner.isVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void resizeViewport( Component c, int extraWidth, boolean ltr ) {
|
||||||
|
if( c == null )
|
||||||
|
return;
|
||||||
|
|
||||||
|
Rectangle vr = c.getBounds();
|
||||||
|
c.setBounds( vr.x - (ltr ? 0 : extraWidth), vr.y, vr.width + extraWidth, vr.height );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,7 +67,6 @@ import com.formdev.flatlaf.util.LoggingFacade;
|
|||||||
* @uiDefault Component.minimumWidth int
|
* @uiDefault Component.minimumWidth int
|
||||||
* @uiDefault Spinner.buttonStyle String button (default), mac or none
|
* @uiDefault Spinner.buttonStyle String button (default), mac or none
|
||||||
* @uiDefault Component.arrowType String chevron (default) or triangle
|
* @uiDefault Component.arrowType String chevron (default) or triangle
|
||||||
* @uiDefault Component.isIntelliJTheme boolean
|
|
||||||
* @uiDefault Spinner.disabledBackground Color
|
* @uiDefault Spinner.disabledBackground Color
|
||||||
* @uiDefault Spinner.disabledForeground Color
|
* @uiDefault Spinner.disabledForeground Color
|
||||||
* @uiDefault Spinner.focusedBackground Color optional
|
* @uiDefault Spinner.focusedBackground Color optional
|
||||||
@@ -92,7 +91,6 @@ public class FlatSpinnerUI
|
|||||||
@Styleable protected int minimumWidth;
|
@Styleable protected int minimumWidth;
|
||||||
@Styleable protected String buttonStyle;
|
@Styleable protected String buttonStyle;
|
||||||
@Styleable protected String arrowType;
|
@Styleable protected String arrowType;
|
||||||
protected boolean isIntelliJTheme;
|
|
||||||
@Styleable protected Color disabledBackground;
|
@Styleable protected Color disabledBackground;
|
||||||
@Styleable protected Color disabledForeground;
|
@Styleable protected Color disabledForeground;
|
||||||
@Styleable protected Color focusedBackground;
|
@Styleable protected Color focusedBackground;
|
||||||
@@ -129,7 +127,6 @@ public class FlatSpinnerUI
|
|||||||
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
||||||
buttonStyle = UIManager.getString( "Spinner.buttonStyle" );
|
buttonStyle = UIManager.getString( "Spinner.buttonStyle" );
|
||||||
arrowType = UIManager.getString( "Component.arrowType" );
|
arrowType = UIManager.getString( "Component.arrowType" );
|
||||||
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
|
||||||
disabledBackground = UIManager.getColor( "Spinner.disabledBackground" );
|
disabledBackground = UIManager.getColor( "Spinner.disabledBackground" );
|
||||||
disabledForeground = UIManager.getColor( "Spinner.disabledForeground" );
|
disabledForeground = UIManager.getColor( "Spinner.disabledForeground" );
|
||||||
focusedBackground = UIManager.getColor( "Spinner.focusedBackground" );
|
focusedBackground = UIManager.getColor( "Spinner.focusedBackground" );
|
||||||
@@ -316,7 +313,7 @@ public class FlatSpinnerUI
|
|||||||
|
|
||||||
return background;
|
return background;
|
||||||
} else
|
} else
|
||||||
return isIntelliJTheme ? FlatUIUtils.getParentBackground( spinner ) : disabledBackground;
|
return disabledBackground;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Color getForeground( boolean enabled ) {
|
protected Color getForeground( boolean enabled ) {
|
||||||
|
|||||||
@@ -16,7 +16,9 @@
|
|||||||
|
|
||||||
package com.formdev.flatlaf.ui;
|
package com.formdev.flatlaf.ui;
|
||||||
|
|
||||||
|
import java.awt.Canvas;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
import java.awt.Component;
|
||||||
import java.awt.Container;
|
import java.awt.Container;
|
||||||
import java.awt.Cursor;
|
import java.awt.Cursor;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
@@ -67,6 +69,8 @@ import com.formdev.flatlaf.util.UIScale;
|
|||||||
* <!-- FlatSplitPaneUI -->
|
* <!-- FlatSplitPaneUI -->
|
||||||
*
|
*
|
||||||
* @uiDefault Component.arrowType String chevron (default) or triangle
|
* @uiDefault Component.arrowType String chevron (default) or triangle
|
||||||
|
* @uiDefault SplitPaneDivider.hoverColor Color optional
|
||||||
|
* @uiDefault SplitPaneDivider.pressedColor Color optional
|
||||||
* @uiDefault SplitPaneDivider.oneTouchArrowColor Color
|
* @uiDefault SplitPaneDivider.oneTouchArrowColor Color
|
||||||
* @uiDefault SplitPaneDivider.oneTouchHoverArrowColor Color
|
* @uiDefault SplitPaneDivider.oneTouchHoverArrowColor Color
|
||||||
* @uiDefault SplitPaneDivider.oneTouchPressedArrowColor Color
|
* @uiDefault SplitPaneDivider.oneTouchPressedArrowColor Color
|
||||||
@@ -83,11 +87,11 @@ public class FlatSplitPaneUI
|
|||||||
implements StyleableUI
|
implements StyleableUI
|
||||||
{
|
{
|
||||||
@Styleable protected String arrowType;
|
@Styleable protected String arrowType;
|
||||||
|
/** @since 3.3 */ @Styleable protected Color draggingColor;
|
||||||
@Styleable protected Color oneTouchArrowColor;
|
@Styleable protected Color oneTouchArrowColor;
|
||||||
@Styleable protected Color oneTouchHoverArrowColor;
|
@Styleable protected Color oneTouchHoverArrowColor;
|
||||||
@Styleable protected Color oneTouchPressedArrowColor;
|
@Styleable protected Color oneTouchPressedArrowColor;
|
||||||
|
|
||||||
private PropertyChangeListener propertyChangeListener;
|
|
||||||
private Map<String, Object> oldStyleValues;
|
private Map<String, Object> oldStyleValues;
|
||||||
|
|
||||||
public static ComponentUI createUI( JComponent c ) {
|
public static ComponentUI createUI( JComponent c ) {
|
||||||
@@ -105,6 +109,8 @@ public class FlatSplitPaneUI
|
|||||||
protected void installDefaults() {
|
protected void installDefaults() {
|
||||||
arrowType = UIManager.getString( "Component.arrowType" );
|
arrowType = UIManager.getString( "Component.arrowType" );
|
||||||
|
|
||||||
|
draggingColor = UIManager.getColor( "SplitPaneDivider.draggingColor" );
|
||||||
|
|
||||||
// get one-touch colors before invoking super.installDefaults() because they are
|
// get one-touch colors before invoking super.installDefaults() because they are
|
||||||
// used in there on LaF switching
|
// used in there on LaF switching
|
||||||
oneTouchArrowColor = UIManager.getColor( "SplitPaneDivider.oneTouchArrowColor" );
|
oneTouchArrowColor = UIManager.getColor( "SplitPaneDivider.oneTouchArrowColor" );
|
||||||
@@ -118,6 +124,8 @@ public class FlatSplitPaneUI
|
|||||||
protected void uninstallDefaults() {
|
protected void uninstallDefaults() {
|
||||||
super.uninstallDefaults();
|
super.uninstallDefaults();
|
||||||
|
|
||||||
|
draggingColor = null;
|
||||||
|
|
||||||
oneTouchArrowColor = null;
|
oneTouchArrowColor = null;
|
||||||
oneTouchHoverArrowColor = null;
|
oneTouchHoverArrowColor = null;
|
||||||
oneTouchPressedArrowColor = null;
|
oneTouchPressedArrowColor = null;
|
||||||
@@ -126,19 +134,9 @@ public class FlatSplitPaneUI
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void installListeners() {
|
protected PropertyChangeListener createPropertyChangeListener() {
|
||||||
super.installListeners();
|
return FlatStylingSupport.createPropertyChangeListener( splitPane, this::installStyle,
|
||||||
|
super.createPropertyChangeListener() );
|
||||||
propertyChangeListener = FlatStylingSupport.createPropertyChangeListener( splitPane, this::installStyle, null );
|
|
||||||
splitPane.addPropertyChangeListener( propertyChangeListener );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void uninstallListeners() {
|
|
||||||
super.uninstallListeners();
|
|
||||||
|
|
||||||
splitPane.removePropertyChangeListener( propertyChangeListener );
|
|
||||||
propertyChangeListener = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -194,12 +192,49 @@ public class FlatSplitPaneUI
|
|||||||
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
|
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Component createDefaultNonContinuousLayoutDivider() {
|
||||||
|
// only used for non-continuous layout if left or right component is heavy weight
|
||||||
|
return new Canvas() {
|
||||||
|
@Override
|
||||||
|
public void paint( Graphics g ) {
|
||||||
|
if( !isContinuousLayout() && getLastDragLocation() != -1 )
|
||||||
|
paintDragDivider( g, 0 );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finishedPaintingChildren( JSplitPane sp, Graphics g ) {
|
||||||
|
if( sp == splitPane && getLastDragLocation() != -1 && !isContinuousLayout() && !draggingHW )
|
||||||
|
paintDragDivider( g, getLastDragLocation() );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void paintDragDivider( Graphics g, int dividerLocation ) {
|
||||||
|
// divider bounds
|
||||||
|
boolean horizontal = (getOrientation() == JSplitPane.HORIZONTAL_SPLIT);
|
||||||
|
int x = horizontal ? dividerLocation : 0;
|
||||||
|
int y = !horizontal ? dividerLocation : 0;
|
||||||
|
int width = horizontal ? dividerSize : splitPane.getWidth();
|
||||||
|
int height = !horizontal ? dividerSize : splitPane.getHeight();
|
||||||
|
|
||||||
|
// paint background
|
||||||
|
g.setColor( FlatUIUtils.deriveColor( draggingColor, splitPane.getBackground() ) );
|
||||||
|
g.fillRect( x, y, width, height );
|
||||||
|
|
||||||
|
// paint divider style (e.g. grip)
|
||||||
|
if( divider instanceof FlatSplitPaneDivider )
|
||||||
|
((FlatSplitPaneDivider)divider).paintStyle( g, x, y, width, height );
|
||||||
|
}
|
||||||
|
|
||||||
//---- class FlatSplitPaneDivider -----------------------------------------
|
//---- class FlatSplitPaneDivider -----------------------------------------
|
||||||
|
|
||||||
protected class FlatSplitPaneDivider
|
protected class FlatSplitPaneDivider
|
||||||
extends BasicSplitPaneDivider
|
extends BasicSplitPaneDivider
|
||||||
{
|
{
|
||||||
@Styleable protected String style = UIManager.getString( "SplitPaneDivider.style" );
|
@Styleable protected String style = UIManager.getString( "SplitPaneDivider.style" );
|
||||||
|
/** @since 3.3 */ @Styleable protected Color hoverColor = UIManager.getColor( "SplitPaneDivider.hoverColor" );
|
||||||
|
/** @since 3.3 */ @Styleable protected Color pressedColor = UIManager.getColor( "SplitPaneDivider.pressedColor" );
|
||||||
@Styleable protected Color gripColor = UIManager.getColor( "SplitPaneDivider.gripColor" );
|
@Styleable protected Color gripColor = UIManager.getColor( "SplitPaneDivider.gripColor" );
|
||||||
@Styleable protected int gripDotCount = FlatUIUtils.getUIInt( "SplitPaneDivider.gripDotCount", 3 );
|
@Styleable protected int gripDotCount = FlatUIUtils.getUIInt( "SplitPaneDivider.gripDotCount", 3 );
|
||||||
@Styleable protected int gripDotSize = FlatUIUtils.getUIInt( "SplitPaneDivider.gripDotSize", 3 );
|
@Styleable protected int gripDotSize = FlatUIUtils.getUIInt( "SplitPaneDivider.gripDotSize", 3 );
|
||||||
@@ -262,15 +297,31 @@ public class FlatSplitPaneUI
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paint( Graphics g ) {
|
public void paint( Graphics g ) {
|
||||||
|
// paint hover or pressed background
|
||||||
|
Color hoverOrPressedColor = (isContinuousLayout() && dragger != null)
|
||||||
|
? pressedColor
|
||||||
|
: (isMouseOver() && dragger == null
|
||||||
|
? hoverColor
|
||||||
|
: null);
|
||||||
|
if( hoverOrPressedColor != null ) {
|
||||||
|
g.setColor( FlatUIUtils.deriveColor( hoverOrPressedColor, splitPane.getBackground() ) );
|
||||||
|
g.fillRect( 0, 0, getWidth(), getHeight() );
|
||||||
|
}
|
||||||
|
|
||||||
super.paint( g );
|
super.paint( g );
|
||||||
|
|
||||||
|
paintStyle( g, 0, 0, getWidth(), getHeight() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @since 3.3 */
|
||||||
|
protected void paintStyle( Graphics g, int x, int y, int width, int height ) {
|
||||||
if( "plain".equals( style ) )
|
if( "plain".equals( style ) )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g );
|
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g );
|
||||||
|
|
||||||
g.setColor( gripColor );
|
g.setColor( gripColor );
|
||||||
paintGrip( g, 0, 0, getWidth(), getHeight() );
|
paintGrip( g, x, y, width, height );
|
||||||
|
|
||||||
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
|
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
|
||||||
}
|
}
|
||||||
@@ -297,6 +348,29 @@ public class FlatSplitPaneUI
|
|||||||
: location == (splitPane.getWidth() - getWidth() - insets.right);
|
: location == (splitPane.getWidth() - getWidth() - insets.right);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setMouseOver( boolean mouseOver ) {
|
||||||
|
super.setMouseOver( mouseOver );
|
||||||
|
repaintIfNecessary();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void prepareForDragging() {
|
||||||
|
super.prepareForDragging();
|
||||||
|
repaintIfNecessary();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void finishDraggingTo( int location ) {
|
||||||
|
super.finishDraggingTo( location );
|
||||||
|
repaintIfNecessary();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void repaintIfNecessary() {
|
||||||
|
if( hoverColor != null || pressedColor != null )
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
|
|
||||||
//---- class FlatOneTouchButton ---------------------------------------
|
//---- class FlatOneTouchButton ---------------------------------------
|
||||||
|
|
||||||
protected class FlatOneTouchButton
|
protected class FlatOneTouchButton
|
||||||
|
|||||||
@@ -100,15 +100,15 @@ public class FlatStylingSupport
|
|||||||
|
|
||||||
/** @since 2 */
|
/** @since 2 */
|
||||||
public interface StyleableUI {
|
public interface StyleableUI {
|
||||||
Map<String, Class<?>> getStyleableInfos( JComponent c );
|
Map<String, Class<?>> getStyleableInfos( JComponent c ) throws IllegalArgumentException;
|
||||||
/** @since 2.5 */ Object getStyleableValue( JComponent c, String key );
|
/** @since 2.5 */ Object getStyleableValue( JComponent c, String key ) throws IllegalArgumentException;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @since 2 */
|
/** @since 2 */
|
||||||
public interface StyleableBorder {
|
public interface StyleableBorder {
|
||||||
Object applyStyleProperty( String key, Object value );
|
Object applyStyleProperty( String key, Object value );
|
||||||
Map<String, Class<?>> getStyleableInfos();
|
Map<String, Class<?>> getStyleableInfos() throws IllegalArgumentException;
|
||||||
/** @since 2.5 */ Object getStyleableValue( String key );
|
/** @since 2.5 */ Object getStyleableValue( String key ) throws IllegalArgumentException;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @since 2.5 */
|
/** @since 2.5 */
|
||||||
@@ -135,7 +135,9 @@ public class FlatStylingSupport
|
|||||||
return getStyle( c ) != null || getStyleClass( c ) != null;
|
return getStyle( c ) != null || getStyleClass( c ) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object getResolvedStyle( JComponent c, String type ) {
|
public static Object getResolvedStyle( JComponent c, String type )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
Object style = getStyle( c );
|
Object style = getStyle( c );
|
||||||
Object styleClass = getStyleClass( c );
|
Object styleClass = getStyleClass( c );
|
||||||
Object styleForClasses = getStyleForClasses( styleClass, type );
|
Object styleForClasses = getStyleForClasses( styleClass, type );
|
||||||
@@ -175,7 +177,9 @@ public class FlatStylingSupport
|
|||||||
* @param type the type of the component
|
* @param type the type of the component
|
||||||
* @return the styles
|
* @return the styles
|
||||||
*/
|
*/
|
||||||
public static Object getStyleForClasses( Object styleClass, String type ) {
|
public static Object getStyleForClasses( Object styleClass, String type )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
if( styleClass == null )
|
if( styleClass == null )
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@@ -198,7 +202,9 @@ public class FlatStylingSupport
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object getStyleForClass( String styleClass, String type ) {
|
private static Object getStyleForClass( String styleClass, String type )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
return joinStyles(
|
return joinStyles(
|
||||||
UIManager.get( "[style]." + styleClass ),
|
UIManager.get( "[style]." + styleClass ),
|
||||||
UIManager.get( "[style]" + type + '.' + styleClass ) );
|
UIManager.get( "[style]" + type + '.' + styleClass ) );
|
||||||
@@ -218,7 +224,9 @@ public class FlatStylingSupport
|
|||||||
* @return new joined style
|
* @return new joined style
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings( "unchecked" )
|
@SuppressWarnings( "unchecked" )
|
||||||
public static Object joinStyles( Object style1, Object style2 ) {
|
public static Object joinStyles( Object style1, Object style2 )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
if( style1 == null )
|
if( style1 == null )
|
||||||
return style2;
|
return style2;
|
||||||
if( style2 == null )
|
if( style2 == null )
|
||||||
@@ -278,6 +286,7 @@ public class FlatStylingSupport
|
|||||||
* @throws IllegalArgumentException on syntax errors
|
* @throws IllegalArgumentException on syntax errors
|
||||||
* @throws ClassCastException if value type does not fit to expected type
|
* @throws ClassCastException if value type does not fit to expected type
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings( "ReturnValueIgnored" ) // Error Prone
|
||||||
public static Map<String, Object> parseAndApply( Map<String, Object> oldStyleValues,
|
public static Map<String, Object> parseAndApply( Map<String, Object> oldStyleValues,
|
||||||
Object style, BiFunction<String, Object, Object> applyProperty )
|
Object style, BiFunction<String, Object, Object> applyProperty )
|
||||||
throws UnknownStyleException, IllegalArgumentException
|
throws UnknownStyleException, IllegalArgumentException
|
||||||
@@ -379,7 +388,9 @@ public class FlatStylingSupport
|
|||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object parseValue( String key, String value ) {
|
private static Object parseValue( String key, String value )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
// simple reference
|
// simple reference
|
||||||
if( value.startsWith( "$" ) )
|
if( value.startsWith( "$" ) )
|
||||||
return UIManager.get( value.substring( 1 ) );
|
return UIManager.get( value.substring( 1 ) );
|
||||||
@@ -474,7 +485,9 @@ public class FlatStylingSupport
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object applyToField( Field f, Object obj, Object value, boolean useMethodHandles ) {
|
private static Object applyToField( Field f, Object obj, Object value, boolean useMethodHandles )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
checkValidField( f );
|
checkValidField( f );
|
||||||
|
|
||||||
if( useMethodHandles && obj instanceof StyleableLookupProvider ) {
|
if( useMethodHandles && obj instanceof StyleableLookupProvider ) {
|
||||||
@@ -504,7 +517,9 @@ public class FlatStylingSupport
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object getFieldValue( Field f, Object obj, boolean useMethodHandles ) {
|
private static Object getFieldValue( Field f, Object obj, boolean useMethodHandles )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
checkValidField( f );
|
checkValidField( f );
|
||||||
|
|
||||||
if( useMethodHandles && obj instanceof StyleableLookupProvider ) {
|
if( useMethodHandles && obj instanceof StyleableLookupProvider ) {
|
||||||
@@ -529,7 +544,9 @@ public class FlatStylingSupport
|
|||||||
return new IllegalArgumentException( "failed to access field '" + f.getDeclaringClass().getName() + "." + f.getName() + "'", ex );
|
return new IllegalArgumentException( "failed to access field '" + f.getDeclaringClass().getName() + "." + f.getName() + "'", ex );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void checkValidField( Field f ) {
|
private static void checkValidField( Field f )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
if( !isValidField( f ) )
|
if( !isValidField( f ) )
|
||||||
throw new IllegalArgumentException( "field '" + f.getDeclaringClass().getName() + "." + f.getName() + "' is final or static" );
|
throw new IllegalArgumentException( "field '" + f.getDeclaringClass().getName() + "." + f.getName() + "' is final or static" );
|
||||||
}
|
}
|
||||||
@@ -539,7 +556,9 @@ public class FlatStylingSupport
|
|||||||
return (modifiers & (Modifier.FINAL|Modifier.STATIC)) == 0 && !f.isSynthetic();
|
return (modifiers & (Modifier.FINAL|Modifier.STATIC)) == 0 && !f.isSynthetic();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Field getStyleableField( StyleableField styleableField ) {
|
private static Field getStyleableField( StyleableField styleableField )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
String fieldName = styleableField.fieldName();
|
String fieldName = styleableField.fieldName();
|
||||||
if( fieldName.isEmpty() )
|
if( fieldName.isEmpty() )
|
||||||
fieldName = styleableField.key();
|
fieldName = styleableField.key();
|
||||||
@@ -647,6 +666,7 @@ public class FlatStylingSupport
|
|||||||
|
|
||||||
static Object applyToAnnotatedObjectOrBorder( Object obj, String key, Object value,
|
static Object applyToAnnotatedObjectOrBorder( Object obj, String key, Object value,
|
||||||
JComponent c, AtomicBoolean borderShared )
|
JComponent c, AtomicBoolean borderShared )
|
||||||
|
throws IllegalArgumentException
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
return applyToAnnotatedObject( obj, key, value );
|
return applyToAnnotatedObject( obj, key, value );
|
||||||
@@ -695,7 +715,9 @@ public class FlatStylingSupport
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static Border cloneBorder( Border border ) {
|
static Border cloneBorder( Border border )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
Class<? extends Border> borderClass = border.getClass();
|
Class<? extends Border> borderClass = border.getClass();
|
||||||
try {
|
try {
|
||||||
return borderClass.getDeclaredConstructor().newInstance();
|
return borderClass.getDeclaredConstructor().newInstance();
|
||||||
@@ -704,7 +726,9 @@ public class FlatStylingSupport
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Icon cloneIcon( Icon icon ) {
|
static Icon cloneIcon( Icon icon )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
Class<? extends Icon> iconClass = icon.getClass();
|
Class<? extends Icon> iconClass = icon.getClass();
|
||||||
try {
|
try {
|
||||||
return iconClass.getDeclaredConstructor().newInstance();
|
return iconClass.getDeclaredConstructor().newInstance();
|
||||||
@@ -717,11 +741,15 @@ public class FlatStylingSupport
|
|||||||
* Returns a map of all fields annotated with {@link Styleable}.
|
* Returns a map of all fields annotated with {@link Styleable}.
|
||||||
* The key is the name of the field and the value the type of the field.
|
* The key is the name of the field and the value the type of the field.
|
||||||
*/
|
*/
|
||||||
public static Map<String, Class<?>> getAnnotatedStyleableInfos( Object obj ) {
|
public static Map<String, Class<?>> getAnnotatedStyleableInfos( Object obj )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
return getAnnotatedStyleableInfos( obj, null );
|
return getAnnotatedStyleableInfos( obj, null );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Map<String, Class<?>> getAnnotatedStyleableInfos( Object obj, Border border ) {
|
public static Map<String, Class<?>> getAnnotatedStyleableInfos( Object obj, Border border )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
Map<String, Class<?>> infos = new StyleableInfosMap<>();
|
Map<String, Class<?>> infos = new StyleableInfosMap<>();
|
||||||
collectAnnotatedStyleableInfos( obj, infos );
|
collectAnnotatedStyleableInfos( obj, infos );
|
||||||
collectStyleableInfos( border, infos );
|
collectStyleableInfos( border, infos );
|
||||||
@@ -732,7 +760,9 @@ public class FlatStylingSupport
|
|||||||
* Search for all fields annotated with {@link Styleable} and add them to the given map.
|
* Search for all fields annotated with {@link Styleable} and add them to the given map.
|
||||||
* The key is the name of the field and the value the type of the field.
|
* The key is the name of the field and the value the type of the field.
|
||||||
*/
|
*/
|
||||||
public static void collectAnnotatedStyleableInfos( Object obj, Map<String, Class<?>> infos ) {
|
public static void collectAnnotatedStyleableInfos( Object obj, Map<String, Class<?>> infos )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
HashSet<String> processedFields = new HashSet<>();
|
HashSet<String> processedFields = new HashSet<>();
|
||||||
Class<?> cls = obj.getClass();
|
Class<?> cls = obj.getClass();
|
||||||
|
|
||||||
@@ -810,7 +840,9 @@ public class FlatStylingSupport
|
|||||||
infos.put( keyPrefix.concat( e.getKey() ), e.getValue() );
|
infos.put( keyPrefix.concat( e.getKey() ), e.getValue() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object getAnnotatedStyleableValue( Object obj, String key ) {
|
public static Object getAnnotatedStyleableValue( Object obj, String key )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
String fieldName = keyToFieldName( key );
|
String fieldName = keyToFieldName( key );
|
||||||
Class<?> cls = obj.getClass();
|
Class<?> cls = obj.getClass();
|
||||||
|
|
||||||
@@ -877,7 +909,9 @@ public class FlatStylingSupport
|
|||||||
extends LinkedHashMap<K,V>
|
extends LinkedHashMap<K,V>
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public V put( K key, V value ) {
|
public V put( K key, V value )
|
||||||
|
throws IllegalArgumentException
|
||||||
|
{
|
||||||
V oldValue = super.put( key, value );
|
V oldValue = super.put( key, value );
|
||||||
if( oldValue != null )
|
if( oldValue != null )
|
||||||
throw new IllegalArgumentException( "duplicate key '" + key + "'" );
|
throw new IllegalArgumentException( "duplicate key '" + key + "'" );
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -24,6 +24,7 @@ import java.util.function.Function;
|
|||||||
import javax.swing.JTable;
|
import javax.swing.JTable;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
|
import javax.swing.border.Border;
|
||||||
import javax.swing.plaf.TableUI;
|
import javax.swing.plaf.TableUI;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -107,17 +108,55 @@ public class FlatTableCellBorder
|
|||||||
public static class Focused
|
public static class Focused
|
||||||
extends FlatTableCellBorder
|
extends FlatTableCellBorder
|
||||||
{
|
{
|
||||||
|
@Override
|
||||||
|
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||||
|
if( c != null && c.getClass().getName().equals( "javax.swing.JTable$BooleanRenderer" ) ) {
|
||||||
|
// boolean renderer in JTable does not use Table.focusSelectedCellHighlightBorder
|
||||||
|
// if cell is selected and focused (as DefaultTableCellRenderer does)
|
||||||
|
// --> delegate to Table.focusSelectedCellHighlightBorder
|
||||||
|
// to make FlatLaf "focus indicator border hiding" work
|
||||||
|
JTable table = (JTable) SwingUtilities.getAncestorOfClass( JTable.class, c );
|
||||||
|
if( table != null &&
|
||||||
|
c.getForeground() == table.getSelectionForeground() &&
|
||||||
|
c.getBackground() == table.getSelectionBackground() )
|
||||||
|
{
|
||||||
|
Border border = UIManager.getBorder( "Table.focusSelectedCellHighlightBorder" );
|
||||||
|
if( border != null ) {
|
||||||
|
border.paintBorder( c, g, x, y, width, height );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
super.paintBorder( c, g, x, y, width, height );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//---- class Selected -----------------------------------------------------
|
//---- class Selected -----------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Border for selected cell that uses margins and paints focus indicator border
|
* Border for selected cell that uses margins and paints focus indicator border.
|
||||||
* if enabled (Table.showCellFocusIndicator=true) or at least one selected cell is editable.
|
* The focus indicator is shown under following conditions:
|
||||||
|
* <ul>
|
||||||
|
* <li>always if enabled via UI property {@code Table.showCellFocusIndicator=true}
|
||||||
|
* <li>for row selection mode if exactly one row is selected and at least one cell in that row is editable
|
||||||
|
* <li>for column selection mode if exactly one column is selected and at least one cell in that column is editable
|
||||||
|
* <li>never for cell selection mode
|
||||||
|
* </ul>
|
||||||
|
* The reason for this logic is to hide the focus indicator when it is not needed,
|
||||||
|
* and only show it when there are editable cells and the user needs to know
|
||||||
|
* which cell is focused to start editing.
|
||||||
|
* <p>
|
||||||
|
* To avoid possible performance issues, checking for editable cells is limited
|
||||||
|
* to {@link #maxCheckCellsEditable}. If there are more cells to check,
|
||||||
|
* the focus indicator is always shown.
|
||||||
*/
|
*/
|
||||||
public static class Selected
|
public static class Selected
|
||||||
extends FlatTableCellBorder
|
extends FlatTableCellBorder
|
||||||
{
|
{
|
||||||
|
/** @since 3.1 */
|
||||||
|
public int maxCheckCellsEditable = 50;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||||
Boolean b = getStyleFromTableUI( c, ui -> ui.showCellFocusIndicator );
|
Boolean b = getStyleFromTableUI( c, ui -> ui.showCellFocusIndicator );
|
||||||
@@ -125,7 +164,7 @@ public class FlatTableCellBorder
|
|||||||
|
|
||||||
if( !showCellFocusIndicator ) {
|
if( !showCellFocusIndicator ) {
|
||||||
JTable table = (JTable) SwingUtilities.getAncestorOfClass( JTable.class, c );
|
JTable table = (JTable) SwingUtilities.getAncestorOfClass( JTable.class, c );
|
||||||
if( table != null && !isSelectionEditable( table ) )
|
if( table != null && !shouldShowCellFocusIndicator( table ) )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,28 +172,57 @@ public class FlatTableCellBorder
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether at least one selected cell is editable.
|
* Returns whether focus indicator border should be shown.
|
||||||
|
*
|
||||||
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
protected boolean isSelectionEditable( JTable table ) {
|
protected boolean shouldShowCellFocusIndicator( JTable table ) {
|
||||||
if( table.getRowSelectionAllowed() ) {
|
boolean rowSelectionAllowed = table.getRowSelectionAllowed();
|
||||||
int columnCount = table.getColumnCount();
|
boolean columnSelectionAllowed = table.getColumnSelectionAllowed();
|
||||||
int[] selectedRows = table.getSelectedRows();
|
|
||||||
for( int selectedRow : selectedRows ) {
|
|
||||||
for( int column = 0; column < columnCount; column++ ) {
|
|
||||||
if( table.isCellEditable( selectedRow, column ) )
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( table.getColumnSelectionAllowed() ) {
|
// do not show for cell selection mode
|
||||||
|
// (unlikely that user wants edit cell in case that multiple cells are selected;
|
||||||
|
// if only a single cell is selected then it is clear where the focus is)
|
||||||
|
if( rowSelectionAllowed && columnSelectionAllowed )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( rowSelectionAllowed ) {
|
||||||
|
// row selection mode
|
||||||
|
|
||||||
|
// do not show if more than one row is selected
|
||||||
|
// (unlikely that user wants edit cell in this case)
|
||||||
|
if( table.getSelectedRowCount() != 1 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// show always if there are too many columns to check for editable
|
||||||
|
int columnCount = table.getColumnCount();
|
||||||
|
if( columnCount > maxCheckCellsEditable )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// check whether at least one selected cell is editable
|
||||||
|
int selectedRow = table.getSelectedRow();
|
||||||
|
for( int column = 0; column < columnCount; column++ ) {
|
||||||
|
if( table.isCellEditable( selectedRow, column ) )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if( columnSelectionAllowed ) {
|
||||||
|
// column selection mode
|
||||||
|
|
||||||
|
// do not show if more than one column is selected
|
||||||
|
// (unlikely that user wants edit cell in this case)
|
||||||
|
if( table.getSelectedColumnCount() != 1 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// show always if there are too many rows to check for editable
|
||||||
int rowCount = table.getRowCount();
|
int rowCount = table.getRowCount();
|
||||||
int[] selectedColumns = table.getSelectedColumns();
|
if( rowCount > maxCheckCellsEditable )
|
||||||
for( int selectedColumn : selectedColumns ) {
|
return true;
|
||||||
for( int row = 0; row < rowCount; row++ ) {
|
|
||||||
if( table.isCellEditable( row, selectedColumn ) )
|
// check whether at least one selected cell is editable
|
||||||
return true;
|
int selectedColumn = table.getSelectedColumn();
|
||||||
}
|
for( int row = 0; row < rowCount; row++ ) {
|
||||||
|
if( table.isCellEditable( row, selectedColumn ) )
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package com.formdev.flatlaf.ui;
|
|||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
|
import java.awt.Container;
|
||||||
import java.awt.Cursor;
|
import java.awt.Cursor;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
@@ -28,16 +29,15 @@ import java.awt.event.MouseEvent;
|
|||||||
import java.awt.geom.Rectangle2D;
|
import java.awt.geom.Rectangle2D;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import javax.swing.CellRendererPane;
|
||||||
import javax.swing.Icon;
|
import javax.swing.Icon;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import javax.swing.JTable;
|
import javax.swing.JTable;
|
||||||
import javax.swing.SwingConstants;
|
import javax.swing.SwingConstants;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.border.Border;
|
|
||||||
import javax.swing.event.MouseInputListener;
|
import javax.swing.event.MouseInputListener;
|
||||||
import javax.swing.plaf.ComponentUI;
|
import javax.swing.plaf.ComponentUI;
|
||||||
import javax.swing.plaf.UIResource;
|
|
||||||
import javax.swing.plaf.basic.BasicTableHeaderUI;
|
import javax.swing.plaf.basic.BasicTableHeaderUI;
|
||||||
import javax.swing.table.JTableHeader;
|
import javax.swing.table.JTableHeader;
|
||||||
import javax.swing.table.TableCellRenderer;
|
import javax.swing.table.TableCellRenderer;
|
||||||
@@ -59,6 +59,10 @@ import com.formdev.flatlaf.util.UIScale;
|
|||||||
*
|
*
|
||||||
* <!-- FlatTableHeaderUI -->
|
* <!-- FlatTableHeaderUI -->
|
||||||
*
|
*
|
||||||
|
* @uiDefault TableHeader.hoverBackground Color optional
|
||||||
|
* @uiDefault TableHeader.hoverForeground Color optional
|
||||||
|
* @uiDefault TableHeader.pressedBackground Color optional
|
||||||
|
* @uiDefault TableHeader.pressedForeground Color optional
|
||||||
* @uiDefault TableHeader.bottomSeparatorColor Color
|
* @uiDefault TableHeader.bottomSeparatorColor Color
|
||||||
* @uiDefault TableHeader.height int
|
* @uiDefault TableHeader.height int
|
||||||
* @uiDefault TableHeader.sortIconPosition String right (default), left, top or bottom
|
* @uiDefault TableHeader.sortIconPosition String right (default), left, top or bottom
|
||||||
@@ -81,6 +85,10 @@ public class FlatTableHeaderUI
|
|||||||
extends BasicTableHeaderUI
|
extends BasicTableHeaderUI
|
||||||
implements StyleableUI
|
implements StyleableUI
|
||||||
{
|
{
|
||||||
|
/** @since 3.1 */ @Styleable protected Color hoverBackground;
|
||||||
|
/** @since 3.1 */ @Styleable protected Color hoverForeground;
|
||||||
|
/** @since 3.1 */ @Styleable protected Color pressedBackground;
|
||||||
|
/** @since 3.1 */ @Styleable protected Color pressedForeground;
|
||||||
@Styleable protected Color bottomSeparatorColor;
|
@Styleable protected Color bottomSeparatorColor;
|
||||||
@Styleable protected int height;
|
@Styleable protected int height;
|
||||||
@Styleable(type=String.class) protected int sortIconPosition;
|
@Styleable(type=String.class) protected int sortIconPosition;
|
||||||
@@ -106,6 +114,11 @@ public class FlatTableHeaderUI
|
|||||||
public void installUI( JComponent c ) {
|
public void installUI( JComponent c ) {
|
||||||
super.installUI( c );
|
super.installUI( c );
|
||||||
|
|
||||||
|
// replace cell renderer pane
|
||||||
|
header.remove( rendererPane );
|
||||||
|
rendererPane = new FlatTableHeaderCellRendererPane();
|
||||||
|
header.add( rendererPane );
|
||||||
|
|
||||||
installStyle();
|
installStyle();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,6 +126,10 @@ public class FlatTableHeaderUI
|
|||||||
protected void installDefaults() {
|
protected void installDefaults() {
|
||||||
super.installDefaults();
|
super.installDefaults();
|
||||||
|
|
||||||
|
hoverBackground = UIManager.getColor( "TableHeader.hoverBackground" );
|
||||||
|
hoverForeground = UIManager.getColor( "TableHeader.hoverForeground" );
|
||||||
|
pressedBackground = UIManager.getColor( "TableHeader.pressedBackground" );
|
||||||
|
pressedForeground = UIManager.getColor( "TableHeader.pressedForeground" );
|
||||||
bottomSeparatorColor = UIManager.getColor( "TableHeader.bottomSeparatorColor" );
|
bottomSeparatorColor = UIManager.getColor( "TableHeader.bottomSeparatorColor" );
|
||||||
height = UIManager.getInt( "TableHeader.height" );
|
height = UIManager.getInt( "TableHeader.height" );
|
||||||
sortIconPosition = parseSortIconPosition( UIManager.getString( "TableHeader.sortIconPosition" ) );
|
sortIconPosition = parseSortIconPosition( UIManager.getString( "TableHeader.sortIconPosition" ) );
|
||||||
@@ -122,6 +139,10 @@ public class FlatTableHeaderUI
|
|||||||
protected void uninstallDefaults() {
|
protected void uninstallDefaults() {
|
||||||
super.uninstallDefaults();
|
super.uninstallDefaults();
|
||||||
|
|
||||||
|
hoverBackground = null;
|
||||||
|
hoverForeground = null;
|
||||||
|
pressedBackground = null;
|
||||||
|
pressedForeground = null;
|
||||||
bottomSeparatorColor = null;
|
bottomSeparatorColor = null;
|
||||||
|
|
||||||
oldStyleValues = null;
|
oldStyleValues = null;
|
||||||
@@ -211,6 +232,12 @@ public class FlatTableHeaderUI
|
|||||||
return super.getRolloverColumn();
|
return super.getRolloverColumn();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void rolloverColumnUpdated( int oldColumn, int newColumn ) {
|
||||||
|
header.repaint( header.getHeaderRect( oldColumn ) );
|
||||||
|
header.repaint( header.getHeaderRect( newColumn ) );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paint( Graphics g, JComponent c ) {
|
public void paint( Graphics g, JComponent c ) {
|
||||||
fixDraggedAndResizingColumns( header );
|
fixDraggedAndResizingColumns( header );
|
||||||
@@ -243,21 +270,8 @@ public class FlatTableHeaderUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// temporary use own default renderer if necessary
|
|
||||||
FlatTableCellHeaderRenderer sortIconRenderer = null;
|
|
||||||
if( sortIconPosition != SwingConstants.RIGHT ) {
|
|
||||||
sortIconRenderer = new FlatTableCellHeaderRenderer( header.getDefaultRenderer() );
|
|
||||||
header.setDefaultRenderer( sortIconRenderer );
|
|
||||||
}
|
|
||||||
|
|
||||||
// paint header
|
// paint header
|
||||||
super.paint( g, c );
|
super.paint( g, c );
|
||||||
|
|
||||||
// restore default renderer
|
|
||||||
if( sortIconRenderer != null ) {
|
|
||||||
sortIconRenderer.reset();
|
|
||||||
header.setDefaultRenderer( sortIconRenderer.delegate );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isSystemDefaultRenderer( Object headerRenderer ) {
|
private boolean isSystemDefaultRenderer( Object headerRenderer ) {
|
||||||
@@ -315,80 +329,129 @@ public class FlatTableHeaderUI
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//---- class FlatTableCellHeaderRenderer ----------------------------------
|
//---- class FlatTableHeaderCellRendererPane ------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A delegating header renderer that is only used to paint sort arrows at
|
* Cell renderer pane that is used to paint hover and pressed background/foreground
|
||||||
* top, bottom or left position.
|
* and to paint sort arrows at top, bottom or left position.
|
||||||
*/
|
*/
|
||||||
private class FlatTableCellHeaderRenderer
|
private class FlatTableHeaderCellRendererPane
|
||||||
implements TableCellRenderer, Border, UIResource
|
extends CellRendererPane
|
||||||
{
|
{
|
||||||
private final TableCellRenderer delegate;
|
private final Icon ascendingSortIcon;
|
||||||
|
private final Icon descendingSortIcon;
|
||||||
|
|
||||||
private JLabel l;
|
public FlatTableHeaderCellRendererPane() {
|
||||||
private int oldHorizontalTextPosition = -1;
|
ascendingSortIcon = UIManager.getIcon( "Table.ascendingSortIcon" );
|
||||||
private Border origBorder;
|
descendingSortIcon = UIManager.getIcon( "Table.descendingSortIcon" );
|
||||||
private Icon sortIcon;
|
|
||||||
|
|
||||||
FlatTableCellHeaderRenderer( TableCellRenderer delegate ) {
|
|
||||||
this.delegate = delegate;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Component getTableCellRendererComponent( JTable table, Object value, boolean isSelected,
|
public void paintComponent( Graphics g, Component c, Container p, int x, int y, int w, int h, boolean shouldValidate ) {
|
||||||
boolean hasFocus, int row, int column )
|
if( !(c instanceof JLabel) ) {
|
||||||
{
|
super.paintComponent( g, c, p, x, y, w, h, shouldValidate );
|
||||||
Component c = delegate.getTableCellRendererComponent( table, value, isSelected, hasFocus, row, column );
|
return;
|
||||||
if( !(c instanceof JLabel) )
|
|
||||||
return c;
|
|
||||||
|
|
||||||
l = (JLabel) c;
|
|
||||||
|
|
||||||
if( sortIconPosition == SwingConstants.LEFT ) {
|
|
||||||
if( oldHorizontalTextPosition < 0 )
|
|
||||||
oldHorizontalTextPosition = l.getHorizontalTextPosition();
|
|
||||||
l.setHorizontalTextPosition( SwingConstants.RIGHT );
|
|
||||||
} else {
|
|
||||||
// top or bottom
|
|
||||||
sortIcon = l.getIcon();
|
|
||||||
origBorder = l.getBorder();
|
|
||||||
l.setIcon( null );
|
|
||||||
l.setBorder( this );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return l;
|
JLabel l = (JLabel) c;
|
||||||
}
|
Color oldBackground = null;
|
||||||
|
Color oldForeground = null;
|
||||||
|
boolean oldOpaque = false;
|
||||||
|
Icon oldIcon = null;
|
||||||
|
int oldHorizontalTextPosition = -1;
|
||||||
|
|
||||||
void reset() {
|
// hover and pressed background/foreground
|
||||||
if( l != null && sortIconPosition == SwingConstants.LEFT && oldHorizontalTextPosition >= 0 )
|
TableColumn draggedColumn = header.getDraggedColumn();
|
||||||
|
Color background = null;
|
||||||
|
Color foreground = null;
|
||||||
|
if( draggedColumn != null &&
|
||||||
|
header.getTable().convertColumnIndexToView( draggedColumn.getModelIndex() )
|
||||||
|
== getColumn( x - header.getDraggedDistance(), w ) )
|
||||||
|
{
|
||||||
|
background = pressedBackground;
|
||||||
|
foreground = pressedForeground;
|
||||||
|
} else if( getRolloverColumn() >= 0 && getRolloverColumn() == getColumn( x, w ) ) {
|
||||||
|
background = hoverBackground;
|
||||||
|
foreground = hoverForeground;
|
||||||
|
}
|
||||||
|
if( background != null ) {
|
||||||
|
oldBackground = l.getBackground();
|
||||||
|
oldOpaque = l.isOpaque();
|
||||||
|
l.setBackground( FlatUIUtils.deriveColor( background, header.getBackground() ) );
|
||||||
|
l.setOpaque( true );
|
||||||
|
}
|
||||||
|
if( foreground != null ) {
|
||||||
|
oldForeground = l.getForeground();
|
||||||
|
l.setForeground( FlatUIUtils.deriveColor( foreground, header.getForeground() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort icon position
|
||||||
|
Icon icon = l.getIcon();
|
||||||
|
boolean isSortIcon = (icon != null && (icon == ascendingSortIcon || icon == descendingSortIcon));
|
||||||
|
if( isSortIcon ) {
|
||||||
|
if( sortIconPosition == SwingConstants.LEFT ) {
|
||||||
|
// left
|
||||||
|
oldHorizontalTextPosition = l.getHorizontalTextPosition();
|
||||||
|
l.setHorizontalTextPosition( SwingConstants.RIGHT );
|
||||||
|
} else if( sortIconPosition == SwingConstants.TOP || sortIconPosition == SwingConstants.BOTTOM ) {
|
||||||
|
// top or bottom
|
||||||
|
oldIcon = icon;
|
||||||
|
l.setIcon( null );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// paint renderer component
|
||||||
|
super.paintComponent( g, c, p, x, y, w, h, shouldValidate );
|
||||||
|
|
||||||
|
// paint top or bottom sort icon
|
||||||
|
if( isSortIcon && (sortIconPosition == SwingConstants.TOP || sortIconPosition == SwingConstants.BOTTOM) ) {
|
||||||
|
int xi = x + ((w - icon.getIconWidth()) / 2);
|
||||||
|
int yi = (sortIconPosition == SwingConstants.TOP)
|
||||||
|
? y + UIScale.scale( 1 )
|
||||||
|
: y + height - icon.getIconHeight()
|
||||||
|
- 1 // for gap
|
||||||
|
- (int) (1 * UIScale.getUserScaleFactor()); // for bottom border
|
||||||
|
icon.paintIcon( c, g, xi, yi );
|
||||||
|
}
|
||||||
|
|
||||||
|
// restore modified renderer component properties
|
||||||
|
if( background != null ) {
|
||||||
|
l.setBackground( oldBackground );
|
||||||
|
l.setOpaque( oldOpaque );
|
||||||
|
}
|
||||||
|
if( foreground != null )
|
||||||
|
l.setForeground( oldForeground );
|
||||||
|
if( oldIcon != null )
|
||||||
|
l.setIcon( oldIcon );
|
||||||
|
if( oldHorizontalTextPosition >= 0 )
|
||||||
l.setHorizontalTextPosition( oldHorizontalTextPosition );
|
l.setHorizontalTextPosition( oldHorizontalTextPosition );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
* Get column index for given coordinates.
|
||||||
if( origBorder != null )
|
*/
|
||||||
origBorder.paintBorder( c, g, x, y, width, height );
|
private int getColumn( int x, int width ) {
|
||||||
|
TableColumnModel columnModel = header.getColumnModel();
|
||||||
|
int columnCount = columnModel.getColumnCount();
|
||||||
|
boolean ltr = header.getComponentOrientation().isLeftToRight();
|
||||||
|
int cx = ltr ? 0 : getWidthInRightToLef();
|
||||||
|
|
||||||
if( sortIcon != null ) {
|
for( int i = 0; i < columnCount; i++ ) {
|
||||||
int xi = x + ((width - sortIcon.getIconWidth()) / 2);
|
int cw = columnModel.getColumn( i ).getWidth();
|
||||||
int yi = (sortIconPosition == SwingConstants.TOP)
|
if( x == cx - (ltr ? 0 : cw) && width == cw )
|
||||||
? y + UIScale.scale( 1 )
|
return i;
|
||||||
: y + height - sortIcon.getIconHeight()
|
|
||||||
- 1 // for gap
|
cx += ltr ? cw : -cw;
|
||||||
- (int) (1 * UIScale.getUserScaleFactor()); // for bottom border
|
|
||||||
sortIcon.paintIcon( c, g, xi, yi );
|
|
||||||
}
|
}
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
// similar to JTableHeader.getWidthInRightToLeft()
|
||||||
public Insets getBorderInsets( Component c ) {
|
private int getWidthInRightToLef() {
|
||||||
return (origBorder != null) ? origBorder.getBorderInsets( c ) : new Insets( 0, 0, 0, 0 );
|
JTable table = header.getTable();
|
||||||
}
|
return (table != null && table.getAutoResizeMode() != JTable.AUTO_RESIZE_OFF)
|
||||||
|
? table.getWidth()
|
||||||
@Override
|
: header.getWidth();
|
||||||
public boolean isBorderOpaque() {
|
|
||||||
return (origBorder != null) ? origBorder.isBorderOpaque() : false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package com.formdev.flatlaf.ui;
|
package com.formdev.flatlaf.ui;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
import java.awt.Component;
|
||||||
import java.awt.Container;
|
import java.awt.Container;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.EventQueue;
|
import java.awt.EventQueue;
|
||||||
@@ -26,18 +27,25 @@ import java.awt.Insets;
|
|||||||
import java.awt.event.FocusEvent;
|
import java.awt.event.FocusEvent;
|
||||||
import java.awt.event.FocusListener;
|
import java.awt.event.FocusListener;
|
||||||
import java.awt.geom.Rectangle2D;
|
import java.awt.geom.Rectangle2D;
|
||||||
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JScrollPane;
|
import javax.swing.JScrollPane;
|
||||||
|
import javax.swing.JTable;
|
||||||
import javax.swing.JViewport;
|
import javax.swing.JViewport;
|
||||||
import javax.swing.LookAndFeel;
|
import javax.swing.LookAndFeel;
|
||||||
|
import javax.swing.SwingConstants;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.plaf.ComponentUI;
|
import javax.swing.plaf.ComponentUI;
|
||||||
|
import javax.swing.plaf.UIResource;
|
||||||
import javax.swing.plaf.basic.BasicTableUI;
|
import javax.swing.plaf.basic.BasicTableUI;
|
||||||
|
import javax.swing.table.DefaultTableCellRenderer;
|
||||||
import javax.swing.table.JTableHeader;
|
import javax.swing.table.JTableHeader;
|
||||||
|
import javax.swing.table.TableCellRenderer;
|
||||||
import com.formdev.flatlaf.FlatClientProperties;
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
|
import com.formdev.flatlaf.icons.FlatCheckBoxIcon;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||||
import com.formdev.flatlaf.util.Graphics2DProxy;
|
import com.formdev.flatlaf.util.Graphics2DProxy;
|
||||||
@@ -116,6 +124,7 @@ public class FlatTableUI
|
|||||||
private boolean oldShowHorizontalLines;
|
private boolean oldShowHorizontalLines;
|
||||||
private boolean oldShowVerticalLines;
|
private boolean oldShowVerticalLines;
|
||||||
private Dimension oldIntercellSpacing;
|
private Dimension oldIntercellSpacing;
|
||||||
|
private TableCellRenderer oldBooleanRenderer;
|
||||||
|
|
||||||
private PropertyChangeListener propertyChangeListener;
|
private PropertyChangeListener propertyChangeListener;
|
||||||
private Map<String, Object> oldStyleValues;
|
private Map<String, Object> oldStyleValues;
|
||||||
@@ -151,19 +160,35 @@ public class FlatTableUI
|
|||||||
if( rowHeight > 0 )
|
if( rowHeight > 0 )
|
||||||
LookAndFeel.installProperty( table, "rowHeight", UIScale.scale( rowHeight ) );
|
LookAndFeel.installProperty( table, "rowHeight", UIScale.scale( rowHeight ) );
|
||||||
|
|
||||||
if( !showHorizontalLines ) {
|
FlatTablePropertyWatcher watcher = FlatTablePropertyWatcher.get( table );
|
||||||
|
if( watcher != null )
|
||||||
|
watcher.enabled = false;
|
||||||
|
|
||||||
|
if( !showHorizontalLines && (watcher == null || !watcher.showHorizontalLinesChanged) ) {
|
||||||
oldShowHorizontalLines = table.getShowHorizontalLines();
|
oldShowHorizontalLines = table.getShowHorizontalLines();
|
||||||
table.setShowHorizontalLines( false );
|
table.setShowHorizontalLines( false );
|
||||||
}
|
}
|
||||||
if( !showVerticalLines ) {
|
if( !showVerticalLines && (watcher == null || !watcher.showVerticalLinesChanged) ) {
|
||||||
oldShowVerticalLines = table.getShowVerticalLines();
|
oldShowVerticalLines = table.getShowVerticalLines();
|
||||||
table.setShowVerticalLines( false );
|
table.setShowVerticalLines( false );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( intercellSpacing != null ) {
|
if( intercellSpacing != null && (watcher == null || !watcher.intercellSpacingChanged) ) {
|
||||||
oldIntercellSpacing = table.getIntercellSpacing();
|
oldIntercellSpacing = table.getIntercellSpacing();
|
||||||
table.setIntercellSpacing( intercellSpacing );
|
table.setIntercellSpacing( intercellSpacing );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( watcher != null )
|
||||||
|
watcher.enabled = true;
|
||||||
|
else
|
||||||
|
table.addPropertyChangeListener( new FlatTablePropertyWatcher() );
|
||||||
|
|
||||||
|
// install boolean renderer
|
||||||
|
oldBooleanRenderer = table.getDefaultRenderer( Boolean.class );
|
||||||
|
if( oldBooleanRenderer instanceof UIResource )
|
||||||
|
table.setDefaultRenderer( Boolean.class, new FlatBooleanRenderer() );
|
||||||
|
else
|
||||||
|
oldBooleanRenderer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -177,15 +202,36 @@ public class FlatTableUI
|
|||||||
|
|
||||||
oldStyleValues = null;
|
oldStyleValues = null;
|
||||||
|
|
||||||
|
FlatTablePropertyWatcher watcher = FlatTablePropertyWatcher.get( table );
|
||||||
|
if( watcher != null )
|
||||||
|
watcher.enabled = false;
|
||||||
|
|
||||||
// restore old show horizontal/vertical lines (if not modified)
|
// restore old show horizontal/vertical lines (if not modified)
|
||||||
if( !showHorizontalLines && oldShowHorizontalLines && !table.getShowHorizontalLines() )
|
if( !showHorizontalLines && oldShowHorizontalLines && !table.getShowHorizontalLines() &&
|
||||||
table.setShowHorizontalLines( true );
|
(watcher == null || !watcher.showHorizontalLinesChanged) )
|
||||||
if( !showVerticalLines && oldShowVerticalLines && !table.getShowVerticalLines() )
|
table.setShowHorizontalLines( true );
|
||||||
table.setShowVerticalLines( true );
|
if( !showVerticalLines && oldShowVerticalLines && !table.getShowVerticalLines() &&
|
||||||
|
(watcher == null || !watcher.showVerticalLinesChanged) )
|
||||||
|
table.setShowVerticalLines( true );
|
||||||
|
|
||||||
// restore old intercell spacing (if not modified)
|
// restore old intercell spacing (if not modified)
|
||||||
if( intercellSpacing != null && table.getIntercellSpacing().equals( intercellSpacing ) )
|
if( intercellSpacing != null && table.getIntercellSpacing().equals( intercellSpacing ) &&
|
||||||
table.setIntercellSpacing( oldIntercellSpacing );
|
(watcher == null || !watcher.intercellSpacingChanged) )
|
||||||
|
table.setIntercellSpacing( oldIntercellSpacing );
|
||||||
|
|
||||||
|
if( watcher != null )
|
||||||
|
watcher.enabled = true;
|
||||||
|
|
||||||
|
// uninstall boolean renderer
|
||||||
|
if( table.getDefaultRenderer( Boolean.class ) instanceof FlatBooleanRenderer ) {
|
||||||
|
if( oldBooleanRenderer instanceof Component ) {
|
||||||
|
// because the old renderer component was not attached to any component hierarchy,
|
||||||
|
// its UI was not yet updated, and it is necessary to do it here
|
||||||
|
SwingUtilities.updateComponentTreeUI( (Component) oldBooleanRenderer );
|
||||||
|
}
|
||||||
|
table.setDefaultRenderer( Boolean.class, oldBooleanRenderer );
|
||||||
|
}
|
||||||
|
oldBooleanRenderer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -277,6 +323,9 @@ public class FlatTableUI
|
|||||||
|
|
||||||
/** @since 2 */
|
/** @since 2 */
|
||||||
protected Object applyStyleProperty( String key, Object value ) {
|
protected Object applyStyleProperty( String key, Object value ) {
|
||||||
|
if( "rowHeight".equals( key ) && value instanceof Integer )
|
||||||
|
value = UIScale.scale( (Integer) value );
|
||||||
|
|
||||||
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, table, key, value );
|
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, table, key, value );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -464,4 +513,70 @@ public class FlatTableUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---- class FlatTablePropertyWatcher -------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener that watches for change of some table properties from application code.
|
||||||
|
* This information is used in {@link FlatTableUI#installDefaults()} and
|
||||||
|
* {@link FlatTableUI#uninstallDefaults()} to decide whether FlatLaf modifies those properties.
|
||||||
|
* If they are modified in application code, FlatLaf no longer changes them.
|
||||||
|
*
|
||||||
|
* The listener is added once for each table, but never removed.
|
||||||
|
* So switching Laf/theme reuses existing listener.
|
||||||
|
*/
|
||||||
|
private static class FlatTablePropertyWatcher
|
||||||
|
implements PropertyChangeListener
|
||||||
|
{
|
||||||
|
boolean enabled = true;
|
||||||
|
boolean showHorizontalLinesChanged;
|
||||||
|
boolean showVerticalLinesChanged;
|
||||||
|
boolean intercellSpacingChanged;
|
||||||
|
|
||||||
|
static FlatTablePropertyWatcher get( JTable table ) {
|
||||||
|
for( PropertyChangeListener l : table.getPropertyChangeListeners() ) {
|
||||||
|
if( l instanceof FlatTablePropertyWatcher )
|
||||||
|
return (FlatTablePropertyWatcher) l;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---- interface PropertyChangeListener ----
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void propertyChange( PropertyChangeEvent e ) {
|
||||||
|
if( !enabled )
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch( e.getPropertyName() ) {
|
||||||
|
case "showHorizontalLines": showHorizontalLinesChanged = true; break;
|
||||||
|
case "showVerticalLines": showVerticalLinesChanged = true; break;
|
||||||
|
case "rowMargin": intercellSpacingChanged = true; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---- class FlatBooleanRenderer ------------------------------------------
|
||||||
|
|
||||||
|
private static class FlatBooleanRenderer
|
||||||
|
extends DefaultTableCellRenderer
|
||||||
|
implements UIResource
|
||||||
|
{
|
||||||
|
private boolean selected;
|
||||||
|
|
||||||
|
FlatBooleanRenderer() {
|
||||||
|
setHorizontalAlignment( SwingConstants.CENTER );
|
||||||
|
setIcon( new FlatCheckBoxIcon() {
|
||||||
|
@Override
|
||||||
|
protected boolean isSelected( Component c ) {
|
||||||
|
return selected;
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setValue( Object value ) {
|
||||||
|
selected = (value != null && (Boolean) value);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,6 @@ import com.formdev.flatlaf.util.LoggingFacade;
|
|||||||
* <!-- FlatTextAreaUI -->
|
* <!-- FlatTextAreaUI -->
|
||||||
*
|
*
|
||||||
* @uiDefault Component.minimumWidth int
|
* @uiDefault Component.minimumWidth int
|
||||||
* @uiDefault Component.isIntelliJTheme boolean
|
|
||||||
* @uiDefault TextArea.disabledBackground Color used if not enabled
|
* @uiDefault TextArea.disabledBackground Color used if not enabled
|
||||||
* @uiDefault TextArea.inactiveBackground Color used if not editable
|
* @uiDefault TextArea.inactiveBackground Color used if not editable
|
||||||
* @uiDefault TextArea.focusedBackground Color optional
|
* @uiDefault TextArea.focusedBackground Color optional
|
||||||
@@ -66,7 +65,6 @@ public class FlatTextAreaUI
|
|||||||
implements StyleableUI
|
implements StyleableUI
|
||||||
{
|
{
|
||||||
@Styleable protected int minimumWidth;
|
@Styleable protected int minimumWidth;
|
||||||
protected boolean isIntelliJTheme;
|
|
||||||
private Color background;
|
private Color background;
|
||||||
@Styleable protected Color disabledBackground;
|
@Styleable protected Color disabledBackground;
|
||||||
@Styleable protected Color inactiveBackground;
|
@Styleable protected Color inactiveBackground;
|
||||||
@@ -103,7 +101,6 @@ public class FlatTextAreaUI
|
|||||||
super.installDefaults();
|
super.installDefaults();
|
||||||
|
|
||||||
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
||||||
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
|
||||||
background = UIManager.getColor( "TextArea.background" );
|
background = UIManager.getColor( "TextArea.background" );
|
||||||
disabledBackground = UIManager.getColor( "TextArea.disabledBackground" );
|
disabledBackground = UIManager.getColor( "TextArea.disabledBackground" );
|
||||||
inactiveBackground = UIManager.getColor( "TextArea.inactiveBackground" );
|
inactiveBackground = UIManager.getColor( "TextArea.inactiveBackground" );
|
||||||
@@ -227,6 +224,6 @@ public class FlatTextAreaUI
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void paintBackground( Graphics g ) {
|
protected void paintBackground( Graphics g ) {
|
||||||
FlatEditorPaneUI.paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground );
|
FlatEditorPaneUI.paintBackground( g, getComponent(), focusedBackground );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ import javax.swing.JTextField;
|
|||||||
import javax.swing.JToggleButton;
|
import javax.swing.JToggleButton;
|
||||||
import javax.swing.JToolBar;
|
import javax.swing.JToolBar;
|
||||||
import javax.swing.LookAndFeel;
|
import javax.swing.LookAndFeel;
|
||||||
|
import javax.swing.SwingConstants;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.event.DocumentEvent;
|
import javax.swing.event.DocumentEvent;
|
||||||
import javax.swing.event.DocumentListener;
|
import javax.swing.event.DocumentListener;
|
||||||
@@ -81,7 +82,6 @@ import com.formdev.flatlaf.util.LoggingFacade;
|
|||||||
* <!-- FlatTextFieldUI -->
|
* <!-- FlatTextFieldUI -->
|
||||||
*
|
*
|
||||||
* @uiDefault Component.minimumWidth int
|
* @uiDefault Component.minimumWidth int
|
||||||
* @uiDefault Component.isIntelliJTheme boolean
|
|
||||||
* @uiDefault TextField.placeholderForeground Color
|
* @uiDefault TextField.placeholderForeground Color
|
||||||
* @uiDefault TextField.focusedBackground Color optional
|
* @uiDefault TextField.focusedBackground Color optional
|
||||||
* @uiDefault TextField.iconTextGap int optional, default is 4
|
* @uiDefault TextField.iconTextGap int optional, default is 4
|
||||||
@@ -95,7 +95,6 @@ public class FlatTextFieldUI
|
|||||||
implements StyleableUI
|
implements StyleableUI
|
||||||
{
|
{
|
||||||
@Styleable protected int minimumWidth;
|
@Styleable protected int minimumWidth;
|
||||||
protected boolean isIntelliJTheme;
|
|
||||||
private Color background;
|
private Color background;
|
||||||
@Styleable protected Color disabledBackground;
|
@Styleable protected Color disabledBackground;
|
||||||
@Styleable protected Color inactiveBackground;
|
@Styleable protected Color inactiveBackground;
|
||||||
@@ -165,7 +164,6 @@ public class FlatTextFieldUI
|
|||||||
|
|
||||||
String prefix = getPropertyPrefix();
|
String prefix = getPropertyPrefix();
|
||||||
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
||||||
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
|
||||||
background = UIManager.getColor( prefix + ".background" );
|
background = UIManager.getColor( prefix + ".background" );
|
||||||
disabledBackground = UIManager.getColor( prefix + ".disabledBackground" );
|
disabledBackground = UIManager.getColor( prefix + ".disabledBackground" );
|
||||||
inactiveBackground = UIManager.getColor( prefix + ".inactiveBackground" );
|
inactiveBackground = UIManager.getColor( prefix + ".inactiveBackground" );
|
||||||
@@ -402,7 +400,7 @@ public class FlatTextFieldUI
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void paintSafely( Graphics g ) {
|
protected void paintSafely( Graphics g ) {
|
||||||
paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground );
|
paintBackground( g, getComponent(), focusedBackground );
|
||||||
paintPlaceholder( g );
|
paintPlaceholder( g );
|
||||||
|
|
||||||
if( hasLeadingIcon() || hasTrailingIcon() )
|
if( hasLeadingIcon() || hasTrailingIcon() )
|
||||||
@@ -422,7 +420,7 @@ debug*/
|
|||||||
// background is painted elsewhere
|
// background is painted elsewhere
|
||||||
}
|
}
|
||||||
|
|
||||||
static void paintBackground( Graphics g, JTextComponent c, boolean isIntelliJTheme, Color focusedBackground ) {
|
static void paintBackground( Graphics g, JTextComponent c, Color focusedBackground ) {
|
||||||
// do not paint background if:
|
// do not paint background if:
|
||||||
// - not opaque and
|
// - not opaque and
|
||||||
// - border is not a flat border and
|
// - border is not a flat border and
|
||||||
@@ -443,14 +441,14 @@ debug*/
|
|||||||
try {
|
try {
|
||||||
FlatUIUtils.setRenderingHints( g2 );
|
FlatUIUtils.setRenderingHints( g2 );
|
||||||
|
|
||||||
g2.setColor( getBackground( c, isIntelliJTheme, focusedBackground ) );
|
g2.setColor( getBackground( c, focusedBackground ) );
|
||||||
FlatUIUtils.paintComponentBackground( g2, 0, 0, c.getWidth(), c.getHeight(), focusWidth, arc );
|
FlatUIUtils.paintComponentBackground( g2, 0, 0, c.getWidth(), c.getHeight(), focusWidth, arc );
|
||||||
} finally {
|
} finally {
|
||||||
g2.dispose();
|
g2.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Color getBackground( JTextComponent c, boolean isIntelliJTheme, Color focusedBackground ) {
|
static Color getBackground( JTextComponent c, Color focusedBackground ) {
|
||||||
Color background = c.getBackground();
|
Color background = c.getBackground();
|
||||||
|
|
||||||
// always use explicitly set color
|
// always use explicitly set color
|
||||||
@@ -461,10 +459,6 @@ debug*/
|
|||||||
if( focusedBackground != null && FlatUIUtils.isPermanentFocusOwner( c ) )
|
if( focusedBackground != null && FlatUIUtils.isPermanentFocusOwner( c ) )
|
||||||
return focusedBackground;
|
return focusedBackground;
|
||||||
|
|
||||||
// for compatibility with IntelliJ themes
|
|
||||||
if( isIntelliJTheme && (!c.isEnabled() || !c.isEditable()) )
|
|
||||||
return FlatUIUtils.getParentBackground( c );
|
|
||||||
|
|
||||||
return background;
|
return background;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -487,10 +481,22 @@ debug*/
|
|||||||
// compute placeholder location
|
// compute placeholder location
|
||||||
Rectangle r = getVisibleEditorRect();
|
Rectangle r = getVisibleEditorRect();
|
||||||
FontMetrics fm = c.getFontMetrics( c.getFont() );
|
FontMetrics fm = c.getFontMetrics( c.getFont() );
|
||||||
String clippedPlaceholder = JavaCompatibility.getClippedString( c, fm, placeholder, r.width );
|
int x = r.x;
|
||||||
int x = r.x + (isLeftToRight() ? 0 : r.width - fm.stringWidth( clippedPlaceholder ));
|
|
||||||
int y = r.y + fm.getAscent() + ((r.height - fm.getHeight()) / 2);
|
int y = r.y + fm.getAscent() + ((r.height - fm.getHeight()) / 2);
|
||||||
|
|
||||||
|
// apply horizontal alignment to x location
|
||||||
|
String clippedPlaceholder = JavaCompatibility.getClippedString( c, fm, placeholder, r.width );
|
||||||
|
int stringWidth = fm.stringWidth( clippedPlaceholder );
|
||||||
|
int halign = (c instanceof JTextField) ? ((JTextField)c).getHorizontalAlignment() : SwingConstants.LEADING;
|
||||||
|
if( halign == SwingConstants.LEADING )
|
||||||
|
halign = isLeftToRight() ? SwingConstants.LEFT : SwingConstants.RIGHT;
|
||||||
|
else if( halign == SwingConstants.TRAILING )
|
||||||
|
halign = isLeftToRight() ? SwingConstants.RIGHT : SwingConstants.LEFT;
|
||||||
|
if( halign == SwingConstants.RIGHT )
|
||||||
|
x += r.width - stringWidth;
|
||||||
|
else if( halign == SwingConstants.CENTER )
|
||||||
|
x = Math.max( 0, x + (r.width / 2) - (stringWidth / 2) );
|
||||||
|
|
||||||
// paint placeholder
|
// paint placeholder
|
||||||
g.setColor( placeholderForeground );
|
g.setColor( placeholderForeground );
|
||||||
FlatUIUtils.drawString( c, g, clippedPlaceholder, x, y );
|
FlatUIUtils.drawString( c, g, clippedPlaceholder, x, y );
|
||||||
|
|||||||
@@ -56,7 +56,6 @@ import com.formdev.flatlaf.util.LoggingFacade;
|
|||||||
* <!-- FlatTextPaneUI -->
|
* <!-- FlatTextPaneUI -->
|
||||||
*
|
*
|
||||||
* @uiDefault Component.minimumWidth int
|
* @uiDefault Component.minimumWidth int
|
||||||
* @uiDefault Component.isIntelliJTheme boolean
|
|
||||||
* @uiDefault TextPane.focusedBackground Color optional
|
* @uiDefault TextPane.focusedBackground Color optional
|
||||||
*
|
*
|
||||||
* @author Karl Tauber
|
* @author Karl Tauber
|
||||||
@@ -66,7 +65,6 @@ public class FlatTextPaneUI
|
|||||||
implements StyleableUI
|
implements StyleableUI
|
||||||
{
|
{
|
||||||
@Styleable protected int minimumWidth;
|
@Styleable protected int minimumWidth;
|
||||||
protected boolean isIntelliJTheme;
|
|
||||||
private Color background;
|
private Color background;
|
||||||
@Styleable protected Color disabledBackground;
|
@Styleable protected Color disabledBackground;
|
||||||
@Styleable protected Color inactiveBackground;
|
@Styleable protected Color inactiveBackground;
|
||||||
@@ -98,7 +96,6 @@ public class FlatTextPaneUI
|
|||||||
|
|
||||||
String prefix = getPropertyPrefix();
|
String prefix = getPropertyPrefix();
|
||||||
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
||||||
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
|
||||||
background = UIManager.getColor( prefix + ".background" );
|
background = UIManager.getColor( prefix + ".background" );
|
||||||
disabledBackground = UIManager.getColor( prefix + ".disabledBackground" );
|
disabledBackground = UIManager.getColor( prefix + ".disabledBackground" );
|
||||||
inactiveBackground = UIManager.getColor( prefix + ".inactiveBackground" );
|
inactiveBackground = UIManager.getColor( prefix + ".inactiveBackground" );
|
||||||
@@ -220,6 +217,6 @@ public class FlatTextPaneUI
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void paintBackground( Graphics g ) {
|
protected void paintBackground( Graphics g ) {
|
||||||
FlatEditorPaneUI.paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground );
|
FlatEditorPaneUI.paintBackground( g, getComponent(), focusedBackground );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ import javax.swing.Icon;
|
|||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JDialog;
|
import javax.swing.JDialog;
|
||||||
|
import javax.swing.JInternalFrame;
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import javax.swing.JMenuBar;
|
import javax.swing.JMenuBar;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
@@ -96,6 +97,7 @@ import com.formdev.flatlaf.util.UIScale;
|
|||||||
* @uiDefault TitlePane.centerTitleIfMenuBarEmbedded boolean
|
* @uiDefault TitlePane.centerTitleIfMenuBarEmbedded boolean
|
||||||
* @uiDefault TitlePane.showIconBesideTitle boolean
|
* @uiDefault TitlePane.showIconBesideTitle boolean
|
||||||
* @uiDefault TitlePane.menuBarTitleGap int
|
* @uiDefault TitlePane.menuBarTitleGap int
|
||||||
|
* @uiDefault TitlePane.menuBarTitleMinimumGap int
|
||||||
* @uiDefault TitlePane.menuBarResizeHeight int
|
* @uiDefault TitlePane.menuBarResizeHeight int
|
||||||
* @uiDefault TitlePane.closeIcon Icon
|
* @uiDefault TitlePane.closeIcon Icon
|
||||||
* @uiDefault TitlePane.iconifyIcon Icon
|
* @uiDefault TitlePane.iconifyIcon Icon
|
||||||
@@ -109,29 +111,30 @@ public class FlatTitlePane
|
|||||||
{
|
{
|
||||||
private static final String KEY_DEBUG_SHOW_RECTANGLES = "FlatLaf.debug.titlebar.showRectangles";
|
private static final String KEY_DEBUG_SHOW_RECTANGLES = "FlatLaf.debug.titlebar.showRectangles";
|
||||||
|
|
||||||
/** @since 2.5 */ protected final Font titleFont = UIManager.getFont( "TitlePane.font" );
|
/** @since 2.5 */ protected final Font titleFont;
|
||||||
protected final Color activeBackground = UIManager.getColor( "TitlePane.background" );
|
protected final Color activeBackground;
|
||||||
protected final Color inactiveBackground = UIManager.getColor( "TitlePane.inactiveBackground" );
|
protected final Color inactiveBackground;
|
||||||
protected final Color activeForeground = UIManager.getColor( "TitlePane.foreground" );
|
protected final Color activeForeground;
|
||||||
protected final Color inactiveForeground = UIManager.getColor( "TitlePane.inactiveForeground" );
|
protected final Color inactiveForeground;
|
||||||
protected final Color embeddedForeground = UIManager.getColor( "TitlePane.embeddedForeground" );
|
protected final Color embeddedForeground;
|
||||||
protected final Color borderColor = UIManager.getColor( "TitlePane.borderColor" );
|
protected final Color borderColor;
|
||||||
|
|
||||||
/** @since 2 */ protected final boolean showIcon = FlatUIUtils.getUIBoolean( "TitlePane.showIcon", true );
|
/** @since 2 */ protected final boolean showIcon;
|
||||||
/** @since 2.5 */ protected final boolean showIconInDialogs = FlatUIUtils.getUIBoolean( "TitlePane.showIconInDialogs", true );
|
/** @since 2.5 */ protected final boolean showIconInDialogs;
|
||||||
/** @since 2 */ protected final int noIconLeftGap = FlatUIUtils.getUIInt( "TitlePane.noIconLeftGap", 8 );
|
/** @since 2 */ protected final int noIconLeftGap;
|
||||||
protected final Dimension iconSize = UIManager.getDimension( "TitlePane.iconSize" );
|
protected final Dimension iconSize;
|
||||||
/** @since 2.4 */ protected final int titleMinimumWidth = FlatUIUtils.getUIInt( "TitlePane.titleMinimumWidth", 60 );
|
/** @since 2.4 */ protected final int titleMinimumWidth;
|
||||||
/** @since 2.4 */ protected final int buttonMinimumWidth = FlatUIUtils.getUIInt( "TitlePane.buttonMinimumWidth", 30 );
|
/** @since 2.4 */ protected final int buttonMinimumWidth;
|
||||||
protected final int buttonMaximizedHeight = UIManager.getInt( "TitlePane.buttonMaximizedHeight" );
|
protected final int buttonMaximizedHeight;
|
||||||
protected final boolean centerTitle = UIManager.getBoolean( "TitlePane.centerTitle" );
|
protected final boolean centerTitle;
|
||||||
protected final boolean centerTitleIfMenuBarEmbedded = FlatUIUtils.getUIBoolean( "TitlePane.centerTitleIfMenuBarEmbedded", true );
|
protected final boolean centerTitleIfMenuBarEmbedded;
|
||||||
/** @since 2.4 */ protected final boolean showIconBesideTitle = UIManager.getBoolean( "TitlePane.showIconBesideTitle" );
|
/** @since 2.4 */ protected final boolean showIconBesideTitle;
|
||||||
protected final int menuBarTitleGap = FlatUIUtils.getUIInt( "TitlePane.menuBarTitleGap", 40 );
|
protected final int menuBarTitleGap;
|
||||||
/** @since 2.4 */ protected final int menuBarTitleMinimumGap = FlatUIUtils.getUIInt( "TitlePane.menuBarTitleMinimumGap", 12 );
|
/** @since 2.4 */ protected final int menuBarTitleMinimumGap;
|
||||||
/** @since 2.4 */ protected final int menuBarResizeHeight = FlatUIUtils.getUIInt( "TitlePane.menuBarResizeHeight", 4 );
|
/** @since 2.4 */ protected final int menuBarResizeHeight;
|
||||||
|
|
||||||
protected final JRootPane rootPane;
|
protected final JRootPane rootPane;
|
||||||
|
protected final String windowStyle;
|
||||||
|
|
||||||
protected JPanel leftPanel;
|
protected JPanel leftPanel;
|
||||||
protected JLabel iconLabel;
|
protected JLabel iconLabel;
|
||||||
@@ -150,6 +153,34 @@ public class FlatTitlePane
|
|||||||
public FlatTitlePane( JRootPane rootPane ) {
|
public FlatTitlePane( JRootPane rootPane ) {
|
||||||
this.rootPane = rootPane;
|
this.rootPane = rootPane;
|
||||||
|
|
||||||
|
Window w = SwingUtilities.getWindowAncestor( rootPane );
|
||||||
|
String defaultWindowStyle = (w != null && w.getType() == Window.Type.UTILITY) ? WINDOW_STYLE_SMALL : null;
|
||||||
|
windowStyle = clientProperty( rootPane, WINDOW_STYLE, defaultWindowStyle, String.class );
|
||||||
|
|
||||||
|
titleFont = FlatUIUtils.getSubUIFont( "TitlePane.font", windowStyle );
|
||||||
|
activeBackground = FlatUIUtils.getSubUIColor( "TitlePane.background", windowStyle );
|
||||||
|
inactiveBackground = FlatUIUtils.getSubUIColor( "TitlePane.inactiveBackground", windowStyle );
|
||||||
|
activeForeground = FlatUIUtils.getSubUIColor( "TitlePane.foreground", windowStyle );
|
||||||
|
inactiveForeground = FlatUIUtils.getSubUIColor( "TitlePane.inactiveForeground", windowStyle );
|
||||||
|
embeddedForeground = FlatUIUtils.getSubUIColor( "TitlePane.embeddedForeground", windowStyle );
|
||||||
|
// not using windowStyle here because TitlePane.borderColor is also used in FlatRootPaneUI
|
||||||
|
borderColor = UIManager.getColor( "TitlePane.borderColor" );
|
||||||
|
|
||||||
|
showIcon = FlatUIUtils.getSubUIBoolean( "TitlePane.showIcon", windowStyle, true );
|
||||||
|
showIconInDialogs = FlatUIUtils.getSubUIBoolean( "TitlePane.showIconInDialogs", windowStyle, true );
|
||||||
|
noIconLeftGap = FlatUIUtils.getSubUIInt( "TitlePane.noIconLeftGap", windowStyle, 8 );
|
||||||
|
iconSize = FlatUIUtils.getSubUIDimension( "TitlePane.iconSize", windowStyle );
|
||||||
|
titleMinimumWidth = FlatUIUtils.getSubUIInt( "TitlePane.titleMinimumWidth", windowStyle, 60 );
|
||||||
|
buttonMinimumWidth = FlatUIUtils.getSubUIInt( "TitlePane.buttonMinimumWidth", windowStyle, 30 );
|
||||||
|
buttonMaximizedHeight = FlatUIUtils.getSubUIInt( "TitlePane.buttonMaximizedHeight", windowStyle, 0 );
|
||||||
|
centerTitle = FlatUIUtils.getSubUIBoolean( "TitlePane.centerTitle", windowStyle, false );
|
||||||
|
centerTitleIfMenuBarEmbedded = FlatUIUtils.getSubUIBoolean( "TitlePane.centerTitleIfMenuBarEmbedded", windowStyle, true );
|
||||||
|
showIconBesideTitle = FlatUIUtils.getSubUIBoolean( "TitlePane.showIconBesideTitle", windowStyle, false );
|
||||||
|
menuBarTitleGap = FlatUIUtils.getSubUIInt( "TitlePane.menuBarTitleGap", windowStyle, 40 );
|
||||||
|
menuBarTitleMinimumGap = FlatUIUtils.getSubUIInt( "TitlePane.menuBarTitleMinimumGap", windowStyle, 12 );
|
||||||
|
menuBarResizeHeight = FlatUIUtils.getSubUIInt( "TitlePane.menuBarResizeHeight", windowStyle, 4 );
|
||||||
|
|
||||||
|
|
||||||
handler = createHandler();
|
handler = createHandler();
|
||||||
setBorder( createTitlePaneBorder() );
|
setBorder( createTitlePaneBorder() );
|
||||||
|
|
||||||
@@ -182,8 +213,8 @@ public class FlatTitlePane
|
|||||||
setUI( new FlatTitleLabelUI() );
|
setUI( new FlatTitleLabelUI() );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
iconLabel.setBorder( new FlatEmptyBorder( UIManager.getInsets( "TitlePane.iconMargins" ) ) );
|
iconLabel.setBorder( new FlatEmptyBorder( FlatUIUtils.getSubUIInsets( "TitlePane.iconMargins", windowStyle ) ) );
|
||||||
titleLabel.setBorder( new FlatEmptyBorder( UIManager.getInsets( "TitlePane.titleMargins" ) ) );
|
titleLabel.setBorder( new FlatEmptyBorder( FlatUIUtils.getSubUIInsets( "TitlePane.titleMargins", windowStyle ) ) );
|
||||||
|
|
||||||
leftPanel.setLayout( new BoxLayout( leftPanel, BoxLayout.LINE_AXIS ) );
|
leftPanel.setLayout( new BoxLayout( leftPanel, BoxLayout.LINE_AXIS ) );
|
||||||
leftPanel.setOpaque( false );
|
leftPanel.setOpaque( false );
|
||||||
@@ -310,7 +341,7 @@ public class FlatTitlePane
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected JButton createButton( String iconKey, String accessibleName, ActionListener action ) {
|
protected JButton createButton( String iconKey, String accessibleName, ActionListener action ) {
|
||||||
JButton button = new JButton( UIManager.getIcon( iconKey ) ) {
|
JButton button = new JButton( FlatUIUtils.getSubUIIcon( iconKey, windowStyle ) ) {
|
||||||
@Override
|
@Override
|
||||||
public Dimension getMinimumSize() {
|
public Dimension getMinimumSize() {
|
||||||
// allow the button to shrink if space is rare
|
// allow the button to shrink if space is rare
|
||||||
@@ -360,9 +391,8 @@ public class FlatTitlePane
|
|||||||
|
|
||||||
if( window instanceof Frame ) {
|
if( window instanceof Frame ) {
|
||||||
Frame frame = (Frame) window;
|
Frame frame = (Frame) window;
|
||||||
boolean maximized = ((frame.getExtendedState() & Frame.MAXIMIZED_BOTH) != 0);
|
|
||||||
|
|
||||||
if( maximized &&
|
if( isWindowMaximized() &&
|
||||||
!(SystemInfo.isLinux && FlatNativeLinuxLibrary.isWMUtilsSupported( window )) &&
|
!(SystemInfo.isLinux && FlatNativeLinuxLibrary.isWMUtilsSupported( window )) &&
|
||||||
rootPane.getClientProperty( "_flatlaf.maximizedBoundsUpToDate" ) == null )
|
rootPane.getClientProperty( "_flatlaf.maximizedBoundsUpToDate" ) == null )
|
||||||
{
|
{
|
||||||
@@ -393,7 +423,7 @@ public class FlatTitlePane
|
|||||||
if( window instanceof Frame ) {
|
if( window instanceof Frame ) {
|
||||||
Frame frame = (Frame) window;
|
Frame frame = (Frame) window;
|
||||||
boolean maximizable = frame.isResizable() && clientPropertyBoolean( rootPane, TITLE_BAR_SHOW_MAXIMIZE, true );
|
boolean maximizable = frame.isResizable() && clientPropertyBoolean( rootPane, TITLE_BAR_SHOW_MAXIMIZE, true );
|
||||||
boolean maximized = ((frame.getExtendedState() & Frame.MAXIMIZED_BOTH) != 0);
|
boolean maximized = isWindowMaximized();
|
||||||
|
|
||||||
iconifyButton.setVisible( clientPropertyBoolean( rootPane, TITLE_BAR_SHOW_ICONIFFY, true ) );
|
iconifyButton.setVisible( clientPropertyBoolean( rootPane, TITLE_BAR_SHOW_ICONIFFY, true ) );
|
||||||
maximizeButton.setVisible( maximizable && !maximized );
|
maximizeButton.setVisible( maximizable && !maximized );
|
||||||
@@ -578,6 +608,10 @@ public class FlatTitlePane
|
|||||||
doLayout();
|
doLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void menuBarInvalidate() {
|
||||||
|
menuBarPlaceholder.invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paint( Graphics g ) {
|
public void paint( Graphics g ) {
|
||||||
super.paint( g );
|
super.paint( g );
|
||||||
@@ -643,7 +677,10 @@ public class FlatTitlePane
|
|||||||
|
|
||||||
/** @since 2.4 */
|
/** @since 2.4 */
|
||||||
protected boolean isWindowMaximized() {
|
protected boolean isWindowMaximized() {
|
||||||
return window instanceof Frame && (((Frame)window).getExtendedState() & Frame.MAXIMIZED_BOTH) != 0;
|
// Windows and macOS use always MAXIMIZED_BOTH.
|
||||||
|
// Only Linux uses MAXIMIZED_VERT and MAXIMIZED_HORIZ (when dragging window to left or right edge).
|
||||||
|
// (searched jdk source code)
|
||||||
|
return window instanceof Frame && (((Frame)window).getExtendedState() & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_BOTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -661,8 +698,30 @@ public class FlatTitlePane
|
|||||||
rootPane.putClientProperty( "_flatlaf.maximizedBoundsUpToDate", true );
|
rootPane.putClientProperty( "_flatlaf.maximizedBoundsUpToDate", true );
|
||||||
|
|
||||||
// maximize window
|
// maximize window
|
||||||
if( !FlatNativeWindowBorder.showWindow( frame, FlatNativeWindowBorder.Provider.SW_MAXIMIZE ) )
|
if( !FlatNativeWindowBorder.showWindow( frame, FlatNativeWindowBorder.Provider.SW_MAXIMIZE ) ) {
|
||||||
frame.setExtendedState( frame.getExtendedState() | Frame.MAXIMIZED_BOTH );
|
int oldState = frame.getExtendedState();
|
||||||
|
int newState = oldState | Frame.MAXIMIZED_BOTH;
|
||||||
|
|
||||||
|
if( SystemInfo.isLinux ) {
|
||||||
|
// Linux supports vertical and horizontal maximization:
|
||||||
|
// - dragging a window to left or right edge of screen vertically maximizes
|
||||||
|
// the window to the left or right half of the screen
|
||||||
|
// - don't know whether user can do horizontal maximization
|
||||||
|
// (Windows and macOS use only MAXIMIZED_BOTH)
|
||||||
|
//
|
||||||
|
// If a window is maximized vertically or horizontally (but not both),
|
||||||
|
// then Frame.setExtendedState() behaves not as expected on Linux.
|
||||||
|
// E.g. if window state is MAXIMIZED_VERT, calling setExtendedState(MAXIMIZED_BOTH)
|
||||||
|
// changes state to MAXIMIZED_HORIZ. But calling setExtendedState(MAXIMIZED_HORIZ)
|
||||||
|
// changes state from MAXIMIZED_VERT to MAXIMIZED_BOTH.
|
||||||
|
// Seems to be a bug in sun.awt.X11.XNETProtocol.requestState(),
|
||||||
|
// which does some strange state XOR-ing...
|
||||||
|
if( (oldState & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_VERT )
|
||||||
|
newState = (oldState & ~Frame.MAXIMIZED_BOTH) | Frame.MAXIMIZED_HORIZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame.setExtendedState( newState );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void updateMaximizedBounds() {
|
protected void updateMaximizedBounds() {
|
||||||
@@ -766,8 +825,7 @@ public class FlatTitlePane
|
|||||||
if( !(window instanceof Frame) || !((Frame)window).isResizable() )
|
if( !(window instanceof Frame) || !((Frame)window).isResizable() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Frame frame = (Frame) window;
|
if( isWindowMaximized() )
|
||||||
if( (frame.getExtendedState() & Frame.MAXIMIZED_BOTH) != 0 )
|
|
||||||
restore();
|
restore();
|
||||||
else
|
else
|
||||||
maximize();
|
maximize();
|
||||||
@@ -781,10 +839,6 @@ public class FlatTitlePane
|
|||||||
window.dispatchEvent( new WindowEvent( window, WindowEvent.WINDOW_CLOSING ) );
|
window.dispatchEvent( new WindowEvent( window, WindowEvent.WINDOW_CLOSING ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasJBRCustomDecoration() {
|
|
||||||
return window != null && JBRCustomDecorations.hasCustomDecoration( window );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether windows uses native window border and has custom decorations enabled.
|
* Returns whether windows uses native window border and has custom decorations enabled.
|
||||||
*/
|
*/
|
||||||
@@ -842,10 +896,7 @@ public class FlatTitlePane
|
|||||||
iconBounds.width += iconInsets.right;
|
iconBounds.width += iconInsets.right;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( hasJBRCustomDecoration() )
|
appIconBounds = iconBounds;
|
||||||
hitTestSpots.add( iconBounds );
|
|
||||||
else
|
|
||||||
appIconBounds = iconBounds;
|
|
||||||
} else if( showIconBesideTitle && titleLabel.getIcon() != null && titleLabel.getUI() instanceof FlatTitleLabelUI ) {
|
} else if( showIconBesideTitle && titleLabel.getIcon() != null && titleLabel.getUI() instanceof FlatTitleLabelUI ) {
|
||||||
FlatTitleLabelUI ui = (FlatTitleLabelUI) titleLabel.getUI();
|
FlatTitleLabelUI ui = (FlatTitleLabelUI) titleLabel.getUI();
|
||||||
|
|
||||||
@@ -873,10 +924,7 @@ public class FlatTitlePane
|
|||||||
iconR.width += 2;
|
iconR.width += 2;
|
||||||
iconR.height += 2;
|
iconR.height += 2;
|
||||||
|
|
||||||
if( hasJBRCustomDecoration() )
|
appIconBounds = iconR;
|
||||||
hitTestSpots.add( iconR );
|
|
||||||
else
|
|
||||||
appIconBounds = iconR;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -929,6 +977,13 @@ public class FlatTitlePane
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// allow internal frames in layered pane to be moved/resized when placed over title bar
|
||||||
|
for( Component c : rootPane.getLayeredPane().getComponents() ) {
|
||||||
|
r = (c instanceof JInternalFrame) ? getNativeHitTestSpot( (JInternalFrame) c ) : null;
|
||||||
|
if( r != null )
|
||||||
|
hitTestSpots.add( r );
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle minimizeButtonBounds = boundsInWindow( iconifyButton );
|
Rectangle minimizeButtonBounds = boundsInWindow( iconifyButton );
|
||||||
Rectangle maximizeButtonBounds = boundsInWindow( maximizeButton.isVisible() ? maximizeButton : restoreButton );
|
Rectangle maximizeButtonBounds = boundsInWindow( maximizeButton.isVisible() ? maximizeButton : restoreButton );
|
||||||
Rectangle closeButtonBounds = boundsInWindow( closeButton );
|
Rectangle closeButtonBounds = boundsInWindow( closeButton );
|
||||||
@@ -1188,6 +1243,13 @@ public class FlatTitlePane
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void windowStateChanged( WindowEvent e ) {
|
public void windowStateChanged( WindowEvent e ) {
|
||||||
|
/*debug
|
||||||
|
System.out.println( "state " + e.getOldState() + " -> " + e.getNewState() + " "
|
||||||
|
+ ((e.getNewState() & Frame.MAXIMIZED_HORIZ) != 0 ? " HORIZ" : "")
|
||||||
|
+ ((e.getNewState() & Frame.MAXIMIZED_VERT) != 0 ? " VERT" : "")
|
||||||
|
);
|
||||||
|
debug*/
|
||||||
|
|
||||||
frameStateChanged();
|
frameStateChanged();
|
||||||
updateNativeTitleBarHeightAndHitTestSpots();
|
updateNativeTitleBarHeightAndHitTestSpots();
|
||||||
}
|
}
|
||||||
@@ -1195,15 +1257,15 @@ public class FlatTitlePane
|
|||||||
//---- interface MouseListener ----
|
//---- interface MouseListener ----
|
||||||
|
|
||||||
private Point dragOffset;
|
private Point dragOffset;
|
||||||
private boolean nativeMove;
|
private boolean linuxNativeMove;
|
||||||
private long lastSingleClickWhen;
|
private long lastSingleClickWhen;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mouseClicked( MouseEvent e ) {
|
public void mouseClicked( MouseEvent e ) {
|
||||||
// on Linux, when using native library, the mouse clicked event
|
// on Linux, when using native library, the mouse clicked event
|
||||||
// is usually not sent and maximize/restore is done in mouse pressed event
|
// is usually not sent and maximize/restore is done in mouse pressed event
|
||||||
// this check is here for the case that a mouse clicked event comes thru for some reason
|
// this check is here for the case that a mouse clicked event comes through for some reason
|
||||||
if( SystemInfo.isLinux && FlatNativeLinuxLibrary.isWMUtilsSupported( window ) ) {
|
if( linuxNativeMove && SystemInfo.isLinux && FlatNativeLinuxLibrary.isWMUtilsSupported( window ) ) {
|
||||||
// see comment in mousePressed()
|
// see comment in mousePressed()
|
||||||
if( lastSingleClickWhen != 0 && (e.getWhen() - lastSingleClickWhen) <= getMultiClickInterval() ) {
|
if( lastSingleClickWhen != 0 && (e.getWhen() - lastSingleClickWhen) <= getMultiClickInterval() ) {
|
||||||
lastSingleClickWhen = 0;
|
lastSingleClickWhen = 0;
|
||||||
@@ -1241,7 +1303,7 @@ public class FlatTitlePane
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
dragOffset = SwingUtilities.convertPoint( FlatTitlePane.this, e.getPoint(), window );
|
dragOffset = SwingUtilities.convertPoint( FlatTitlePane.this, e.getPoint(), window );
|
||||||
nativeMove = false;
|
linuxNativeMove = false;
|
||||||
|
|
||||||
// on Linux, move or maximize/restore window
|
// on Linux, move or maximize/restore window
|
||||||
if( SystemInfo.isLinux && FlatNativeLinuxLibrary.isWMUtilsSupported( window ) ) {
|
if( SystemInfo.isLinux && FlatNativeLinuxLibrary.isWMUtilsSupported( window ) ) {
|
||||||
@@ -1261,7 +1323,7 @@ public class FlatTitlePane
|
|||||||
case 1:
|
case 1:
|
||||||
// move window via _NET_WM_MOVERESIZE message
|
// move window via _NET_WM_MOVERESIZE message
|
||||||
e.consume();
|
e.consume();
|
||||||
nativeMove = FlatNativeLinuxLibrary.moveOrResizeWindow( window, e, FlatNativeLinuxLibrary.MOVE );
|
linuxNativeMove = FlatNativeLinuxLibrary.moveOrResizeWindow( window, e, FlatNativeLinuxLibrary.MOVE );
|
||||||
lastSingleClickWhen = e.getWhen();
|
lastSingleClickWhen = e.getWhen();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -1291,7 +1353,7 @@ public class FlatTitlePane
|
|||||||
if( window == null || dragOffset == null )
|
if( window == null || dragOffset == null )
|
||||||
return; // should newer occur
|
return; // should newer occur
|
||||||
|
|
||||||
if( nativeMove )
|
if( linuxNativeMove )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if( !SwingUtilities.isLeftMouseButton( e ) )
|
if( !SwingUtilities.isLeftMouseButton( e ) )
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package com.formdev.flatlaf.ui;
|
|||||||
|
|
||||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
import java.awt.Container;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
@@ -173,6 +174,12 @@ public class FlatToolBarSeparatorUI
|
|||||||
if( size != null )
|
if( size != null )
|
||||||
return scale( size );
|
return scale( size );
|
||||||
|
|
||||||
|
// get separator width
|
||||||
|
int separatorWidth = this.separatorWidth;
|
||||||
|
FlatToolBarUI toolBarUI = getToolBarUI( c );
|
||||||
|
if( toolBarUI != null && toolBarUI.separatorWidth != null )
|
||||||
|
separatorWidth = toolBarUI.separatorWidth;
|
||||||
|
|
||||||
// make sure that gap on left and right side of line have same size
|
// make sure that gap on left and right side of line have same size
|
||||||
int sepWidth = (scale( (separatorWidth - LINE_WIDTH) / 2 ) * 2) + scale( LINE_WIDTH );
|
int sepWidth = (scale( (separatorWidth - LINE_WIDTH) / 2 ) * 2) + scale( LINE_WIDTH );
|
||||||
|
|
||||||
@@ -196,6 +203,12 @@ public class FlatToolBarSeparatorUI
|
|||||||
float lineWidth = scale( 1f );
|
float lineWidth = scale( 1f );
|
||||||
float offset = scale( 2f );
|
float offset = scale( 2f );
|
||||||
|
|
||||||
|
// get separator color
|
||||||
|
Color separatorColor = this.separatorColor;
|
||||||
|
FlatToolBarUI toolBarUI = getToolBarUI( c );
|
||||||
|
if( toolBarUI != null && toolBarUI.separatorColor != null )
|
||||||
|
separatorColor = toolBarUI.separatorColor;
|
||||||
|
|
||||||
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g );
|
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g );
|
||||||
g.setColor( separatorColor );
|
g.setColor( separatorColor );
|
||||||
|
|
||||||
@@ -210,4 +223,11 @@ public class FlatToolBarSeparatorUI
|
|||||||
private boolean isVertical( JComponent c ) {
|
private boolean isVertical( JComponent c ) {
|
||||||
return ((JToolBar.Separator)c).getOrientation() == SwingConstants.VERTICAL;
|
return ((JToolBar.Separator)c).getOrientation() == SwingConstants.VERTICAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private FlatToolBarUI getToolBarUI( JComponent c ) {
|
||||||
|
Container parent = c.getParent();
|
||||||
|
return (parent instanceof JToolBar && ((JToolBar)parent).getUI() instanceof FlatToolBarUI)
|
||||||
|
? (FlatToolBarUI) ((JToolBar)parent).getUI()
|
||||||
|
: null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,10 +39,12 @@ import javax.swing.JComboBox;
|
|||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JToolBar;
|
import javax.swing.JToolBar;
|
||||||
import javax.swing.LayoutFocusTraversalPolicy;
|
import javax.swing.LayoutFocusTraversalPolicy;
|
||||||
|
import javax.swing.RootPaneContainer;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.border.Border;
|
import javax.swing.border.Border;
|
||||||
import javax.swing.plaf.ComponentUI;
|
import javax.swing.plaf.ComponentUI;
|
||||||
import javax.swing.plaf.basic.BasicToolBarUI;
|
import javax.swing.plaf.basic.BasicToolBarUI;
|
||||||
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||||
import com.formdev.flatlaf.util.LoggingFacade;
|
import com.formdev.flatlaf.util.LoggingFacade;
|
||||||
@@ -91,6 +93,10 @@ public class FlatToolBarUI
|
|||||||
@Styleable protected Insets borderMargins;
|
@Styleable protected Insets borderMargins;
|
||||||
@Styleable protected Color gripColor;
|
@Styleable protected Color gripColor;
|
||||||
|
|
||||||
|
// for FlatToolBarSeparatorUI
|
||||||
|
/** @since 3.3 */ @Styleable protected Integer separatorWidth;
|
||||||
|
/** @since 3.3 */ @Styleable protected Color separatorColor;
|
||||||
|
|
||||||
private FocusTraversalPolicy focusTraversalPolicy;
|
private FocusTraversalPolicy focusTraversalPolicy;
|
||||||
private Boolean oldFloatable;
|
private Boolean oldFloatable;
|
||||||
private Map<String, Object> oldStyleValues;
|
private Map<String, Object> oldStyleValues;
|
||||||
@@ -156,6 +162,13 @@ public class FlatToolBarUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected RootPaneContainer createFloatingWindow( JToolBar toolbar ) {
|
||||||
|
RootPaneContainer floatingWindow = super.createFloatingWindow( toolbar );
|
||||||
|
floatingWindow.getRootPane().putClientProperty( FlatClientProperties.WINDOW_STYLE, FlatClientProperties.WINDOW_STYLE_SMALL );
|
||||||
|
return floatingWindow;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ContainerListener createToolBarContListener() {
|
protected ContainerListener createToolBarContListener() {
|
||||||
return new ToolBarContListener() {
|
return new ToolBarContListener() {
|
||||||
|
|||||||
@@ -158,6 +158,10 @@ public class FlatTreeUI
|
|||||||
// only used via styling (not in UI defaults, but has likewise client properties)
|
// only used via styling (not in UI defaults, but has likewise client properties)
|
||||||
/** @since 2 */ @Styleable protected boolean paintSelection = true;
|
/** @since 2 */ @Styleable protected boolean paintSelection = true;
|
||||||
|
|
||||||
|
private Icon defaultLeafIcon;
|
||||||
|
private Icon defaultClosedIcon;
|
||||||
|
private Icon defaultOpenIcon;
|
||||||
|
|
||||||
private boolean paintLines;
|
private boolean paintLines;
|
||||||
private Color defaultCellNonSelectionBackground;
|
private Color defaultCellNonSelectionBackground;
|
||||||
private Color defaultSelectionBackground;
|
private Color defaultSelectionBackground;
|
||||||
@@ -193,6 +197,10 @@ public class FlatTreeUI
|
|||||||
showCellFocusIndicator = UIManager.getBoolean( "Tree.showCellFocusIndicator" );
|
showCellFocusIndicator = UIManager.getBoolean( "Tree.showCellFocusIndicator" );
|
||||||
showDefaultIcons = UIManager.getBoolean( "Tree.showDefaultIcons" );
|
showDefaultIcons = UIManager.getBoolean( "Tree.showDefaultIcons" );
|
||||||
|
|
||||||
|
defaultLeafIcon = UIManager.getIcon( "Tree.leafIcon" );
|
||||||
|
defaultClosedIcon = UIManager.getIcon( "Tree.closedIcon" );
|
||||||
|
defaultOpenIcon = UIManager.getIcon( "Tree.openIcon" );
|
||||||
|
|
||||||
paintLines = UIManager.getBoolean( "Tree.paintLines" );
|
paintLines = UIManager.getBoolean( "Tree.paintLines" );
|
||||||
defaultCellNonSelectionBackground = UIManager.getColor( "Tree.textBackground" );
|
defaultCellNonSelectionBackground = UIManager.getColor( "Tree.textBackground" );
|
||||||
defaultSelectionBackground = selectionBackground;
|
defaultSelectionBackground = selectionBackground;
|
||||||
@@ -219,6 +227,10 @@ public class FlatTreeUI
|
|||||||
selectionInactiveForeground = null;
|
selectionInactiveForeground = null;
|
||||||
selectionBorderColor = null;
|
selectionBorderColor = null;
|
||||||
|
|
||||||
|
defaultLeafIcon = null;
|
||||||
|
defaultClosedIcon = null;
|
||||||
|
defaultOpenIcon = null;
|
||||||
|
|
||||||
defaultCellNonSelectionBackground = null;
|
defaultCellNonSelectionBackground = null;
|
||||||
defaultSelectionBackground = null;
|
defaultSelectionBackground = null;
|
||||||
defaultSelectionForeground = null;
|
defaultSelectionForeground = null;
|
||||||
@@ -233,9 +245,14 @@ public class FlatTreeUI
|
|||||||
// remove default leaf/closed/opened icons
|
// remove default leaf/closed/opened icons
|
||||||
if( !showDefaultIcons && currentCellRenderer instanceof DefaultTreeCellRenderer ) {
|
if( !showDefaultIcons && currentCellRenderer instanceof DefaultTreeCellRenderer ) {
|
||||||
DefaultTreeCellRenderer renderer = (DefaultTreeCellRenderer) currentCellRenderer;
|
DefaultTreeCellRenderer renderer = (DefaultTreeCellRenderer) currentCellRenderer;
|
||||||
renderer.setLeafIcon( null );
|
if( renderer.getLeafIcon() == defaultLeafIcon &&
|
||||||
renderer.setClosedIcon( null );
|
renderer.getClosedIcon() == defaultClosedIcon &&
|
||||||
renderer.setOpenIcon( null );
|
renderer.getOpenIcon() == defaultOpenIcon )
|
||||||
|
{
|
||||||
|
renderer.setLeafIcon( null );
|
||||||
|
renderer.setClosedIcon( null );
|
||||||
|
renderer.setOpenIcon( null );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,6 +327,21 @@ public class FlatTreeUI
|
|||||||
tree.revalidate();
|
tree.revalidate();
|
||||||
tree.repaint();
|
tree.repaint();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "enabled":
|
||||||
|
// if default icons are not shown and the renderer is a subclass
|
||||||
|
// of DefaultTreeCellRenderer, then invalidate tree node sizes
|
||||||
|
// because the custom renderer may use an icon for enabled state
|
||||||
|
// but none for disabled state
|
||||||
|
if( !showDefaultIcons &&
|
||||||
|
currentCellRenderer instanceof DefaultTreeCellRenderer &&
|
||||||
|
currentCellRenderer.getClass() != DefaultTreeCellRenderer.class &&
|
||||||
|
treeState != null )
|
||||||
|
{
|
||||||
|
treeState.invalidateSizes();
|
||||||
|
updateSize();
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -388,6 +420,9 @@ public class FlatTreeUI
|
|||||||
|
|
||||||
/** @since 2 */
|
/** @since 2 */
|
||||||
protected Object applyStyleProperty( String key, Object value ) {
|
protected Object applyStyleProperty( String key, Object value ) {
|
||||||
|
if( "rowHeight".equals( key ) && value instanceof Integer )
|
||||||
|
value = UIScale.scale( (Integer) value );
|
||||||
|
|
||||||
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, tree, key, value );
|
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, tree, key, value );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -543,7 +578,7 @@ public class FlatTreeUI
|
|||||||
if( isSelected && isWideSelection() ) {
|
if( isSelected && isWideSelection() ) {
|
||||||
Color oldColor = g.getColor();
|
Color oldColor = g.getColor();
|
||||||
g.setColor( selectionInactiveBackground );
|
g.setColor( selectionInactiveBackground );
|
||||||
paintWideSelection( g, clipBounds, insets, bounds, path, row, isExpanded, hasBeenExpanded, isLeaf );
|
paintWideSelection( g, bounds, row );
|
||||||
g.setColor( oldColor );
|
g.setColor( oldColor );
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -601,7 +636,7 @@ public class FlatTreeUI
|
|||||||
|
|
||||||
if( isWideSelection() ) {
|
if( isWideSelection() ) {
|
||||||
// wide selection
|
// wide selection
|
||||||
paintWideSelection( g, clipBounds, insets, bounds, path, row, isExpanded, hasBeenExpanded, isLeaf );
|
paintWideSelection( g, bounds, row );
|
||||||
} else {
|
} else {
|
||||||
// non-wide selection
|
// non-wide selection
|
||||||
paintCellBackground( g, rendererComponent, bounds, row, true );
|
paintCellBackground( g, rendererComponent, bounds, row, true );
|
||||||
@@ -670,9 +705,7 @@ public class FlatTreeUI
|
|||||||
return oldColor;
|
return oldColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void paintWideSelection( Graphics g, Rectangle clipBounds, Insets insets, Rectangle bounds,
|
private void paintWideSelection( Graphics g, Rectangle bounds, int row ) {
|
||||||
TreePath path, int row, boolean isExpanded, boolean hasBeenExpanded, boolean isLeaf )
|
|
||||||
{
|
|
||||||
float arcTop, arcBottom;
|
float arcTop, arcBottom;
|
||||||
arcTop = arcBottom = UIScale.scale( selectionArc / 2f );
|
arcTop = arcBottom = UIScale.scale( selectionArc / 2f );
|
||||||
|
|
||||||
@@ -695,7 +728,7 @@ public class FlatTreeUI
|
|||||||
|
|
||||||
if( rendererComponent instanceof JLabel ) {
|
if( rendererComponent instanceof JLabel ) {
|
||||||
JLabel label = (JLabel) rendererComponent;
|
JLabel label = (JLabel) rendererComponent;
|
||||||
Icon icon = label.getIcon();
|
Icon icon = label.isEnabled() ? label.getIcon() : label.getDisabledIcon();
|
||||||
imageOffset = (icon != null && label.getText() != null)
|
imageOffset = (icon != null && label.getText() != null)
|
||||||
? icon.getIconWidth() + Math.max( label.getIconTextGap() - 1, 0 )
|
? icon.getIconWidth() + Math.max( label.getIconTextGap() - 1, 0 )
|
||||||
: 0;
|
: 0;
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ import java.util.IdentityHashMap;
|
|||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
import javax.swing.Icon;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JScrollPane;
|
import javax.swing.JScrollPane;
|
||||||
import javax.swing.JTable;
|
import javax.swing.JTable;
|
||||||
@@ -166,6 +167,88 @@ public class FlatUIUtils
|
|||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @since 3.2 */
|
||||||
|
public static Color getSubUIColor( String key, String subKey ) {
|
||||||
|
if( subKey != null ) {
|
||||||
|
Color value = UIManager.getColor( buildSubKey( key, subKey ) );
|
||||||
|
if( value != null )
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
return UIManager.getColor( key );
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @since 3.2 */
|
||||||
|
public static boolean getSubUIBoolean( String key, String subKey, boolean defaultValue ) {
|
||||||
|
if( subKey != null ) {
|
||||||
|
Object value = UIManager.get( buildSubKey( key, subKey ) );
|
||||||
|
if( value instanceof Boolean )
|
||||||
|
return (Boolean) value;
|
||||||
|
}
|
||||||
|
return getUIBoolean( key, defaultValue );
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @since 3.2 */
|
||||||
|
public static int getSubUIInt( String key, String subKey, int defaultValue ) {
|
||||||
|
if( subKey != null ) {
|
||||||
|
Object value = UIManager.get( buildSubKey( key, subKey ) );
|
||||||
|
if( value instanceof Integer )
|
||||||
|
return (Integer) value;
|
||||||
|
}
|
||||||
|
return getUIInt( key, defaultValue );
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @since 3.2 */
|
||||||
|
public static Insets getSubUIInsets( String key, String subKey ) {
|
||||||
|
if( subKey != null ) {
|
||||||
|
Insets value = UIManager.getInsets( buildSubKey( key, subKey ) );
|
||||||
|
if( value != null )
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
return UIManager.getInsets( key );
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @since 3.2 */
|
||||||
|
public static Dimension getSubUIDimension( String key, String subKey ) {
|
||||||
|
if( subKey != null ) {
|
||||||
|
Dimension value = UIManager.getDimension( buildSubKey( key, subKey ) );
|
||||||
|
if( value != null )
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
return UIManager.getDimension( key );
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @since 3.2 */
|
||||||
|
public static Icon getSubUIIcon( String key, String subKey ) {
|
||||||
|
if( subKey != null ) {
|
||||||
|
Icon value = UIManager.getIcon( buildSubKey( key, subKey ) );
|
||||||
|
if( value != null )
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
return UIManager.getIcon( key );
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @since 3.2 */
|
||||||
|
public static Font getSubUIFont( String key, String subKey ) {
|
||||||
|
if( subKey != null ) {
|
||||||
|
Font value = UIManager.getFont( buildSubKey( key, subKey ) );
|
||||||
|
if( value != null )
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
return UIManager.getFont( key );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts {@code subKey} at last dot in {@code key}.
|
||||||
|
* <p>
|
||||||
|
* E.g. {@code buildSubKey( "TitlePane.font", "small" )} returns {@code "TitlePane.small.font"}.
|
||||||
|
*/
|
||||||
|
private static String buildSubKey( String key, String subKey ) {
|
||||||
|
int dot = key.lastIndexOf( '.' );
|
||||||
|
return (dot >= 0)
|
||||||
|
? key.substring( 0, dot ) + '.' + subKey + '.' + key.substring( dot + 1 )
|
||||||
|
: key;
|
||||||
|
}
|
||||||
|
|
||||||
/** @since 1.1.2 */
|
/** @since 1.1.2 */
|
||||||
public static boolean getBoolean( JComponent c, String systemPropertyKey,
|
public static boolean getBoolean( JComponent c, String systemPropertyKey,
|
||||||
String clientPropertyKey, String uiKey, boolean defaultValue )
|
String clientPropertyKey, String uiKey, boolean defaultValue )
|
||||||
@@ -200,6 +283,10 @@ public class FlatUIUtils
|
|||||||
return (border instanceof UIResource) ? new NonUIResourceBorder( border ) : border;
|
return (border instanceof UIResource) ? new NonUIResourceBorder( border ) : border;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Border unwrapNonUIResourceBorder( Border border ) {
|
||||||
|
return (border instanceof NonUIResourceBorder) ? ((NonUIResourceBorder)border).delegate : border;
|
||||||
|
}
|
||||||
|
|
||||||
public static int minimumWidth( JComponent c, int minimumWidth ) {
|
public static int minimumWidth( JComponent c, int minimumWidth ) {
|
||||||
return FlatClientProperties.clientPropertyInt( c, FlatClientProperties.MINIMUM_WIDTH, minimumWidth );
|
return FlatClientProperties.clientPropertyInt( c, FlatClientProperties.MINIMUM_WIDTH, minimumWidth );
|
||||||
}
|
}
|
||||||
@@ -212,15 +299,10 @@ public class FlatUIUtils
|
|||||||
if( c == null )
|
if( c == null )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// check whether used in cell editor (check 3 levels up)
|
// check whether used as table cell editor
|
||||||
Component c2 = c;
|
Container parent = c.getParent();
|
||||||
for( int i = 0; i <= 2 && c2 != null; i++ ) {
|
if( parent instanceof JTable && ((JTable)parent).getEditorComponent() == c )
|
||||||
Container parent = c2.getParent();
|
return true;
|
||||||
if( parent instanceof JTable && ((JTable)parent).getEditorComponent() == c2 )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
c2 = parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check whether used as cell editor
|
// check whether used as cell editor
|
||||||
// Table.editor is set in JTable.GenericEditor constructor
|
// Table.editor is set in JTable.GenericEditor constructor
|
||||||
@@ -647,7 +729,7 @@ public class FlatUIUtils
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a (rounded) rectangle used to paint components (border, background, etc).
|
* Creates a (rounded) rectangle used to paint components (border, background, etc.).
|
||||||
* The given arc diameter is limited to min(width,height).
|
* The given arc diameter is limited to min(width,height).
|
||||||
*/
|
*/
|
||||||
public static Shape createComponentRectangle( float x, float y, float w, float h, float arc ) {
|
public static Shape createComponentRectangle( float x, float y, float w, float h, float arc ) {
|
||||||
@@ -721,7 +803,7 @@ public class FlatUIUtils
|
|||||||
{
|
{
|
||||||
dotSize = UIScale.scale( dotSize );
|
dotSize = UIScale.scale( dotSize );
|
||||||
gap = UIScale.scale( gap );
|
gap = UIScale.scale( gap );
|
||||||
int gripSize = (dotSize * dotCount) + ((gap * (dotCount - 1)));
|
int gripSize = (dotSize * dotCount) + (gap * (dotCount - 1));
|
||||||
|
|
||||||
// calculate grip position
|
// calculate grip position
|
||||||
float gx;
|
float gx;
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ package com.formdev.flatlaf.ui;
|
|||||||
|
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JViewport;
|
import javax.swing.JViewport;
|
||||||
import javax.swing.plaf.ComponentUI;
|
import javax.swing.plaf.ComponentUI;
|
||||||
@@ -48,14 +47,9 @@ public class FlatViewportUI
|
|||||||
|
|
||||||
Component view = ((JViewport)c).getView();
|
Component view = ((JViewport)c).getView();
|
||||||
if( view instanceof JComponent ) {
|
if( view instanceof JComponent ) {
|
||||||
try {
|
ComponentUI ui = JavaCompatibility2.getUI( (JComponent) view );
|
||||||
Method m = view.getClass().getMethod( "getUI" );
|
if( ui instanceof ViewportPainter )
|
||||||
Object ui = m.invoke( view );
|
((ViewportPainter)ui).paintViewport( g, (JComponent) view, (JViewport) c );
|
||||||
if( ui instanceof ViewportPainter )
|
|
||||||
((ViewportPainter)ui).paintViewport( g, (JComponent) view, (JViewport) c );
|
|
||||||
} catch( Exception ex ) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -606,9 +606,10 @@ debug*/
|
|||||||
if( resizeDir == S_RESIZE_CURSOR || resizeDir == SW_RESIZE_CURSOR || resizeDir == SE_RESIZE_CURSOR ) {
|
if( resizeDir == S_RESIZE_CURSOR || resizeDir == SW_RESIZE_CURSOR || resizeDir == SE_RESIZE_CURSOR ) {
|
||||||
newBounds.height = (yOnScreen + dragBottomOffset) - newBounds.y;
|
newBounds.height = (yOnScreen + dragBottomOffset) - newBounds.y;
|
||||||
if( limitToParentBounds() ) {
|
if( limitToParentBounds() ) {
|
||||||
int parentHeight = getParentBounds().height;
|
Rectangle parentBounds = getParentBounds();
|
||||||
if( newBounds.y + newBounds.height > parentHeight )
|
int parentBottomY = parentBounds.y + parentBounds.height;
|
||||||
newBounds.height = parentHeight - newBounds.y;
|
if( newBounds.y + newBounds.height > parentBottomY )
|
||||||
|
newBounds.height = parentBottomY - newBounds.y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -624,9 +625,10 @@ debug*/
|
|||||||
if( resizeDir == E_RESIZE_CURSOR || resizeDir == NE_RESIZE_CURSOR || resizeDir == SE_RESIZE_CURSOR ) {
|
if( resizeDir == E_RESIZE_CURSOR || resizeDir == NE_RESIZE_CURSOR || resizeDir == SE_RESIZE_CURSOR ) {
|
||||||
newBounds.width = (xOnScreen + dragRightOffset) - newBounds.x;
|
newBounds.width = (xOnScreen + dragRightOffset) - newBounds.x;
|
||||||
if( limitToParentBounds() ) {
|
if( limitToParentBounds() ) {
|
||||||
int parentWidth = getParentBounds().width;
|
Rectangle parentBounds = getParentBounds();
|
||||||
if( newBounds.x + newBounds.width > parentWidth )
|
int parentRightX = parentBounds.x + parentBounds.width;
|
||||||
newBounds.width = parentWidth - newBounds.x;
|
if( newBounds.x + newBounds.width > parentRightX )
|
||||||
|
newBounds.width = parentRightX - newBounds.x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -88,10 +88,6 @@ class FlatWindowsNativeWindowBorder
|
|||||||
if( !SystemInfo.isWindows_10_orLater )
|
if( !SystemInfo.isWindows_10_orLater )
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
// requires x86 architecture
|
|
||||||
if( !SystemInfo.isX86 && !SystemInfo.isX86_64 )
|
|
||||||
return null;
|
|
||||||
|
|
||||||
// check whether native library was successfully loaded
|
// check whether native library was successfully loaded
|
||||||
if( !FlatNativeLibrary.isLoaded() )
|
if( !FlatNativeLibrary.isLoaded() )
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -1,306 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.ui;
|
|
||||||
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Component;
|
|
||||||
import java.awt.Container;
|
|
||||||
import java.awt.EventQueue;
|
|
||||||
import java.awt.Graphics;
|
|
||||||
import java.awt.Graphics2D;
|
|
||||||
import java.awt.Rectangle;
|
|
||||||
import java.awt.Toolkit;
|
|
||||||
import java.awt.Window;
|
|
||||||
import java.awt.event.HierarchyEvent;
|
|
||||||
import java.awt.event.HierarchyListener;
|
|
||||||
import java.beans.PropertyChangeListener;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import javax.swing.JRootPane;
|
|
||||||
import javax.swing.SwingUtilities;
|
|
||||||
import javax.swing.UIManager;
|
|
||||||
import javax.swing.plaf.BorderUIResource;
|
|
||||||
import com.formdev.flatlaf.FlatLaf;
|
|
||||||
import com.formdev.flatlaf.util.LoggingFacade;
|
|
||||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
|
||||||
import com.formdev.flatlaf.util.SystemInfo;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Support for custom window decorations provided by JetBrains Runtime (based on OpenJDK).
|
|
||||||
* Requires that the application runs on Windows 10 in a JetBrains Runtime 11 or later.
|
|
||||||
* <ul>
|
|
||||||
* <li><a href="https://confluence.jetbrains.com/display/JBR/JetBrains+Runtime">https://confluence.jetbrains.com/display/JBR/JetBrains+Runtime</a></li>
|
|
||||||
* <li><a href="https://github.com/JetBrains/JetBrainsRuntime">https://github.com/JetBrains/JetBrainsRuntime</a></li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* @author Karl Tauber
|
|
||||||
*/
|
|
||||||
public class JBRCustomDecorations
|
|
||||||
{
|
|
||||||
private static Boolean supported;
|
|
||||||
private static Method Window_hasCustomDecoration;
|
|
||||||
private static Method Window_setHasCustomDecoration;
|
|
||||||
private static Method WWindowPeer_setCustomDecorationTitleBarHeight;
|
|
||||||
private static Method WWindowPeer_setCustomDecorationHitTestSpots;
|
|
||||||
private static Method AWTAccessor_getComponentAccessor;
|
|
||||||
private static Method AWTAccessor_ComponentAccessor_getPeer;
|
|
||||||
|
|
||||||
public static boolean isSupported() {
|
|
||||||
initialize();
|
|
||||||
return supported;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Object install( JRootPane rootPane ) {
|
|
||||||
if( !isSupported() )
|
|
||||||
return null;
|
|
||||||
|
|
||||||
// check whether root pane already has a parent, which is the case when switching LaF
|
|
||||||
Container parent = rootPane.getParent();
|
|
||||||
if( parent != null ) {
|
|
||||||
if( parent instanceof Window )
|
|
||||||
FlatNativeWindowBorder.install( (Window) parent );
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use hierarchy listener to wait until the root pane is added to a window.
|
|
||||||
// Enabling JBR decorations must be done very early, probably before
|
|
||||||
// window becomes displayable (window.isDisplayable()). Tried also using
|
|
||||||
// "ancestor" property change event on root pane, but this is invoked too late.
|
|
||||||
HierarchyListener addListener = new HierarchyListener() {
|
|
||||||
@Override
|
|
||||||
public void hierarchyChanged( HierarchyEvent e ) {
|
|
||||||
if( e.getChanged() != rootPane || (e.getChangeFlags() & HierarchyEvent.PARENT_CHANGED) == 0 )
|
|
||||||
return;
|
|
||||||
|
|
||||||
Container parent = e.getChangedParent();
|
|
||||||
if( parent instanceof Window )
|
|
||||||
FlatNativeWindowBorder.install( (Window) parent );
|
|
||||||
|
|
||||||
// remove listener since it is actually not possible to uninstall JBR decorations
|
|
||||||
// use invokeLater to remove listener to avoid that listener
|
|
||||||
// is removed while listener queue is processed
|
|
||||||
EventQueue.invokeLater( () -> {
|
|
||||||
rootPane.removeHierarchyListener( this );
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
rootPane.addHierarchyListener( addListener );
|
|
||||||
return addListener;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void uninstall( JRootPane rootPane, Object data ) {
|
|
||||||
// remove listener (if not yet done)
|
|
||||||
if( data instanceof HierarchyListener )
|
|
||||||
rootPane.removeHierarchyListener( (HierarchyListener) data );
|
|
||||||
|
|
||||||
// since it is actually not possible to uninstall JBR decorations,
|
|
||||||
// simply reduce titleBarHeight so that it is still possible to resize window
|
|
||||||
// and remove hitTestSpots
|
|
||||||
Container parent = rootPane.getParent();
|
|
||||||
if( parent instanceof Window )
|
|
||||||
setHasCustomDecoration( (Window) parent, false );
|
|
||||||
}
|
|
||||||
|
|
||||||
static boolean hasCustomDecoration( Window window ) {
|
|
||||||
if( !isSupported() )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
try {
|
|
||||||
return (Boolean) Window_hasCustomDecoration.invoke( window );
|
|
||||||
} catch( Exception ex ) {
|
|
||||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setHasCustomDecoration( Window window, boolean hasCustomDecoration ) {
|
|
||||||
if( !isSupported() )
|
|
||||||
return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
if( hasCustomDecoration )
|
|
||||||
Window_setHasCustomDecoration.invoke( window );
|
|
||||||
else
|
|
||||||
setTitleBarHeightAndHitTestSpots( window, 4, Collections.emptyList() );
|
|
||||||
} catch( Exception ex ) {
|
|
||||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setTitleBarHeightAndHitTestSpots( Window window, int titleBarHeight, List<Rectangle> hitTestSpots ) {
|
|
||||||
if( !isSupported() )
|
|
||||||
return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
Object compAccessor = AWTAccessor_getComponentAccessor.invoke( null );
|
|
||||||
Object peer = AWTAccessor_ComponentAccessor_getPeer.invoke( compAccessor, window );
|
|
||||||
WWindowPeer_setCustomDecorationTitleBarHeight.invoke( peer, titleBarHeight );
|
|
||||||
WWindowPeer_setCustomDecorationHitTestSpots.invoke( peer, hitTestSpots );
|
|
||||||
} catch( Exception ex ) {
|
|
||||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void initialize() {
|
|
||||||
if( supported != null )
|
|
||||||
return;
|
|
||||||
supported = false;
|
|
||||||
|
|
||||||
// requires JetBrains Runtime 11 and Windows 10
|
|
||||||
if( !SystemInfo.isJetBrainsJVM_11_orLater || !SystemInfo.isWindows_10_orLater )
|
|
||||||
return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
Class<?> awtAcessorClass = Class.forName( "sun.awt.AWTAccessor" );
|
|
||||||
Class<?> compAccessorClass = Class.forName( "sun.awt.AWTAccessor$ComponentAccessor" );
|
|
||||||
AWTAccessor_getComponentAccessor = awtAcessorClass.getDeclaredMethod( "getComponentAccessor" );
|
|
||||||
AWTAccessor_ComponentAccessor_getPeer = compAccessorClass.getDeclaredMethod( "getPeer", Component.class );
|
|
||||||
|
|
||||||
Class<?> peerClass = Class.forName( "sun.awt.windows.WWindowPeer" );
|
|
||||||
WWindowPeer_setCustomDecorationTitleBarHeight = peerClass.getDeclaredMethod( "setCustomDecorationTitleBarHeight", int.class );
|
|
||||||
WWindowPeer_setCustomDecorationHitTestSpots = peerClass.getDeclaredMethod( "setCustomDecorationHitTestSpots", List.class );
|
|
||||||
WWindowPeer_setCustomDecorationTitleBarHeight.setAccessible( true );
|
|
||||||
WWindowPeer_setCustomDecorationHitTestSpots.setAccessible( true );
|
|
||||||
|
|
||||||
Window_hasCustomDecoration = Window.class.getDeclaredMethod( "hasCustomDecoration" );
|
|
||||||
Window_setHasCustomDecoration = Window.class.getDeclaredMethod( "setHasCustomDecoration" );
|
|
||||||
Window_hasCustomDecoration.setAccessible( true );
|
|
||||||
Window_setHasCustomDecoration.setAccessible( true );
|
|
||||||
|
|
||||||
supported = true;
|
|
||||||
} catch( Exception ex ) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//---- class JBRWindowTopBorder -------------------------------------------
|
|
||||||
|
|
||||||
static class JBRWindowTopBorder
|
|
||||||
extends BorderUIResource.EmptyBorderUIResource
|
|
||||||
{
|
|
||||||
private static JBRWindowTopBorder instance;
|
|
||||||
|
|
||||||
private final Color activeLightColor = new Color( 0x707070 );
|
|
||||||
private final Color activeDarkColor = new Color( 0x2D2E2F );
|
|
||||||
private final Color inactiveLightColor = new Color( 0xaaaaaa );
|
|
||||||
private final Color inactiveDarkColor = new Color( 0x494A4B );
|
|
||||||
|
|
||||||
private boolean colorizationAffectsBorders;
|
|
||||||
private Color activeColor;
|
|
||||||
|
|
||||||
static JBRWindowTopBorder getInstance() {
|
|
||||||
if( instance == null )
|
|
||||||
instance = new JBRWindowTopBorder();
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
JBRWindowTopBorder() {
|
|
||||||
super( 1, 0, 0, 0 );
|
|
||||||
|
|
||||||
update();
|
|
||||||
installListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
void update() {
|
|
||||||
colorizationAffectsBorders = isColorizationColorAffectsBorders();
|
|
||||||
activeColor = calculateActiveBorderColor();
|
|
||||||
}
|
|
||||||
|
|
||||||
void installListeners() {
|
|
||||||
Toolkit toolkit = Toolkit.getDefaultToolkit();
|
|
||||||
toolkit.addPropertyChangeListener( "win.dwm.colorizationColor.affects.borders", e -> {
|
|
||||||
colorizationAffectsBorders = isColorizationColorAffectsBorders();
|
|
||||||
activeColor = calculateActiveBorderColor();
|
|
||||||
} );
|
|
||||||
|
|
||||||
PropertyChangeListener l = e -> {
|
|
||||||
activeColor = calculateActiveBorderColor();
|
|
||||||
};
|
|
||||||
toolkit.addPropertyChangeListener( "win.dwm.colorizationColor", l );
|
|
||||||
toolkit.addPropertyChangeListener( "win.dwm.colorizationColorBalance", l );
|
|
||||||
toolkit.addPropertyChangeListener( "win.frame.activeBorderColor", l );
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isColorizationColorAffectsBorders() {
|
|
||||||
Object value = Toolkit.getDefaultToolkit().getDesktopProperty( "win.dwm.colorizationColor.affects.borders" );
|
|
||||||
return (value instanceof Boolean) ? (Boolean) value : true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Color getColorizationColor() {
|
|
||||||
return (Color) Toolkit.getDefaultToolkit().getDesktopProperty( "win.dwm.colorizationColor" );
|
|
||||||
}
|
|
||||||
|
|
||||||
int getColorizationColorBalance() {
|
|
||||||
Object value = Toolkit.getDefaultToolkit().getDesktopProperty( "win.dwm.colorizationColorBalance" );
|
|
||||||
return (value instanceof Integer) ? (Integer) value : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Color calculateActiveBorderColor() {
|
|
||||||
if( !colorizationAffectsBorders )
|
|
||||||
return null;
|
|
||||||
|
|
||||||
Color colorizationColor = getColorizationColor();
|
|
||||||
if( colorizationColor != null ) {
|
|
||||||
int colorizationColorBalance = getColorizationColorBalance();
|
|
||||||
if( colorizationColorBalance < 0 || colorizationColorBalance > 100 )
|
|
||||||
colorizationColorBalance = 100;
|
|
||||||
|
|
||||||
if( colorizationColorBalance == 0 )
|
|
||||||
return new Color( 0xD9D9D9 );
|
|
||||||
if( colorizationColorBalance == 100 )
|
|
||||||
return colorizationColor;
|
|
||||||
|
|
||||||
float alpha = colorizationColorBalance / 100.0f;
|
|
||||||
float remainder = 1 - alpha;
|
|
||||||
int r = Math.round( colorizationColor.getRed() * alpha + 0xD9 * remainder );
|
|
||||||
int g = Math.round( colorizationColor.getGreen() * alpha + 0xD9 * remainder );
|
|
||||||
int b = Math.round( colorizationColor.getBlue() * alpha + 0xD9 * remainder );
|
|
||||||
|
|
||||||
// avoid potential IllegalArgumentException in Color constructor
|
|
||||||
r = Math.min( Math.max( r, 0 ), 255 );
|
|
||||||
g = Math.min( Math.max( g, 0 ), 255 );
|
|
||||||
b = Math.min( Math.max( b, 0 ), 255 );
|
|
||||||
|
|
||||||
return new Color( r, g, b );
|
|
||||||
}
|
|
||||||
|
|
||||||
Color activeBorderColor = (Color) Toolkit.getDefaultToolkit().getDesktopProperty( "win.frame.activeBorderColor" );
|
|
||||||
return (activeBorderColor != null) ? activeBorderColor : UIManager.getColor( "MenuBar.borderColor" );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
|
||||||
Window window = SwingUtilities.windowForComponent( c );
|
|
||||||
boolean active = window != null && window.isActive();
|
|
||||||
boolean dark = FlatLaf.isLafDark();
|
|
||||||
|
|
||||||
g.setColor( active
|
|
||||||
? (activeColor != null ? activeColor : (dark ? activeDarkColor : activeLightColor))
|
|
||||||
: (dark ? inactiveDarkColor : inactiveLightColor) );
|
|
||||||
HiDPIUtils.paintAtScale1x( (Graphics2D) g, x, y, width, height, this::paintImpl );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void paintImpl( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
|
|
||||||
g.fillRect( x, y, width, 1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
void repaintBorder( Component c ) {
|
|
||||||
c.repaint( 0, 0, c.getWidth(), 1 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2024 FormDev Software GmbH
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.formdev.flatlaf.ui;
|
||||||
|
|
||||||
|
import java.lang.invoke.MethodHandle;
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.lang.invoke.MethodType;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import javax.swing.JComponent;
|
||||||
|
import javax.swing.JList;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JTable;
|
||||||
|
import javax.swing.JTree;
|
||||||
|
import javax.swing.plaf.ComponentUI;
|
||||||
|
import javax.swing.text.JTextComponent;
|
||||||
|
import com.formdev.flatlaf.util.LoggingFacade;
|
||||||
|
import com.formdev.flatlaf.util.SystemInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides Java version compatibility methods.
|
||||||
|
* <p>
|
||||||
|
* WARNING: This is private API and may change.
|
||||||
|
*
|
||||||
|
* @author Karl Tauber
|
||||||
|
* @since 3.3
|
||||||
|
*/
|
||||||
|
public class JavaCompatibility2
|
||||||
|
{
|
||||||
|
private static boolean getUIMethodInitialized;
|
||||||
|
private static MethodHandle getUIMethod;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Java 8: getUI() method on various components (e.g. JButton, JList, etc)
|
||||||
|
* <br>
|
||||||
|
* Java 9: javax.swing.JComponent.getUI()
|
||||||
|
*/
|
||||||
|
public static ComponentUI getUI( JComponent c ) {
|
||||||
|
try {
|
||||||
|
// Java 9+
|
||||||
|
if( SystemInfo.isJava_9_orLater ) {
|
||||||
|
if( !getUIMethodInitialized ) {
|
||||||
|
getUIMethodInitialized = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
MethodType mt = MethodType.methodType( ComponentUI.class, new Class[0] );
|
||||||
|
getUIMethod = MethodHandles.publicLookup().findVirtual( JComponent.class, "getUI", mt );
|
||||||
|
} catch( Exception ex ) {
|
||||||
|
// ignore
|
||||||
|
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( getUIMethod != null )
|
||||||
|
return (ComponentUI) getUIMethod.invoke( c );
|
||||||
|
}
|
||||||
|
|
||||||
|
// components often used (e.g. as view in scroll panes)
|
||||||
|
if( c instanceof JPanel )
|
||||||
|
return ((JPanel)c).getUI();
|
||||||
|
if( c instanceof JList )
|
||||||
|
return ((JList<?>)c).getUI();
|
||||||
|
if( c instanceof JTable )
|
||||||
|
return ((JTable)c).getUI();
|
||||||
|
if( c instanceof JTree )
|
||||||
|
return ((JTree)c).getUI();
|
||||||
|
if( c instanceof JTextComponent )
|
||||||
|
return ((JTextComponent)c).getUI();
|
||||||
|
|
||||||
|
// Java 8 and fallback
|
||||||
|
Method m = c.getClass().getMethod( "getUI" );
|
||||||
|
return (ComponentUI) m.invoke( c );
|
||||||
|
} catch( Throwable ex ) {
|
||||||
|
// ignore
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -80,7 +80,7 @@ public class FontUtils
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a font family previously registered via {@link #registerFontFamilyLoader(String, Runnable)}.
|
* Loads a font family previously registered via {@link #registerFontFamilyLoader(String, Runnable)}.
|
||||||
* If the family is already loaded or no londer is registered for that family, nothing happens.
|
* If the family is already loaded or no loader is registered for that family, nothing happens.
|
||||||
*/
|
*/
|
||||||
public static void loadFontFamily( String family ) {
|
public static void loadFontFamily( String family ) {
|
||||||
if( !hasLoaders() )
|
if( !hasLoaders() )
|
||||||
@@ -109,7 +109,7 @@ public class FontUtils
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all font familiy names available in the graphics environment.
|
* Returns all font family names available in the graphics environment.
|
||||||
* This invokes {@link GraphicsEnvironment#getAvailableFontFamilyNames()} and
|
* This invokes {@link GraphicsEnvironment#getAvailableFontFamilyNames()} and
|
||||||
* appends families registered for lazy loading via {@link #registerFontFamilyLoader(String, Runnable)}
|
* appends families registered for lazy loading via {@link #registerFontFamilyLoader(String, Runnable)}
|
||||||
* to the result.
|
* to the result.
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import java.awt.Paint;
|
|||||||
import java.awt.Polygon;
|
import java.awt.Polygon;
|
||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
import java.awt.RenderingHints;
|
import java.awt.RenderingHints;
|
||||||
import java.awt.RenderingHints.Key;
|
|
||||||
import java.awt.Shape;
|
import java.awt.Shape;
|
||||||
import java.awt.Stroke;
|
import java.awt.Stroke;
|
||||||
import java.awt.font.FontRenderContext;
|
import java.awt.font.FontRenderContext;
|
||||||
@@ -368,12 +367,12 @@ public class Graphics2DProxy
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setRenderingHint( Key hintKey, Object hintValue ) {
|
public void setRenderingHint( RenderingHints.Key hintKey, Object hintValue ) {
|
||||||
delegate.setRenderingHint( hintKey, hintValue );
|
delegate.setRenderingHint( hintKey, hintValue );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getRenderingHint( Key hintKey ) {
|
public Object getRenderingHint( RenderingHints.Key hintKey ) {
|
||||||
return delegate.getRenderingHint( hintKey );
|
return delegate.getRenderingHint( hintKey );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,40 +52,47 @@ public class HiDPIUtils
|
|||||||
AffineTransform t = g.getTransform();
|
AffineTransform t = g.getTransform();
|
||||||
|
|
||||||
// get scale X/Y and shear X/Y
|
// get scale X/Y and shear X/Y
|
||||||
double scaleX = t.getScaleX();
|
final double scaleX = t.getScaleX();
|
||||||
double scaleY = t.getScaleY();
|
final double scaleY = t.getScaleY();
|
||||||
double shearX = t.getShearX();
|
final double shearX = t.getShearX();
|
||||||
double shearY = t.getShearY();
|
final double shearY = t.getShearY();
|
||||||
|
|
||||||
// check whether rotated
|
// check whether rotated
|
||||||
// (also check for negative scale X/Y because shear X/Y are zero for 180 degrees rotation)
|
// (also check for negative scale X/Y because shear X/Y are zero for 180 degrees rotation)
|
||||||
boolean rotated = (shearX != 0 || shearY != 0 || scaleX <= 0 || scaleY <= 0);
|
boolean rotated = (shearX != 0 || shearY != 0 || scaleX <= 0 || scaleY <= 0);
|
||||||
|
|
||||||
|
// calculate non rotated scale factors
|
||||||
|
final double realScaleX, realScaleY;
|
||||||
if( rotated ) {
|
if( rotated ) {
|
||||||
// resulting scale X/Y values are always positive
|
// resulting scale X/Y values are always positive
|
||||||
scaleX = Math.hypot( scaleX, shearX );
|
realScaleX = Math.hypot( scaleX, shearX );
|
||||||
scaleY = Math.hypot( scaleY, shearY );
|
realScaleY = Math.hypot( scaleY, shearY );
|
||||||
} else {
|
} else {
|
||||||
// make scale X/Y positive
|
// make scale X/Y positive
|
||||||
scaleX = Math.abs( scaleX );
|
realScaleX = Math.abs( scaleX );
|
||||||
scaleY = Math.abs( scaleY );
|
realScaleY = Math.abs( scaleY );
|
||||||
}
|
}
|
||||||
|
|
||||||
// check whether scaled
|
// check whether scaled
|
||||||
if( scaleX == 1 && scaleY == 1 ) {
|
if( realScaleX == 1 && realScaleY == 1 ) {
|
||||||
painter.paint( g, x, y, width, height, 1 );
|
painter.paint( g, x, y, width, height, 1 );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// calculate x and y (this is equal to t.translate( x, y ))
|
||||||
|
double px = (x * scaleX) + (y * shearX) + t.getTranslateX();
|
||||||
|
double py = (y * scaleY) + (x * shearY) + t.getTranslateY();
|
||||||
|
|
||||||
// scale rectangle
|
// scale rectangle
|
||||||
Rectangle2D.Double scaledRect = scale( scaleX, scaleY, t, x, y, width, height );
|
Rectangle2D.Double scaledRect = scale( realScaleX, realScaleY, px, py, width, height );
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// unscale to factor 1.0, keep rotation and move origin (to whole numbers)
|
// unscale to factor 1.0, keep rotation and move origin (to whole numbers)
|
||||||
AffineTransform t1x;
|
AffineTransform t1x;
|
||||||
if( rotated ) {
|
if( rotated ) {
|
||||||
t1x = new AffineTransform( t.getScaleX(), t.getShearY(), t.getShearX(), t.getScaleY(),
|
t1x = new AffineTransform( scaleX, shearY, shearX, scaleY,
|
||||||
Math.floor( scaledRect.x ), Math.floor( scaledRect.y ) );
|
Math.floor( scaledRect.x ), Math.floor( scaledRect.y ) );
|
||||||
t1x.scale( 1. / scaleX, 1. / scaleY );
|
t1x.scale( 1. / realScaleX, 1. / realScaleY );
|
||||||
} else
|
} else
|
||||||
t1x = new AffineTransform( 1, 0, 0, 1, Math.floor( scaledRect.x ), Math.floor( scaledRect.y ) );
|
t1x = new AffineTransform( 1, 0, 0, 1, Math.floor( scaledRect.x ), Math.floor( scaledRect.y ) );
|
||||||
g.setTransform( t1x );
|
g.setTransform( t1x );
|
||||||
@@ -94,7 +101,7 @@ public class HiDPIUtils
|
|||||||
int sheight = (int) scaledRect.height;
|
int sheight = (int) scaledRect.height;
|
||||||
|
|
||||||
// paint
|
// paint
|
||||||
painter.paint( g, 0, 0, swidth, sheight, scaleX );
|
painter.paint( g, 0, 0, swidth, sheight, realScaleX );
|
||||||
} finally {
|
} finally {
|
||||||
// restore original transform
|
// restore original transform
|
||||||
g.setTransform( t );
|
g.setTransform( t );
|
||||||
@@ -106,10 +113,7 @@ public class HiDPIUtils
|
|||||||
* sun.java2d.pipe.PixelToParallelogramConverter.fillRectangle(),
|
* sun.java2d.pipe.PixelToParallelogramConverter.fillRectangle(),
|
||||||
* which is used by Graphics.fillRect().
|
* which is used by Graphics.fillRect().
|
||||||
*/
|
*/
|
||||||
private static Rectangle2D.Double scale( double scaleX, double scaleY, AffineTransform t, int x, int y, int width, int height ) {
|
private static Rectangle2D.Double scale( double scaleX, double scaleY, double px, double py, int width, int height ) {
|
||||||
double px = (x * scaleX) + t.getTranslateX();
|
|
||||||
double py = (y * scaleY) + t.getTranslateY();
|
|
||||||
|
|
||||||
double newX = normalize( px );
|
double newX = normalize( px );
|
||||||
double newY = normalize( py );
|
double newY = normalize( py );
|
||||||
double newWidth = normalize( px + (width * scaleX) ) - newX;
|
double newWidth = normalize( px + (width * scaleX) ) - newX;
|
||||||
|
|||||||
@@ -116,7 +116,11 @@ public class NativeLibrary
|
|||||||
try {
|
try {
|
||||||
// for development environment
|
// for development environment
|
||||||
if( "file".equals( libraryUrl.getProtocol() ) ) {
|
if( "file".equals( libraryUrl.getProtocol() ) ) {
|
||||||
File libraryFile = new File( libraryUrl.getPath() );
|
String binPath = libraryUrl.getPath();
|
||||||
|
String srcPath = binPath.replace( "flatlaf-core/bin/main/", "flatlaf-core/src/main/resources/" );
|
||||||
|
File libraryFile = new File( srcPath ); // use from 'src' folder if available
|
||||||
|
if( !libraryFile.isFile() )
|
||||||
|
libraryFile = new File( binPath ); // use from 'bin' or 'output' folder if available
|
||||||
if( libraryFile.isFile() ) {
|
if( libraryFile.isFile() ) {
|
||||||
// load library without copying
|
// load library without copying
|
||||||
System.load( libraryFile.getCanonicalPath() );
|
System.load( libraryFile.getCanonicalPath() );
|
||||||
|
|||||||
@@ -100,8 +100,13 @@ debug*/
|
|||||||
Image image = getResolutionVariant( destImageWidth, destImageHeight );
|
Image image = getResolutionVariant( destImageWidth, destImageHeight );
|
||||||
|
|
||||||
// size of image
|
// size of image
|
||||||
int imageWidth = image.getWidth( null );
|
int imageWidth = -1;
|
||||||
int imageHeight = image.getHeight( null );
|
int imageHeight = -1;
|
||||||
|
|
||||||
|
if (image != null) {
|
||||||
|
imageWidth = image.getWidth( null );
|
||||||
|
imageHeight = image.getHeight( null );
|
||||||
|
}
|
||||||
|
|
||||||
// paint red rectangle if image has invalid size (e.g. not found)
|
// paint red rectangle if image has invalid size (e.g. not found)
|
||||||
if( imageWidth < 0 || imageHeight < 0 ) {
|
if( imageWidth < 0 || imageHeight < 0 ) {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package com.formdev.flatlaf.util;
|
|||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
import com.formdev.flatlaf.ui.FlatNativeWindowsLibrary;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides information about the current system.
|
* Provides information about the current system.
|
||||||
@@ -34,9 +35,7 @@ public class SystemInfo
|
|||||||
// OS versions
|
// OS versions
|
||||||
public static final long osVersion;
|
public static final long osVersion;
|
||||||
public static final boolean isWindows_10_orLater;
|
public static final boolean isWindows_10_orLater;
|
||||||
/** <strong>Note</strong>: This requires Java 8u321, 11.0.14, 17.0.2 or 18 (or later).
|
/** @since 2 */ public static final boolean isWindows_11_orLater;
|
||||||
* (see https://bugs.openjdk.java.net/browse/JDK-8274840)
|
|
||||||
* @since 2 */ public static final boolean isWindows_11_orLater;
|
|
||||||
public static final boolean isMacOS_10_11_ElCapitan_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_14_Mojave_orLater;
|
||||||
public static final boolean isMacOS_10_15_Catalina_orLater;
|
public static final boolean isMacOS_10_15_Catalina_orLater;
|
||||||
@@ -80,8 +79,6 @@ public class SystemInfo
|
|||||||
// OS versions
|
// OS versions
|
||||||
osVersion = scanVersion( System.getProperty( "os.version" ) );
|
osVersion = scanVersion( System.getProperty( "os.version" ) );
|
||||||
isWindows_10_orLater = (isWindows && osVersion >= toVersion( 10, 0, 0, 0 ));
|
isWindows_10_orLater = (isWindows && osVersion >= toVersion( 10, 0, 0, 0 ));
|
||||||
isWindows_11_orLater = (isWindows_10_orLater && osName.length() > "windows ".length() &&
|
|
||||||
scanVersion( osName.substring( "windows ".length() ) ) >= toVersion( 11, 0, 0, 0 ));
|
|
||||||
isMacOS_10_11_ElCapitan_orLater = (isMacOS && osVersion >= toVersion( 10, 11, 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_14_Mojave_orLater = (isMacOS && osVersion >= toVersion( 10, 14, 0, 0 ));
|
||||||
isMacOS_10_15_Catalina_orLater = (isMacOS && osVersion >= toVersion( 10, 15, 0, 0 ));
|
isMacOS_10_15_Catalina_orLater = (isMacOS && osVersion >= toVersion( 10, 15, 0, 0 ));
|
||||||
@@ -116,9 +113,27 @@ public class SystemInfo
|
|||||||
|
|
||||||
// features
|
// features
|
||||||
// available since Java 12; backported to Java 11.0.8 and 8u292
|
// available since Java 12; backported to Java 11.0.8 and 8u292
|
||||||
isMacFullWindowContentSupported =
|
isMacFullWindowContentSupported = isMacOS &&
|
||||||
javaVersion >= toVersion( 11, 0, 8, 0 ) ||
|
(javaVersion >= toVersion( 11, 0, 8, 0 ) ||
|
||||||
(javaVersion >= toVersion( 1, 8, 0, 292 ) && !isJava_9_orLater);
|
(javaVersion >= toVersion( 1, 8, 0, 292 ) && !isJava_9_orLater));
|
||||||
|
|
||||||
|
|
||||||
|
// Note: Keep following at the end of this block because (optional) loading
|
||||||
|
// of native library uses fields of this class. E.g. isX86_64
|
||||||
|
|
||||||
|
// Windows 11 detection is implemented in Java 8u321, 11.0.14, 17.0.2 and 18 (or later).
|
||||||
|
// (see https://bugs.openjdk.java.net/browse/JDK-8274840)
|
||||||
|
// For older Java versions, use native library to get OS build number.
|
||||||
|
boolean isWin_11_orLater = false;
|
||||||
|
try {
|
||||||
|
isWin_11_orLater = isWindows_10_orLater &&
|
||||||
|
(scanVersion( StringUtils.removeLeading( osName, "windows " ) ) >= toVersion( 11, 0, 0, 0 ) ||
|
||||||
|
(FlatNativeWindowsLibrary.isLoaded() && FlatNativeWindowsLibrary.getOSBuildNumber() >= 22000));
|
||||||
|
} catch( Throwable ex ) {
|
||||||
|
// catch to avoid that application can not start if native library is not up-to-date
|
||||||
|
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||||
|
}
|
||||||
|
isWindows_11_orLater = isWin_11_orLater;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long scanVersion( String version ) {
|
public static long scanVersion( String version ) {
|
||||||
|
|||||||
@@ -204,7 +204,7 @@ public class UIScale
|
|||||||
if( SystemInfo.isWindows ) {
|
if( SystemInfo.isWindows ) {
|
||||||
// Special handling for Windows to be compatible with OS scaling,
|
// Special handling for Windows to be compatible with OS scaling,
|
||||||
// which distinguish between "screen scaling" and "text scaling".
|
// which distinguish between "screen scaling" and "text scaling".
|
||||||
// - Windows "screen scaling" scales everything (text, icon, gaps, etc)
|
// - Windows "screen scaling" scales everything (text, icon, gaps, etc.)
|
||||||
// and may have different scaling factors for each screen.
|
// and may have different scaling factors for each screen.
|
||||||
// - Windows "text scaling" increases only the font size, but on all screens.
|
// - Windows "text scaling" increases only the font size, but on all screens.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -20,9 +20,12 @@ import java.awt.Dimension;
|
|||||||
import java.awt.Image;
|
import java.awt.Image;
|
||||||
import java.awt.image.AbstractMultiResolutionImage;
|
import java.awt.image.AbstractMultiResolutionImage;
|
||||||
import java.awt.image.BaseMultiResolutionImage;
|
import java.awt.image.BaseMultiResolutionImage;
|
||||||
|
import java.awt.image.ImageObserver;
|
||||||
|
import java.awt.image.ImageProducer;
|
||||||
import java.awt.image.MultiResolutionImage;
|
import java.awt.image.MultiResolutionImage;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.IdentityHashMap;
|
import java.util.IdentityHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
@@ -116,6 +119,26 @@ public class MultiResolutionImageSupport
|
|||||||
return mapAndCacheImage( mrImage );
|
return mapAndCacheImage( mrImage );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getWidth( ImageObserver observer ) {
|
||||||
|
return mrImage.getWidth( observer );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getHeight( ImageObserver observer ) {
|
||||||
|
return mrImage.getHeight( observer );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ImageProducer getSource() {
|
||||||
|
return mrImage.getSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getProperty( String name, ImageObserver observer ) {
|
||||||
|
return mrImage.getProperty( name, observer );
|
||||||
|
}
|
||||||
|
|
||||||
private Image mapAndCacheImage( Image image ) {
|
private Image mapAndCacheImage( Image image ) {
|
||||||
return cache.computeIfAbsent( image, img -> {
|
return cache.computeIfAbsent( image, img -> {
|
||||||
// using ImageIcon here makes sure that the image is loaded
|
// using ImageIcon here makes sure that the image is loaded
|
||||||
@@ -134,7 +157,7 @@ public class MultiResolutionImageSupport
|
|||||||
{
|
{
|
||||||
private final Dimension[] dimensions;
|
private final Dimension[] dimensions;
|
||||||
private final Function<Dimension, Image> producer;
|
private final Function<Dimension, Image> producer;
|
||||||
private final IdentityHashMap<Dimension, Image> cache = new IdentityHashMap<>();
|
private final HashMap<Dimension, Image> cache = new HashMap<>();
|
||||||
|
|
||||||
ProducerMultiResolutionImage( Dimension[] dimensions, Function<Dimension, Image> producer ) {
|
ProducerMultiResolutionImage( Dimension[] dimensions, Function<Dimension, Image> producer ) {
|
||||||
this.dimensions = dimensions;
|
this.dimensions = dimensions;
|
||||||
@@ -159,6 +182,16 @@ public class MultiResolutionImageSupport
|
|||||||
return produceAndCacheImage( dimensions[0] );
|
return produceAndCacheImage( dimensions[0] );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getWidth( ImageObserver observer ) {
|
||||||
|
return dimensions[0].width;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getHeight( ImageObserver observer ) {
|
||||||
|
return dimensions[0].height;
|
||||||
|
}
|
||||||
|
|
||||||
private Image produceAndCacheImage( Dimension size ) {
|
private Image produceAndCacheImage( Dimension size ) {
|
||||||
return cache.computeIfAbsent( size, size2 -> {
|
return cache.computeIfAbsent( size, size2 -> {
|
||||||
// using ImageIcon here makes sure that the image is loaded
|
// using ImageIcon here makes sure that the image is loaded
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* @author Karl Tauber
|
* @author Karl Tauber
|
||||||
*/
|
*/
|
||||||
module com.formdev.flatlaf {
|
module com.formdev.flatlaf {
|
||||||
|
|||||||
@@ -57,7 +57,7 @@
|
|||||||
@menuAcceleratorSelectionForeground = @selectionForeground
|
@menuAcceleratorSelectionForeground = @selectionForeground
|
||||||
|
|
||||||
# misc
|
# misc
|
||||||
@cellFocusColor = #000
|
@cellFocusColor = lighten(@selectionBackground,10%)
|
||||||
@icon = shade(@foreground,7%)
|
@icon = shade(@foreground,7%)
|
||||||
|
|
||||||
# accent colors (blueish)
|
# accent colors (blueish)
|
||||||
@@ -246,6 +246,7 @@ PasswordField.revealIconColor = @foreground
|
|||||||
|
|
||||||
#---- Popup ----
|
#---- Popup ----
|
||||||
|
|
||||||
|
[mac]Popup.roundedBorderWidth = 1
|
||||||
Popup.dropShadowColor = #000
|
Popup.dropShadowColor = #000
|
||||||
Popup.dropShadowOpacity = 0.25
|
Popup.dropShadowOpacity = 0.25
|
||||||
|
|
||||||
@@ -331,6 +332,8 @@ Table.gridColor = lighten($Table.background,8%)
|
|||||||
|
|
||||||
#---- TableHeader ----
|
#---- TableHeader ----
|
||||||
|
|
||||||
|
TableHeader.hoverBackground = lighten($TableHeader.background,5%,derived)
|
||||||
|
TableHeader.pressedBackground = lighten($TableHeader.background,10%,derived)
|
||||||
TableHeader.separatorColor = lighten($TableHeader.background,10%)
|
TableHeader.separatorColor = lighten($TableHeader.background,10%)
|
||||||
TableHeader.bottomSeparatorColor = $TableHeader.separatorColor
|
TableHeader.bottomSeparatorColor = $TableHeader.separatorColor
|
||||||
|
|
||||||
|
|||||||
@@ -288,6 +288,8 @@ ComboBox.buttonPressedArrowColor = @buttonPressedArrowColor
|
|||||||
ComboBox.popupInsets = 0,0,0,0
|
ComboBox.popupInsets = 0,0,0,0
|
||||||
ComboBox.selectionInsets = 0,0,0,0
|
ComboBox.selectionInsets = 0,0,0,0
|
||||||
ComboBox.selectionArc = 0
|
ComboBox.selectionArc = 0
|
||||||
|
ComboBox.borderCornerRadius = $Popup.borderCornerRadius
|
||||||
|
[mac]ComboBox.roundedBorderWidth = $Popup.roundedBorderWidth
|
||||||
|
|
||||||
|
|
||||||
#---- Component ----
|
#---- Component ----
|
||||||
@@ -503,6 +505,8 @@ PasswordField.revealIcon = com.formdev.flatlaf.icons.FlatRevealIcon
|
|||||||
|
|
||||||
#---- Popup ----
|
#---- Popup ----
|
||||||
|
|
||||||
|
Popup.borderCornerRadius = 4
|
||||||
|
[mac]Popup.roundedBorderWidth = 0
|
||||||
Popup.dropShadowPainted = true
|
Popup.dropShadowPainted = true
|
||||||
Popup.dropShadowInsets = -4,-4,4,4
|
Popup.dropShadowInsets = -4,-4,4,4
|
||||||
|
|
||||||
@@ -511,6 +515,8 @@ Popup.dropShadowInsets = -4,-4,4,4
|
|||||||
|
|
||||||
PopupMenu.border = com.formdev.flatlaf.ui.FlatPopupMenuBorder
|
PopupMenu.border = com.formdev.flatlaf.ui.FlatPopupMenuBorder
|
||||||
PopupMenu.borderInsets = 4,1,4,1
|
PopupMenu.borderInsets = 4,1,4,1
|
||||||
|
PopupMenu.borderCornerRadius = $Popup.borderCornerRadius
|
||||||
|
[mac]PopupMenu.roundedBorderWidth = $Popup.roundedBorderWidth
|
||||||
PopupMenu.background = @menuBackground
|
PopupMenu.background = @menuBackground
|
||||||
PopupMenu.scrollArrowColor = @buttonArrowColor
|
PopupMenu.scrollArrowColor = @buttonArrowColor
|
||||||
|
|
||||||
@@ -594,10 +600,15 @@ ScrollBar.allowsAbsolutePositioning = true
|
|||||||
|
|
||||||
#---- ScrollPane ----
|
#---- ScrollPane ----
|
||||||
|
|
||||||
ScrollPane.border = com.formdev.flatlaf.ui.FlatBorder
|
ScrollPane.border = com.formdev.flatlaf.ui.FlatScrollPaneBorder
|
||||||
ScrollPane.background = $ScrollBar.track
|
ScrollPane.background = $ScrollBar.track
|
||||||
ScrollPane.fillUpperCorner = true
|
ScrollPane.fillUpperCorner = true
|
||||||
ScrollPane.smoothScrolling = true
|
ScrollPane.smoothScrolling = true
|
||||||
|
ScrollPane.arc = 0
|
||||||
|
#ScrollPane.List.arc = -1
|
||||||
|
#ScrollPane.Table.arc = -1
|
||||||
|
#ScrollPane.TextComponent.arc = -1
|
||||||
|
#ScrollPane.Tree.arc = -1
|
||||||
|
|
||||||
|
|
||||||
#---- SearchField ----
|
#---- SearchField ----
|
||||||
@@ -668,7 +679,12 @@ SplitPaneDivider.gripGap = 2
|
|||||||
|
|
||||||
TabbedPane.tabHeight = 32
|
TabbedPane.tabHeight = 32
|
||||||
TabbedPane.tabSelectionHeight = 3
|
TabbedPane.tabSelectionHeight = 3
|
||||||
TabbedPane.cardTabSelectionHeight = 2
|
TabbedPane.cardTabSelectionHeight = 3
|
||||||
|
TabbedPane.tabArc = 0
|
||||||
|
TabbedPane.tabSelectionArc = 0
|
||||||
|
TabbedPane.cardTabArc = 12
|
||||||
|
TabbedPane.selectedInsets = 0,0,0,0
|
||||||
|
TabbedPane.tabSelectionInsets = 0,0,0,0
|
||||||
TabbedPane.contentSeparatorHeight = 1
|
TabbedPane.contentSeparatorHeight = 1
|
||||||
TabbedPane.showTabSeparators = false
|
TabbedPane.showTabSeparators = false
|
||||||
TabbedPane.tabSeparatorsFullHeight = false
|
TabbedPane.tabSeparatorsFullHeight = false
|
||||||
@@ -689,6 +705,8 @@ TabbedPane.tabAreaAlignment = leading
|
|||||||
TabbedPane.tabAlignment = center
|
TabbedPane.tabAlignment = center
|
||||||
# allowed values: preferred, equal or compact
|
# allowed values: preferred, equal or compact
|
||||||
TabbedPane.tabWidthMode = preferred
|
TabbedPane.tabWidthMode = preferred
|
||||||
|
# allowed values: none, auto, left or right
|
||||||
|
TabbedPane.tabRotation = none
|
||||||
|
|
||||||
# allowed values: underlined or card
|
# allowed values: underlined or card
|
||||||
TabbedPane.tabType = underlined
|
TabbedPane.tabType = underlined
|
||||||
@@ -723,7 +741,7 @@ Table.showVerticalLines = false
|
|||||||
Table.showTrailingVerticalLine = false
|
Table.showTrailingVerticalLine = false
|
||||||
Table.consistentHomeEndKeyBehavior = true
|
Table.consistentHomeEndKeyBehavior = true
|
||||||
Table.intercellSpacing = 0,0
|
Table.intercellSpacing = 0,0
|
||||||
Table.scrollPaneBorder = com.formdev.flatlaf.ui.FlatBorder
|
Table.scrollPaneBorder = com.formdev.flatlaf.ui.FlatScrollPaneBorder
|
||||||
Table.ascendingSortIcon = com.formdev.flatlaf.icons.FlatAscendingSortIcon
|
Table.ascendingSortIcon = com.formdev.flatlaf.icons.FlatAscendingSortIcon
|
||||||
Table.descendingSortIcon = com.formdev.flatlaf.icons.FlatDescendingSortIcon
|
Table.descendingSortIcon = com.formdev.flatlaf.icons.FlatDescendingSortIcon
|
||||||
Table.sortIconColor = @icon
|
Table.sortIconColor = @icon
|
||||||
@@ -805,6 +823,7 @@ TitlePane.titleMinimumWidth = 60
|
|||||||
TitlePane.buttonSize = 44,30
|
TitlePane.buttonSize = 44,30
|
||||||
TitlePane.buttonMinimumWidth = 30
|
TitlePane.buttonMinimumWidth = 30
|
||||||
TitlePane.buttonMaximizedHeight = 22
|
TitlePane.buttonMaximizedHeight = 22
|
||||||
|
TitlePane.buttonSymbolHeight = 10
|
||||||
TitlePane.centerTitle = false
|
TitlePane.centerTitle = false
|
||||||
TitlePane.centerTitleIfMenuBarEmbedded = true
|
TitlePane.centerTitleIfMenuBarEmbedded = true
|
||||||
TitlePane.showIconBesideTitle = false
|
TitlePane.showIconBesideTitle = false
|
||||||
@@ -826,6 +845,16 @@ TitlePane.closePressedBackground = fade($TitlePane.closeHoverBackground,90%)
|
|||||||
TitlePane.closeHoverForeground = #fff
|
TitlePane.closeHoverForeground = #fff
|
||||||
TitlePane.closePressedForeground = #fff
|
TitlePane.closePressedForeground = #fff
|
||||||
|
|
||||||
|
# window style "small"
|
||||||
|
TitlePane.small.font = -1
|
||||||
|
TitlePane.small.showIcon = false
|
||||||
|
TitlePane.small.buttonSize = 30,20
|
||||||
|
TitlePane.small.buttonSymbolHeight = 8
|
||||||
|
TitlePane.small.closeIcon = com.formdev.flatlaf.icons.FlatWindowCloseIcon, small
|
||||||
|
TitlePane.small.iconifyIcon = com.formdev.flatlaf.icons.FlatWindowIconifyIcon, small
|
||||||
|
TitlePane.small.maximizeIcon = com.formdev.flatlaf.icons.FlatWindowMaximizeIcon, small
|
||||||
|
TitlePane.small.restoreIcon = com.formdev.flatlaf.icons.FlatWindowRestoreIcon, small
|
||||||
|
|
||||||
|
|
||||||
#---- ToggleButton ----
|
#---- ToggleButton ----
|
||||||
|
|
||||||
@@ -880,6 +909,12 @@ ToolBar.spacingBorder = $Button.toolbar.spacingInsets
|
|||||||
ToolTipManager.enableToolTipMode = activeApplication
|
ToolTipManager.enableToolTipMode = activeApplication
|
||||||
|
|
||||||
|
|
||||||
|
#---- ToolTip ----
|
||||||
|
|
||||||
|
ToolTip.borderCornerRadius = $Popup.borderCornerRadius
|
||||||
|
[mac]ToolTip.roundedBorderWidth = $Popup.roundedBorderWidth
|
||||||
|
|
||||||
|
|
||||||
#---- Tree ----
|
#---- Tree ----
|
||||||
|
|
||||||
Tree.border = 1,1,1,1
|
Tree.border = 1,1,1,1
|
||||||
|
|||||||
@@ -57,7 +57,7 @@
|
|||||||
@menuAcceleratorSelectionForeground = @selectionForeground
|
@menuAcceleratorSelectionForeground = @selectionForeground
|
||||||
|
|
||||||
# misc
|
# misc
|
||||||
@cellFocusColor = #000
|
@cellFocusColor = darken(@selectionBackground,20%)
|
||||||
@icon = shade(@background,27%)
|
@icon = shade(@background,27%)
|
||||||
|
|
||||||
# accent colors (blueish)
|
# accent colors (blueish)
|
||||||
@@ -338,6 +338,8 @@ Table.gridColor = darken($Table.background,8%)
|
|||||||
|
|
||||||
#---- TableHeader ----
|
#---- TableHeader ----
|
||||||
|
|
||||||
|
TableHeader.hoverBackground = darken($TableHeader.background,5%,derived)
|
||||||
|
TableHeader.pressedBackground = darken($TableHeader.background,10%,derived)
|
||||||
TableHeader.separatorColor = darken($TableHeader.background,10%)
|
TableHeader.separatorColor = darken($TableHeader.background,10%)
|
||||||
TableHeader.bottomSeparatorColor = $TableHeader.separatorColor
|
TableHeader.bottomSeparatorColor = $TableHeader.separatorColor
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,15 @@ info = lazy(ToolTip.background)
|
|||||||
infoText = lazy(ToolTip.foreground)
|
infoText = lazy(ToolTip.foreground)
|
||||||
|
|
||||||
|
|
||||||
|
#---- variables ----
|
||||||
|
|
||||||
|
# make sure that accent color (set via FlatLaf.setSystemColorGetter()) is ignored
|
||||||
|
@accentColor = null
|
||||||
|
|
||||||
|
# use fixed color because it is used in borders
|
||||||
|
@cellFocusColor = #222
|
||||||
|
|
||||||
|
|
||||||
#---- Button ----
|
#---- Button ----
|
||||||
|
|
||||||
Button.startBackground = $Button.background
|
Button.startBackground = $Button.background
|
||||||
@@ -103,6 +112,9 @@ ToggleButton.endBackground = $ToggleButton.background
|
|||||||
@ijMenuCheckBackgroundL20 = lighten(@selectionBackground,20%,derived noAutoInverse)
|
@ijMenuCheckBackgroundL20 = lighten(@selectionBackground,20%,derived noAutoInverse)
|
||||||
@ijMenuCheckBackgroundD10 = darken(@selectionBackground,10%,derived noAutoInverse)
|
@ijMenuCheckBackgroundD10 = darken(@selectionBackground,10%,derived noAutoInverse)
|
||||||
|
|
||||||
|
@ijTextBackgroundL3 = lighten(Panel.background,3%,lazy)
|
||||||
|
@ijTextBackgroundL4 = lighten(Panel.background,4%,lazy)
|
||||||
|
|
||||||
[Arc_Theme]CheckBoxMenuItem.foreground = lazy(MenuItem.foreground)
|
[Arc_Theme]CheckBoxMenuItem.foreground = lazy(MenuItem.foreground)
|
||||||
[Arc_Theme]PopupMenu.foreground = lazy(MenuItem.foreground)
|
[Arc_Theme]PopupMenu.foreground = lazy(MenuItem.foreground)
|
||||||
[Arc_Theme]RadioButtonMenuItem.foreground = lazy(MenuItem.foreground)
|
[Arc_Theme]RadioButtonMenuItem.foreground = lazy(MenuItem.foreground)
|
||||||
@@ -126,53 +138,110 @@ ToggleButton.endBackground = $ToggleButton.background
|
|||||||
[Arc_Theme_Dark]RadioButtonMenuItem.foreground = lazy(MenuItem.foreground)
|
[Arc_Theme_Dark]RadioButtonMenuItem.foreground = lazy(MenuItem.foreground)
|
||||||
[Arc_Theme_Dark]ProgressBar.selectionBackground = #ddd
|
[Arc_Theme_Dark]ProgressBar.selectionBackground = #ddd
|
||||||
[Arc_Theme_Dark]ProgressBar.selectionForeground = #ddd
|
[Arc_Theme_Dark]ProgressBar.selectionForeground = #ddd
|
||||||
|
[Arc_Theme_Dark]ToolBar.separatorColor = lazy(Separator.foreground)
|
||||||
|
|
||||||
[Arc_Theme_Dark_-_Orange]CheckBoxMenuItem.foreground = lazy(MenuItem.foreground)
|
[Arc_Theme_Dark_-_Orange]CheckBoxMenuItem.foreground = lazy(MenuItem.foreground)
|
||||||
[Arc_Theme_Dark_-_Orange]PopupMenu.foreground = lazy(MenuItem.foreground)
|
[Arc_Theme_Dark_-_Orange]PopupMenu.foreground = lazy(MenuItem.foreground)
|
||||||
[Arc_Theme_Dark_-_Orange]RadioButtonMenuItem.foreground = lazy(MenuItem.foreground)
|
[Arc_Theme_Dark_-_Orange]RadioButtonMenuItem.foreground = lazy(MenuItem.foreground)
|
||||||
[Arc_Theme_Dark_-_Orange]ProgressBar.selectionBackground = #ddd
|
[Arc_Theme_Dark_-_Orange]ProgressBar.selectionBackground = #ddd
|
||||||
[Arc_Theme_Dark_-_Orange]ProgressBar.selectionForeground = #fff
|
[Arc_Theme_Dark_-_Orange]ProgressBar.selectionForeground = #fff
|
||||||
|
[Arc_Theme_Dark_-_Orange]ToolBar.separatorColor = lazy(Separator.foreground)
|
||||||
|
|
||||||
|
[Carbon]Table.selectionBackground = lazy(List.selectionBackground)
|
||||||
|
[Carbon]Table.selectionInactiveForeground = lazy(List.selectionInactiveForeground)
|
||||||
|
[Carbon]TextField.background = @ijTextBackgroundL4
|
||||||
|
|
||||||
[Cobalt_2]Component.accentColor = lazy(Component.focusColor)
|
[Cobalt_2]Component.accentColor = lazy(Component.focusColor)
|
||||||
[Cobalt_2]CheckBox.icon.background = #002946
|
[Cobalt_2]CheckBox.icon.background = #002946
|
||||||
[Cobalt_2]CheckBox.icon.checkmarkColor = #002946
|
[Cobalt_2]CheckBox.icon.checkmarkColor = #002946
|
||||||
[Cobalt_2]MenuItem.checkBackground = @ijMenuCheckBackgroundL10
|
[Cobalt_2]MenuItem.checkBackground = @ijMenuCheckBackgroundL10
|
||||||
[Cobalt_2]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
|
[Cobalt_2]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
|
||||||
|
[Cobalt_2]ComboBox.background = @ijTextBackgroundL3
|
||||||
|
[Cobalt_2]ComboBox.buttonBackground = @ijTextBackgroundL3
|
||||||
|
[Cobalt_2]TextField.background = @ijTextBackgroundL3
|
||||||
|
[Cobalt_2]Table.background = lazy(List.background)
|
||||||
|
[Cobalt_2]Tree.background = lazy(List.background)
|
||||||
|
|
||||||
[Cyan_light]MenuItem.checkBackground = @ijMenuCheckBackgroundL20
|
[Cyan_light]MenuItem.checkBackground = @ijMenuCheckBackgroundL20
|
||||||
[Cyan_light]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL20
|
[Cyan_light]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL20
|
||||||
|
|
||||||
|
[Dark_Flat_Theme]*.inactiveForeground = #808080
|
||||||
[Dark_Flat_Theme]Component.accentColor = lazy(List.selectionBackground)
|
[Dark_Flat_Theme]Component.accentColor = lazy(List.selectionBackground)
|
||||||
[Dark_Flat_Theme]TableHeader.background = #3B3B3B
|
[Dark_Flat_Theme]TableHeader.background = #3B3B3B
|
||||||
|
[Dark_Flat_Theme]TextPane.foreground = lazy(TextField.foreground)
|
||||||
|
[Dark_Flat_Theme]CheckBoxMenuItem.selectionForeground = lazy(MenuItem.selectionForeground)
|
||||||
|
[Dark_Flat_Theme]List.selectionForeground = lazy(Tree.selectionForeground)
|
||||||
|
[Dark_Flat_Theme]RadioButtonMenuItem.selectionForeground = lazy(MenuItem.selectionForeground)
|
||||||
|
[Dark_Flat_Theme]Separator.foreground = lazy(ToolBar.separatorColor)
|
||||||
|
|
||||||
[Dark_purple]Slider.focusedColor = fade($Component.focusColor,70%,derived)
|
[Dark_purple]Slider.focusedColor = fade($Component.focusColor,70%,derived)
|
||||||
|
|
||||||
[Dracula---Zihan_Ma]Component.accentColor = lazy(Component.focusColor)
|
[Dracula---Zihan_Ma]Component.accentColor = lazy(Component.focusColor)
|
||||||
|
[Dracula---Zihan_Ma]ComboBox.selectionBackground = lazy(List.selectionBackground)
|
||||||
[Dracula---Zihan_Ma]ProgressBar.selectionBackground = #fff
|
[Dracula---Zihan_Ma]ProgressBar.selectionBackground = #fff
|
||||||
[Dracula---Zihan_Ma]ProgressBar.selectionForeground = #fff
|
[Dracula---Zihan_Ma]ProgressBar.selectionForeground = #fff
|
||||||
|
|
||||||
|
[Gradianto_Dark_Fuchsia]*.selectionBackground = #8452a7
|
||||||
|
[Gradianto_Dark_Fuchsia]*.selectionInactiveBackground = #562C6A
|
||||||
[Gradianto_Dark_Fuchsia]MenuItem.checkBackground = @ijMenuCheckBackgroundL10
|
[Gradianto_Dark_Fuchsia]MenuItem.checkBackground = @ijMenuCheckBackgroundL10
|
||||||
[Gradianto_Dark_Fuchsia]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
|
[Gradianto_Dark_Fuchsia]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
|
||||||
|
[Gradianto_Dark_Fuchsia]TextField.background = @ijTextBackgroundL4
|
||||||
|
[Gradianto_Dark_Fuchsia]Tree.background = lazy(List.background)
|
||||||
|
[Gradianto_Dark_Fuchsia]Separator.foreground = lazy(ScrollBar.track)
|
||||||
|
[Gradianto_Dark_Fuchsia]ToolBar.separatorColor = lazy(ScrollBar.track)
|
||||||
|
[Gradianto_Dark_Fuchsia]ProgressBar.background = lazy(ScrollBar.track)
|
||||||
|
[Gradianto_Dark_Fuchsia]Slider.trackColor = lazy(ScrollBar.track)
|
||||||
|
|
||||||
|
[Gradianto_Deep_Ocean]TextField.background = @ijTextBackgroundL3
|
||||||
|
[Gradianto_Deep_Ocean]Tree.background = lazy(List.background)
|
||||||
|
|
||||||
|
[Gradianto_Midnight_Blue]ScrollBar.thumb = #533B6B
|
||||||
|
[Gradianto_Midnight_Blue]Table.selectionForeground = lazy(List.selectionForeground)
|
||||||
|
[Gradianto_Midnight_Blue]TextField.background = @ijTextBackgroundL4
|
||||||
|
[Gradianto_Midnight_Blue]Tree.background = lazy(List.background)
|
||||||
|
|
||||||
|
[Gradianto_Nature_Green]Table.selectionForeground = lazy(List.selectionForeground)
|
||||||
|
[Gradianto_Nature_Green]TextField.background = @ijTextBackgroundL4
|
||||||
|
|
||||||
|
[Gray]Separator.foreground = lazy(Slider.trackColor)
|
||||||
|
[Gray]ToolBar.separatorColor = lazy(Slider.trackColor)
|
||||||
|
|
||||||
[Gruvbox_Dark_Hard]Component.accentColor = lazy(TabbedPane.underlineColor)
|
[Gruvbox_Dark_Hard]Component.accentColor = lazy(TabbedPane.underlineColor)
|
||||||
[Gruvbox_Dark_Hard]ToggleButton.selectedBackground = $ToggleButton.selectedBackground
|
[Gruvbox_Dark_Hard]ToggleButton.selectedBackground = $ToggleButton.selectedBackground
|
||||||
[Gruvbox_Dark_Hard]ToggleButton.toolbar.selectedBackground = $ToggleButton.toolbar.selectedBackground
|
[Gruvbox_Dark_Hard]ToggleButton.toolbar.selectedBackground = $ToggleButton.toolbar.selectedBackground
|
||||||
|
[Gruvbox_Dark_Hard]ComboBox.background = @ijTextBackgroundL3
|
||||||
|
[Gruvbox_Dark_Hard]ComboBox.buttonBackground = @ijTextBackgroundL3
|
||||||
|
[Gruvbox_Dark_Hard]TextField.background = @ijTextBackgroundL3
|
||||||
|
|
||||||
[Gruvbox_Dark_Medium]Component.accentColor = lazy(TabbedPane.underlineColor)
|
[Gruvbox_Dark_Medium]Component.accentColor = lazy(TabbedPane.underlineColor)
|
||||||
[Gruvbox_Dark_Medium]ToggleButton.selectedBackground = $ToggleButton.selectedBackground
|
[Gruvbox_Dark_Medium]ToggleButton.selectedBackground = $ToggleButton.selectedBackground
|
||||||
[Gruvbox_Dark_Medium]ToggleButton.toolbar.selectedBackground = $ToggleButton.toolbar.selectedBackground
|
[Gruvbox_Dark_Medium]ToggleButton.toolbar.selectedBackground = $ToggleButton.toolbar.selectedBackground
|
||||||
|
[Gruvbox_Dark_Medium]ComboBox.background = @ijTextBackgroundL3
|
||||||
|
[Gruvbox_Dark_Medium]ComboBox.buttonBackground = @ijTextBackgroundL3
|
||||||
|
[Gruvbox_Dark_Medium]TextField.background = @ijTextBackgroundL3
|
||||||
|
|
||||||
[Gruvbox_Dark_Soft]Component.accentColor = lazy(TabbedPane.underlineColor)
|
[Gruvbox_Dark_Soft]Component.accentColor = lazy(TabbedPane.underlineColor)
|
||||||
[Gruvbox_Dark_Soft]MenuItem.checkBackground = @ijMenuCheckBackgroundL10
|
[Gruvbox_Dark_Soft]MenuItem.checkBackground = @ijMenuCheckBackgroundL10
|
||||||
[Gruvbox_Dark_Soft]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
|
[Gruvbox_Dark_Soft]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
|
||||||
[Gruvbox_Dark_Soft]ToggleButton.selectedBackground = $ToggleButton.selectedBackground
|
[Gruvbox_Dark_Soft]ToggleButton.selectedBackground = $ToggleButton.selectedBackground
|
||||||
[Gruvbox_Dark_Soft]ToggleButton.toolbar.selectedBackground = $ToggleButton.toolbar.selectedBackground
|
[Gruvbox_Dark_Soft]ToggleButton.toolbar.selectedBackground = $ToggleButton.toolbar.selectedBackground
|
||||||
|
[Gruvbox_Dark_Soft]ComboBox.background = @ijTextBackgroundL3
|
||||||
|
[Gruvbox_Dark_Soft]ComboBox.buttonBackground = @ijTextBackgroundL3
|
||||||
|
[Gruvbox_Dark_Soft]TextField.background = @ijTextBackgroundL3
|
||||||
|
|
||||||
|
[Hiberbee_Dark]*.disabledForeground = #7F7E7D
|
||||||
|
[Hiberbee_Dark]*.disabledText = #7F7E7D
|
||||||
|
[Hiberbee_Dark]*.inactiveForeground = #7F7E7D
|
||||||
|
[Hiberbee_Dark]ProgressBar.background = lazy(Separator.foreground)
|
||||||
|
[Hiberbee_Dark]Slider.trackColor = lazy(Separator.foreground)
|
||||||
[Hiberbee_Dark]TabbedPane.focusColor = #5A5A5A
|
[Hiberbee_Dark]TabbedPane.focusColor = #5A5A5A
|
||||||
[Hiberbee_Dark]TabbedPane.selectedBackground = #434241
|
[Hiberbee_Dark]TabbedPane.selectedBackground = #434241
|
||||||
[Hiberbee_Dark]TabbedPane.selectedForeground = #70D7FF
|
[Hiberbee_Dark]TabbedPane.selectedForeground = #70D7FF
|
||||||
[Hiberbee_Dark]ToggleButton.selectedBackground = $ToggleButton.selectedBackground
|
[Hiberbee_Dark]ToggleButton.selectedBackground = $ToggleButton.selectedBackground
|
||||||
[Hiberbee_Dark]ToggleButton.toolbar.selectedBackground = $ToggleButton.toolbar.selectedBackground
|
[Hiberbee_Dark]ToggleButton.toolbar.selectedBackground = $ToggleButton.toolbar.selectedBackground
|
||||||
|
[Hiberbee_Dark]Table.selectionInactiveBackground = lazy(List.selectionInactiveBackground)
|
||||||
|
[Hiberbee_Dark]Tree.selectionBackground = lazy(List.selectionBackground)
|
||||||
|
[Hiberbee_Dark]Tree.selectionInactiveBackground = lazy(List.selectionInactiveBackground)
|
||||||
|
|
||||||
[High_contrast]Component.accentColor = lazy(Component.focusColor)
|
[High_contrast]Component.accentColor = lazy(Component.focusColor)
|
||||||
[High_contrast]ToggleButton.selectedBackground = #fff
|
[High_contrast]ToggleButton.selectedBackground = #fff
|
||||||
@@ -185,9 +254,20 @@ ToggleButton.endBackground = $ToggleButton.background
|
|||||||
toolbar.selectedBackground: #fff
|
toolbar.selectedBackground: #fff
|
||||||
[High_contrast][style]ToggleButton.inTextField = $[High_contrast][style]Button.inTextField
|
[High_contrast][style]ToggleButton.inTextField = $[High_contrast][style]Button.inTextField
|
||||||
|
|
||||||
|
[Light_Flat]*.disabledForeground = #8C8C8C
|
||||||
|
[Light_Flat]*.inactiveForeground = #8C8C8C
|
||||||
|
[Light_Flat]CheckBox.icon[filled].background = #fff
|
||||||
|
[Light_Flat]CheckBox.icon[filled].checkmarkColor = #fff
|
||||||
[Light_Flat]Component.accentColor = lazy(TabbedPane.underlineColor)
|
[Light_Flat]Component.accentColor = lazy(TabbedPane.underlineColor)
|
||||||
|
[Light_Flat]ComboBox.background = lazy(ComboBox.editableBackground)
|
||||||
|
[Light_Flat]ComboBox.buttonBackground = lazy(ComboBox.editableBackground)
|
||||||
|
[Light_Flat]Separator.foreground = lazy(ToolBar.separatorColor)
|
||||||
[Light_Flat]TableHeader.background = #E5E5E9
|
[Light_Flat]TableHeader.background = #E5E5E9
|
||||||
|
[Light_Flat]TextPane.foreground = lazy(TextField.foreground)
|
||||||
|
[Light_Flat]CheckBoxMenuItem.selectionForeground = lazy(MenuItem.selectionForeground)
|
||||||
|
[Light_Flat]RadioButtonMenuItem.selectionForeground = lazy(MenuItem.selectionForeground)
|
||||||
|
|
||||||
|
[Monocai]Button.default.foreground = #2D2A2F
|
||||||
[Monocai]MenuItem.checkBackground = @ijMenuCheckBackgroundL10
|
[Monocai]MenuItem.checkBackground = @ijMenuCheckBackgroundL10
|
||||||
[Monocai]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
|
[Monocai]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
|
||||||
@Monocai.acceleratorForeground = lazy(MenuItem.disabledForeground)
|
@Monocai.acceleratorForeground = lazy(MenuItem.disabledForeground)
|
||||||
@@ -200,21 +280,67 @@ ToggleButton.endBackground = $ToggleButton.background
|
|||||||
[Monocai]MenuItem.acceleratorSelectionForeground = @Monocai.acceleratorSelectionForeground
|
[Monocai]MenuItem.acceleratorSelectionForeground = @Monocai.acceleratorSelectionForeground
|
||||||
[Monocai]RadioButtonMenuItem.acceleratorForeground = @Monocai.acceleratorForeground
|
[Monocai]RadioButtonMenuItem.acceleratorForeground = @Monocai.acceleratorForeground
|
||||||
[Monocai]RadioButtonMenuItem.acceleratorSelectionForeground = @Monocai.acceleratorSelectionForeground
|
[Monocai]RadioButtonMenuItem.acceleratorSelectionForeground = @Monocai.acceleratorSelectionForeground
|
||||||
|
[Monocai]TextField.background = @ijTextBackgroundL4
|
||||||
|
@Monocai.selectionBackground = lazy(TextField.selectionBackground)
|
||||||
|
[Monocai]ComboBox.selectionBackground = @Monocai.selectionBackground
|
||||||
|
[Monocai]List.selectionBackground = @Monocai.selectionBackground
|
||||||
|
[Monocai]Table.selectionBackground = @Monocai.selectionBackground
|
||||||
|
[Monocai]Tree.selectionBackground = @Monocai.selectionBackground
|
||||||
|
@Monocai.selectionInactiveBackground = lazy(MenuItem.selectionBackground)
|
||||||
|
[Monocai]List.selectionInactiveBackground = @Monocai.selectionInactiveBackground
|
||||||
|
[Monocai]Table.selectionInactiveBackground = @Monocai.selectionInactiveBackground
|
||||||
|
[Monocai]Tree.selectionInactiveBackground = @Monocai.selectionInactiveBackground
|
||||||
|
|
||||||
[Monokai_Pro]TitledBorder.titleColor = @foreground
|
[Monokai_Pro---Subtheme]Table.selectionInactiveForeground = lazy(List.selectionInactiveForeground)
|
||||||
|
[Monokai_Pro---Subtheme]Tree.selectionBackground = lazy(List.selectionBackground)
|
||||||
|
[Monokai_Pro---Subtheme]Separator.foreground = lazy(Slider.trackColor)
|
||||||
|
[Monokai_Pro---Subtheme]ToolBar.separatorColor = lazy(Slider.trackColor)
|
||||||
|
|
||||||
|
[Nord]*.inactiveForeground = #616E88
|
||||||
[Nord]MenuItem.checkBackground = @ijMenuCheckBackgroundL10
|
[Nord]MenuItem.checkBackground = @ijMenuCheckBackgroundL10
|
||||||
[Nord]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
|
[Nord]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
|
||||||
|
[Nord]List.selectionBackground = lazy(Tree.selectionBackground)
|
||||||
|
[Nord]List.selectionForeground = lazy(Tree.selectionForeground)
|
||||||
|
[Nord]Table.selectionBackground = lazy(Tree.selectionBackground)
|
||||||
|
[Nord]Table.selectionForeground = lazy(Tree.selectionForeground)
|
||||||
|
[Nord]TextField.selectionBackground = lazy(Tree.selectionBackground)
|
||||||
|
[Nord]TextField.selectionForeground = lazy(Tree.selectionForeground)
|
||||||
|
[Nord]Tree.selectionInactiveForeground = lazy(List.selectionInactiveForeground)
|
||||||
|
|
||||||
|
[NotReallyMDTheme]*.selectionInactiveBackground = #21384E
|
||||||
|
[NotReallyMDTheme]ToolBar.separatorColor = lazy(Separator.foreground)
|
||||||
|
|
||||||
|
[One_Dark]List.selectionInactiveForeground = lazy(Tree.selectionInactiveForeground)
|
||||||
[One_Dark]MenuItem.checkBackground = @ijMenuCheckBackgroundL10
|
[One_Dark]MenuItem.checkBackground = @ijMenuCheckBackgroundL10
|
||||||
[One_Dark]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
|
[One_Dark]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
|
||||||
|
[One_Dark]ProgressBar.background = lazy(Separator.foreground)
|
||||||
|
[One_Dark]Slider.trackColor = lazy(Separator.foreground)
|
||||||
[One_Dark]Slider.focusedColor = fade(#568af2,40%)
|
[One_Dark]Slider.focusedColor = fade(#568af2,40%)
|
||||||
|
[One_Dark]Table.background = lazy(Tree.background)
|
||||||
|
[One_Dark]Table.selectionBackground = lazy(Tree.selectionBackground)
|
||||||
|
[One_Dark]TextField.selectionBackground = lazy(List.selectionBackground)
|
||||||
|
[One_Dark]Tree.selectionForeground = lazy(List.selectionForeground)
|
||||||
|
|
||||||
|
[Solarized_Dark---4lex4]*.inactiveForeground = #657B83
|
||||||
[Solarized_Dark---4lex4]Component.accentColor = lazy(TabbedPane.underlineColor)
|
[Solarized_Dark---4lex4]Component.accentColor = lazy(TabbedPane.underlineColor)
|
||||||
|
[Solarized_Dark---4lex4]ComboBox.background = lazy(ComboBox.editableBackground)
|
||||||
|
[Solarized_Dark---4lex4]ComboBox.buttonBackground = lazy(ComboBox.editableBackground)
|
||||||
[Solarized_Dark---4lex4]Slider.focusedColor = fade($Component.focusColor,80%,derived)
|
[Solarized_Dark---4lex4]Slider.focusedColor = fade($Component.focusColor,80%,derived)
|
||||||
|
[Solarized_Dark---4lex4]ToolBar.separatorColor = lazy(Separator.foreground)
|
||||||
|
|
||||||
|
[Solarized_Light---4lex4]*.inactiveForeground = #839496
|
||||||
|
[Solarized_Light---4lex4]Button.default.hoverBackground = darken($Button.default.background,3%,derived)
|
||||||
[Solarized_Light---4lex4]Component.accentColor = lazy(TabbedPane.underlineColor)
|
[Solarized_Light---4lex4]Component.accentColor = lazy(TabbedPane.underlineColor)
|
||||||
|
|
||||||
|
[Spacegray]ComboBox.background = @ijTextBackgroundL4
|
||||||
|
[Spacegray]ComboBox.buttonBackground = @ijTextBackgroundL4
|
||||||
|
[Spacegray]TextField.background = @ijTextBackgroundL4
|
||||||
|
[Spacegray]TextField.selectionBackground = lazy(Tree.selectionBackground)
|
||||||
|
[Spacegray]TextField.selectionForeground = lazy(Tree.selectionForeground)
|
||||||
|
|
||||||
|
[vuesion-theme]*.disabledForeground = #8C8C8C
|
||||||
|
[vuesion-theme]*.disabledText = #8C8C8C
|
||||||
|
[vuesion-theme]*.inactiveForeground = #8C8C8C
|
||||||
[vuesion-theme]Component.accentColor = lazy(Button.default.endBackground)
|
[vuesion-theme]Component.accentColor = lazy(Button.default.endBackground)
|
||||||
[vuesion-theme]MenuItem.checkBackground = @ijMenuCheckBackgroundL10
|
[vuesion-theme]MenuItem.checkBackground = @ijMenuCheckBackgroundL10
|
||||||
[vuesion-theme]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
|
[vuesion-theme]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
|
||||||
@@ -222,6 +348,12 @@ ToggleButton.endBackground = $ToggleButton.background
|
|||||||
[vuesion-theme]Slider.trackColor = #303a45
|
[vuesion-theme]Slider.trackColor = #303a45
|
||||||
[vuesion-theme]Slider.thumbColor = #ececee
|
[vuesion-theme]Slider.thumbColor = #ececee
|
||||||
[vuesion-theme]Slider.focusedColor = fade(#ececee,20%)
|
[vuesion-theme]Slider.focusedColor = fade(#ececee,20%)
|
||||||
|
[vuesion-theme]ComboBox.background = @ijTextBackgroundL4
|
||||||
|
[vuesion-theme]ComboBox.buttonBackground = @ijTextBackgroundL4
|
||||||
|
[vuesion-theme]TextField.background = @ijTextBackgroundL4
|
||||||
|
[vuesion-theme]TextField.selectionBackground = lighten(#303A45,15%)
|
||||||
|
|
||||||
|
[Xcode-Dark]TextField.background = @ijTextBackgroundL4
|
||||||
|
|
||||||
|
|
||||||
# Material Theme UI Lite
|
# Material Theme UI Lite
|
||||||
@@ -231,62 +363,106 @@ ToggleButton.endBackground = $ToggleButton.background
|
|||||||
[dark][author-Mallowigi]MenuItem.checkBackground = @ijMenuCheckBackgroundL20
|
[dark][author-Mallowigi]MenuItem.checkBackground = @ijMenuCheckBackgroundL20
|
||||||
[dark][author-Mallowigi]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL20
|
[dark][author-Mallowigi]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL20
|
||||||
|
|
||||||
|
[author-Mallowigi]Tree.selectionInactiveBackground = lazy(List.selectionInactiveBackground)
|
||||||
|
|
||||||
|
[Arc_Dark]ComboBox.selectionBackground = lazy(List.selectionBackground)
|
||||||
|
[Arc_Dark]Table.selectionBackground = lazy(List.selectionBackground)
|
||||||
|
|
||||||
|
[Atom_One_Dark]Separator.foreground = lazy(Slider.trackColor)
|
||||||
|
[Atom_One_Dark]ToolBar.separatorColor = lazy(Slider.trackColor)
|
||||||
|
|
||||||
|
[Atom_One_Light]List.selectionBackground = lazy(Table.selectionBackground)
|
||||||
|
[Atom_One_Light]Tree.selectionBackground = lazy(Table.selectionBackground)
|
||||||
|
[Atom_One_Light]TabbedPane.contentAreaColor = lazy(Separator.foreground)
|
||||||
|
|
||||||
|
[Dracula---Mallowigi]*.selectionBackground = #44475A
|
||||||
|
[Dracula---Mallowigi]List.selectionInactiveForeground = lazy(Tree.selectionInactiveForeground)
|
||||||
[Dracula---Mallowigi]ProgressBar.selectionBackground = #fff
|
[Dracula---Mallowigi]ProgressBar.selectionBackground = #fff
|
||||||
[Dracula---Mallowigi]ProgressBar.selectionForeground = #fff
|
[Dracula---Mallowigi]ProgressBar.selectionForeground = #fff
|
||||||
|
[Dracula---Mallowigi]RadioButtonMenuItem.selectionForeground = lazy(CheckBoxMenuItem.selectionForeground)
|
||||||
[Dracula_Contrast]ProgressBar.selectionBackground = #fff
|
[Dracula---Mallowigi]Table.selectionForeground = lazy(List.selectionForeground)
|
||||||
[Dracula_Contrast]ProgressBar.selectionForeground = #fff
|
[Dracula---Mallowigi]Separator.foreground = lazy(Slider.trackColor)
|
||||||
|
[Dracula---Mallowigi]ToolBar.separatorColor = lazy(Slider.trackColor)
|
||||||
|
|
||||||
[GitHub]ProgressBar.selectionBackground = #222
|
[GitHub]ProgressBar.selectionBackground = #222
|
||||||
[GitHub]ProgressBar.selectionForeground = #222
|
[GitHub]ProgressBar.selectionForeground = #222
|
||||||
|
[GitHub]TextField.background = @ijTextBackgroundL3
|
||||||
|
[GitHub]List.selectionBackground = lazy(Table.selectionBackground)
|
||||||
|
[GitHub]Tree.selectionBackground = lazy(Table.selectionBackground)
|
||||||
|
|
||||||
[GitHub_Contrast]ProgressBar.selectionBackground = #222
|
[GitHub_Dark]ComboBox.selectionBackground = lazy(Tree.selectionBackground)
|
||||||
[GitHub_Contrast]ProgressBar.selectionForeground = #222
|
[GitHub_Dark]Table.selectionBackground = lazy(Tree.selectionBackground)
|
||||||
|
[GitHub_Dark]Separator.foreground = lazy(Slider.trackColor)
|
||||||
|
[GitHub_Dark]ToolBar.separatorColor = lazy(Slider.trackColor)
|
||||||
|
|
||||||
|
[Light_Owl]CheckBoxMenuItem.selectionForeground = lazy(CheckBoxMenuItem.foreground)
|
||||||
|
[Light_Owl]ComboBox.selectionForeground = lazy(ComboBox.foreground)
|
||||||
[Light_Owl]List.selectionInactiveForeground = lazy(List.foreground)
|
[Light_Owl]List.selectionInactiveForeground = lazy(List.foreground)
|
||||||
|
[Light_Owl]Menu.selectionForeground = lazy(Menu.foreground)
|
||||||
|
[Light_Owl]MenuBar.selectionForeground = lazy(MenuBar.foreground)
|
||||||
|
[Light_Owl]MenuItem.selectionForeground = lazy(MenuItem.foreground)
|
||||||
[Light_Owl]ProgressBar.selectionBackground = #111
|
[Light_Owl]ProgressBar.selectionBackground = #111
|
||||||
[Light_Owl]ProgressBar.selectionForeground = #fff
|
[Light_Owl]ProgressBar.selectionForeground = #fff
|
||||||
[Light_Owl]TabbedPane.selectedForeground = lazy(TabbedPane.foreground)
|
[Light_Owl]Spinner.selectionForeground = lazy(Spinner.foreground)
|
||||||
[Light_Owl]Table.selectionForeground = lazy(Table.foreground)
|
[Light_Owl]Table.selectionForeground = lazy(Table.foreground)
|
||||||
|
[Light_Owl]TextField.selectionForeground = lazy(TextField.foreground)
|
||||||
|
[Light_Owl]TextField.background = @ijTextBackgroundL3
|
||||||
|
[Light_Owl]List.selectionBackground = lazy(Table.selectionBackground)
|
||||||
|
[Light_Owl]Tree.selectionBackground = lazy(Table.selectionBackground)
|
||||||
|
|
||||||
[Light_Owl_Contrast]List.selectionInactiveForeground = lazy(List.foreground)
|
[Material_Darker]*.selectionBackground = lighten(#2D2D2D,15%)
|
||||||
[Light_Owl_Contrast]ProgressBar.selectionBackground = #111
|
[Material_Darker]Separator.foreground = lazy(Slider.trackColor)
|
||||||
[Light_Owl_Contrast]ProgressBar.selectionForeground = #fff
|
[Material_Darker]ToolBar.separatorColor = lazy(Slider.trackColor)
|
||||||
[Light_Owl_Contrast]TabbedPane.selectedForeground = lazy(TabbedPane.foreground)
|
|
||||||
[Light_Owl_Contrast]Table.selectionForeground = lazy(Table.foreground)
|
|
||||||
|
|
||||||
|
[Material_Deep_Ocean]*.selectionBackground = lighten(#222533,15%)
|
||||||
|
[Material_Deep_Ocean]Separator.foreground = lazy(Slider.trackColor)
|
||||||
|
[Material_Deep_Ocean]ToolBar.separatorColor = lazy(Slider.trackColor)
|
||||||
|
|
||||||
|
[Material_Lighter]List.selectionInactiveForeground = lazy(Tree.selectionInactiveForeground)
|
||||||
[Material_Lighter]ProgressBar.selectionBackground = #222
|
[Material_Lighter]ProgressBar.selectionBackground = #222
|
||||||
[Material_Lighter]ProgressBar.selectionForeground = #fff
|
[Material_Lighter]ProgressBar.selectionForeground = #fff
|
||||||
|
[Material_Lighter]ComboBox.selectionBackground = lazy(List.selectionBackground)
|
||||||
[Material_Lighter_Contrast]ProgressBar.selectionBackground = #222
|
[Material_Lighter]Table.selectionBackground = lazy(List.selectionBackground)
|
||||||
[Material_Lighter_Contrast]ProgressBar.selectionForeground = #fff
|
[Material_Lighter]List.selectionForeground = lazy(Table.selectionForeground)
|
||||||
|
[Material_Lighter]RadioButtonMenuItem.selectionForeground = lazy(Table.selectionForeground)
|
||||||
|
[Material_Lighter]Tree.selectionForeground = lazy(Table.selectionForeground)
|
||||||
|
|
||||||
[Material_Oceanic]ProgressBar.selectionBackground = #ddd
|
[Material_Oceanic]ProgressBar.selectionBackground = #ddd
|
||||||
[Material_Oceanic]ProgressBar.selectionForeground = #ddd
|
[Material_Oceanic]ProgressBar.selectionForeground = #ddd
|
||||||
|
[Material_Oceanic]Separator.foreground = lazy(Slider.trackColor)
|
||||||
[Material_Oceanic_Contrast]ProgressBar.selectionBackground = #ddd
|
[Material_Oceanic]ToolBar.separatorColor = lazy(Slider.trackColor)
|
||||||
[Material_Oceanic_Contrast]ProgressBar.selectionForeground = #ddd
|
|
||||||
|
|
||||||
[Material_Palenight]ProgressBar.selectionBackground = #ddd
|
[Material_Palenight]ProgressBar.selectionBackground = #ddd
|
||||||
[Material_Palenight]ProgressBar.selectionForeground = #ddd
|
[Material_Palenight]ProgressBar.selectionForeground = #ddd
|
||||||
|
[Material_Palenight]List.selectionBackground = lazy(Table.selectionBackground)
|
||||||
|
[Material_Palenight]Tree.selectionBackground = lazy(Table.selectionBackground)
|
||||||
|
[Material_Palenight]Separator.foreground = lazy(Slider.trackColor)
|
||||||
|
[Material_Palenight]ToolBar.separatorColor = lazy(Slider.trackColor)
|
||||||
|
|
||||||
[Material_Palenight_Contrast]ProgressBar.selectionBackground = #ddd
|
[Monokai_Pro---Mallowigi]List.selectionForeground = lazy(Table.selectionForeground)
|
||||||
[Material_Palenight_Contrast]ProgressBar.selectionForeground = #ddd
|
[Monokai_Pro---Mallowigi]RadioButtonMenuItem.selectionForeground = lazy(Table.selectionForeground)
|
||||||
|
[Monokai_Pro---Mallowigi]Table.selectionInactiveForeground = lazy(List.selectionInactiveForeground)
|
||||||
|
[Monokai_Pro---Mallowigi]Tree.selectionForeground = lazy(Table.selectionForeground)
|
||||||
|
[Monokai_Pro---Mallowigi]Tree.selectionInactiveForeground = lazy(List.selectionInactiveForeground)
|
||||||
|
[Monokai_Pro---Mallowigi]Separator.foreground = lazy(Slider.trackColor)
|
||||||
|
[Monokai_Pro---Mallowigi]ToolBar.separatorColor = lazy(Slider.trackColor)
|
||||||
|
|
||||||
|
[Moonlight]ComboBox.selectionBackground = lazy(List.selectionBackground)
|
||||||
|
[Moonlight]Table.selectionBackground = lazy(List.selectionBackground)
|
||||||
|
[Moonlight]Separator.foreground = lazy(Slider.trackColor)
|
||||||
|
[Moonlight]ToolBar.separatorColor = lazy(Slider.trackColor)
|
||||||
|
|
||||||
[Night_Owl]ProgressBar.selectionBackground = #ddd
|
[Night_Owl]ProgressBar.selectionBackground = #ddd
|
||||||
[Night_Owl]ProgressBar.selectionForeground = #ddd
|
[Night_Owl]ProgressBar.selectionForeground = #ddd
|
||||||
|
|
||||||
[Night_Owl_Contrast]ProgressBar.selectionBackground = #ddd
|
|
||||||
[Night_Owl_Contrast]ProgressBar.selectionForeground = #ddd
|
|
||||||
|
|
||||||
[Solarized_Dark---Mallowigi]ProgressBar.selectionBackground = #ccc
|
[Solarized_Dark---Mallowigi]ProgressBar.selectionBackground = #ccc
|
||||||
[Solarized_Dark---Mallowigi]ProgressBar.selectionForeground = #ccc
|
[Solarized_Dark---Mallowigi]ProgressBar.selectionForeground = #ccc
|
||||||
|
[Solarized_Dark---Mallowigi]Separator.foreground = lazy(Slider.trackColor)
|
||||||
[Solarized_Dark_Contrast]ProgressBar.selectionBackground = #ccc
|
[Solarized_Dark---Mallowigi]ToolBar.separatorColor = lazy(Slider.trackColor)
|
||||||
[Solarized_Dark_Contrast]ProgressBar.selectionForeground = #ccc
|
|
||||||
|
|
||||||
[Solarized_Light---Mallowigi]ProgressBar.selectionBackground = #222
|
[Solarized_Light---Mallowigi]ProgressBar.selectionBackground = #222
|
||||||
[Solarized_Light---Mallowigi]ProgressBar.selectionForeground = #fff
|
[Solarized_Light---Mallowigi]ProgressBar.selectionForeground = #fff
|
||||||
|
[Solarized_Light---Mallowigi]ComboBox.selectionBackground = lazy(List.selectionBackground)
|
||||||
[Solarized_Light_Contrast]ProgressBar.selectionBackground = #222
|
[Solarized_Light---Mallowigi]Table.selectionBackground = lazy(List.selectionBackground)
|
||||||
[Solarized_Light_Contrast]ProgressBar.selectionForeground = #fff
|
[Solarized_Light---Mallowigi]Separator.foreground = lazy(Slider.trackColor)
|
||||||
|
[Solarized_Light---Mallowigi]ToolBar.separatorColor = lazy(Slider.trackColor)
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -12,42 +12,6 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
|
|
||||||
#---- FileChooser ----
|
|
||||||
|
|
||||||
#fields
|
|
||||||
FileChooser.lookInLabel.textAndMnemonic = Look &In:
|
|
||||||
FileChooser.saveInLabelText = Save In:
|
|
||||||
FileChooser.fileNameLabel.textAndMnemonic = File &Name:
|
|
||||||
FileChooser.folderNameLabel.textAndMnemonic = Folder &name:
|
|
||||||
FileChooser.filesOfTypeLabel.textAndMnemonic = Files of &Type:
|
|
||||||
|
|
||||||
# toolbar
|
|
||||||
FileChooser.upFolderToolTipText = Up One Level
|
|
||||||
FileChooser.upFolderAccessibleName = Up
|
|
||||||
FileChooser.homeFolderToolTipText = Home
|
|
||||||
FileChooser.homeFolderAccessibleName = Home
|
|
||||||
FileChooser.newFolderToolTipText = Create New Folder
|
|
||||||
FileChooser.newFolderAccessibleName = New Folder
|
|
||||||
FileChooser.listViewButtonToolTipText = List
|
|
||||||
FileChooser.listViewButtonAccessibleName = List
|
|
||||||
FileChooser.detailsViewButtonToolTipText = Details
|
|
||||||
FileChooser.detailsViewButtonAccessibleName = Details
|
|
||||||
|
|
||||||
# details table header
|
|
||||||
FileChooser.fileNameHeaderText = Name
|
|
||||||
FileChooser.fileSizeHeaderText = Size
|
|
||||||
FileChooser.fileTypeHeaderText = Type
|
|
||||||
FileChooser.fileDateHeaderText = Modified
|
|
||||||
FileChooser.fileAttrHeaderText = Attributes
|
|
||||||
|
|
||||||
# popup menu
|
|
||||||
FileChooser.viewMenuLabelText = View
|
|
||||||
FileChooser.refreshActionLabelText = Refresh
|
|
||||||
FileChooser.newFolderActionLabelText = New Folder
|
|
||||||
FileChooser.listViewActionLabelText = List
|
|
||||||
FileChooser.detailsViewActionLabelText = Details
|
|
||||||
|
|
||||||
|
|
||||||
#---- SplitPaneDivider ----
|
#---- SplitPaneDivider ----
|
||||||
|
|
||||||
SplitPaneDivider.collapseLeftToolTipText = Collapse Left Pane
|
SplitPaneDivider.collapseLeftToolTipText = Collapse Left Pane
|
||||||
|
|||||||
@@ -12,42 +12,6 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
|
|
||||||
#---- FileChooser ----
|
|
||||||
|
|
||||||
#fields
|
|
||||||
FileChooser.lookInLabel.textAndMnemonic = Suchen &in:
|
|
||||||
FileChooser.saveInLabelText = Speichern in:
|
|
||||||
FileChooser.fileNameLabel.textAndMnemonic = &Dateiname:
|
|
||||||
FileChooser.folderNameLabel.textAndMnemonic = Ordner&name:
|
|
||||||
FileChooser.filesOfTypeLabel.textAndMnemonic = Datei&typ:
|
|
||||||
|
|
||||||
# toolbar
|
|
||||||
FileChooser.upFolderToolTipText = Eine Ebene h\u00F6her
|
|
||||||
FileChooser.upFolderAccessibleName = Nach oben
|
|
||||||
FileChooser.homeFolderToolTipText = Home
|
|
||||||
FileChooser.homeFolderAccessibleName = Home
|
|
||||||
FileChooser.newFolderToolTipText = Neuen Ordner erstellen
|
|
||||||
FileChooser.newFolderAccessibleName = Neuer Ordner
|
|
||||||
FileChooser.listViewButtonToolTipText = Liste
|
|
||||||
FileChooser.listViewButtonAccessibleName = Liste
|
|
||||||
FileChooser.detailsViewButtonToolTipText = Details
|
|
||||||
FileChooser.detailsViewButtonAccessibleName = Details
|
|
||||||
|
|
||||||
# details table header
|
|
||||||
FileChooser.fileNameHeaderText = Name
|
|
||||||
FileChooser.fileSizeHeaderText = Gr\u00F6\u00DFe
|
|
||||||
FileChooser.fileTypeHeaderText = Typ
|
|
||||||
FileChooser.fileDateHeaderText = \u00C4nderungsdatum
|
|
||||||
FileChooser.fileAttrHeaderText = Attribute
|
|
||||||
|
|
||||||
# popup menu
|
|
||||||
FileChooser.viewMenuLabelText = Ansicht
|
|
||||||
FileChooser.refreshActionLabelText = Aktualisieren
|
|
||||||
FileChooser.newFolderActionLabelText = Neuer Ordner
|
|
||||||
FileChooser.listViewActionLabelText = Liste
|
|
||||||
FileChooser.detailsViewActionLabelText = Details
|
|
||||||
|
|
||||||
|
|
||||||
#---- TabbedPane ----
|
#---- TabbedPane ----
|
||||||
|
|
||||||
TabbedPane.moreTabsButtonToolTipText = Verdeckte Tabs anzeigen
|
TabbedPane.moreTabsButtonToolTipText = Verdeckte Tabs anzeigen
|
||||||
|
|||||||
@@ -12,42 +12,6 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
|
|
||||||
#---- FileChooser ----
|
|
||||||
|
|
||||||
#fields
|
|
||||||
FileChooser.lookInLabel.textAndMnemonic = Buscar &en:
|
|
||||||
FileChooser.saveInLabelText = Guardar en:
|
|
||||||
FileChooser.fileNameLabel.textAndMnemonic = &Nombre de fichero:
|
|
||||||
FileChooser.folderNameLabel.textAndMnemonic = &Nombre de carpeta:
|
|
||||||
FileChooser.filesOfTypeLabel.textAndMnemonic = Ficheros de &Tipo:
|
|
||||||
|
|
||||||
# toolbar
|
|
||||||
FileChooser.upFolderToolTipText = Subir un nivel
|
|
||||||
FileChooser.upFolderAccessibleName = Subir
|
|
||||||
FileChooser.homeFolderToolTipText = Inicio
|
|
||||||
FileChooser.homeFolderAccessibleName = Inicio
|
|
||||||
FileChooser.newFolderToolTipText = Crear nueva carpeta
|
|
||||||
FileChooser.newFolderAccessibleName = Nueva carpeta
|
|
||||||
FileChooser.listViewButtonToolTipText = Lista
|
|
||||||
FileChooser.listViewButtonAccessibleName = Lista
|
|
||||||
FileChooser.detailsViewButtonToolTipText = Detalles
|
|
||||||
FileChooser.detailsViewButtonAccessibleName = Detalles
|
|
||||||
|
|
||||||
# details table header
|
|
||||||
FileChooser.fileNameHeaderText = Nombre
|
|
||||||
FileChooser.fileSizeHeaderText = Tama\u00F1o
|
|
||||||
FileChooser.fileTypeHeaderText = Tipo
|
|
||||||
FileChooser.fileDateHeaderText = Modificado
|
|
||||||
FileChooser.fileAttrHeaderText = Atributos
|
|
||||||
|
|
||||||
# popup menu
|
|
||||||
FileChooser.viewMenuLabelText = Ver
|
|
||||||
FileChooser.refreshActionLabelText = Refrescar
|
|
||||||
FileChooser.newFolderActionLabelText = Nueva carpeta
|
|
||||||
FileChooser.listViewActionLabelText = Lista
|
|
||||||
FileChooser.detailsViewActionLabelText = Detalles
|
|
||||||
|
|
||||||
|
|
||||||
#---- SplitPaneDivider ----
|
#---- SplitPaneDivider ----
|
||||||
|
|
||||||
SplitPaneDivider.collapseLeftToolTipText = Contraer Panel Izquierdo
|
SplitPaneDivider.collapseLeftToolTipText = Contraer Panel Izquierdo
|
||||||
|
|||||||
@@ -12,37 +12,3 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
|
|
||||||
#---- FileChooser ----
|
|
||||||
|
|
||||||
#fields
|
|
||||||
FileChooser.lookInLabel.textAndMnemonic = Rechercher &dans:
|
|
||||||
FileChooser.saveInLabelText = Enregistrer dans:
|
|
||||||
FileChooser.fileNameLabel.textAndMnemonic = &Nom du fichier:
|
|
||||||
FileChooser.folderNameLabel.textAndMnemonic = &Nom du dossier:
|
|
||||||
FileChooser.filesOfTypeLabel.textAndMnemonic = &Type de fichier:
|
|
||||||
|
|
||||||
# toolbar
|
|
||||||
FileChooser.upFolderToolTipText = Remonte d'un niveau
|
|
||||||
FileChooser.upFolderAccessibleName = Monter
|
|
||||||
FileChooser.homeFolderToolTipText = R\u00E9pertoire de base
|
|
||||||
FileChooser.homeFolderAccessibleName = R\u00E9pertoire de base
|
|
||||||
FileChooser.newFolderToolTipText = Cr\u00E9e un dossier
|
|
||||||
FileChooser.newFolderAccessibleName = Nouveau dossier
|
|
||||||
FileChooser.listViewButtonToolTipText = Liste
|
|
||||||
FileChooser.listViewButtonAccessibleName = Liste
|
|
||||||
FileChooser.detailsViewButtonToolTipText = D\u00E9tails
|
|
||||||
FileChooser.detailsViewButtonAccessibleName = D\u00E9tails
|
|
||||||
|
|
||||||
# details table header
|
|
||||||
FileChooser.fileNameHeaderText = Nom
|
|
||||||
FileChooser.fileSizeHeaderText = Taille
|
|
||||||
FileChooser.fileTypeHeaderText = Type
|
|
||||||
FileChooser.fileDateHeaderText = Modifi\u00E9
|
|
||||||
FileChooser.fileAttrHeaderText = Attributs
|
|
||||||
|
|
||||||
# popup menu
|
|
||||||
FileChooser.viewMenuLabelText = Affichage
|
|
||||||
FileChooser.refreshActionLabelText = Actualiser
|
|
||||||
FileChooser.newFolderActionLabelText = Nouveau dossier
|
|
||||||
FileChooser.listViewActionLabelText = Liste
|
|
||||||
FileChooser.detailsViewActionLabelText = D\u00E9tails
|
|
||||||
|
|||||||
@@ -67,11 +67,11 @@
|
|||||||
@nsControlAccentColor = #007aff
|
@nsControlAccentColor = #007aff
|
||||||
|
|
||||||
# accent colors are:
|
# accent colors are:
|
||||||
# @nsSelectedTextBackgroundColor
|
# @nsSelectedTextBackgroundColor for @textSelectionBackground
|
||||||
# @nsSelectedContentBackgroundColor
|
# @nsSelectedContentBackgroundColor for @selectionBackground
|
||||||
# @nsSelectedControlColor
|
# @nsSelectedControlColor unused
|
||||||
# @nsKeyboardFocusIndicatorColor
|
# @nsKeyboardFocusIndicatorColor for @accentFocusColor
|
||||||
# @nsControlAccentColor
|
# @nsControlAccentColor for @accentColor
|
||||||
|
|
||||||
|
|
||||||
#---- variables ----
|
#---- variables ----
|
||||||
@@ -88,12 +88,12 @@
|
|||||||
@menuBackground = lighten(@background,8%)
|
@menuBackground = lighten(@background,8%)
|
||||||
|
|
||||||
# selection
|
# selection
|
||||||
@selectionBackground = if(systemColor(accent), shade(spin(systemColor(accent),4),20%), @nsSelectedContentBackgroundColor)
|
@selectionBackground = shade(spin(if(systemColor(accent), systemColor(accent), @accentColor),4),20%)
|
||||||
@selectionForeground = @nsSelectedMenuItemTextColor
|
@selectionForeground = @nsSelectedMenuItemTextColor
|
||||||
@selectionInactiveBackground = @nsUnemphasizedSelectedContentBackgroundColor
|
@selectionInactiveBackground = @nsUnemphasizedSelectedContentBackgroundColor
|
||||||
|
|
||||||
# text selection
|
# text selection
|
||||||
@textSelectionBackground = systemColor(highlight,if(systemColor(accent), darken(desaturate(systemColor(accent),60%),10%), @nsSelectedTextBackgroundColor))
|
@textSelectionBackground = systemColor(highlight,darken(desaturate(if(systemColor(accent), systemColor(accent), @accentColor),60%),10%))
|
||||||
@textSelectionForeground = @nsSelectedTextColor
|
@textSelectionForeground = @nsSelectedTextColor
|
||||||
|
|
||||||
# menu
|
# menu
|
||||||
@@ -102,7 +102,7 @@
|
|||||||
|
|
||||||
# accent colors (blueish)
|
# accent colors (blueish)
|
||||||
@accentColor = systemColor(accent,@nsControlAccentColor)
|
@accentColor = systemColor(accent,@nsControlAccentColor)
|
||||||
@accentFocusColor = if(systemColor(accent), fade(spin(systemColor(accent),-10),50%), @nsKeyboardFocusIndicatorColor)
|
@accentFocusColor = fade(lighten(spin(if(systemColor(accent), systemColor(accent), @accentColor),-8),5%),50%)
|
||||||
|
|
||||||
|
|
||||||
#---- Button ----
|
#---- Button ----
|
||||||
@@ -149,6 +149,7 @@ ComboBox.selectionBackground = @menuSelectionBackground
|
|||||||
ComboBox.popupInsets = 5,0,5,0
|
ComboBox.popupInsets = 5,0,5,0
|
||||||
ComboBox.selectionInsets = 0,5,0,5
|
ComboBox.selectionInsets = 0,5,0,5
|
||||||
ComboBox.selectionArc = 8
|
ComboBox.selectionArc = 8
|
||||||
|
ComboBox.borderCornerRadius = 8
|
||||||
|
|
||||||
|
|
||||||
#---- Component ----
|
#---- Component ----
|
||||||
@@ -205,6 +206,7 @@ PasswordField.selectionForeground = @textSelectionForeground
|
|||||||
#---- PopupMenu ----
|
#---- PopupMenu ----
|
||||||
|
|
||||||
PopupMenu.borderInsets = 6,1,6,1
|
PopupMenu.borderInsets = 6,1,6,1
|
||||||
|
PopupMenu.borderCornerRadius = 8
|
||||||
|
|
||||||
|
|
||||||
#---- ProgressBar ----
|
#---- ProgressBar ----
|
||||||
@@ -259,6 +261,13 @@ Spinner.buttonPressedArrowColor = lighten($Spinner.buttonArrowColor,20%,derived
|
|||||||
Spinner.buttonSeparatorWidth = 0
|
Spinner.buttonSeparatorWidth = 0
|
||||||
|
|
||||||
|
|
||||||
|
#---- TabbedPane ----
|
||||||
|
|
||||||
|
TabbedPane.tabArc = $Button.arc
|
||||||
|
TabbedPane.tabSelectionArc = 999
|
||||||
|
TabbedPane.cardTabArc = $Button.arc
|
||||||
|
|
||||||
|
|
||||||
#---- TextArea ---
|
#---- TextArea ---
|
||||||
|
|
||||||
TextArea.disabledBackground = @disabledComponentBackground
|
TextArea.disabledBackground = @disabledComponentBackground
|
||||||
@@ -286,3 +295,8 @@ ToggleButton.disabledBackground = $Button.disabledBackground
|
|||||||
ToggleButton.selectedBackground = lighten($ToggleButton.background,20%,derived)
|
ToggleButton.selectedBackground = lighten($ToggleButton.background,20%,derived)
|
||||||
|
|
||||||
ToggleButton.toolbar.selectedBackground = #fff3
|
ToggleButton.toolbar.selectedBackground = #fff3
|
||||||
|
|
||||||
|
|
||||||
|
#---- ToolBar ----
|
||||||
|
|
||||||
|
ToolBar.hoverButtonGroupArc = 14
|
||||||
|
|||||||
@@ -67,11 +67,11 @@
|
|||||||
@nsControlAccentColor = #007aff
|
@nsControlAccentColor = #007aff
|
||||||
|
|
||||||
# accent colors are:
|
# accent colors are:
|
||||||
# @nsSelectedTextBackgroundColor
|
# @nsSelectedTextBackgroundColor for @textSelectionBackground
|
||||||
# @nsSelectedContentBackgroundColor
|
# @nsSelectedContentBackgroundColor for @selectionBackground
|
||||||
# @nsSelectedControlColor
|
# @nsSelectedControlColor unused
|
||||||
# @nsKeyboardFocusIndicatorColor
|
# @nsKeyboardFocusIndicatorColor for @accentFocusColor
|
||||||
# @nsControlAccentColor
|
# @nsControlAccentColor for @accentColor
|
||||||
|
|
||||||
|
|
||||||
#---- variables ----
|
#---- variables ----
|
||||||
@@ -88,12 +88,12 @@
|
|||||||
@menuBackground = darken(@background,4%)
|
@menuBackground = darken(@background,4%)
|
||||||
|
|
||||||
# selection
|
# selection
|
||||||
@selectionBackground = if(systemColor(accent), shade(spin(systemColor(accent),4),10%), @nsSelectedContentBackgroundColor)
|
@selectionBackground = shade(spin(if(systemColor(accent), systemColor(accent), @accentColor),4),10%)
|
||||||
@selectionForeground = @nsSelectedMenuItemTextColor
|
@selectionForeground = @nsSelectedMenuItemTextColor
|
||||||
@selectionInactiveBackground = @nsUnemphasizedSelectedContentBackgroundColor
|
@selectionInactiveBackground = @nsUnemphasizedSelectedContentBackgroundColor
|
||||||
|
|
||||||
# text selection
|
# text selection
|
||||||
@textSelectionBackground = systemColor(highlight,if(systemColor(accent), tint(systemColor(accent),70%), @nsSelectedTextBackgroundColor))
|
@textSelectionBackground = systemColor(highlight,tint(if(systemColor(accent), systemColor(accent), @accentColor),70%))
|
||||||
@textSelectionForeground = @foreground
|
@textSelectionForeground = @foreground
|
||||||
|
|
||||||
# menu
|
# menu
|
||||||
@@ -103,7 +103,7 @@
|
|||||||
|
|
||||||
# accent colors (blueish)
|
# accent colors (blueish)
|
||||||
@accentColor = systemColor(accent,@nsControlAccentColor)
|
@accentColor = systemColor(accent,@nsControlAccentColor)
|
||||||
@accentFocusColor = if(systemColor(accent), fade(spin(systemColor(accent),4),50%), @nsKeyboardFocusIndicatorColor)
|
@accentFocusColor = fade(spin(if(systemColor(accent), systemColor(accent), @accentColor),4),50%)
|
||||||
|
|
||||||
|
|
||||||
#---- Button ----
|
#---- Button ----
|
||||||
@@ -150,6 +150,7 @@ ComboBox.selectionBackground = @menuSelectionBackground
|
|||||||
ComboBox.popupInsets = 5,0,5,0
|
ComboBox.popupInsets = 5,0,5,0
|
||||||
ComboBox.selectionInsets = 0,5,0,5
|
ComboBox.selectionInsets = 0,5,0,5
|
||||||
ComboBox.selectionArc = 8
|
ComboBox.selectionArc = 8
|
||||||
|
ComboBox.borderCornerRadius = 8
|
||||||
|
|
||||||
|
|
||||||
#---- Component ----
|
#---- Component ----
|
||||||
@@ -206,6 +207,7 @@ PasswordField.selectionForeground = @textSelectionForeground
|
|||||||
#---- PopupMenu ----
|
#---- PopupMenu ----
|
||||||
|
|
||||||
PopupMenu.borderInsets = 6,1,6,1
|
PopupMenu.borderInsets = 6,1,6,1
|
||||||
|
PopupMenu.borderCornerRadius = 8
|
||||||
|
|
||||||
|
|
||||||
#---- ProgressBar ----
|
#---- ProgressBar ----
|
||||||
@@ -258,6 +260,13 @@ Spinner.buttonHoverArrowColor = lighten($Spinner.buttonArrowColor,20%,derived no
|
|||||||
Spinner.buttonPressedArrowColor = lighten($Spinner.buttonArrowColor,30%,derived noAutoInverse)
|
Spinner.buttonPressedArrowColor = lighten($Spinner.buttonArrowColor,30%,derived noAutoInverse)
|
||||||
|
|
||||||
|
|
||||||
|
#---- TabbedPane ----
|
||||||
|
|
||||||
|
TabbedPane.tabArc = $Button.arc
|
||||||
|
TabbedPane.tabSelectionArc = 999
|
||||||
|
TabbedPane.cardTabArc = $Button.arc
|
||||||
|
|
||||||
|
|
||||||
#---- TextArea ---
|
#---- TextArea ---
|
||||||
|
|
||||||
TextArea.disabledBackground = @disabledComponentBackground
|
TextArea.disabledBackground = @disabledComponentBackground
|
||||||
@@ -282,3 +291,8 @@ TextPane.selectionForeground = @textSelectionForeground
|
|||||||
#---- ToggleButton ----
|
#---- ToggleButton ----
|
||||||
|
|
||||||
ToggleButton.disabledBackground = $Button.disabledBackground
|
ToggleButton.disabledBackground = $Button.disabledBackground
|
||||||
|
|
||||||
|
|
||||||
|
#---- ToolBar ----
|
||||||
|
|
||||||
|
ToolBar.hoverButtonGroupArc = 14
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user