Compare commits

..

112 Commits
3.1 ... 3.2.4

Author SHA1 Message Date
Karl Tauber
97d290795e release 3.2.4 2023-10-21 18:23:17 +02:00
Karl Tauber
2a237ff5fc Popup: fixed potential NPE in (unusual) case that the popup invoker is null (only on Linux with Wayland and Java 21; regression in 3.2.3) (issue #752) 2023-10-21 18:21:59 +02:00
Karl Tauber
13a418f74e release 3.2.3 2023-10-21 17:11:32 +02:00
Karl Tauber
5c56dbfed6 Popup: popups that request focus were not shown on Linux with Wayland and Java 21 (issue #752) 2023-10-21 17:04:22 +02:00
Karl Tauber
0d2f37e1da release 3.2.2 2023-10-15 18:12:11 +02:00
Karl Tauber
0494c2161c FileChooser: avoid unnecessary logging of InaccessibleObjectException when running in Java 16 (issue #741) 2023-10-15 18:00:33 +02:00
Karl Tauber
635a620439 jsvg: updated to 1.2.0 2023-10-15 16:42:15 +02:00
Karl Tauber
0a7c76ec72 GitHub Actions:
- build using Java 21 (use toolchain because Gradle 8.4 does not support running on Java 21)
- no longer build on Java 19 and 20
2023-10-15 16:38:28 +02:00
Karl Tauber
9ad8fb38e8 update to Gradle 8.4 2023-10-15 16:34:42 +02:00
Karl Tauber
1dbe968952 TabbedPane: fixed NPE when using focusable component as tab component and switching theme (issue #745) 2023-10-15 11:43:58 +02:00
Karl Tauber
460b6492cb Button: fixed painting icon and text at wrong location when using HTML text, left/right vertical alignment and running in Java 19+ (issue #746) 2023-10-14 19:16:23 +02:00
Karl Tauber
67b0faa9ae Merge PR #738: Fix typo 2023-09-28 16:25:11 +02:00
Karl Tauber
5553425a1a CheckBox and RadioButton: fixed cut off right side when border is removed and horizontal alignment is set to right (issue #734) 2023-09-28 16:22:52 +02:00
valerakostin
8ff516e43a Fix typo 2023-09-22 11:14:50 +02:00
Karl Tauber
b6207bafde release 3.2.1 2023-09-04 13:22:50 +02:00
Karl Tauber
b9f43fd560 jsvg: updated to 1.1.0 2023-09-04 13:13:14 +02:00
Karl Tauber
c617d9f569 Theme Editor: removed shapshot download link from README.md 2023-09-04 13:09:49 +02:00
Karl Tauber
9efb9761c6 MultiResolutionImageSupport optimizations:
- ProducerMultiResolutionImage: avoid creation of base image to get image width and height, because if screen is scaled then the base image would be never painted, but consumes memory and takes time to create it
- MappedMultiResolutionImage: delegate getting width/height/source/property to original image, to defer/avoid creation of mapped image
2023-09-04 13:08:21 +02:00
Karl Tauber
03f9115fbf MultiResolutionImageSupport: fixed memory leak in create(int,Dimension[],Function<Dimension,Image>) (issue #726) 2023-09-04 12:22:40 +02:00
Karl Tauber
a2859cedb5 Popop: fixed drop shadow if popup overlaps a heavyweight component (Windows 10 only; issue #626) 2023-09-02 12:48:46 +02:00
Karl Tauber
cdee0594f8 TextField: fixed placeholder text painting, which did not respect horizontal alignment property of JTextField (issue #721) 2023-08-27 16:30:16 +02:00
Karl Tauber
808833d749 UIDefaultsDump: dump action maps (ActionMap) 2023-08-25 14:02:22 +02:00
Karl Tauber
581c64b601 FileChooser: fixed occasional NPE in FlatShortcutsPanel on Windows (issue #718) 2023-08-23 19:40:59 +02:00
Karl Tauber
c953ff84d0 added explicit file encoding for Eclipse projects 2023-08-12 22:45:02 +02:00
Karl Tauber
96cd207df3 README.md: minor updates 2023-08-12 17:04:21 +02:00
Karl Tauber
7a75f62a6a README.md: new applications using FlatLaf:
- Constellation
- Ghidra
- jadx
- muCommander
- Guiffy
- HashGarten
- MediathekView
- Astah
- Big Faceless (BFO) PDF Viewer
- Chatty
- BGBlitz
- Linux Task Manager (LTM)
2023-08-12 16:35:00 +02:00
Karl Tauber
61e5fe58c2 README.md: organized applications using FlatLaf into categories 2023-08-12 15:57:32 +02:00
Karl Tauber
1a3baba702 README.md: removed versions and 'New' badge from applications using FlatLaf 2023-08-12 14:04:23 +02:00
Karl Tauber
58dc14bb46 Gradle: use System.getProperty( "org.gradle.parallel" ) instead of rootProject.property( "org.gradle.parallel" ) because this did not work with VM command-line option -Dorg.gradle.parallel=false 2023-08-12 13:38:42 +02:00
Karl Tauber
a5b7e04943 Gradle: check whether parallel build is enabled when running 'publish' task
https://stackoverflow.com/questions/72664149/gradle-maven-publish-sonatype-creates-multiple-repositories-that-cant-be-clos
2023-08-12 13:23:11 +02:00
Karl Tauber
22f2aa5475 README.md: introduced "Sponsor" badge icon
SVGO option `convertPathData` enabled
2023-08-11 13:21:56 +02:00
Karl Tauber
d4e9cb12be updated sigtest for FlatLaf 3.2
(generated in clean workspace with gradle task `sigtestGenerate`)
2023-08-10 23:31:26 +02:00
Karl Tauber
75da361480 GitHub Actions: disable parallel build for publishing to maven central; otherwise two staging repos are created, which can not be closed and released
https://stackoverflow.com/questions/72664149/gradle-maven-publish-sonatype-creates-multiple-repositories-that-cant-be-clos
2023-08-10 19:31:55 +02:00
Karl Tauber
7488bcb7b0 update to Gradle 8.2.1 2023-08-10 19:06:10 +02:00
Karl Tauber
1b1a9be107 release 3.2 2023-08-10 18:34:38 +02:00
Karl Tauber
db2f94aa53 IntelliJ Themes: fixed Table background in "One Dark" theme 2023-08-10 16:06:11 +02:00
Karl Tauber
810146b993 Demo: auto-reload current theme in development environment if .properties files have changed 2023-08-09 14:22:05 +02:00
Karl Tauber
93091662ab IntelliJ Themes: fixed colors for selection background/foreground, Separator, Slider track and ProgressBar background in various themes 2023-08-09 13:58:40 +02:00
Karl Tauber
d349227fbf IntelliJ Themes: fixed wrong disabled text colors in "Dark Flat", "Hiberbee Dark", "Light Flat", "Nord", "Solarized Dark" and "Solarized Light" themes 2023-08-08 17:13:30 +02:00
Karl Tauber
c9423e3aa8 CHANGELOG.md: fixed type on previous commit 2023-08-07 20:00:00 +02:00
Karl Tauber
b9737ca4f1 Merge PR #709: x86: Narrow version range for not using system icons 2023-08-07 19:55:11 +02:00
Karl Tauber
4b4990635d 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) 2023-08-07 19:35:04 +02:00
Karl Tauber
afaa2c8c78 FileChooser: show localized text for all locales supported by Metal (issue #680) 2023-08-06 18:35:25 +02:00
Karl Tauber
f506ef0d4f Theme Editor: improve order of directories in combobox 2023-08-06 18:34:29 +02:00
Sung Ho Yoon
d30fe66cac Narrow version range for not using system icons 2023-08-06 09:35:00 +09:00
Karl Tauber
270e998e86 Theme Editor:
- fixed missing icon on "open" button (regression in commit 35fa3197c8)
- added icons to "File" menu for add and save actions
2023-08-05 19:18:51 +02:00
Karl Tauber
c395386c05 Merge PR #702: Window decorations: support toolbox-style "small" window title bar 2023-08-05 17:05:54 +02:00
Karl Tauber
4f1207b0db Merge PR #703: TabbedPane: support rounded underline selection and rounded card tabs 2023-08-05 16:59:57 +02:00
Karl Tauber
dc3878e290 Native window libraries: added flatlaf-windows-arm64.dll (for issue #443, PR #707)
built by GitHub Actions:
https://github.com/JFormDesigner/FlatLaf/actions/runs/5771160235

locally signed Windows DLLs with FormDev Software GmbH code signing certificate
2023-08-05 16:26:11 +02:00
Karl Tauber
be2876149d Merge PR #707: Windows on ARM Support 2023-08-05 16:14:00 +02:00
Karl Tauber
52bae9dfb0 Windows on ARM:
- changed DLL filename from aarch64 to arm64
- publish ARM DLL to Maven Central
2023-08-05 16:11:46 +02:00
Karl Tauber
bb636bac3f IntelliJ Themes: fixed ModifyCollectionInEnhancedForLoop Error Prone error 2023-08-04 16:29:21 +02:00
Sung Ho Yoon
502b18fa86 Remove check for x86
Now that the aarch64 library is added, this
check is unnecessary.
2023-08-04 22:10:48 +09:00
Sung Ho Yoon
e0a5450264 Load Windows on ARM (aarch64) native library 2023-08-04 22:10:13 +09:00
Karl Tauber
5ffb23c37f Merge PR #704: Tweak ZAP's name 2023-08-04 12:33:23 +02:00
Sung Ho Yoon
b75f22b7bd Add windows-aarch64 build configuration 2023-08-04 19:19:06 +09:00
Karl Tauber
35fa3197c8 Demo: moved SVG icons to JFormDesigner forms 2023-08-04 12:08:04 +02:00
Karl Tauber
f03725ae36 IntelliJ Themes: fixed ComboBox backgrounds in all "Material UI Lite" themes and in some other themes 2023-08-04 11:18:28 +02:00
Karl Tauber
2b640e2129 IntelliJ Themes: fixed foreground colors of disabled text in "Vuesion" theme 2023-08-04 00:59:41 +02:00
Karl Tauber
2a983f5c03 IntelliJ Themes: fixed background colors of enabled text components, to distinguish from disabled (issue #528) 2023-08-04 00:25:51 +02:00
Karl Tauber
cacc5daa14 IntelliJ Themes: updated theme "Monokai Pro Theme" from version 1.10 2023-08-03 00:37:42 +02:00
Karl Tauber
593502287d IntelliJ Themes: removed all "Contrast" themes from "Material UI Lite" 2023-08-03 00:26:59 +02:00
Karl Tauber
7a9bdf9be0 IntelliJ Themes: updated themes to newest versions (used IJThemesUpdater) 2023-08-02 15:03:57 +02:00
Karl Tauber
170c22c5ed IntelliJ Themes: fixed unselected CheckBox and RadioButton icon colors for themes "Atom One Light", "Cyan Light", "GitHub", "Light Owl", "Material Lighter" and "Solarized Light" 2023-08-02 14:25:15 +02:00
Karl Tauber
7e8fa58bd7 IntelliJ Themes: reduced memory footprint and improved setup speed by ignoring IntelliJ UI properties that are not used in FlatLaf
also fixed `ToggleButton.tab.selectedBackground`
2023-08-02 00:40:49 +02:00
Rick M
046200625c Make world possessive not plural 2023-08-01 16:20:11 -04:00
Rick M
710ed55152 Tweak ZAP's name
Per: https://www.zaproxy.org/blog/2023-08-01-zap-is-joining-the-software-security-project/
2023-08-01 16:18:41 -04:00
Karl Tauber
ce527329a6 ComboBox: fixed search in item list for text with spaces (issue #691) 2023-08-01 15:19:15 +02:00
Karl Tauber
b455dd41ab TabbedPane: going back to 3px tab selection for macOS themes 2023-07-31 22:36:59 +02:00
Karl Tauber
b47ed94f40 PopupMenu: make sure that popup menu does not overlap any operating system task bar (issue #701) 2023-07-31 22:21:35 +02:00
Karl Tauber
f1351a2093 TabbedPane: support rounded underline selection and rounded card tabs 2023-07-31 13:36:18 +02:00
Karl Tauber
c1c5e81df0 fixed error reported by Error Prone 2023-07-30 16:07:26 +02:00
Karl Tauber
8e3c8ba6c5 Window decorations: support toolbox-style "small" window title bar (issue #659) 2023-07-30 15:26:44 +02:00
Karl Tauber
dfe4404a17 fixed build error in flatlaf-testing-modular-app caused by moving to JSVG (PR #684) 2023-07-30 14:33:24 +02:00
Karl Tauber
b3fb63c9f5 ComboBox: improved location of selected item in popup if list is large and scrollable 2023-07-30 14:01:24 +02:00
Karl Tauber
9db3dfff26 CHANGELOG.md: added info about recently merged PR #684 2023-07-30 13:58:49 +02:00
Karl Tauber
3c9051e7de Merge PR #684: Replace svgSalamander with jsvg 2023-07-30 13:46:06 +02:00
Karl Tauber
798a6d061c jsvg: use String instead of URL as cache key to avoid this problem: https://errorprone.info/bugpattern/URLEqualsHashCode 2023-07-17 23:42:26 +02:00
Karl Tauber
19afbe99d9 FormattedTextField: On Linux, fixed IllegalArgumentException: Invalid location if JFormattedTextField.setDocument() is invoked in a focus gained listener on that formatted text field. (issue #698) 2023-07-17 15:46:11 +02:00
Karl Tauber
4715d8d16c jsvg: use RenderingHints.VALUE_STROKE_PURE for correct line rendering 2023-07-17 12:43:09 +02:00
Karl Tauber
193da2bc4d jsvg: updated flatlaf-extras/README.md; removed svgSalamander from libs.versions.toml 2023-07-10 13:49:30 +02:00
Karl Tauber
799f8efe22 jsvg: simplified/fixed loading from input stream; replaced internal usage of URI with URL 2023-07-10 13:41:54 +02:00
Karl Tauber
f6062e1ec4 jsvg: fixed color filter in FlatSVGIcon 2023-07-09 23:16:50 +02:00
Karl Tauber
c790778a46 Window decorations: support moving/resizing JInternalFrame that is child of JLayeredPane and overlaps FlatLaf title bar (issue #658) 2023-07-09 18:23:20 +02:00
Karl Tauber
4344f1b3a0 IntelliJ Themes: fixed focused tab background color for themes "Arc *", "Material Design Dark", "Monocai", "One Dark", "Spacegray" and "Xcode-Dark" (issue #697) 2023-07-09 14:09:01 +02:00
Karl Tauber
d520b30500 TestFlatStylingScale unit tests added for commit fde65b2730, issue #682 2023-07-02 18:47:10 +02:00
Karl Tauber
11c02e5f50 FlatWindowDecorationsTest: redesigned UI; added "FlatLaf window decorations" checkbox 2023-07-02 18:03:39 +02:00
Karl Tauber
aa4c6ee9da Native window libraries: updated Windows DLLs (for issue #673)
built by GitHub Actions:
https://github.com/JFormDesigner/FlatLaf/actions/runs/5431957508

locally signed Windows DLLs with FormDev Software GmbH code signing certificate
2023-07-01 18:37:32 +02:00
Karl Tauber
98f8557392 flatlaf-natives-windows: reworked linking/loading of jawt.dll; now loading jawt.dll when first used (issue #673) 2023-07-01 18:16:59 +02:00
Karl Tauber
6f6a860887 IntelliJ Themes: "Monocai" theme: fixed unreadable text color of default buttons (issue #693) 2023-06-21 17:30:59 +02:00
Karl Tauber
38695e9e16 updated Error Prone to 2.20.0 2023-06-21 17:16:22 +02:00
Karl Tauber
242c478cb3 GitHub Actions:
- build using Java 20 (use toolchain because Gradle 8.1.1 does not support running and compiling on Java 20 because Kotlin does not support 20 as target version)
- use temurin distribution as default because it is pre-installed on ubuntu-latest
2023-06-21 17:14:29 +02:00
Karl Tauber
f003e835bd macOS themes: changing @accentColor variable in FlatLaf properties files did not change all accent related colors for all components 2023-06-21 12:15:12 +02:00
Karl Tauber
267defb321 added system property flatlaf.useNativeLibrary to allow disabling loading of FlatLaf native library (issue #674) 2023-06-21 00:13:35 +02:00
Karl Tauber
4392c7627b 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)
2023-06-21 00:02:01 +02:00
Karl Tauber
fde65b2730 Styling: fixed scaling of some styling properties (rowHeight for Table and Tree; iconTextGap for Button, CheckBox and RadioButton) (issue #682) 2023-06-20 23:45:41 +02:00
Karl Tauber
e908362f0a fixed IllegalComponentStateException when invoker is not showing in SubMenuUsabilityHelper (issue #692) 2023-06-20 23:15:11 +02:00
Jannis Weis
a40b837634 Replace svgSalamander with jsvg 2023-05-29 16:30:12 +02:00
Karl Tauber
b391465fbf Gradle:
- moved FlatLaf version numbers from build.gradle.kts to gradle.properties
- enabled Gradle parallel build
2023-05-20 12:30:23 +02:00
Karl Tauber
bad0428f5b UIDefaultsLoader and FlatStylingSupport: explicitly specify throws IllegalArgumentException and improved catching 2023-05-20 12:26:46 +02:00
Karl Tauber
97018df2f9 added Error Prone (https://errorprone.info/) and fixed reported errors and warnings
- CI runs Error Prone with Java 11
- use Gradle task `errorprone` to run it on development machine
- fixes are mostly cosmetic except:
  - use Locale.ENGLISH for String.toLowerCase()
  - use explicit character encoding when reading/writing files
  - TabbedPane: wrong logic in mouse-wheel scrolling
  - SplitPane: simplified property change listener (fixes hiding field `propertyChangeListener` of superclass)
2023-05-19 22:58:12 +02:00
Karl Tauber
9d84501bc8 Gradle: moved declaration of all external dependencies to libs.versions.toml and use Gradle version catalog 2023-05-18 15:37:03 +02:00
Karl Tauber
e9fb2b3fdc update to Gradle 8.1.1 2023-05-18 15:32:05 +02:00
Karl T
f60250fd8a Merge pull request #681 from Plyha/spark
Add Spark to Applications
2023-05-18 14:58:39 +02:00
ilya khlevnoy
5fc3cae28a Add Spark to Applications 2023-05-17 23:07:35 +03:00
Karl T
e7935be85b Merge pull request #671 from kumait/main
Add Kafka Visualizer to Applications
2023-04-23 17:01:56 +02:00
kumait
89363b2ea1 Add Kafka Visualizer to Applications 2023-04-22 18:11:55 -04:00
Karl Tauber
e84390ee46 release 3.1.1 2023-04-18 15:01:44 +02:00
Karl Tauber
65a0f467ae Native libraries: Fixed IllegalArgumentException: URI scheme is not "file" when using FlatLaf in WebStart. (issue #668; regression in FlatLaf 3.1) 2023-04-17 21:33:56 +02:00
Karl Tauber
4afb150106 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.
2023-04-17 13:45:05 +02:00
Karl Tauber
0f6702217e updated CHANGELOG.md and README.md for FlatLaf 3.1 2023-04-12 13:55:22 +02:00
Karl Tauber
13a0097858 updated sigtest for FlatLaf 3.1
(generated in clean workspace with gradle task `sigtestGenerate`)
2023-04-03 12:24:38 +02:00
220 changed files with 10454 additions and 32891 deletions

View File

@@ -24,11 +24,10 @@ jobs:
- 8
- 11 # LTS
- 17 # LTS
- 19
toolchain: [""]
# include:
# - java: 17
# toolchain: 19 # latest
include:
- java: 17
toolchain: 21 # latest
steps:
- uses: actions/checkout@v3
@@ -40,9 +39,13 @@ jobs:
uses: actions/setup-java@v3
with:
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
- name: Check with Error Prone
if: matrix.java == '11'
run: ./gradlew errorprone clean -Dtoolchain=${{ matrix.toolchain }}
- name: Build with Gradle
run: ./gradlew build -Dtoolchain=${{ matrix.toolchain }}
@@ -73,11 +76,11 @@ jobs:
uses: actions/setup-java@v3
with:
java-version: 11
distribution: adopt # pre-installed on ubuntu-latest
distribution: temurin # pre-installed on ubuntu-latest
cache: gradle
- name: Publish snapshot to oss.sonatype.org
run: ./gradlew publish :flatlaf-theme-editor:build -PskipFonts -Dorg.gradle.internal.publish.checksums.insecure=true
run: ./gradlew publish :flatlaf-theme-editor:build -PskipFonts -Dorg.gradle.internal.publish.checksums.insecure=true -Dorg.gradle.parallel=false
env:
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
@@ -109,11 +112,11 @@ jobs:
uses: actions/setup-java@v3
with:
java-version: 11
distribution: adopt # pre-installed on ubuntu-latest
distribution: temurin # pre-installed on ubuntu-latest
cache: gradle
- 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:
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}

View File

@@ -36,7 +36,7 @@ jobs:
uses: actions/setup-java@v3
with:
java-version: 11
distribution: adopt # pre-installed on ubuntu-latest
distribution: temurin # pre-installed on ubuntu-latest
cache: gradle
- name: Build with Gradle

View File

@@ -33,7 +33,7 @@ jobs:
uses: actions/setup-java@v3
with:
java-version: 11
distribution: adopt
distribution: temurin
cache: gradle
- name: Build with Gradle

View File

@@ -1,12 +1,150 @@
FlatLaf Change Log
==================
## 3.2.4
#### Fixed bugs
- Popup: Fixed potential NPE in (unusual) case that the popup invoker is `null`
(only on Linux with Wayland and Java 21; regression in 3.2.3). (issue #752)
## 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.
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)
@@ -20,6 +158,18 @@ FlatLaf Change Log
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

278
README.md
View File

@@ -6,7 +6,7 @@ Swing desktop applications.
It looks almost flat (no shadows or gradients), clean, simple and elegant.
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
IntelliJ IDEA 2019.2+ and uses almost the same colors and icons.
@@ -66,6 +66,11 @@ Otherwise download `flatlaf-<version>.jar` here:
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.formdev/flatlaf/badge.svg?style=flat-square&color=007ec6)](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
@@ -137,6 +142,7 @@ 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 announcement on Reddit](https://www.reddit.com/r/java/comments/dl0hu3/flatlaf_flat_look_and_feel/)
@@ -144,121 +150,193 @@ Buzz
Applications using FlatLaf
--------------------------
- ![New](images/new.svg)
### Featured
- ![Sponsor](images/sponsor.svg) [JFormDesigner](https://www.formdev.com/)
(**commercial**) - Java/Swing GUI Designer (from the FlatLaf creators)
- ![Sponsor](images/sponsor.svg)
[JProfiler](https://www.ej-technologies.com/products/jprofiler/overview.html)
12 (**commercial**) - the award-winning all-in-one Java profiler
- ![New](images/new.svg) [JFormDesigner](https://www.formdev.com/) 8
(**commercial**) - Java/Swing GUI Designer
- ![New](images/new.svg) [Jeyla Studio](https://www.jeylastudio.com/) - Salon
Software
- ![New](images/new.svg) [Fanurio](https://www.fanuriotimetracking.com/) 3.3.2
(**commercial**) - time tracking and billing for freelancers and teams
- ![New](images/new.svg) [Antares](https://www.antarescircuit.io/) - a free,
powerful platform for designing, simulating and explaining digital circuits
- ![New](images/new.svg)
[Logisim-evolution](https://github.com/logisim-evolution/logisim-evolution)
3.6 - Digital logic design tool and simulator
- ![New](images/new.svg) [Cinecred](https://loadingbyte.com/cinecred/) - create
beautiful film credit sequences
- ![New](images/new.svg) [tinyMediaManager](https://www.tinymediamanager.org/)
v4 (**commercial**) - a media management tool
- ![New](images/new.svg) [Weasis](https://nroduit.github.io/) - medical DICOM
viewer used in healthcare by hospitals, health networks, etc
- ![New](images/new.svg)
[Makelangelo Software](https://github.com/MarginallyClever/Makelangelo-software)
7.3.0 - for plotters, especially the wall-hanging polargraph
- ![Hot](images/hot.svg) [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
- ![Hot](images/hot.svg) [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
- ![Hot](images/hot.svg)
(**commercial**) - the award-winning all-in-one Java profiler
- ![Sponsor](images/sponsor.svg)
[install4j](https://www.ej-technologies.com/products/install4j/overview.html)
9.0 (**commercial**) - the powerful multi-platform Java installer builder
- ![Hot](images/hot.svg) [DbVisualizer](https://www.dbvis.com/) 12.0
(**commercial**) - the powerful multi-platform Java installer builder
- ![Sponsor](images/sponsor.svg) [DbVisualizer](https://www.dbvis.com/)
(**commercial**) - the universal database tool for developers, analysts and
DBAs
- ![Hot](images/hot.svg) [MagicPlot](https://magicplot.com/) 3.0
(**commercial**) - Software for nonlinear fitting, plotting and data analysis
- ![Hot](images/hot.svg)
[Thermo-Calc](https://thermocalc.com/products/thermo-calc/) 2021a
(**commercial**) - Thermodynamics and Properties Software
- ![Hot](images/hot.svg) [OWASP ZAP](https://www.zaproxy.org/) 2.10 - the worlds
most widely used web app scanner
- ![Hot](images/hot.svg) [Apache NetBeans](https://netbeans.apache.org/) - IDE
for Java, PHP, HTML and much more
- ![Sponsor](images/sponsor.svg)
[Thermo-Calc](https://thermocalc.com/products/thermo-calc/) (**commercial**) -
Thermodynamics and Properties Software
### Data
- ![Hot](images/hot.svg) [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
- ![Hot](images/hot.svg) [MagicPlot](https://magicplot.com/) (**commercial**) -
Software for nonlinear fitting, plotting and data analysis
- ![New](images/new.svg) [Constellation](https://www.constellation-app.com/) -
Data Visualization and Analytics (based on NetBeans platform)
- ![New](images/new.svg)
[Kafka Visualizer](https://github.com/kumait/kafkavisualizer) - Kafka GUI
client
### Security
- ![Hot](images/hot.svg) [ZAP](https://www.zaproxy.org/) - the world's most
widely used web app scanner
- ![Hot](images/hot.svg)
[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
- ![New](images/new.svg)
[Ghidra](https://github.com/NationalSecurityAgency/ghidra) - a software
reverse engineering (SRE) framework
- ![New](images/new.svg) [jadx](https://github.com/skylot/jadx) - Dex to Java
decompiler
- [BurpCustomizer](https://github.com/CoreyD97/BurpCustomizer) - adds more
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/)
- ![New](images/new.svg)
[muCommander](https://github.com/mucommander/mucommander) - lightweight
cross-platform file manager
- ![New](images/new.svg) [Guiffy](https://www.guiffy.com/) (**commercial**) -
advanced cross-platform Diff/Merge
- ![New](images/new.svg) [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
- ![Hot](images/hot.svg) [jAlbum](https://jalbum.net/) (**commercial**) -
creates photo album websites
- ![New](images/new.svg) [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
- ![New](images/new.svg) [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
- ![New](images/new.svg) [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
- ![Hot](images/hot.svg) [JOSM](https://josm.openstreetmap.de/) - an extensible
editor for [OpenStreetMap](https://www.openstreetmap.org/) (requires FlatLaf
JOSM plugin)
- ![Hot](images/hot.svg) [jAlbum](https://jalbum.net/) 21 (**commercial**) -
creates photo album websites
- [PDF Studio](https://www.qoppa.com/pdfstudio/) 2021 (**commercial**) - create,
review and edit PDF documents
- [XMLmind XML Editor](https://www.xmlmind.com/xmleditor/) 9.3 (**commercial**)
- [Total Validator](https://www.totalvalidator.com/) 15 (**commercial**) -
checks your website
- [j-lawyer](https://github.com/jlawyerorg/j-lawyer-org) - Kanzleisoftware
- [MegaMek](https://github.com/MegaMek/megamek),
[MegaMekLab](https://github.com/MegaMek/megameklab) and
[MekHQ](https://github.com/MegaMek/mekhq) v0.47.5+ - a sci-fi tabletop
BattleTech simulator suite handling battles, unit building, and campaigns
- [GUIslice Builder](https://github.com/ImpulseAdventure/GUIslice-Builder)
0.13.b024 - GUI builder for
[GUIslice](https://github.com/ImpulseAdventure/GUIslice), a lightweight GUI
framework for embedded displays
- [Rest Suite](https://github.com/supanadit/restsuite) - Rest API testing
- [ControllerBuddy](https://github.com/bwRavencl/ControllerBuddy) - advanced
gamepad mapping software
- [SpringRemote](https://github.com/HaleyWang/SpringRemote) - remote Linux SSH
connections manager
- [jEnTunnel](https://github.com/ggrandes/jentunnel) - manage SSH Tunnels made
easy
- [Mapton](https://mapton.org/)
([source code](https://github.com/trixon/mapton)) - some kind of map
application (based on NetBeans platform)
- [MeteoInfo](https://github.com/meteoinfo/MeteoInfo) - GIS and scientific
computation environment for meteorological community
### Business / Legal
- ![Sponsor](images/sponsor.svg)
[j-lawyer](https://github.com/jlawyerorg/j-lawyer-org) - Kanzleisoftware
- ![Sponsor](images/sponsor.svg) [Jeyla Studio](https://www.jeylastudio.com/) -
Salon Software
- [Fanurio](https://www.fanuriotimetracking.com/) (**commercial**) - time
tracking and billing for freelancers and teams
- [Jes](https://www.jes-eur.de) - Die Java-EÜR
- [mendelson AS2](https://sourceforge.net/projects/mec-as2/),
[AS4](https://sourceforge.net/projects/mendelson-as4/) and
[OFTP2](https://sourceforge.net/projects/mendelson-oftp2/) (open-source) and
[mendelson AS2](https://mendelson-e-c.com/as2/),
[AS4](https://mendelson-e-c.com/as4/) and
[OFTP2](https://mendelson-e-c.com/oftp2) (**commercial**)
- [IGMAS+](https://www.gfz-potsdam.de/igmas) - Interactive Gravity and Magnetic
Application System
- [MeteoInfo](https://github.com/meteoinfo/MeteoInfo) 2.2 - GIS and scientific
computation environment for meteorological community
- [lsfusion platform](https://github.com/lsfusion/platform) 4 - information
systems development platform
- [JPass](https://github.com/gaborbata/jpass) - password manager with strong
encryption
- [Jes - Die Java-EÜR](https://www.jes-eur.de)
- [Mapton](https://mapton.org/) 2.0
([source code](https://github.com/trixon/mapton)) - some kind of map
application (based on NetBeans platform)
- [Pseudo Assembler IDE](https://github.com/tomasz-herman/PseudoAssemblerIDE) -
IDE for Pseudo-Assembler
- [Linotte](https://github.com/cpc6128/LangageLinotte) 3.1 - French programming
language created to learn programming
- [MEKA](https://github.com/Waikato/meka) 1.9.3 - multi-label classifiers and
evaluation procedures using the Weka machine learning framework
- [Shutter Encoder](https://www.shutterencoder.com/) 14.2
([source code](https://github.com/paulpacifico/shutter-encoder)) -
professional video converter and compression tool (screenshots show **old**
look)
- [Sound Analysis](https://github.com/tomasz-herman/SoundAnalysis) - analyze
sound files in time or frequency domain
- [RemoteLight](https://github.com/Drumber/RemoteLight) - multifunctional LED
control software
- [ThunderFocus](https://github.com/marcocipriani01/ThunderFocus) -
Arduino-based telescope focuser
- [Novel-Grabber](https://github.com/Flameish/Novel-Grabber) - download novels
from any webnovel and lightnovel site
- [lectureStudio](https://www.lecturestudio.org/) 4.3.1060 - digitize your
lectures with ease
### Messaging
- ![New](images/new.svg) [Spark](https://github.com/igniterealtime/Spark) -
cross-platform IM client optimized for businesses and organizations
- ![New](images/new.svg) [Chatty](https://github.com/chatty/chatty) - Twitch
Chat Client
### Gaming
- ![New](images/new.svg) ![Sponsor](images/sponsor.svg)
[BGBlitz](https://www.bgblitz.com/) (**commercial**) - professional Backgammon
- ![New](images/new.svg) [MapTool](https://github.com/RPTools/maptool) - virtual
Tabletop for playing role-playing games
- [MegaMek](https://github.com/MegaMek/megamek),
[MegaMekLab](https://github.com/MegaMek/megameklab) and
[MekHQ](https://github.com/MegaMek/mekhq) - a sci-fi tabletop BattleTech
simulator suite handling battles, unit building, and campaigns
- [ControllerBuddy](https://github.com/bwRavencl/ControllerBuddy) - advanced
gamepad mapping software
### Utilities
- [MooInfo](https://github.com/rememberber/MooInfo) - visual implementation of
OSHI, to view information about the system and hardware
- ![New](images/new.svg)
[Linux Task Manager (LTM)](https://github.com/ajee10x/LTM-LinuxTaskManager) -
GUI for monitoring and managing various aspects of a Linux system
- [Rest Suite](https://github.com/supanadit/restsuite) - Rest API testing
- [SpringRemote](https://github.com/HaleyWang/SpringRemote) - remote Linux SSH
connections manager
- [jEnTunnel](https://github.com/ggrandes/jentunnel) - manage SSH Tunnels made
easy
- [Android Tool](https://github.com/fast-geek/Android-Tool) - makes popular adb
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

View File

@@ -14,10 +14,9 @@
* limitations under the License.
*/
val releaseVersion = "3.1"
val developmentVersion = "3.2-SNAPSHOT"
import net.ltgt.gradle.errorprone.errorprone
version = if( rootProject.hasProperty( "release" ) ) releaseVersion else developmentVersion
version = property( if( hasProperty( "release" ) ) "flatlaf.releaseVersion" else "flatlaf.developmentVersion" ) as String
allprojects {
version = rootProject.version
@@ -43,6 +42,10 @@ if( !toolchainJavaVersion.isNullOrEmpty() )
println()
plugins {
alias( libs.plugins.errorprone ) apply false
}
allprojects {
tasks {
withType<JavaCompile>().configureEach {
@@ -81,4 +84,56 @@ allprojects {
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
)
}
}
}
}
}
}

View File

@@ -26,7 +26,7 @@ tasks {
// depend on :flatlaf-core:compileJava because it generates the JNI headers
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" )
include( extension.headers )
filter<org.apache.tools.ant.filters.FixCrLfFilter>(

View File

@@ -122,3 +122,11 @@ signing {
tasks.withType<Sign>().configureEach {
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'." )
}
}

View File

@@ -0,0 +1,2 @@
eclipse.preferences.version=1
encoding/<project>=ISO-8859-1

View File

@@ -27,12 +27,11 @@ plugins {
val sigtest = configurations.create( "sigtest" )
dependencies {
testImplementation( "org.junit.jupiter:junit-jupiter-api:5.7.2" )
testImplementation( "org.junit.jupiter:junit-jupiter-params" )
testRuntimeOnly( "org.junit.jupiter:junit-jupiter-engine" )
testImplementation( libs.bundles.junit )
testRuntimeOnly( libs.junit.engine )
// https://github.com/jtulach/netbeans-apitest
sigtest( "org.netbeans.tools:sigtest-maven-plugin:1.7" )
sigtest( libs.sigtest )
}
java {
@@ -43,7 +42,7 @@ java {
tasks {
compileJava {
// generate JNI headers
options.headerOutputDirectory.set( buildDir.resolve( "generated/jni-headers" ) )
options.headerOutputDirectory.set( layout.buildDirectory.dir( "generated/jni-headers" ) )
}
jar {
@@ -130,6 +129,7 @@ flatlafPublish {
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-linux-x86_64.so", "linux-x86_64", "so" ),
)
}

View File

@@ -1,5 +1,5 @@
#Signature file v4.1
#Version 3.0
#Version 3.2.4
CLSS public abstract interface com.formdev.flatlaf.FlatClientProperties
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_ROUND_RECT = "JComponent.roundRect"
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 MINIMUM_HEIGHT = "JComponent.minimumHeight"
fld public final static java.lang.String MINIMUM_WIDTH = "JComponent.minimumWidth"
@@ -19,6 +20,7 @@ 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_WARNING = "warning"
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_FORCE_HEAVY_WEIGHT = "Popup.forceHeavyWeight"
fld public final static java.lang.String PROGRESS_BAR_LARGE_HEIGHT = "JProgressBar.largeHeight"
@@ -94,6 +96,8 @@ fld public final static java.lang.String TITLE_BAR_SHOW_TITLE = "JRootPane.title
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 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 boolean clientPropertyBoolean(javax.swing.JComponent,java.lang.String,boolean)
meth public static boolean clientPropertyEquals(javax.swing.JComponent,java.lang.String,java.lang.Object)
@@ -278,6 +282,7 @@ 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 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_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_UBUNTU_FONT = "flatlaf.useUbuntuFont"
fld public final static java.lang.String USE_WINDOW_DECORATIONS = "flatlaf.useWindowDecorations"
@@ -296,7 +301,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(java.io.InputStream) throws java.io.IOException
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
outer com.formdev.flatlaf.IntelliJTheme

View File

@@ -17,6 +17,8 @@
package com.formdev.flatlaf;
import java.awt.Color;
import java.awt.IllegalComponentStateException;
import java.awt.Window;
import java.util.Objects;
import javax.swing.JComponent;
import javax.swing.SwingConstants;
@@ -124,6 +126,7 @@ public interface FlatClientProperties
*/
String SQUARE_SIZE = "JButton.squareSize";
//---- JComponent ---------------------------------------------------------
/**
@@ -266,6 +269,7 @@ public interface FlatClientProperties
*/
String COMPONENT_TITLE_BAR_CAPTION = "JComponent.titleBarCaption";
//---- Popup --------------------------------------------------------------
/**
@@ -305,6 +309,7 @@ public interface FlatClientProperties
*/
String POPUP_FORCE_HEAVY_WEIGHT = "Popup.forceHeavyWeight";
//---- JProgressBar -------------------------------------------------------
/**
@@ -323,6 +328,7 @@ public interface FlatClientProperties
*/
String PROGRESS_BAR_SQUARE = "JProgressBar.square";
//---- JRootPane ----------------------------------------------------------
/**
@@ -472,6 +478,37 @@ public interface FlatClientProperties
*/
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 -------------------------------------------
/**
@@ -490,6 +527,7 @@ public interface FlatClientProperties
*/
String SCROLL_PANE_SMOOTH_SCROLLING = "JScrollPane.smoothScrolling";
//---- JSplitPane ---------------------------------------------------------
/**
@@ -524,6 +562,7 @@ public interface FlatClientProperties
*/
String SPLIT_PANE_EXPANDABLE_SIDE_RIGHT = "right";
//---- JTabbedPane --------------------------------------------------------
/**
@@ -919,6 +958,7 @@ public interface FlatClientProperties
*/
String TABBED_PANE_TRAILING_COMPONENT = "JTabbedPane.trailingComponent";
//---- JTextField ---------------------------------------------------------
/**
@@ -1088,6 +1128,7 @@ public interface FlatClientProperties
*/
String TEXT_FIELD_CLEAR_CALLBACK = "JTextField.clearCallback";
//---- JToggleButton ------------------------------------------------------
/**
@@ -1129,6 +1170,7 @@ public interface FlatClientProperties
*/
String TAB_BUTTON_SELECTED_BACKGROUND = "JToggleButton.tab.selectedBackground";
//---- JTree --------------------------------------------------------------
/**
@@ -1148,6 +1190,7 @@ public interface FlatClientProperties
*/
String TREE_PAINT_SELECTION = "JTree.paintSelection";
//---- helper methods -----------------------------------------------------
/**

View File

@@ -50,7 +50,8 @@ class FlatInputMaps
}
modifyInputMap( defaults, "ComboBox.ancestorInputMap",
"SPACE", "spacePopup",
// Space key still shows popup, but from FlatComboBoxUI.FlatKeySelectionManager
// "SPACE", "spacePopup",
"UP", mac( "selectPrevious2", "selectPrevious" ),
"DOWN", mac( "selectNext2", "selectNext" ),

View File

@@ -71,6 +71,7 @@ import javax.swing.plaf.FontUIResource;
import javax.swing.plaf.IconUIResource;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicLookAndFeel;
import javax.swing.plaf.metal.MetalLookAndFeel;
import javax.swing.text.StyleContext;
import javax.swing.text.html.HTMLEditorKit;
import com.formdev.flatlaf.ui.FlatNativeWindowBorder;
@@ -391,7 +392,7 @@ public abstract class FlatLaf
Method m = UIManager.class.getMethod( "createLookAndFeel", String.class );
aquaLaf = (BasicLookAndFeel) m.invoke( null, "Mac OS X" );
} else
aquaLaf = (BasicLookAndFeel) Class.forName( aquaLafClassName ).getDeclaredConstructor().newInstance();
aquaLaf = Class.forName( aquaLafClassName ).asSubclass( BasicLookAndFeel.class ).getDeclaredConstructor().newInstance();
} catch( Exception ex ) {
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to initialize Aqua look and feel '" + aquaLafClassName + "'.", ex );
throw new IllegalStateException();
@@ -543,7 +544,7 @@ public abstract class FlatLaf
// which can happen in applications that use some plugin system
// and load FlatLaf in a plugin that uses its own classloader.
// (e.g. Apache NetBeans)
if( defaults.get( "FileChooser.fileNameHeaderText" ) != null )
if( defaults.get( "TabbedPane.moreTabsButtonToolTipText" ) != null )
return;
// load FlatLaf resource bundle and add content to defaults
@@ -581,10 +582,13 @@ public abstract class FlatLaf
Object activeFont = new ActiveFont( null, null, -1, 0, 0, 0, 0 );
// override fonts
List<String> fontKeys = new ArrayList<>( 50 );
for( Object key : defaults.keySet() ) {
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
defaults.put( "RootPane.font", activeFont );
@@ -1428,26 +1432,36 @@ public abstract class FlatLaf
private class FlatUIDefaults
extends UIDefaults
{
private UIDefaults metalDefaults;
FlatUIDefaults( int initialCapacity, float loadFactor ) {
super( initialCapacity, loadFactor );
}
@Override
public Object get( Object key ) {
Object value = getValue( key );
return (value != null) ? (value != NULL_VALUE ? value : null) : super.get( key );
return get( key, null );
}
@Override
public Object get( Object key, Locale l ) {
Object value = getValue( key );
return (value != null) ? (value != NULL_VALUE ? value : null) : super.get( key, l );
Object value = getFromUIDefaultsGetters( key );
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
List<Function<Object, Object>> uiDefaultsGetters = FlatLaf.this.uiDefaultsGetters;
if( uiDefaultsGetters == null )
return null;
@@ -1459,6 +1473,22 @@ public abstract class FlatLaf
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 ---------------------------------------------------
@@ -1541,7 +1571,7 @@ public abstract class FlatLaf
int newStyle = (style != -1)
? style
: (styleChange != 0)
? baseStyle & ~((styleChange >> 16) & 0xffff) | (styleChange & 0xffff)
? (baseStyle & ~((styleChange >> 16) & 0xffff)) | (styleChange & 0xffff)
: baseStyle;
// new size

View File

@@ -21,6 +21,7 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Locale;
import java.util.Properties;
/**
@@ -96,7 +97,7 @@ public class FlatPropertiesLaf
protected ArrayList<Class<?>> getLafClassesForDefaultsLoading() {
ArrayList<Class<?>> lafClasses = new ArrayList<>();
lafClasses.add( FlatLaf.class );
switch( baseTheme.toLowerCase() ) {
switch( baseTheme.toLowerCase( Locale.ENGLISH ) ) {
default:
case "light":
lafClasses.add( FlatLightLaf.class );

View File

@@ -150,10 +150,24 @@ public interface FlatSystemProperties
* <p>
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
* <strong>Default</strong> {@code true}
*
* @since 2.5
*/
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.
* The path can be absolute or relative to current application working directory.

View File

@@ -23,13 +23,17 @@ import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import javax.swing.UIDefaults;
import javax.swing.plaf.ColorUIResource;
import com.formdev.flatlaf.json.Json;
@@ -61,9 +65,9 @@ public class IntelliJTheme
private final boolean isMaterialUILite;
private final Map<String, String> colors;
private final Map<String, Object> ui;
private final Map<String, Object> icons;
private Map<String, String> colors;
private Map<String, Object> ui;
private Map<String, Object> icons;
private Map<String, ColorUIResource> namedColors = Collections.emptyMap();
@@ -196,8 +200,9 @@ public class IntelliJTheme
defaults.put( "HelpButton.focusedBackground", defaults.get( "Button.focusedBackground" ) );
// IDEA uses TextField.background for editable ComboBox and Spinner
defaults.put( "ComboBox.editableBackground", defaults.get( "TextField.background" ) );
defaults.put( "Spinner.background", defaults.get( "TextField.background" ) );
Object textFieldBackground = get( defaults, themeSpecificDefaults, "TextField.background" );
defaults.put( "ComboBox.editableBackground", textFieldBackground );
defaults.put( "Spinner.background", textFieldBackground );
// Spinner arrow button always has same colors as ComboBox arrow button
defaults.put( "Spinner.buttonBackground", defaults.get( "ComboBox.buttonEditableBackground" ) );
@@ -205,22 +210,41 @@ public class IntelliJTheme
defaults.put( "Spinner.buttonDisabledArrowColor", defaults.get( "ComboBox.buttonDisabledArrowColor" ) );
// some themes specify colors for TextField.background, but forget to specify it for other components
// (probably because those components are not used in IntelliJ)
if( uiKeys.contains( "TextField.background" ) ) {
Object textFieldBackground = defaults.get( "TextField.background" );
if( !uiKeys.contains( "FormattedTextField.background" ) )
defaults.put( "FormattedTextField.background", textFieldBackground );
if( !uiKeys.contains( "PasswordField.background" ) )
defaults.put( "PasswordField.background", textFieldBackground );
if( !uiKeys.contains( "EditorPane.background" ) )
defaults.put( "EditorPane.background", textFieldBackground );
if( !uiKeys.contains( "TextArea.background" ) )
defaults.put( "TextArea.background", textFieldBackground );
if( !uiKeys.contains( "TextPane.background" ) )
defaults.put( "TextPane.background", textFieldBackground );
if( !uiKeys.contains( "Spinner.background" ) )
defaults.put( "Spinner.background", textFieldBackground );
}
// (probably because those components are not used in IntelliJ IDEA)
putAll( defaults, textFieldBackground,
"EditorPane.background",
"FormattedTextField.background",
"PasswordField.background",
"TextArea.background",
"TextPane.background"
);
putAll( defaults, get( defaults, themeSpecificDefaults, "TextField.selectionBackground" ),
"EditorPane.selectionBackground",
"FormattedTextField.selectionBackground",
"PasswordField.selectionBackground",
"TextArea.selectionBackground",
"TextPane.selectionBackground"
);
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
if( !uiKeys.contains( "ToggleButton.startBackground" ) && !uiKeys.contains( "*.startBackground" ) )
@@ -247,6 +271,33 @@ public class IntelliJTheme
if( 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
for( Map.Entry<Object, Object> e : themeSpecificDefaults.entrySet() ) {
Object key = e.getKey();
@@ -261,6 +312,20 @@ public class IntelliJTheme
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 ) {
@@ -334,17 +399,30 @@ public class IntelliJTheme
if( "".equals( value ) )
return; // ignore empty value
uiKeys.add( key );
// fix ComboBox size and Spinner border in all Material UI Lite themes
if( isMaterialUILite && (key.equals( "ComboBox.padding" ) || key.equals( "Spinner.border" )) )
return; // ignore
// ignore some properties that affect sizes
if( key.endsWith( ".border" ) ||
key.endsWith( ".rowHeight" ) ||
key.equals( "ComboBox.padding" ) ||
key.equals( "Spinner.padding" ) ||
key.equals( "Tree.leftChildIndent" ) ||
key.equals( "Tree.rightChildIndent" ) )
return; // ignore
// map keys
key = uiKeyMapping.getOrDefault( key, key );
if( key.isEmpty() )
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();
// map named colors
@@ -390,7 +468,8 @@ public class IntelliJTheme
// replace all values in UI defaults that match the wildcard key
for( Object k : defaultsKeysCache ) {
if( k.equals( "Desktop.background" ) ||
k.equals( "DesktopIcon.background" ) )
k.equals( "DesktopIcon.background" ) ||
k.equals( "TabbedPane.focusColor" ) )
continue;
if( k instanceof String ) {
@@ -461,7 +540,7 @@ public class IntelliJTheme
/**
* 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.
*/
private void applyCheckBoxColors( UIDefaults defaults ) {
@@ -481,18 +560,6 @@ public class IntelliJTheme
if( !key.startsWith( "Checkbox." ) || !(value instanceof String) )
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 )
key = StringUtils.removeTrailing( key, ".Dark" );
@@ -506,6 +573,7 @@ public class IntelliJTheme
if( color != null ) {
defaults.put( newKey, color );
String key2 = checkboxDuplicateColors.get( key + ".Dark");
if( key2 != null ) {
// 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
@@ -570,17 +638,59 @@ public class IntelliJTheme
defaults.put( destKey, defaults.get( srcKey ) );
}
private static final Set<String> uiKeyExcludes;
private static final Set<String> uiKeyDoNotOverride;
/** Rename UI default keys (key --> value). */
private static final Map<String, String> uiKeyMapping = new HashMap<>();
/** 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> checkboxKeyMapping = new HashMap<>();
private static final Map<String, String> checkboxDuplicateColors = new HashMap<>();
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
uiKeyMapping.put( "ComboBox.background", "" ); // ignore
uiKeyMapping.put( "ComboBox.buttonBackground", "" ); // ignore
uiKeyMapping.put( "ComboBox.nonEditableBackground", "ComboBox.background" );
uiKeyMapping.put( "ComboBox.ArrowButton.background", "ComboBox.buttonEditableBackground" );
uiKeyMapping.put( "ComboBox.ArrowButton.disabledIconColor", "ComboBox.buttonDisabledArrowColor" );
@@ -638,9 +748,9 @@ public class IntelliJTheme
uiKeyCopying.put( "Spinner.buttonDisabledSeparatorColor", "Component.disabledBorderColor" );
// TabbedPane
uiKeyCopying.put( "TabbedPane.selectedBackground", "DefaultTabs.underlinedTabBackground" );
uiKeyCopying.put( "TabbedPane.selectedForeground", "DefaultTabs.underlinedTabForeground" );
uiKeyCopying.put( "TabbedPane.inactiveUnderlineColor", "DefaultTabs.inactiveUnderlineColor" );
uiKeyMapping.put( "DefaultTabs.underlinedTabBackground", "TabbedPane.selectedBackground" );
uiKeyMapping.put( "DefaultTabs.underlinedTabForeground", "TabbedPane.selectedForeground" );
uiKeyMapping.put( "DefaultTabs.inactiveUnderlineColor", "TabbedPane.inactiveUnderlineColor" );
// TitlePane
uiKeyCopying.put( "TitlePane.inactiveBackground", "TitlePane.background" );

View File

@@ -23,11 +23,14 @@ import java.awt.GraphicsEnvironment;
import java.awt.Toolkit;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.StringTokenizer;
import javax.swing.text.StyleContext;
import com.formdev.flatlaf.util.LoggingFacade;
@@ -68,7 +71,7 @@ class LinuxFontPolicy
if( word.endsWith( "," ) )
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" ) )
style |= Font.ITALIC;
else if( lword.equals( "bold" ) )
@@ -104,7 +107,7 @@ class LinuxFontPolicy
size = 1;
// handle logical font names
String logicalFamily = mapFcName( family.toLowerCase() );
String logicalFamily = mapFcName( family.toLowerCase( Locale.ENGLISH ) );
if( logicalFamily != null )
family = logicalFamily;
@@ -143,7 +146,7 @@ class LinuxFontPolicy
return createFont( Font.DIALOG, style, size, dsize );
// 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" ) )
style |= Font.BOLD;
@@ -257,6 +260,7 @@ class LinuxFontPolicy
return createFont( family, style, size, dsize );
}
@SuppressWarnings( "MixedMutabilityReturnType" ) // Error Prone
private static List<String> readConfig( String filename ) {
File userHome = new File( System.getProperty( "user.home" ) );
@@ -277,7 +281,9 @@ class LinuxFontPolicy
// read config file
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;
while( (line = reader.readLine()) != null )
lines.add( line );

View File

@@ -153,7 +153,7 @@ debug*/
// get invoker screen bounds
Component invoker = popup.getInvoker();
invokerBounds = (invoker != null)
invokerBounds = (invoker != null && invoker.isShowing())
? new Rectangle( invoker.getLocationOnScreen(), invoker.getSize() )
: null;

View File

@@ -27,8 +27,12 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.StreamTokenizer;
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.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
@@ -271,8 +275,9 @@ class UIDefaultsLoader
continue;
}
String value = resolveValue( (String) e.getValue(), propertiesGetter );
String value = (String) e.getValue();
try {
value = resolveValue( value, propertiesGetter );
defaults.put( key, parseValue( key, value, null, null, resolver, addonClassLoaders ) );
} catch( RuntimeException ex ) {
logParseError( key, value, ex, true );
@@ -297,7 +302,9 @@ class UIDefaultsLoader
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();
String value0 = value;
@@ -326,7 +333,9 @@ class UIDefaultsLoader
return resolveValue( newValue, propertiesGetter );
}
static String resolveValueFromUIManager( String value ) {
static String resolveValueFromUIManager( String value )
throws IllegalArgumentException
{
if( value.startsWith( VARIABLE_PREFIX ) ) {
@SuppressWarnings( "unchecked" )
Map<String, String> variables = (Map<String, String>) UIManager.get( KEY_VARIABLES );
@@ -348,8 +357,11 @@ class UIDefaultsLoader
// convert binary color to string
if( newValue instanceof Color ) {
Color color = (Color) newValue;
int rgb = color.getRGB() & 0xffffff;
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" );
@@ -362,12 +374,15 @@ class UIDefaultsLoader
private static Map<Class<?>, ValueType> javaValueTypes;
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() );
}
static Object parseValue( String key, String value, Class<?> javaValueType, ValueType[] resultValueType,
Function<String, String> resolver, List<ClassLoader> addonClassLoaders )
throws IllegalArgumentException
{
if( resultValueType == null )
resultValueType = tempResultValueType;
@@ -397,7 +412,7 @@ class UIDefaultsLoader
if( value.startsWith( "if(" ) && value.endsWith( ")" ) ) {
List<String> params = splitFunctionParams( value.substring( 3, value.length() - 1 ), ',' );
if( params.size() != 3 )
throwMissingParametersException( value );
throw newMissingParametersException( value );
boolean ifCondition = parseCondition( params.get( 0 ), resolver, addonClassLoaders );
String ifValue = params.get( ifCondition ? 1 : 2 );
@@ -537,7 +552,7 @@ class UIDefaultsLoader
case INTEGERORFLOAT:return parseIntegerOrFloat( value );
case FLOAT: return parseFloat( value );
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 DIMENSION: return parseDimension( value );
case COLOR: return parseColorOrFunction( value, resolver );
@@ -546,7 +561,7 @@ class UIDefaultsLoader
case SCALEDFLOAT: return parseScaledFloat( value );
case SCALEDINSETS: return parseScaledInsets( 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 GRAYFILTER: return parseGrayFilter( value );
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 ) {
// top,left,bottom,right[,lineColor[,lineThickness[,arc]]]
// Syntax: top,left,bottom,right[,lineColor[,lineThickness[,arc]]]
List<String> parts = splitFunctionParams( value, ',' );
Insets insets = parseInsets( value );
ColorUIResource lineColor = (parts.size() >= 5)
@@ -625,13 +642,29 @@ class UIDefaultsLoader
: new FlatEmptyBorder( insets );
};
} 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 -> {
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 ) {
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to instantiate '" + value + "'.", ex );
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 );
try {
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 );
try {
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( ")" ) )
return parseColorFunctions( value, resolver );
@@ -702,10 +741,10 @@ class UIDefaultsLoader
/**
* Parses a hex color in {@code #RGB}, {@code #RGBA}, {@code #RRGGBB} or {@code #RRGGBBAA}
* 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 );
return ((rgba & 0xff000000) == 0xff000000)
? new ColorUIResource( rgba )
@@ -716,10 +755,10 @@ class UIDefaultsLoader
* 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},
* 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();
if( (len != 4 && len != 5 && len != 7 && len != 9) || value.charAt( 0 ) != '#' )
throw newInvalidColorException( value );
@@ -760,7 +799,9 @@ class UIDefaultsLoader
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( '(' );
if( paramsStart < 0 )
throw new IllegalArgumentException( "missing opening parenthesis in function '" + value + "'" );
@@ -768,7 +809,7 @@ class UIDefaultsLoader
String function = StringUtils.substringTrimmed( value, 0, paramsStart );
List<String> params = splitFunctionParams( value.substring( paramsStart + 1, value.length() - 1 ), ',' );
if( params.isEmpty() )
throwMissingParametersException( value );
throw newMissingParametersException( value );
if( parseColorDepth > 100 )
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
* 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 )
throwMissingParametersException( value );
throw newMissingParametersException( value );
boolean ifCondition = parseCondition( params.get( 0 ), resolver, Collections.emptyList() );
String ifValue = params.get( ifCondition ? 1 : 2 );
@@ -827,9 +870,11 @@ class UIDefaultsLoader
* - name: system color name
* - defaultValue: default color value used if system color is not available
*/
private static Object parseColorSystemColor( String value, List<String> params, Function<String, String> resolver ) {
private static Object parseColorSystemColor( String value, List<String> params, Function<String, String> resolver )
throws IllegalArgumentException
{
if( params.size() < 1 )
throwMissingParametersException( value );
throw newMissingParametersException( value );
ColorUIResource systemColor = getSystemColor( params.get( 0 ) );
if( systemColor != null )
@@ -869,6 +914,7 @@ class UIDefaultsLoader
*/
private static ColorUIResource parseColorRgbOrRgba( boolean hasAlpha, List<String> params,
Function<String, String> resolver )
throws IllegalArgumentException
{
if( hasAlpha && params.size() == 2 ) {
// syntax rgba(color,alpha), which allows adding alpha to any color
@@ -898,7 +944,9 @@ class UIDefaultsLoader
* - lightness: 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 saturation = parsePercentage( params.get( 1 ) );
int lightness = parsePercentage( params.get( 2 ) );
@@ -918,6 +966,7 @@ class UIDefaultsLoader
*/
private static Object parseColorHSLIncreaseDecrease( int hslIndex, boolean increase,
List<String> params, Function<String, String> resolver )
throws IllegalArgumentException
{
String colorStr = params.get( 0 );
int amount = parsePercentage( params.get( 1 ) );
@@ -961,7 +1010,9 @@ class UIDefaultsLoader
* - amount: percentage 0-100%
* - 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 );
int amount = parsePercentage( params.get( 1 ) );
boolean derived = false;
@@ -995,7 +1046,9 @@ class UIDefaultsLoader
* - angle: number of degrees to rotate
* - 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 );
int amount = parseInteger( params.get( 1 ) );
boolean derived = false;
@@ -1023,6 +1076,7 @@ class UIDefaultsLoader
*/
private static Object parseColorChange( int hslIndex,
List<String> params, Function<String, String> resolver )
throws IllegalArgumentException
{
String colorStr = params.get( 0 );
int value = (hslIndex == 0)
@@ -1051,7 +1105,9 @@ class UIDefaultsLoader
* - 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
*/
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;
if( color1Str == null )
color1Str = params.get( i++ );
@@ -1078,7 +1134,9 @@ class UIDefaultsLoader
* - threshold: the threshold (in range 0-100%) to specify where the transition
* 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 darkStr = params.get( 1 );
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
* - 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 backgroundStr = params.get( 1 );
@@ -1128,6 +1188,7 @@ class UIDefaultsLoader
private static Object parseFunctionBaseColor( String colorStr, ColorFunction function,
boolean derived, Function<String, String> resolver )
throws IllegalArgumentException
{
// parse base color
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]
*/
private static Object parseFont( String value ) {
private static Object parseFont( String value )
throws IllegalArgumentException
{
Object font = fontCache.get( value );
if( font != null )
return font;
@@ -1257,7 +1320,9 @@ class UIDefaultsLoader
return font;
}
private static int parsePercentage( String value ) {
private static int parsePercentage( String value )
throws IllegalArgumentException, NumberFormatException
{
if( !value.endsWith( "%" ) )
throw new NumberFormatException( "invalid percentage '" + value + "'" );
@@ -1273,7 +1338,9 @@ class UIDefaultsLoader
return val;
}
private static Boolean parseBoolean( String value ) {
private static Boolean parseBoolean( String value )
throws IllegalArgumentException
{
switch( value ) {
case "false": return false;
case "true": return true;
@@ -1281,13 +1348,17 @@ class UIDefaultsLoader
throw new IllegalArgumentException( "invalid boolean '" + value + "'" );
}
private static Character parseCharacter( String value ) {
private static Character parseCharacter( String value )
throws IllegalArgumentException
{
if( value.length() != 1 )
throw new IllegalArgumentException( "invalid character '" + value + "'" );
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( "%" ) ) {
int percent = parsePercentage( value );
return (max * percent) / 100;
@@ -1299,7 +1370,9 @@ class UIDefaultsLoader
return integer;
}
private static Integer parseInteger( String value ) {
private static Integer parseInteger( String value )
throws NumberFormatException
{
try {
return Integer.parseInt( value );
} catch( NumberFormatException ex ) {
@@ -1307,7 +1380,9 @@ class UIDefaultsLoader
}
}
private static Number parseIntegerOrFloat( String value ) {
private static Number parseIntegerOrFloat( String value )
throws NumberFormatException
{
try {
return Integer.parseInt( value );
} catch( NumberFormatException ex ) {
@@ -1319,7 +1394,9 @@ class UIDefaultsLoader
}
}
private static Float parseFloat( String value ) {
private static Float parseFloat( String value )
throws NumberFormatException
{
try {
return Float.parseFloat( value );
} 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 );
return t -> {
return UIScale.scale( val );
};
}
private static ActiveValue parseScaledFloat( String value ) {
private static ActiveValue parseScaledFloat( String value )
throws NumberFormatException
{
float val = parseFloat( value );
return t -> {
return UIScale.scale( val );
};
}
private static ActiveValue parseScaledInsets( String value ) {
private static ActiveValue parseScaledInsets( String value )
throws IllegalArgumentException
{
Insets insets = parseInsets( value );
return t -> {
return UIScale.scale( insets );
};
}
private static ActiveValue parseScaledDimension( String value ) {
private static ActiveValue parseScaledDimension( String value )
throws IllegalArgumentException
{
Dimension dimension = parseDimension( value );
return t -> {
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 );
try {
int brightness = Integer.parseInt( numbers.get( 0 ) );
@@ -1399,6 +1486,86 @@ class UIDefaultsLoader
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
* if not found. If key is prefixed by '?', then no error is reported.
@@ -1416,7 +1583,7 @@ class UIDefaultsLoader
return value;
}
private static void throwMissingParametersException( String value ) {
throw new IllegalArgumentException( "missing parameters in function '" + value + "'" );
private static IllegalArgumentException newMissingParametersException( String value ) {
return new IllegalArgumentException( "missing parameters in function '" + value + "'" );
}
}

View File

@@ -53,8 +53,8 @@ public class FlatInternalFrameCloseIcon
g.setColor( FlatButtonUI.buttonStateColor( c, c.getForeground(), null, null, hoverForeground, pressedForeground ) );
float mx = width / 2;
float my = height / 2;
float mx = width / 2f;
float my = height / 2f;
float r = 3.25f;
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD, 4 );

View File

@@ -94,8 +94,8 @@ public class FlatTabbedPaneCloseIcon
Color fg = FlatButtonUI.buttonStateColor( c, closeForeground, null, null, closeHoverForeground, closePressedForeground );
g.setColor( FlatUIUtils.deriveColor( fg, c.getForeground() ) );
float mx = width / 2;
float my = height / 2;
float mx = width / 2f;
float my = height / 2f;
float r = ((bg != null) ? closeCrossFilledSize : closeCrossPlainSize) / 2;
// paint cross

View File

@@ -21,7 +21,6 @@ import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatButtonUI;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.util.HiDPIUtils;
@@ -30,6 +29,7 @@ import com.formdev.flatlaf.util.HiDPIUtils;
* Base class for window icons.
*
* @uiDefault TitlePane.buttonSize Dimension
* @uiDefault TitlePane.buttonSymbolHeight int
* @uiDefault TitlePane.buttonHoverBackground Color
* @uiDefault TitlePane.buttonPressedBackground Color
*
@@ -38,17 +38,22 @@ import com.formdev.flatlaf.util.HiDPIUtils;
public abstract class FlatWindowAbstractIcon
extends FlatAbstractIcon
{
private final int symbolHeight;
private final Color hoverBackground;
private final Color pressedBackground;
public FlatWindowAbstractIcon() {
this( UIManager.getDimension( "TitlePane.buttonSize" ),
UIManager.getColor( "TitlePane.buttonHoverBackground" ),
UIManager.getColor( "TitlePane.buttonPressedBackground" ) );
/** @since 3.2 */
protected FlatWindowAbstractIcon( String windowStyle ) {
this( FlatUIUtils.getSubUIDimension( "TitlePane.buttonSize", windowStyle ),
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 );
this.symbolHeight = symbolHeight;
this.hoverBackground = hoverBackground;
this.pressedBackground = pressedBackground;
}
@@ -80,4 +85,9 @@ public abstract class FlatWindowAbstractIcon
protected Color getForeground( Component c ) {
return c.getForeground();
}
/** @since 3.2 */
protected int getSymbolHeight() {
return symbolHeight;
}
}

View File

@@ -21,8 +21,8 @@ import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.geom.Path2D;
import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatButtonUI;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.util.SystemInfo;
/**
@@ -38,18 +38,27 @@ import com.formdev.flatlaf.util.SystemInfo;
public class FlatWindowCloseIcon
extends FlatWindowAbstractIcon
{
private final Color hoverForeground = UIManager.getColor( "TitlePane.closeHoverForeground" );
private final Color pressedForeground = UIManager.getColor( "TitlePane.closePressedForeground" );
private final Color hoverForeground;
private final Color pressedForeground;
public FlatWindowCloseIcon() {
super( UIManager.getDimension( "TitlePane.buttonSize" ),
UIManager.getColor( "TitlePane.closeHoverBackground" ),
UIManager.getColor( "TitlePane.closePressedBackground" ) );
this( null );
}
/** @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
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 iy = y + ((height - iwh) / 2);
int ix2 = ix + iwh - 1;

View File

@@ -27,11 +27,17 @@ public class FlatWindowIconifyIcon
extends FlatWindowAbstractIcon
{
public FlatWindowIconifyIcon() {
this( null );
}
/** @since 3.2 */
public FlatWindowIconifyIcon( String windowStyle ) {
super( windowStyle );
}
@Override
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 ix = x + ((width - iw) / 2);
int iy = y + ((height - ih) / 2);

View File

@@ -29,11 +29,17 @@ public class FlatWindowMaximizeIcon
extends FlatWindowAbstractIcon
{
public FlatWindowMaximizeIcon() {
this( null );
}
/** @since 3.2 */
public FlatWindowMaximizeIcon( String windowStyle ) {
super( windowStyle );
}
@Override
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 iy = y + ((height - iwh) / 2);
float thickness = SystemInfo.isWindows_11_orLater ? (float) scaleFactor : (int) scaleFactor;

View File

@@ -32,18 +32,24 @@ public class FlatWindowRestoreIcon
extends FlatWindowAbstractIcon
{
public FlatWindowRestoreIcon() {
this( null );
}
/** @since 3.2 */
public FlatWindowRestoreIcon( String windowStyle ) {
super( windowStyle );
}
@Override
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 iy = y + ((height - iwh) / 2);
float thickness = SystemInfo.isWindows_11_orLater ? (float) scaleFactor : (int) scaleFactor;
int arc = Math.max( (int) (1.5 * scaleFactor), 2 );
int arcOuter = (int) (arc + (1.5 * scaleFactor));
int rwh = (int) (8 * scaleFactor);
int rwh = (int) ((getSymbolHeight() - 2) * scaleFactor);
int ro2 = iwh - rwh;
// upper-right rectangle

View File

@@ -502,9 +502,9 @@ class JsonParser {
}
private boolean isHexDigit() {
return current >= '0' && current <= '9'
|| current >= 'a' && current <= 'f'
|| current >= 'A' && current <= 'F';
return (current >= '0' && current <= '9')
|| (current >= 'a' && current <= 'f')
|| (current >= 'A' && current <= 'F');
}
private boolean isEndOfText() {

View File

@@ -69,7 +69,7 @@ public class Location {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
if (!(obj instanceof Location)) {
return false;
}
Location other = (Location)obj;

View File

@@ -53,6 +53,8 @@ import javax.swing.plaf.ToolBarUI;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicButtonListener;
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.FlatLaf;
import com.formdev.flatlaf.icons.FlatHelpButtonIcon;
@@ -362,6 +364,9 @@ public class FlatButtonUI
return ((FlatHelpButtonIcon)helpButtonIcon).applyStyleProperty( key, value );
}
if( "iconTextGap".equals( key ) && value instanceof Integer )
value = UIScale.scale( (Integer) value );
if( borderShared == null )
borderShared = new AtomicBoolean( true );
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
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
@@ -783,6 +824,67 @@ public class FlatButtonUI
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 -------------------------------------------
protected class FlatButtonListener

View File

@@ -256,10 +256,14 @@ public class FlatCaret
// select all
if( c instanceof JFormattedTextField ) {
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
select( 0, doc.getLength() );
select( 0, c2.getDocument().getLength() );
} );
} else {
select( 0, doc.getLength() );

View File

@@ -24,6 +24,7 @@ import java.awt.Component;
import java.awt.ComponentOrientation;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
@@ -48,10 +49,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.CellRendererPane;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComboBox.KeySelectionManager;
import javax.swing.JComponent;
import javax.swing.JList;
import javax.swing.JPanel;
@@ -102,7 +105,6 @@ import com.formdev.flatlaf.util.SystemInfo;
* @uiDefault ComboBox.maximumRowCount int
* @uiDefault ComboBox.buttonStyle String auto (default), button, mac or none
* @uiDefault Component.arrowType String chevron (default) or triangle
* @uiDefault Component.isIntelliJTheme boolean
* @uiDefault ComboBox.editableBackground Color optional; defaults to ComboBox.background
* @uiDefault ComboBox.focusedBackground Color optional
* @uiDefault ComboBox.disabledBackground Color
@@ -134,7 +136,6 @@ public class FlatComboBoxUI
@Styleable protected int editorColumns;
@Styleable protected String buttonStyle;
@Styleable protected String arrowType;
protected boolean isIntelliJTheme;
private Color background;
@Styleable protected Color editableBackground;
@@ -182,6 +183,9 @@ public class FlatComboBoxUI
private void installUIImpl( JComponent c ) {
super.installUI( c );
// install key selection manager that shows popup when Space key is pressed
comboBox.setKeySelectionManager( new FlatKeySelectionManager( comboBox.getKeySelectionManager() ) );
installStyle();
}
@@ -240,7 +244,6 @@ public class FlatComboBoxUI
editorColumns = UIManager.getInt( "ComboBox.editorColumns" );
buttonStyle = UIManager.getString( "ComboBox.buttonStyle" );
arrowType = UIManager.getString( "Component.arrowType" );
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
background = UIManager.getColor( "ComboBox.background" );
editableBackground = UIManager.getColor( "ComboBox.editableBackground" );
@@ -679,7 +682,7 @@ public class FlatComboBoxUI
return (editableBackground != null && comboBox.isEditable()) ? editableBackground : background;
} else
return isIntelliJTheme ? FlatUIUtils.getParentBackground( comboBox ) : disabledBackground;
return disabledBackground;
}
protected Color getForeground( boolean enabled ) {
@@ -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 );
}
@@ -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 );
}
}
}

View File

@@ -59,7 +59,6 @@ import com.formdev.flatlaf.util.LoggingFacade;
* <!-- FlatEditorPaneUI -->
*
* @uiDefault Component.minimumWidth int
* @uiDefault Component.isIntelliJTheme boolean
* @uiDefault EditorPane.focusedBackground Color optional
*
* @author Karl Tauber
@@ -69,7 +68,6 @@ public class FlatEditorPaneUI
implements StyleableUI
{
@Styleable protected int minimumWidth;
protected boolean isIntelliJTheme;
private Color background;
@Styleable protected Color disabledBackground;
@Styleable protected Color inactiveBackground;
@@ -101,7 +99,6 @@ public class FlatEditorPaneUI
String prefix = getPropertyPrefix();
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
background = UIManager.getColor( prefix + ".background" );
disabledBackground = UIManager.getColor( prefix + ".disabledBackground" );
inactiveBackground = UIManager.getColor( prefix + ".inactiveBackground" );
@@ -252,11 +249,11 @@ public class FlatEditorPaneUI
@Override
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 ) {
g.setColor( FlatTextFieldUI.getBackground( c, isIntelliJTheme, focusedBackground ) );
static void paintBackground( Graphics g, JTextComponent c, Color focusedBackground ) {
g.setColor( FlatTextFieldUI.getBackground( c, focusedBackground ) );
g.fillRect( 0, 0, c.getWidth(), c.getHeight() );
}
}

View File

@@ -29,6 +29,7 @@ import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.function.Function;
import javax.swing.AbstractButton;
import javax.swing.Box;
@@ -53,6 +54,7 @@ import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.metal.MetalFileChooserUI;
import javax.swing.table.TableCellRenderer;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.icons.FlatFileViewDirectoryIcon;
import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.ScaledImageIcon;
import com.formdev.flatlaf.util.SystemInfo;
@@ -346,12 +348,12 @@ public class FlatFileChooserUI
fileView.clearIconCache();
}
private boolean doNotUseSystemIcons() {
private static boolean doNotUseSystemIcons() {
// 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 &&
SystemInfo.isX86 &&
(SystemInfo.isJava_17_orLater && !SystemInfo.isJava_18_orLater);
(SystemInfo.isJava_17_orLater && SystemInfo.javaVersion < SystemInfo.toVersion( 17, 0, 3, 0 ));
}
//---- class FlatFileView -------------------------------------------------
@@ -407,7 +409,7 @@ public class FlatFileChooserUI
protected final File[] files;
protected final JToggleButton[] buttons;
protected final ButtonGroup buttonGroup;
protected final ButtonGroup buttonGroup = new ButtonGroup();
@SuppressWarnings( "unchecked" )
public FlatShortcutsPanel( JFileChooser fc ) {
@@ -426,19 +428,22 @@ public class FlatFileChooserUI
File[] files = getChooserShortcutPanelFiles( fsv );
if( filesFunction != null )
files = filesFunction.apply( files );
this.files = files;
// create toolbar buttons
buttons = new JToggleButton[files.length];
buttonGroup = new ButtonGroup();
for( int i = 0; i < files.length; i++ ) {
// wrap drive path
if( fsv.isFileSystemRoot( files[i] ) )
files[i] = fsv.createFileObject( files[i].getAbsolutePath() );
ArrayList<File> filesList = new ArrayList<>();
ArrayList<JToggleButton> buttonsList = new ArrayList<>();
for( File file : files ) {
if( file == null )
continue;
// wrap drive path
if( fsv.isFileSystemRoot( file ) )
file = fsv.createFileObject( file.getAbsolutePath() );
File file = files[i];
String name = getDisplayName( fsv, file );
Icon icon = getIcon( fsv, file );
if( name == null )
continue;
// remove path from name
int lastSepIndex = name.lastIndexOf( File.separatorChar );
@@ -453,15 +458,21 @@ public class FlatFileChooserUI
// create button
JToggleButton button = createButton( name, icon );
File f = file;
button.addActionListener( e -> {
fc.setCurrentDirectory( file );
fc.setCurrentDirectory( f );
} );
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() );
}
@@ -526,6 +537,9 @@ public class FlatFileChooserUI
return icon;
}
if( doNotUseSystemIcons() )
return new FlatFileViewDirectoryIcon();
// Java 17+ supports getting larger system icons
try {
if( SystemInfo.isJava_17_orLater ) {
@@ -541,10 +555,12 @@ public class FlatFileChooserUI
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 );
// 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

View File

@@ -40,7 +40,6 @@ import javax.swing.plaf.ComponentUI;
* <!-- FlatTextFieldUI -->
*
* @uiDefault Component.minimumWidth int
* @uiDefault Component.isIntelliJTheme boolean
* @uiDefault FormattedTextField.placeholderForeground Color
* @uiDefault FormattedTextField.focusedBackground Color optional
* @uiDefault FormattedTextField.iconTextGap int optional, default is 4

View File

@@ -24,6 +24,7 @@ import java.awt.Rectangle;
import java.beans.PropertyChangeEvent;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import javax.swing.Icon;
@@ -179,7 +180,7 @@ public class FlatLabelUI
// BASE_SIZE rule is parsed in javax.swing.text.html.StyleSheet.addRule()
String style = "<style>BASE_SIZE " + c.getFont().getSize() + "</style>";
String lowerText = text.toLowerCase();
String lowerText = text.toLowerCase( Locale.ENGLISH );
int headIndex;
int styleIndex;
@@ -228,7 +229,7 @@ public class FlatLabelUI
int tagBegin = i + 1;
for( i += 2; i < textLength; 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 ) )
return true;

View File

@@ -18,6 +18,7 @@ package com.formdev.flatlaf.ui;
import java.io.File;
import java.net.URL;
import java.security.CodeSource;
import com.formdev.flatlaf.FlatSystemProperties;
import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.NativeLibrary;
@@ -32,6 +33,7 @@ import com.formdev.flatlaf.util.SystemInfo;
*/
class FlatNativeLibrary
{
private static boolean initialized;
private static NativeLibrary nativeLibrary;
/**
@@ -44,24 +46,41 @@ class FlatNativeLibrary
}
private static void initialize() {
if( nativeLibrary != null )
if( initialized )
return;
initialized = true;
if( !FlatSystemProperties.getBoolean( FlatSystemProperties.USE_NATIVE_LIBRARY, true ) )
return;
String classifier;
String ext;
if( SystemInfo.isWindows_10_orLater && (SystemInfo.isX86 || SystemInfo.isX86_64) ) {
// 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)
if( SystemInfo.isAARCH64 )
classifier = "windows-arm64";
else if( SystemInfo.isX86_64 )
classifier = "windows-x86_64";
else
classifier = "windows-x86";
classifier = SystemInfo.isX86_64 ? "windows-x86_64" : "windows-x86";
ext = "dll";
// 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();
// 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.isLinux && SystemInfo.isX86_64 ) {
// Linux: requires x86_64
@@ -128,10 +147,15 @@ class FlatNativeLibrary
private static File findLibraryBesideJar( String classifier, String ext ) {
try {
// get location of FlatLaf jar
URL jarUrl = FlatNativeLibrary.class.getProtectionDomain().getCodeSource().getLocation();
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

View File

@@ -66,7 +66,6 @@ import com.formdev.flatlaf.util.UIScale;
* <!-- FlatTextFieldUI -->
*
* @uiDefault Component.minimumWidth int
* @uiDefault Component.isIntelliJTheme boolean
* @uiDefault PasswordField.placeholderForeground Color
* @uiDefault PasswordField.focusedBackground Color optional
* @uiDefault PasswordField.iconTextGap int optional, default is 4

View File

@@ -36,6 +36,7 @@ import java.awt.Window;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseEvent;
import java.awt.event.WindowFocusListener;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
@@ -83,6 +84,8 @@ public class FlatPopupFactory
y = pt.y;
}
fixLinuxWaylandJava21focusIssue( owner );
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 )
@@ -103,6 +106,10 @@ public class FlatPopupFactory
return popup;
}
// check whether popup overlaps a heavy weight component
if( !forceHeavyWeight && overlapsHeavyWeightComponent( owner, contents, x, y ) )
forceHeavyWeight = true;
// create drop shadow popup
return new DropShadowPopup( getPopupForScreenOfOwner( owner, contents, x, y, forceHeavyWeight ), owner, contents );
}
@@ -389,9 +396,68 @@ public class FlatPopupFactory
FlatNativeWindowsLibrary.setWindowCornerPreference( hwnd, FlatNativeWindowsLibrary.DWMWCP_DONOTROUND );
}
private static boolean overlapsHeavyWeightComponent( Component owner, Component contents, int x, int y ) {
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 the 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;
}
}
}
//---- class NonFlashingPopup ---------------------------------------------
private class NonFlashingPopup
private static class NonFlashingPopup
extends Popup
{
private Popup delegate;

View File

@@ -193,27 +193,38 @@ public class FlatPopupMenuUI
@Override
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
if( popup instanceof BasicComboPopup ||
(popup.getComponentCount() > 0 && popup.getComponent( 0 ) instanceof JScrollPane) )
return super.getPopup( popup, x, y );
// do not add scroller if popup fits into screen
Dimension prefSize = popup.getPreferredSize();
int screenHeight = getScreenHeightAt( x, y );
if( prefSize.height <= screenHeight )
if( popupSize.height <= screenBounds.height )
return super.getPopup( popup, x, y );
// create scroller
FlatPopupScroller scroller = new FlatPopupScroller( popup );
scroller.setPreferredSize( new Dimension( prefSize.width, screenHeight ) );
scroller.setPreferredSize( new Dimension( popupSize.width, screenBounds.height ) );
// create popup
PopupFactory popupFactory = PopupFactory.getSharedInstance();
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())
GraphicsConfiguration gc = null;
for( GraphicsDevice device : GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices() ) {
@@ -234,7 +245,7 @@ public class FlatPopupMenuUI
Toolkit toolkit = Toolkit.getDefaultToolkit();
Rectangle screenBounds = (gc != null) ? gc.getBounds() : new Rectangle( toolkit.getScreenSize() );
Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets( gc );
return screenBounds.height - screenInsets.top - screenInsets.bottom;
return FlatUIUtils.subtractInsets( screenBounds, screenInsets );
}
//---- class FlatPopupMenuLayout ------------------------------------------

View File

@@ -35,6 +35,7 @@ import javax.swing.CellRendererPane;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.LookAndFeel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
@@ -208,6 +209,9 @@ public class FlatRadioButtonUI
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 );
}
@@ -275,20 +279,27 @@ public class FlatRadioButtonUI
int focusWidth = getIconFocusWidth( c );
if( focusWidth > 0 ) {
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 );
int leftOrRightInset = ltr ? insets.left : insets.right;
if( focusWidth > leftOrRightInset ) {
if( (focusWidth > insets.left || focusWidth > insets.right) &&
(halign == SwingConstants.LEFT || halign == SwingConstants.RIGHT) )
{
// 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).
// In this case the width has been increased in getPreferredSize() and
// here it is necessary to fix icon and text painting location.
int offset = focusWidth - leftOrRightInset;
if( !ltr )
offset = -offset;
int offset = (halign == SwingConstants.LEFT)
? Math.max( focusWidth - insets.left, 0 )
: -Math.max( focusWidth - insets.right, 0 );
// move the graphics origin to the left (or right)
g.translate( offset, 0 );
super.paint( g, c );
super.paint( FlatLabelUI.createGraphicsHTMLTextYCorrection( g, c ), c );
g.translate( -offset, 0 );
return;
}
@@ -325,6 +336,11 @@ public class FlatRadioButtonUI
: 0;
}
@Override
public int getBaseline( JComponent c, int width, int height ) {
return FlatButtonUI.getBaselineImpl( c, width, height );
}
//---- class FlatRadioButtonListener --------------------------------------
/** @since 2 */

View File

@@ -23,6 +23,7 @@ import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.IllegalComponentStateException;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.LayoutManager2;
@@ -366,6 +367,11 @@ public class FlatRootPaneUI
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;
}
}

View File

@@ -360,8 +360,8 @@ public class FlatScrollPaneUI
protected void updateViewport( PropertyChangeEvent e ) {
super.updateViewport( e );
JViewport oldViewport = (JViewport) (e.getOldValue());
JViewport newViewport = (JViewport) (e.getNewValue());
JViewport oldViewport = (JViewport) e.getOldValue();
JViewport newViewport = (JViewport) e.getNewValue();
removeViewportListeners( oldViewport );
addViewportListeners( newViewport );

View File

@@ -67,7 +67,6 @@ import com.formdev.flatlaf.util.LoggingFacade;
* @uiDefault Component.minimumWidth int
* @uiDefault Spinner.buttonStyle String button (default), mac or none
* @uiDefault Component.arrowType String chevron (default) or triangle
* @uiDefault Component.isIntelliJTheme boolean
* @uiDefault Spinner.disabledBackground Color
* @uiDefault Spinner.disabledForeground Color
* @uiDefault Spinner.focusedBackground Color optional
@@ -92,7 +91,6 @@ public class FlatSpinnerUI
@Styleable protected int minimumWidth;
@Styleable protected String buttonStyle;
@Styleable protected String arrowType;
protected boolean isIntelliJTheme;
@Styleable protected Color disabledBackground;
@Styleable protected Color disabledForeground;
@Styleable protected Color focusedBackground;
@@ -129,7 +127,6 @@ public class FlatSpinnerUI
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
buttonStyle = UIManager.getString( "Spinner.buttonStyle" );
arrowType = UIManager.getString( "Component.arrowType" );
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
disabledBackground = UIManager.getColor( "Spinner.disabledBackground" );
disabledForeground = UIManager.getColor( "Spinner.disabledForeground" );
focusedBackground = UIManager.getColor( "Spinner.focusedBackground" );
@@ -316,7 +313,7 @@ public class FlatSpinnerUI
return background;
} else
return isIntelliJTheme ? FlatUIUtils.getParentBackground( spinner ) : disabledBackground;
return disabledBackground;
}
protected Color getForeground( boolean enabled ) {

View File

@@ -87,7 +87,6 @@ public class FlatSplitPaneUI
@Styleable protected Color oneTouchHoverArrowColor;
@Styleable protected Color oneTouchPressedArrowColor;
private PropertyChangeListener propertyChangeListener;
private Map<String, Object> oldStyleValues;
public static ComponentUI createUI( JComponent c ) {
@@ -126,19 +125,9 @@ public class FlatSplitPaneUI
}
@Override
protected void installListeners() {
super.installListeners();
propertyChangeListener = FlatStylingSupport.createPropertyChangeListener( splitPane, this::installStyle, null );
splitPane.addPropertyChangeListener( propertyChangeListener );
}
@Override
protected void uninstallListeners() {
super.uninstallListeners();
splitPane.removePropertyChangeListener( propertyChangeListener );
propertyChangeListener = null;
protected PropertyChangeListener createPropertyChangeListener() {
return FlatStylingSupport.createPropertyChangeListener( splitPane, this::installStyle,
super.createPropertyChangeListener() );
}
@Override

View File

@@ -100,15 +100,15 @@ public class FlatStylingSupport
/** @since 2 */
public interface StyleableUI {
Map<String, Class<?>> getStyleableInfos( JComponent c );
/** @since 2.5 */ Object getStyleableValue( JComponent c, String key );
Map<String, Class<?>> getStyleableInfos( JComponent c ) throws IllegalArgumentException;
/** @since 2.5 */ Object getStyleableValue( JComponent c, String key ) throws IllegalArgumentException;
}
/** @since 2 */
public interface StyleableBorder {
Object applyStyleProperty( String key, Object value );
Map<String, Class<?>> getStyleableInfos();
/** @since 2.5 */ Object getStyleableValue( String key );
Map<String, Class<?>> getStyleableInfos() throws IllegalArgumentException;
/** @since 2.5 */ Object getStyleableValue( String key ) throws IllegalArgumentException;
}
/** @since 2.5 */
@@ -135,7 +135,9 @@ public class FlatStylingSupport
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 styleClass = getStyleClass( c );
Object styleForClasses = getStyleForClasses( styleClass, type );
@@ -175,7 +177,9 @@ public class FlatStylingSupport
* @param type the type of the component
* @return the styles
*/
public static Object getStyleForClasses( Object styleClass, String type ) {
public static Object getStyleForClasses( Object styleClass, String type )
throws IllegalArgumentException
{
if( styleClass == null )
return null;
@@ -198,7 +202,9 @@ public class FlatStylingSupport
return null;
}
private static Object getStyleForClass( String styleClass, String type ) {
private static Object getStyleForClass( String styleClass, String type )
throws IllegalArgumentException
{
return joinStyles(
UIManager.get( "[style]." + styleClass ),
UIManager.get( "[style]" + type + '.' + styleClass ) );
@@ -218,7 +224,9 @@ public class FlatStylingSupport
* @return new joined style
*/
@SuppressWarnings( "unchecked" )
public static Object joinStyles( Object style1, Object style2 ) {
public static Object joinStyles( Object style1, Object style2 )
throws IllegalArgumentException
{
if( style1 == null )
return style2;
if( style2 == null )
@@ -278,6 +286,7 @@ public class FlatStylingSupport
* @throws IllegalArgumentException on syntax errors
* @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,
Object style, BiFunction<String, Object, Object> applyProperty )
throws UnknownStyleException, IllegalArgumentException
@@ -379,7 +388,9 @@ public class FlatStylingSupport
return map;
}
private static Object parseValue( String key, String value ) {
private static Object parseValue( String key, String value )
throws IllegalArgumentException
{
// simple reference
if( value.startsWith( "$" ) )
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 );
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 );
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 );
}
private static void checkValidField( Field f ) {
private static void checkValidField( Field f )
throws IllegalArgumentException
{
if( !isValidField( f ) )
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();
}
private static Field getStyleableField( StyleableField styleableField ) {
private static Field getStyleableField( StyleableField styleableField )
throws IllegalArgumentException
{
String fieldName = styleableField.fieldName();
if( fieldName.isEmpty() )
fieldName = styleableField.key();
@@ -647,6 +666,7 @@ public class FlatStylingSupport
static Object applyToAnnotatedObjectOrBorder( Object obj, String key, Object value,
JComponent c, AtomicBoolean borderShared )
throws IllegalArgumentException
{
try {
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();
try {
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();
try {
return iconClass.getDeclaredConstructor().newInstance();
@@ -717,11 +741,15 @@ public class FlatStylingSupport
* 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.
*/
public static Map<String, Class<?>> getAnnotatedStyleableInfos( Object obj ) {
public static Map<String, Class<?>> getAnnotatedStyleableInfos( Object obj )
throws IllegalArgumentException
{
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<>();
collectAnnotatedStyleableInfos( obj, 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.
* 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<>();
Class<?> cls = obj.getClass();
@@ -810,7 +840,9 @@ public class FlatStylingSupport
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 );
Class<?> cls = obj.getClass();
@@ -877,7 +909,9 @@ public class FlatStylingSupport
extends LinkedHashMap<K,V>
{
@Override
public V put( K key, V value ) {
public V put( K key, V value )
throws IllegalArgumentException
{
V oldValue = super.put( key, value );
if( oldValue != null )
throw new IllegalArgumentException( "duplicate key '" + key + "'" );

View File

@@ -49,6 +49,7 @@ import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.geom.Area;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeEvent;
@@ -143,6 +144,11 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault TabbedPane.tabHeight int
* @uiDefault TabbedPane.tabSelectionHeight int
* @uiDefault TabbedPane.cardTabSelectionHeight int
* @uiDefault TabbedPane.tabArc int
* @uiDefault TabbedPane.tabSelectionArc int
* @uiDefault TabbedPane.cardTabArc int
* @uiDefault TabbedPane.selectedInsets Insets
* @uiDefault TabbedPane.tabSelectionInsets Insets
* @uiDefault TabbedPane.contentSeparatorHeight int
* @uiDefault TabbedPane.showTabSeparators boolean
* @uiDefault TabbedPane.tabSeparatorsFullHeight boolean
@@ -219,6 +225,11 @@ public class FlatTabbedPaneUI
@Styleable protected int tabHeight;
@Styleable protected int tabSelectionHeight;
/** @since 2 */ @Styleable protected int cardTabSelectionHeight;
/** @since 3.2 */ @Styleable protected int tabArc;
/** @since 3.2 */ @Styleable protected int tabSelectionArc;
/** @since 3.2 */ @Styleable protected int cardTabArc;
/** @since 3.2 */ @Styleable protected Insets selectedInsets;
/** @since 3.2 */ @Styleable protected Insets tabSelectionInsets;
@Styleable protected int contentSeparatorHeight;
@Styleable protected boolean showTabSeparators;
@Styleable protected boolean tabSeparatorsFullHeight;
@@ -344,6 +355,11 @@ public class FlatTabbedPaneUI
tabHeight = UIManager.getInt( "TabbedPane.tabHeight" );
tabSelectionHeight = UIManager.getInt( "TabbedPane.tabSelectionHeight" );
cardTabSelectionHeight = UIManager.getInt( "TabbedPane.cardTabSelectionHeight" );
tabArc = UIManager.getInt( "TabbedPane.tabArc" );
tabSelectionArc = UIManager.getInt( "TabbedPane.tabSelectionArc" );
cardTabArc = UIManager.getInt( "TabbedPane.cardTabArc" );
selectedInsets = UIManager.getInsets( "TabbedPane.selectedInsets" );
tabSelectionInsets = UIManager.getInsets( "TabbedPane.tabSelectionInsets" );
contentSeparatorHeight = UIManager.getInt( "TabbedPane.contentSeparatorHeight" );
showTabSeparators = UIManager.getBoolean( "TabbedPane.showTabSeparators" );
tabSeparatorsFullHeight = UIManager.getBoolean( "TabbedPane.tabSeparatorsFullHeight" );
@@ -1184,10 +1200,41 @@ public class FlatTabbedPaneUI
protected void paintTabBackground( Graphics g, int tabPlacement, int tabIndex,
int x, int y, int w, int h, boolean isSelected )
{
boolean isCard = (getTabType() == TAB_TYPE_CARD);
// fill whole tab background if tab is rounded or has insets
if( (!isCard && tabArc > 0) ||
(isCard && cardTabArc > 0) ||
(!isCard && selectedInsets != null &&
(selectedInsets.top != 0 || selectedInsets.left != 0 ||
selectedInsets.bottom != 0 || selectedInsets.right != 0)) )
{
Color background = tabPane.getBackgroundAt( tabIndex );
g.setColor( FlatUIUtils.deriveColor( background, tabPane.getBackground() ) );
g.fillRect( x, y, w, h );
}
// apply insets
if( !isCard && selectedInsets != null ) {
Insets insets = new Insets( 0, 0, 0, 0 );
rotateInsets( selectedInsets, insets, tabPane.getTabPlacement() );
x += scale( insets.left );
y += scale( insets.top );
w -= scale( insets.left + insets.right );
h -= scale( insets.top + insets.bottom );
}
// paint tab background
Color background = getTabBackground( tabPlacement, tabIndex, isSelected );
g.setColor( FlatUIUtils.deriveColor( background, tabPane.getBackground() ) );
g.fillRect( x, y, w, h );
if( !isCard && tabArc > 0 ) {
float arc = scale( (float) tabArc ) / 2f;
FlatUIUtils.paintSelection( (Graphics2D) g, x, y, w, h, null, arc, arc, arc, arc, 0 );
} else if( isCard && cardTabArc > 0 )
((Graphics2D)g).fill( createCardTabOuterPath( tabPlacement, x, y, w, h ) );
else
g.fillRect( x, y, w, h );
}
/** @since 2 */
@@ -1241,42 +1288,38 @@ public class FlatTabbedPaneUI
protected void paintCardTabBorder( Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h ) {
Graphics2D g2 = (Graphics2D) g;
float borderWidth = scale( (float) contentSeparatorHeight );
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
path.append( createCardTabOuterPath( tabPlacement, x, y, w, h ), false );
path.append( createCardTabInnerPath( tabPlacement, x, y, w, h ), false );
g.setColor( (tabSeparatorColor != null) ? tabSeparatorColor : contentAreaColor );
g2.fill( path );
}
/** @since 3.2 */
protected Shape createCardTabOuterPath( int tabPlacement, int x, int y, int w, int h ) {
float arc = scale( (float) cardTabArc ) / 2f;
switch( tabPlacement ) {
default:
case TOP:
case BOTTOM:
// paint left and right tab border
g2.fill( new Rectangle2D.Float( x, y, borderWidth, h ) );
g2.fill( new Rectangle2D.Float( x + w - borderWidth, y, borderWidth, h ) );
break;
case LEFT:
case RIGHT:
// paint top and bottom tab border
g2.fill( new Rectangle2D.Float( x, y, w, borderWidth ) );
g2.fill( new Rectangle2D.Float( x, y + h - borderWidth, w, borderWidth ) );
break;
case TOP: return FlatUIUtils.createRoundRectanglePath( x, y, w, h, arc, arc, 0, 0 );
case BOTTOM: return FlatUIUtils.createRoundRectanglePath( x, y, w, h, 0, 0, arc, arc );
case LEFT: return FlatUIUtils.createRoundRectanglePath( x, y, w, h, arc, 0, arc, 0 );
case RIGHT: return FlatUIUtils.createRoundRectanglePath( x, y, w, h, 0, arc, 0, arc );
}
}
if( cardTabSelectionHeight <= 0 ) {
// if there is no tab selection indicator, paint a top border as well
switch( tabPlacement ) {
default:
case TOP:
g2.fill( new Rectangle2D.Float( x, y, w, borderWidth ) );
break;
case BOTTOM:
g2.fill( new Rectangle2D.Float( x, y + h - borderWidth, w, borderWidth ) );
break;
case LEFT:
g2.fill( new Rectangle2D.Float( x, y, borderWidth, h ) );
break;
case RIGHT:
g2.fill( new Rectangle2D.Float( x + w - borderWidth, y, borderWidth, h ) );
break;
}
/** @since 3.2 */
protected Shape createCardTabInnerPath( int tabPlacement, int x, int y, int w, int h ) {
float bw = scale( (float) contentSeparatorHeight );
float arc = (scale( (float) cardTabArc ) / 2f) - bw;
switch( tabPlacement ) {
default:
case TOP: return FlatUIUtils.createRoundRectanglePath( x + bw, y + bw, w - (bw * 2), h - bw, arc, arc, 0, 0 );
case BOTTOM: return FlatUIUtils.createRoundRectanglePath( x + bw, y, w - (bw * 2), h - bw, 0, 0, arc, arc );
case LEFT: return FlatUIUtils.createRoundRectanglePath( x + bw, y + bw, w - bw, h - (bw * 2), arc, 0, arc, 0 );
case RIGHT: return FlatUIUtils.createRoundRectanglePath( x, y + bw, w - bw, h - (bw * 2), 0, arc, 0, arc );
}
}
@@ -1324,38 +1367,62 @@ public class FlatTabbedPaneUI
? (isTabbedPaneOrChildFocused() ? underlineColor : inactiveUnderlineColor)
: disabledUnderlineColor );
// paint underline selection
boolean atBottom = (getTabType() != TAB_TYPE_CARD);
boolean isCard = (getTabType() == TAB_TYPE_CARD);
boolean atBottom = !isCard;
Insets contentInsets = atBottom
? ((!rotateTabRuns && runCount > 1 && !isScrollTabLayout() && getRunForTab( tabPane.getTabCount(), tabIndex ) > 0)
? new Insets( 0, 0, 0, 0 )
: getContentBorderInsets( tabPlacement ))
: null;
int tabSelectionHeight = scale( atBottom ? this.tabSelectionHeight : cardTabSelectionHeight );
int sx, sy;
int tabSelectionHeight = scale( isCard ? cardTabSelectionHeight : this.tabSelectionHeight );
float arc = scale( (float) (isCard ? cardTabArc : tabSelectionArc) ) / 2f;
int sx = x, sy = y, sw = w, sh = h;
switch( tabPlacement ) {
case TOP:
default:
sy = atBottom ? (y + h + contentInsets.top - tabSelectionHeight) : y;
g.fillRect( x, sy, w, tabSelectionHeight );
sh = tabSelectionHeight;
break;
case BOTTOM:
sy = atBottom ? (y - contentInsets.bottom) : (y + h - tabSelectionHeight);
g.fillRect( x, sy, w, tabSelectionHeight );
sh = tabSelectionHeight;
break;
case LEFT:
sx = atBottom ? (x + w + contentInsets.left - tabSelectionHeight) : x;
g.fillRect( sx, y, tabSelectionHeight, h );
sw = tabSelectionHeight;
break;
case RIGHT:
sx = atBottom ? (x - contentInsets.right) : (x + w - tabSelectionHeight);
g.fillRect( sx, y, tabSelectionHeight, h );
sw = tabSelectionHeight;
break;
}
// apply insets
if( !isCard && tabSelectionInsets != null ) {
Insets insets = new Insets( 0, 0, 0, 0 );
rotateInsets( tabSelectionInsets, insets, tabPane.getTabPlacement() );
sx += scale( insets.left );
sy += scale( insets.top );
sw -= scale( insets.left + insets.right );
sh -= scale( insets.top + insets.bottom );
}
// paint underline selection
if( arc <= 0 )
g.fillRect( sx, sy, sw, sh );
else {
if( isCard ) {
Area area = new Area( createCardTabOuterPath( tabPlacement, x, y, w, h ) );
area.intersect( new Area( new Rectangle2D.Float( sx, sy, sw, sh ) ) );
((Graphics2D)g).fill( area );
} else
FlatUIUtils.paintSelection( (Graphics2D) g, sx, sy, sw, sh, null, arc, arc, arc, arc, 0 );
}
}
/** @since 2.2 */
@@ -1967,7 +2034,7 @@ public class FlatTabbedPaneUI
//---- class TabCloseButton -----------------------------------------------
private class TabCloseButton
private static class TabCloseButton
extends JButton
implements UIResource
{
@@ -1977,7 +2044,7 @@ public class FlatTabbedPaneUI
//---- class ContainerUIResource ------------------------------------------
private class ContainerUIResource
private static class ContainerUIResource
extends JPanel
implements UIResource
{
@@ -2382,7 +2449,7 @@ public class FlatTabbedPaneUI
if( isPreciseWheel &&
getScrollButtonsPlacement() == BOTH &&
getScrollButtonsPolicy() == AS_NEEDED_SINGLE &&
(isLeftToRight() || !horizontal) || // scroll buttons are hidden in right-to-left
(isLeftToRight() || !horizontal) && // scroll buttons are hidden in right-to-left
scrollBackwardButtonPrefSize != null )
{
// special cases for scrolling with touchpad or high-resolution wheel:
@@ -3051,7 +3118,7 @@ public class FlatTabbedPaneUI
break;
case CENTER:
shiftTabs( 0, (diff) / 2 );
shiftTabs( 0, diff / 2 );
topHeight += diff / 2;
bottomHeight += diff - (diff / 2);
break;
@@ -3500,7 +3567,7 @@ public class FlatTabbedPaneUI
//---- class FlatSelectedTabRepainter -------------------------------------
private static class FlatSelectedTabRepainter
implements PropertyChangeListener//, Runnable
implements PropertyChangeListener
{
private static FlatSelectedTabRepainter instance;
@@ -3550,17 +3617,31 @@ public class FlatTabbedPaneUI
break;
case "activeWindow":
repaintSelectedTabs( keyboardFocusManager.getPermanentFocusOwner() );
Component permanentFocusOwner = keyboardFocusManager.getPermanentFocusOwner();
if( permanentFocusOwner != null )
repaintSelectedTabs( permanentFocusOwner );
break;
}
}
private void repaintSelectedTabs( Component c ) {
if( c instanceof JTabbedPane )
repaintSelectedTab( (JTabbedPane) c );
// Use invokeLater because this method may be invoked while UI update
// is in progress. This may happen if a focusable component (e.g. text field)
// is used as tab component (see JTabbedPane.setTabComponentAt()).
// uninstallTabContainer() removes all components from tabbed pane and
// the text field looses focus.
EventQueue.invokeLater( () -> {
// because this is invoked later, check whether component is still displayable
if( !c.isDisplayable() )
return;
while( (c = SwingUtilities.getAncestorOfClass( JTabbedPane.class, c )) != null )
repaintSelectedTab( (JTabbedPane) c );
if( c instanceof JTabbedPane )
repaintSelectedTab( (JTabbedPane) c );
Component c2 = c;
while( (c2 = SwingUtilities.getAncestorOfClass( JTabbedPane.class, c2 )) != null )
repaintSelectedTab( (JTabbedPane) c2 );
} );
}
private void repaintSelectedTab( JTabbedPane tabbedPane ) {

View File

@@ -277,6 +277,9 @@ public class FlatTableUI
/** @since 2 */
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 );
}

View File

@@ -54,7 +54,6 @@ import com.formdev.flatlaf.util.LoggingFacade;
* <!-- FlatTextAreaUI -->
*
* @uiDefault Component.minimumWidth int
* @uiDefault Component.isIntelliJTheme boolean
* @uiDefault TextArea.disabledBackground Color used if not enabled
* @uiDefault TextArea.inactiveBackground Color used if not editable
* @uiDefault TextArea.focusedBackground Color optional
@@ -66,7 +65,6 @@ public class FlatTextAreaUI
implements StyleableUI
{
@Styleable protected int minimumWidth;
protected boolean isIntelliJTheme;
private Color background;
@Styleable protected Color disabledBackground;
@Styleable protected Color inactiveBackground;
@@ -103,7 +101,6 @@ public class FlatTextAreaUI
super.installDefaults();
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
background = UIManager.getColor( "TextArea.background" );
disabledBackground = UIManager.getColor( "TextArea.disabledBackground" );
inactiveBackground = UIManager.getColor( "TextArea.inactiveBackground" );
@@ -227,6 +224,6 @@ public class FlatTextAreaUI
@Override
protected void paintBackground( Graphics g ) {
FlatEditorPaneUI.paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground );
FlatEditorPaneUI.paintBackground( g, getComponent(), focusedBackground );
}
}

View File

@@ -45,6 +45,7 @@ import javax.swing.JTextField;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import javax.swing.LookAndFeel;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
@@ -81,7 +82,6 @@ import com.formdev.flatlaf.util.LoggingFacade;
* <!-- FlatTextFieldUI -->
*
* @uiDefault Component.minimumWidth int
* @uiDefault Component.isIntelliJTheme boolean
* @uiDefault TextField.placeholderForeground Color
* @uiDefault TextField.focusedBackground Color optional
* @uiDefault TextField.iconTextGap int optional, default is 4
@@ -95,7 +95,6 @@ public class FlatTextFieldUI
implements StyleableUI
{
@Styleable protected int minimumWidth;
protected boolean isIntelliJTheme;
private Color background;
@Styleable protected Color disabledBackground;
@Styleable protected Color inactiveBackground;
@@ -165,7 +164,6 @@ public class FlatTextFieldUI
String prefix = getPropertyPrefix();
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
background = UIManager.getColor( prefix + ".background" );
disabledBackground = UIManager.getColor( prefix + ".disabledBackground" );
inactiveBackground = UIManager.getColor( prefix + ".inactiveBackground" );
@@ -402,7 +400,7 @@ public class FlatTextFieldUI
@Override
protected void paintSafely( Graphics g ) {
paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground );
paintBackground( g, getComponent(), focusedBackground );
paintPlaceholder( g );
if( hasLeadingIcon() || hasTrailingIcon() )
@@ -422,7 +420,7 @@ debug*/
// 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:
// - not opaque and
// - border is not a flat border and
@@ -443,14 +441,14 @@ debug*/
try {
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 );
} finally {
g2.dispose();
}
}
static Color getBackground( JTextComponent c, boolean isIntelliJTheme, Color focusedBackground ) {
static Color getBackground( JTextComponent c, Color focusedBackground ) {
Color background = c.getBackground();
// always use explicitly set color
@@ -461,10 +459,6 @@ debug*/
if( focusedBackground != null && FlatUIUtils.isPermanentFocusOwner( c ) )
return focusedBackground;
// for compatibility with IntelliJ themes
if( isIntelliJTheme && (!c.isEnabled() || !c.isEditable()) )
return FlatUIUtils.getParentBackground( c );
return background;
}
@@ -487,10 +481,22 @@ debug*/
// compute placeholder location
Rectangle r = getVisibleEditorRect();
FontMetrics fm = c.getFontMetrics( c.getFont() );
String clippedPlaceholder = JavaCompatibility.getClippedString( c, fm, placeholder, r.width );
int x = r.x + (isLeftToRight() ? 0 : r.width - fm.stringWidth( clippedPlaceholder ));
int x = r.x;
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
g.setColor( placeholderForeground );
FlatUIUtils.drawString( c, g, clippedPlaceholder, x, y );

View File

@@ -56,7 +56,6 @@ import com.formdev.flatlaf.util.LoggingFacade;
* <!-- FlatTextPaneUI -->
*
* @uiDefault Component.minimumWidth int
* @uiDefault Component.isIntelliJTheme boolean
* @uiDefault TextPane.focusedBackground Color optional
*
* @author Karl Tauber
@@ -66,7 +65,6 @@ public class FlatTextPaneUI
implements StyleableUI
{
@Styleable protected int minimumWidth;
protected boolean isIntelliJTheme;
private Color background;
@Styleable protected Color disabledBackground;
@Styleable protected Color inactiveBackground;
@@ -98,7 +96,6 @@ public class FlatTextPaneUI
String prefix = getPropertyPrefix();
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
background = UIManager.getColor( prefix + ".background" );
disabledBackground = UIManager.getColor( prefix + ".disabledBackground" );
inactiveBackground = UIManager.getColor( prefix + ".inactiveBackground" );
@@ -220,6 +217,6 @@ public class FlatTextPaneUI
@Override
protected void paintBackground( Graphics g ) {
FlatEditorPaneUI.paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground );
FlatEditorPaneUI.paintBackground( g, getComponent(), focusedBackground );
}
}

View File

@@ -57,6 +57,7 @@ import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
@@ -96,6 +97,7 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault TitlePane.centerTitleIfMenuBarEmbedded boolean
* @uiDefault TitlePane.showIconBesideTitle boolean
* @uiDefault TitlePane.menuBarTitleGap int
* @uiDefault TitlePane.menuBarTitleMinimumGap int
* @uiDefault TitlePane.menuBarResizeHeight int
* @uiDefault TitlePane.closeIcon Icon
* @uiDefault TitlePane.iconifyIcon Icon
@@ -109,29 +111,30 @@ public class FlatTitlePane
{
private static final String KEY_DEBUG_SHOW_RECTANGLES = "FlatLaf.debug.titlebar.showRectangles";
/** @since 2.5 */ protected final Font titleFont = UIManager.getFont( "TitlePane.font" );
protected final Color activeBackground = UIManager.getColor( "TitlePane.background" );
protected final Color inactiveBackground = UIManager.getColor( "TitlePane.inactiveBackground" );
protected final Color activeForeground = UIManager.getColor( "TitlePane.foreground" );
protected final Color inactiveForeground = UIManager.getColor( "TitlePane.inactiveForeground" );
protected final Color embeddedForeground = UIManager.getColor( "TitlePane.embeddedForeground" );
protected final Color borderColor = UIManager.getColor( "TitlePane.borderColor" );
/** @since 2.5 */ protected final Font titleFont;
protected final Color activeBackground;
protected final Color inactiveBackground;
protected final Color activeForeground;
protected final Color inactiveForeground;
protected final Color embeddedForeground;
protected final Color borderColor;
/** @since 2 */ protected final boolean showIcon = FlatUIUtils.getUIBoolean( "TitlePane.showIcon", true );
/** @since 2.5 */ protected final boolean showIconInDialogs = FlatUIUtils.getUIBoolean( "TitlePane.showIconInDialogs", true );
/** @since 2 */ protected final int noIconLeftGap = FlatUIUtils.getUIInt( "TitlePane.noIconLeftGap", 8 );
protected final Dimension iconSize = UIManager.getDimension( "TitlePane.iconSize" );
/** @since 2.4 */ protected final int titleMinimumWidth = FlatUIUtils.getUIInt( "TitlePane.titleMinimumWidth", 60 );
/** @since 2.4 */ protected final int buttonMinimumWidth = FlatUIUtils.getUIInt( "TitlePane.buttonMinimumWidth", 30 );
protected final int buttonMaximizedHeight = UIManager.getInt( "TitlePane.buttonMaximizedHeight" );
protected final boolean centerTitle = UIManager.getBoolean( "TitlePane.centerTitle" );
protected final boolean centerTitleIfMenuBarEmbedded = FlatUIUtils.getUIBoolean( "TitlePane.centerTitleIfMenuBarEmbedded", true );
/** @since 2.4 */ protected final boolean showIconBesideTitle = UIManager.getBoolean( "TitlePane.showIconBesideTitle" );
protected final int menuBarTitleGap = FlatUIUtils.getUIInt( "TitlePane.menuBarTitleGap", 40 );
/** @since 2.4 */ protected final int menuBarTitleMinimumGap = FlatUIUtils.getUIInt( "TitlePane.menuBarTitleMinimumGap", 12 );
/** @since 2.4 */ protected final int menuBarResizeHeight = FlatUIUtils.getUIInt( "TitlePane.menuBarResizeHeight", 4 );
/** @since 2 */ protected final boolean showIcon;
/** @since 2.5 */ protected final boolean showIconInDialogs;
/** @since 2 */ protected final int noIconLeftGap;
protected final Dimension iconSize;
/** @since 2.4 */ protected final int titleMinimumWidth;
/** @since 2.4 */ protected final int buttonMinimumWidth;
protected final int buttonMaximizedHeight;
protected final boolean centerTitle;
protected final boolean centerTitleIfMenuBarEmbedded;
/** @since 2.4 */ protected final boolean showIconBesideTitle;
protected final int menuBarTitleGap;
/** @since 2.4 */ protected final int menuBarTitleMinimumGap;
/** @since 2.4 */ protected final int menuBarResizeHeight;
protected final JRootPane rootPane;
protected final String windowStyle;
protected JPanel leftPanel;
protected JLabel iconLabel;
@@ -150,6 +153,34 @@ public class FlatTitlePane
public FlatTitlePane( JRootPane 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();
setBorder( createTitlePaneBorder() );
@@ -182,8 +213,8 @@ public class FlatTitlePane
setUI( new FlatTitleLabelUI() );
}
};
iconLabel.setBorder( new FlatEmptyBorder( UIManager.getInsets( "TitlePane.iconMargins" ) ) );
titleLabel.setBorder( new FlatEmptyBorder( UIManager.getInsets( "TitlePane.titleMargins" ) ) );
iconLabel.setBorder( new FlatEmptyBorder( FlatUIUtils.getSubUIInsets( "TitlePane.iconMargins", windowStyle ) ) );
titleLabel.setBorder( new FlatEmptyBorder( FlatUIUtils.getSubUIInsets( "TitlePane.titleMargins", windowStyle ) ) );
leftPanel.setLayout( new BoxLayout( leftPanel, BoxLayout.LINE_AXIS ) );
leftPanel.setOpaque( false );
@@ -310,7 +341,7 @@ public class FlatTitlePane
}
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
public Dimension getMinimumSize() {
// allow the button to shrink if space is rare
@@ -682,7 +713,7 @@ public class FlatTitlePane
// 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;
newState = (oldState & ~Frame.MAXIMIZED_BOTH) | Frame.MAXIMIZED_HORIZ;
}
frame.setExtendedState( newState );
@@ -952,6 +983,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 maximizeButtonBounds = boundsInWindow( maximizeButton.isVisible() ? maximizeButton : restoreButton );
Rectangle closeButtonBounds = boundsInWindow( closeButton );

View File

@@ -39,10 +39,12 @@ import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JToolBar;
import javax.swing.LayoutFocusTraversalPolicy;
import javax.swing.RootPaneContainer;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicToolBarUI;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.util.LoggingFacade;
@@ -156,6 +158,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
protected ContainerListener createToolBarContListener() {
return new ToolBarContListener() {

View File

@@ -420,6 +420,9 @@ public class FlatTreeUI
/** @since 2 */
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 );
}
@@ -575,7 +578,7 @@ public class FlatTreeUI
if( isSelected && isWideSelection() ) {
Color oldColor = g.getColor();
g.setColor( selectionInactiveBackground );
paintWideSelection( g, clipBounds, insets, bounds, path, row, isExpanded, hasBeenExpanded, isLeaf );
paintWideSelection( g, bounds, row );
g.setColor( oldColor );
}
return;
@@ -633,7 +636,7 @@ public class FlatTreeUI
if( isWideSelection() ) {
// wide selection
paintWideSelection( g, clipBounds, insets, bounds, path, row, isExpanded, hasBeenExpanded, isLeaf );
paintWideSelection( g, bounds, row );
} else {
// non-wide selection
paintCellBackground( g, rendererComponent, bounds, row, true );
@@ -702,9 +705,7 @@ public class FlatTreeUI
return oldColor;
}
private void paintWideSelection( Graphics g, Rectangle clipBounds, Insets insets, Rectangle bounds,
TreePath path, int row, boolean isExpanded, boolean hasBeenExpanded, boolean isLeaf )
{
private void paintWideSelection( Graphics g, Rectangle bounds, int row ) {
float arcTop, arcBottom;
arcTop = arcBottom = UIScale.scale( selectionArc / 2f );

View File

@@ -46,6 +46,7 @@ import java.util.IdentityHashMap;
import java.util.WeakHashMap;
import java.util.function.Predicate;
import java.util.function.Supplier;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JScrollPane;
import javax.swing.JTable;
@@ -166,6 +167,88 @@ public class FlatUIUtils
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 */
public static boolean getBoolean( JComponent c, String systemPropertyKey,
String clientPropertyKey, String uiKey, boolean defaultValue )
@@ -725,7 +808,7 @@ public class FlatUIUtils
{
dotSize = UIScale.scale( dotSize );
gap = UIScale.scale( gap );
int gripSize = (dotSize * dotCount) + ((gap * (dotCount - 1)));
int gripSize = (dotSize * dotCount) + (gap * (dotCount - 1));
// calculate grip position
float gx;

View File

@@ -88,10 +88,6 @@ class FlatWindowsNativeWindowBorder
if( !SystemInfo.isWindows_10_orLater )
return null;
// requires x86 architecture
if( !SystemInfo.isX86 && !SystemInfo.isX86_64 )
return null;
// check whether native library was successfully loaded
if( !FlatNativeLibrary.isLoaded() )
return null;

View File

@@ -28,7 +28,6 @@ import java.awt.Paint;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.RenderingHints.Key;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.font.FontRenderContext;
@@ -368,12 +367,12 @@ public class Graphics2DProxy
}
@Override
public void setRenderingHint( Key hintKey, Object hintValue ) {
public void setRenderingHint( RenderingHints.Key hintKey, Object hintValue ) {
delegate.setRenderingHint( hintKey, hintValue );
}
@Override
public Object getRenderingHint( Key hintKey ) {
public Object getRenderingHint( RenderingHints.Key hintKey ) {
return delegate.getRenderingHint( hintKey );
}

View File

@@ -20,9 +20,12 @@ import java.awt.Dimension;
import java.awt.Image;
import java.awt.image.AbstractMultiResolutionImage;
import java.awt.image.BaseMultiResolutionImage;
import java.awt.image.ImageObserver;
import java.awt.image.ImageProducer;
import java.awt.image.MultiResolutionImage;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.function.Function;
@@ -116,6 +119,26 @@ public class MultiResolutionImageSupport
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 ) {
return cache.computeIfAbsent( image, img -> {
// using ImageIcon here makes sure that the image is loaded
@@ -134,7 +157,7 @@ public class MultiResolutionImageSupport
{
private final Dimension[] dimensions;
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 ) {
this.dimensions = dimensions;
@@ -159,6 +182,16 @@ public class MultiResolutionImageSupport
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 ) {
return cache.computeIfAbsent( size, size2 -> {
// using ImageIcon here makes sure that the image is loaded

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
/**
/*
* @author Karl Tauber
*/
module com.formdev.flatlaf {

View File

@@ -671,7 +671,12 @@ SplitPaneDivider.gripGap = 2
TabbedPane.tabHeight = 32
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.showTabSeparators = false
TabbedPane.tabSeparatorsFullHeight = false
@@ -808,6 +813,7 @@ TitlePane.titleMinimumWidth = 60
TitlePane.buttonSize = 44,30
TitlePane.buttonMinimumWidth = 30
TitlePane.buttonMaximizedHeight = 22
TitlePane.buttonSymbolHeight = 10
TitlePane.centerTitle = false
TitlePane.centerTitleIfMenuBarEmbedded = true
TitlePane.showIconBesideTitle = false
@@ -829,6 +835,16 @@ TitlePane.closePressedBackground = fade($TitlePane.closeHoverBackground,90%)
TitlePane.closeHoverForeground = #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 ----

View File

@@ -112,6 +112,9 @@ ToggleButton.endBackground = $ToggleButton.background
@ijMenuCheckBackgroundL20 = lighten(@selectionBackground,20%,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]PopupMenu.foreground = lazy(MenuItem.foreground)
[Arc_Theme]RadioButtonMenuItem.foreground = lazy(MenuItem.foreground)
@@ -135,53 +138,110 @@ ToggleButton.endBackground = $ToggleButton.background
[Arc_Theme_Dark]RadioButtonMenuItem.foreground = lazy(MenuItem.foreground)
[Arc_Theme_Dark]ProgressBar.selectionBackground = #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]PopupMenu.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.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]CheckBox.icon.background = #002946
[Cobalt_2]CheckBox.icon.checkmarkColor = #002946
[Cobalt_2]MenuItem.checkBackground = @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.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL20
[Dark_Flat_Theme]*.inactiveForeground = #808080
[Dark_Flat_Theme]Component.accentColor = lazy(List.selectionBackground)
[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)
[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.selectionForeground = #fff
[Gradianto_Dark_Fuchsia]*.selectionBackground = #8452a7
[Gradianto_Dark_Fuchsia]*.selectionInactiveBackground = #562C6A
[Gradianto_Dark_Fuchsia]MenuItem.checkBackground = @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]ToggleButton.selectedBackground = $ToggleButton.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]ToggleButton.selectedBackground = $ToggleButton.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]MenuItem.checkBackground = @ijMenuCheckBackgroundL10
[Gruvbox_Dark_Soft]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
[Gruvbox_Dark_Soft]ToggleButton.selectedBackground = $ToggleButton.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.selectedBackground = #434241
[Hiberbee_Dark]TabbedPane.selectedForeground = #70D7FF
[Hiberbee_Dark]ToggleButton.selectedBackground = $ToggleButton.selectedBackground
[Hiberbee_Dark]ToggleButton.toolbar.selectedBackground = $ToggleButton.toolbar.selectedBackground
[Hiberbee_Dark]Table.selectionInactiveBackground = lazy(List.selectionInactiveBackground)
[Hiberbee_Dark]Tree.selectionBackground = lazy(List.selectionBackground)
[Hiberbee_Dark]Tree.selectionInactiveBackground = lazy(List.selectionInactiveBackground)
[High_contrast]Component.accentColor = lazy(Component.focusColor)
[High_contrast]ToggleButton.selectedBackground = #fff
@@ -194,9 +254,20 @@ ToggleButton.endBackground = $ToggleButton.background
toolbar.selectedBackground: #fff
[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]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]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.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
@Monocai.acceleratorForeground = lazy(MenuItem.disabledForeground)
@@ -209,22 +280,67 @@ ToggleButton.endBackground = $ToggleButton.background
[Monocai]MenuItem.acceleratorSelectionForeground = @Monocai.acceleratorSelectionForeground
[Monocai]RadioButtonMenuItem.acceleratorForeground = @Monocai.acceleratorForeground
[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.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.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]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]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]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)
[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]MenuItem.checkBackground = @ijMenuCheckBackgroundL10
[vuesion-theme]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
@@ -232,6 +348,12 @@ ToggleButton.endBackground = $ToggleButton.background
[vuesion-theme]Slider.trackColor = #303a45
[vuesion-theme]Slider.thumbColor = #ececee
[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
@@ -241,62 +363,106 @@ ToggleButton.endBackground = $ToggleButton.background
[dark][author-Mallowigi]MenuItem.checkBackground = @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.selectionForeground = #fff
[Dracula_Contrast]ProgressBar.selectionBackground = #fff
[Dracula_Contrast]ProgressBar.selectionForeground = #fff
[Dracula---Mallowigi]RadioButtonMenuItem.selectionForeground = lazy(CheckBoxMenuItem.selectionForeground)
[Dracula---Mallowigi]Table.selectionForeground = lazy(List.selectionForeground)
[Dracula---Mallowigi]Separator.foreground = lazy(Slider.trackColor)
[Dracula---Mallowigi]ToolBar.separatorColor = lazy(Slider.trackColor)
[GitHub]ProgressBar.selectionBackground = #222
[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_Contrast]ProgressBar.selectionForeground = #222
[GitHub_Dark]ComboBox.selectionBackground = lazy(Tree.selectionBackground)
[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]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.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]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)
[Light_Owl_Contrast]ProgressBar.selectionBackground = #111
[Light_Owl_Contrast]ProgressBar.selectionForeground = #fff
[Light_Owl_Contrast]TabbedPane.selectedForeground = lazy(TabbedPane.foreground)
[Light_Owl_Contrast]Table.selectionForeground = lazy(Table.foreground)
[Material_Darker]*.selectionBackground = lighten(#2D2D2D,15%)
[Material_Darker]Separator.foreground = lazy(Slider.trackColor)
[Material_Darker]ToolBar.separatorColor = lazy(Slider.trackColor)
[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.selectionForeground = #fff
[Material_Lighter_Contrast]ProgressBar.selectionBackground = #222
[Material_Lighter_Contrast]ProgressBar.selectionForeground = #fff
[Material_Lighter]ComboBox.selectionBackground = lazy(List.selectionBackground)
[Material_Lighter]Table.selectionBackground = lazy(List.selectionBackground)
[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.selectionForeground = #ddd
[Material_Oceanic_Contrast]ProgressBar.selectionBackground = #ddd
[Material_Oceanic_Contrast]ProgressBar.selectionForeground = #ddd
[Material_Oceanic]Separator.foreground = lazy(Slider.trackColor)
[Material_Oceanic]ToolBar.separatorColor = lazy(Slider.trackColor)
[Material_Palenight]ProgressBar.selectionBackground = #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
[Material_Palenight_Contrast]ProgressBar.selectionForeground = #ddd
[Monokai_Pro---Mallowigi]List.selectionForeground = lazy(Table.selectionForeground)
[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.selectionForeground = #ddd
[Night_Owl_Contrast]ProgressBar.selectionBackground = #ddd
[Night_Owl_Contrast]ProgressBar.selectionForeground = #ddd
[Solarized_Dark---Mallowigi]ProgressBar.selectionBackground = #ccc
[Solarized_Dark---Mallowigi]ProgressBar.selectionForeground = #ccc
[Solarized_Dark_Contrast]ProgressBar.selectionBackground = #ccc
[Solarized_Dark_Contrast]ProgressBar.selectionForeground = #ccc
[Solarized_Dark---Mallowigi]Separator.foreground = lazy(Slider.trackColor)
[Solarized_Dark---Mallowigi]ToolBar.separatorColor = lazy(Slider.trackColor)
[Solarized_Light---Mallowigi]ProgressBar.selectionBackground = #222
[Solarized_Light---Mallowigi]ProgressBar.selectionForeground = #fff
[Solarized_Light_Contrast]ProgressBar.selectionBackground = #222
[Solarized_Light_Contrast]ProgressBar.selectionForeground = #fff
[Solarized_Light---Mallowigi]ComboBox.selectionBackground = lazy(List.selectionBackground)
[Solarized_Light---Mallowigi]Table.selectionBackground = lazy(List.selectionBackground)
[Solarized_Light---Mallowigi]Separator.foreground = lazy(Slider.trackColor)
[Solarized_Light---Mallowigi]ToolBar.separatorColor = lazy(Slider.trackColor)

View File

@@ -12,42 +12,6 @@
# 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.collapseLeftToolTipText = Collapse Left Pane

View File

@@ -12,42 +12,6 @@
# 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.moreTabsButtonToolTipText = Verdeckte Tabs anzeigen

View File

@@ -12,42 +12,6 @@
# 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.collapseLeftToolTipText = Contraer Panel Izquierdo

View File

@@ -12,37 +12,3 @@
# 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

View File

@@ -67,11 +67,11 @@
@nsControlAccentColor = #007aff
# accent colors are:
# @nsSelectedTextBackgroundColor
# @nsSelectedContentBackgroundColor
# @nsSelectedControlColor
# @nsKeyboardFocusIndicatorColor
# @nsControlAccentColor
# @nsSelectedTextBackgroundColor for @textSelectionBackground
# @nsSelectedContentBackgroundColor for @selectionBackground
# @nsSelectedControlColor unused
# @nsKeyboardFocusIndicatorColor for @accentFocusColor
# @nsControlAccentColor for @accentColor
#---- variables ----
@@ -88,12 +88,12 @@
@menuBackground = lighten(@background,8%)
# 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
@selectionInactiveBackground = @nsUnemphasizedSelectedContentBackgroundColor
# 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
# menu
@@ -102,7 +102,7 @@
# accent colors (blueish)
@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 ----
@@ -261,6 +261,13 @@ Spinner.buttonPressedArrowColor = lighten($Spinner.buttonArrowColor,20%,derived
Spinner.buttonSeparatorWidth = 0
#---- TabbedPane ----
TabbedPane.tabArc = $Button.arc
TabbedPane.tabSelectionArc = 999
TabbedPane.cardTabArc = $Button.arc
#---- TextArea ---
TextArea.disabledBackground = @disabledComponentBackground

View File

@@ -67,11 +67,11 @@
@nsControlAccentColor = #007aff
# accent colors are:
# @nsSelectedTextBackgroundColor
# @nsSelectedContentBackgroundColor
# @nsSelectedControlColor
# @nsKeyboardFocusIndicatorColor
# @nsControlAccentColor
# @nsSelectedTextBackgroundColor for @textSelectionBackground
# @nsSelectedContentBackgroundColor for @selectionBackground
# @nsSelectedControlColor unused
# @nsKeyboardFocusIndicatorColor for @accentFocusColor
# @nsControlAccentColor for @accentColor
#---- variables ----
@@ -88,12 +88,12 @@
@menuBackground = darken(@background,4%)
# 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
@selectionInactiveBackground = @nsUnemphasizedSelectedContentBackgroundColor
# 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
# menu
@@ -103,7 +103,7 @@
# accent colors (blueish)
@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 ----
@@ -260,6 +260,13 @@ Spinner.buttonHoverArrowColor = lighten($Spinner.buttonArrowColor,20%,derived no
Spinner.buttonPressedArrowColor = lighten($Spinner.buttonArrowColor,30%,derived noAutoInverse)
#---- TabbedPane ----
TabbedPane.tabArc = $Button.arc
TabbedPane.tabSelectionArc = 999
TabbedPane.cardTabArc = $Button.arc
#---- TextArea ---
TextArea.disabledBackground = @disabledComponentBackground

View File

@@ -21,6 +21,7 @@ import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Insets;
import java.util.Objects;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.UIDefaults.ActiveValue;
@@ -153,4 +154,103 @@ public class TestUIDefaultsLoader
new Font( name, style, size ),
((ActiveValue)UIDefaultsLoader.parseValue( "dummyFont", actualStyle, null )).createValue( null ) );
}
@Test
void parseInstance() {
String className = TestInstance.class.getName();
assertEquals( new TestInstance(), ((LazyValue)UIDefaultsLoader.parseValue( "dummyIcon", className, null )).createValue( null ) );
assertInstanceEquals( new TestInstance(), null );
assertInstanceEquals( new TestInstance( "some string" ), "some string" );
assertInstanceEquals( new TestInstance( false ), "false" );
assertInstanceEquals( new TestInstance( true ), "true" );
assertInstanceEquals( new TestInstance( 123 ), "123" );
assertInstanceEquals( new TestInstance( 123.456f ), "123.456" );
assertInstanceEquals( new TestInstance( Color.red ), "#f00" );
assertInstanceEquals( new TestInstance( "some string", true ), "some string, true" );
assertInstanceEquals( new TestInstance( "some string", true, 123 ), "some string, true, 123" );
assertInstanceEquals( new TestInstance( "some string", 123, true ), "some string, 123, true" );
assertInstanceEquals( new TestInstance( "some string", 123.456f, true ), "some string, 123.456, true" );
assertInstanceEquals( new TestInstance( 123, "some string" ), "123, some string" );
}
private void assertInstanceEquals( TestInstance expected, String params ) {
String value = TestInstance.class.getName() + (params != null ? "," + params : "");
assertEquals( expected, ((LazyValue)UIDefaultsLoader.parseValue( "dummyIcon", value, null )).createValue( null ) );
}
//---- class TestInstance -------------------------------------------------
@SuppressWarnings( "EqualsHashCode" ) // Error Prone
public static class TestInstance
{
private String s;
private boolean b;
private int i;
private float f;
private Color color;
public TestInstance() {
}
public TestInstance( String s ) {
this.s = s;
}
public TestInstance( boolean b ) {
this.b = b;
}
public TestInstance( int i ) {
this.i = i;
}
public TestInstance( float f ) {
this.f = f;
}
public TestInstance( Color color ) {
this.color = color;
}
public TestInstance( String s, boolean b ) {
this.s = s;
this.b = b;
}
public TestInstance( String s, boolean b, int i ) {
this.s = s;
this.b = b;
this.i = i;
}
public TestInstance( String s, int i, boolean b ) {
this.s = s;
this.b = b;
this.i = i;
}
public TestInstance( String s, float f, boolean b ) {
this.s = s;
this.b = b;
this.f = f;
}
protected TestInstance( int i, String s ) {
this.s = s;
this.i = i;
}
@Override
public boolean equals( Object obj ) {
if( !(obj instanceof TestInstance) )
return false;
TestInstance inst = (TestInstance) obj;
return Objects.equals( s, inst.s ) &&
b == inst.b &&
i == inst.i &&
f == inst.f &&
Objects.equals( color, inst.color );
}
}
}

View File

@@ -732,6 +732,11 @@ public class TestFlatStyleableInfo
"tabHeight", int.class,
"tabSelectionHeight", int.class,
"cardTabSelectionHeight", int.class,
"tabArc", int.class,
"tabSelectionArc", int.class,
"cardTabArc", int.class,
"selectedInsets", Insets.class,
"tabSelectionInsets", Insets.class,
"contentSeparatorHeight", int.class,
"showTabSeparators", boolean.class,
"tabSeparatorsFullHeight", boolean.class,

View File

@@ -738,6 +738,11 @@ public class TestFlatStyleableValue
testInteger( c, ui, "tabHeight", 123 );
testInteger( c, ui, "tabSelectionHeight", 123 );
testInteger( c, ui, "cardTabSelectionHeight", 123 );
testInteger( c, ui, "tabArc", 123 );
testInteger( c, ui, "tabSelectionArc", 123 );
testInteger( c, ui, "cardTabArc", 123 );
testInsets( c, ui, "selectedInsets", 1,2,3,4 );
testInsets( c, ui, "tabSelectionInsets", 1,2,3,4 );
testInteger( c, ui, "contentSeparatorHeight", 123 );
testBoolean( c, ui, "showTabSeparators", false );
testBoolean( c, ui, "tabSeparatorsFullHeight", false );
@@ -1214,6 +1219,7 @@ public class TestFlatStyleableValue
//---- class TestIcon -----------------------------------------------------
@SuppressWarnings( "EqualsHashCode" ) // Error Prone
public static class TestIcon
implements Icon
{

View File

@@ -917,6 +917,11 @@ public class TestFlatStyling
ui.applyStyle( "tabHeight: 30" );
ui.applyStyle( "tabSelectionHeight: 3" );
ui.applyStyle( "cardTabSelectionHeight: 2" );
ui.applyStyle( "tabArc: 3" );
ui.applyStyle( "tabSelectionArc: 4" );
ui.applyStyle( "cardTabArc: 5" );
ui.applyStyle( "selectedInsets: 1,2,3,4" );
ui.applyStyle( "tabSelectionInsets: 1,2,3,4" );
ui.applyStyle( "contentSeparatorHeight: 1" );
ui.applyStyle( "showTabSeparators: false" );
ui.applyStyle( "tabSeparatorsFullHeight: false" );

View File

@@ -0,0 +1,117 @@
/*
* 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 static org.junit.jupiter.api.Assertions.assertEquals;
import javax.swing.*;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import com.formdev.flatlaf.FlatClientProperties;
/**
* @author Karl Tauber
*/
public class TestFlatStylingScale
{
private static final float[] FACTORS = { 1f, 1.5f, 2f };
@BeforeAll
static void setup() {
TestUtils.setup( false );
}
@AfterAll
static void cleanup() {
TestUtils.cleanup();
}
static float[] factors() {
return FACTORS;
}
@ParameterizedTest
@MethodSource( "factors" )
void button( float factor ) {
abstractButton( factor, new JButton() );
}
@ParameterizedTest
@MethodSource( "factors" )
void checkBox( float factor ) {
abstractButton( factor, new JCheckBox() );
}
@ParameterizedTest
@MethodSource( "factors" )
void radioButton( float factor ) {
abstractButton( factor, new JRadioButton() );
}
private void abstractButton( float factor, AbstractButton button ) {
TestUtils.scaleFont( factor );
button.putClientProperty( FlatClientProperties.STYLE, "iconTextGap: 100" );
assertEquals( (int) (100 * factor), button.getIconTextGap() );
TestUtils.resetFont();
}
@ParameterizedTest
@MethodSource( "factors" )
void tabbedPane( float factor ) {
TestUtils.scaleFont( factor );
JTabbedPane tabbedPane = new JTabbedPane();
FlatTabbedPaneUI ui = (FlatTabbedPaneUI) tabbedPane.getUI();
tabbedPane.putClientProperty( FlatClientProperties.STYLE, "textIconGap: 100" );
assertEquals( 100, ui.getStyleableValue( tabbedPane, "textIconGap" ) );
TestUtils.resetFont();
}
@ParameterizedTest
@MethodSource( "factors" )
void table( float factor ) {
TestUtils.scaleFont( factor );
JTable table = new JTable();
table.putClientProperty( FlatClientProperties.STYLE, "rowHeight: 100" );
assertEquals( (int) (100 * factor), table.getRowHeight() );
TestUtils.resetFont();
}
@ParameterizedTest
@MethodSource( "factors" )
void tree( float factor ) {
TestUtils.scaleFont( factor );
JTree tree = new JTree();
tree.putClientProperty( FlatClientProperties.STYLE, "rowHeight: 10" );
assertEquals( 10 * factor, tree.getRowHeight() );
TestUtils.resetFont();
}
}

View File

@@ -30,6 +30,7 @@ import com.formdev.flatlaf.FlatSystemProperties;
*/
public class TestUtils
{
@SuppressWarnings( "MutablePublicArray" ) // Error Prone
public static final float[] FACTORS = { 1f, 1.25f, 1.5f, 1.75f, 2f, 2.25f, 2.5f, 2.75f, 3f, 3.25f, 3.5f, 3.75f, 4f, 5f, 6f };
public static void setup( boolean withFocus ) {

View File

@@ -0,0 +1,2 @@
eclipse.preferences.version=1
encoding/<project>=ISO-8859-1

View File

@@ -27,8 +27,8 @@ dependencies {
implementation( project( ":flatlaf-fonts-roboto" ) )
implementation( project( ":flatlaf-fonts-roboto-mono" ) )
implementation( project( ":flatlaf-intellij-themes" ) )
implementation( "com.miglayout:miglayout-swing:5.3" )
implementation( "com.jgoodies:jgoodies-forms:1.9.0" )
implementation( libs.miglayout.swing )
implementation( libs.jgoodies.forms )
// implementation( project( ":flatlaf-natives-jna" ) )
}

View File

@@ -440,9 +440,9 @@ class DemoFrame
Class<? extends LookAndFeel> lafClass = UIManager.getLookAndFeel().getClass();
try {
FlatLaf.setup( lafClass.newInstance() );
FlatLaf.setup( lafClass.getDeclaredConstructor().newInstance() );
FlatLaf.updateUI();
} catch( InstantiationException | IllegalAccessException ex ) {
} catch( Exception ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex );
}
}
@@ -591,6 +591,7 @@ class DemoFrame
undoMenuItem.setText("Undo");
undoMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
undoMenuItem.setMnemonic('U');
undoMenuItem.setIcon(new FlatSVGIcon("com/formdev/flatlaf/demo/icons/undo.svg"));
undoMenuItem.addActionListener(e -> menuItemActionPerformed(e));
editMenu.add(undoMenuItem);
@@ -598,6 +599,7 @@ class DemoFrame
redoMenuItem.setText("Redo");
redoMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Y, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
redoMenuItem.setMnemonic('R');
redoMenuItem.setIcon(new FlatSVGIcon("com/formdev/flatlaf/demo/icons/redo.svg"));
redoMenuItem.addActionListener(e -> menuItemActionPerformed(e));
editMenu.add(redoMenuItem);
editMenu.addSeparator();
@@ -606,18 +608,21 @@ class DemoFrame
cutMenuItem.setText("Cut");
cutMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
cutMenuItem.setMnemonic('C');
cutMenuItem.setIcon(new FlatSVGIcon("com/formdev/flatlaf/demo/icons/menu-cut.svg"));
editMenu.add(cutMenuItem);
//---- copyMenuItem ----
copyMenuItem.setText("Copy");
copyMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
copyMenuItem.setMnemonic('O');
copyMenuItem.setIcon(new FlatSVGIcon("com/formdev/flatlaf/demo/icons/copy.svg"));
editMenu.add(copyMenuItem);
//---- pasteMenuItem ----
pasteMenuItem.setText("Paste");
pasteMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
pasteMenuItem.setMnemonic('P');
pasteMenuItem.setIcon(new FlatSVGIcon("com/formdev/flatlaf/demo/icons/menu-paste.svg"));
editMenu.add(pasteMenuItem);
editMenu.addSeparator();
@@ -827,34 +832,41 @@ class DemoFrame
//---- backButton ----
backButton.setToolTipText("Back");
backButton.setIcon(new FlatSVGIcon("com/formdev/flatlaf/demo/icons/back.svg"));
toolBar.add(backButton);
//---- forwardButton ----
forwardButton.setToolTipText("Forward");
forwardButton.setIcon(new FlatSVGIcon("com/formdev/flatlaf/demo/icons/forward.svg"));
toolBar.add(forwardButton);
toolBar.addSeparator();
//---- cutButton ----
cutButton.setToolTipText("Cut");
cutButton.setIcon(new FlatSVGIcon("com/formdev/flatlaf/demo/icons/menu-cut.svg"));
toolBar.add(cutButton);
//---- copyButton ----
copyButton.setToolTipText("Copy");
copyButton.setIcon(new FlatSVGIcon("com/formdev/flatlaf/demo/icons/copy.svg"));
toolBar.add(copyButton);
//---- pasteButton ----
pasteButton.setToolTipText("Paste");
pasteButton.setIcon(new FlatSVGIcon("com/formdev/flatlaf/demo/icons/menu-paste.svg"));
toolBar.add(pasteButton);
toolBar.addSeparator();
//---- refreshButton ----
refreshButton.setToolTipText("Refresh");
refreshButton.setIcon(new FlatSVGIcon("com/formdev/flatlaf/demo/icons/refresh.svg"));
toolBar.add(refreshButton);
toolBar.addSeparator();
//---- showToggleButton ----
showToggleButton.setSelected(true);
showToggleButton.setToolTipText("Show Details");
showToggleButton.setIcon(new FlatSVGIcon("com/formdev/flatlaf/demo/icons/show.svg"));
toolBar.add(showToggleButton);
}
contentPane.add(toolBar, BorderLayout.NORTH);
@@ -901,21 +913,6 @@ class DemoFrame
menuBar1.add( Box.createGlue() );
menuBar1.add( usersButton );
undoMenuItem.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/undo.svg" ) );
redoMenuItem.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/redo.svg" ) );
cutMenuItem.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/menu-cut.svg" ) );
copyMenuItem.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/copy.svg" ) );
pasteMenuItem.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/menu-paste.svg" ) );
backButton.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/back.svg" ) );
forwardButton.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/forward.svg" ) );
cutButton.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/menu-cut.svg" ) );
copyButton.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/copy.svg" ) );
pasteButton.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/menu-paste.svg" ) );
refreshButton.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/refresh.svg" ) );
showToggleButton.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/show.svg" ) );
cutMenuItem.addActionListener( new DefaultEditorKit.CutAction() );
copyMenuItem.addActionListener( new DefaultEditorKit.CopyAction() );
pasteMenuItem.addActionListener( new DefaultEditorKit.PasteAction() );
@@ -950,6 +947,9 @@ class DemoFrame
if( SystemInfo.isMacOS )
unsupported( underlineMenuSelectionMenuItem );
if( "false".equals( System.getProperty( "flatlaf.animatedLafChange" ) ) )
animatedLafChangeMenuItem.setSelected( false );
// remove contentPanel bottom insets
MigLayout layout = (MigLayout) contentPanel.getLayout();
LC lc = ConstraintParser.parseLayoutConstraint( (String) layout.getLayoutConstraints() );

View File

@@ -1,4 +1,4 @@
JFDML JFormDesigner: "7.0.4.0.360" Java: "17" encoding: "UTF-8"
JFDML JFormDesigner: "8.1.0.0.283" Java: "19.0.2" encoding: "UTF-8"
new FormModel {
contentType: "form/swing"
@@ -21,10 +21,12 @@ new FormModel {
add( new FormComponent( "javax.swing.JButton" ) {
name: "backButton"
"toolTipText": "Back"
"icon": new com.jformdesigner.model.SwingIcon( 0, "/com/formdev/flatlaf/demo/icons/back.svg" )
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "forwardButton"
"toolTipText": "Forward"
"icon": new com.jformdesigner.model.SwingIcon( 0, "/com/formdev/flatlaf/demo/icons/forward.svg" )
} )
add( new FormComponent( "javax.swing.JToolBar$Separator" ) {
name: "separator5"
@@ -32,14 +34,17 @@ new FormModel {
add( new FormComponent( "javax.swing.JButton" ) {
name: "cutButton"
"toolTipText": "Cut"
"icon": new com.jformdesigner.model.SwingIcon( 0, "/com/formdev/flatlaf/demo/icons/menu-cut.svg" )
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "copyButton"
"toolTipText": "Copy"
"icon": new com.jformdesigner.model.SwingIcon( 0, "/com/formdev/flatlaf/demo/icons/copy.svg" )
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "pasteButton"
"toolTipText": "Paste"
"icon": new com.jformdesigner.model.SwingIcon( 0, "/com/formdev/flatlaf/demo/icons/menu-paste.svg" )
} )
add( new FormComponent( "javax.swing.JToolBar$Separator" ) {
name: "separator6"
@@ -47,6 +52,7 @@ new FormModel {
add( new FormComponent( "javax.swing.JButton" ) {
name: "refreshButton"
"toolTipText": "Refresh"
"icon": new com.jformdesigner.model.SwingIcon( 0, "/com/formdev/flatlaf/demo/icons/refresh.svg" )
} )
add( new FormComponent( "javax.swing.JToolBar$Separator" ) {
name: "separator7"
@@ -55,6 +61,7 @@ new FormModel {
name: "showToggleButton"
"selected": true
"toolTipText": "Show Details"
"icon": new com.jformdesigner.model.SwingIcon( 0, "/com/formdev/flatlaf/demo/icons/show.svg" )
} )
}, new FormLayoutConstraints( class java.lang.String ) {
"value": "North"
@@ -185,6 +192,7 @@ new FormModel {
"text": "Undo"
"accelerator": static javax.swing.KeyStroke getKeyStroke( 90, 4226, false )
"mnemonic": 85
"icon": new com.jformdesigner.model.SwingIcon( 0, "/com/formdev/flatlaf/demo/icons/undo.svg" )
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "menuItemActionPerformed", true ) )
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
@@ -192,6 +200,7 @@ new FormModel {
"text": "Redo"
"accelerator": static javax.swing.KeyStroke getKeyStroke( 89, 4226, false )
"mnemonic": 82
"icon": new com.jformdesigner.model.SwingIcon( 0, "/com/formdev/flatlaf/demo/icons/redo.svg" )
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "menuItemActionPerformed", true ) )
} )
add( new FormComponent( "javax.swing.JPopupMenu$Separator" ) {
@@ -202,18 +211,21 @@ new FormModel {
"text": "Cut"
"accelerator": static javax.swing.KeyStroke getKeyStroke( 88, 4226, false )
"mnemonic": 67
"icon": new com.jformdesigner.model.SwingIcon( 0, "/com/formdev/flatlaf/demo/icons/menu-cut.svg" )
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "copyMenuItem"
"text": "Copy"
"accelerator": static javax.swing.KeyStroke getKeyStroke( 67, 4226, false )
"mnemonic": 79
"icon": new com.jformdesigner.model.SwingIcon( 0, "/com/formdev/flatlaf/demo/icons/copy.svg" )
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "pasteMenuItem"
"text": "Paste"
"accelerator": static javax.swing.KeyStroke getKeyStroke( 86, 4226, false )
"mnemonic": 80
"icon": new com.jformdesigner.model.SwingIcon( 0, "/com/formdev/flatlaf/demo/icons/menu-paste.svg" )
} )
add( new FormComponent( "javax.swing.JPopupMenu$Separator" ) {
name: "separator3"

View File

@@ -32,6 +32,7 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
@@ -82,14 +83,13 @@ public class IJThemesPanel
private File lastDirectory;
private boolean isAdjustingThemesList;
private long lastLafChangeTime = System.currentTimeMillis();
public IJThemesPanel() {
initComponents();
saveButton.setEnabled( false );
sourceCodeButton.setEnabled( false );
saveButton.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/download.svg" ) );
sourceCodeButton.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/github.svg" ) );
// create renderer
themesList.setCellRenderer( new DefaultListCellRenderer() {
@@ -370,7 +370,10 @@ public class IJThemesPanel
if( themeInfo == null || themeInfo.resourceName == null )
return;
String themeUrl = (themeInfo.sourceCodeUrl + '/' + themeInfo.sourceCodePath).replace( " ", "%20" );
String themeUrl = themeInfo.sourceCodeUrl;
if( themeInfo.sourceCodePath != null )
themeUrl += '/' + themeInfo.sourceCodePath;
themeUrl = themeUrl.replace( " ", "%20" );
try {
Desktop.getDesktop().browse( new URI( themeUrl ) );
} catch( IOException | URISyntaxException ex ) {
@@ -409,14 +412,59 @@ public class IJThemesPanel
}
private void lafChanged( PropertyChangeEvent e ) {
if( "lookAndFeel".equals( e.getPropertyName() ) )
if( "lookAndFeel".equals( e.getPropertyName() ) ) {
selectedCurrentLookAndFeel();
lastLafChangeTime = System.currentTimeMillis();
}
}
private void windowActivated() {
// refresh themes list on window activation
if( themesManager.hasThemesFromDirectoryChanged() )
updateThemesList();
else {
// check whether core .properties files of current Laf have changed
// in development environment since last Laf change and reload theme
LookAndFeel laf = UIManager.getLookAndFeel();
if( laf instanceof FlatLaf ) {
List<Class<?>> lafClasses = new ArrayList<>();
if( laf instanceof IntelliJTheme.ThemeLaf ) {
boolean dark = ((FlatLaf)laf).isDark();
lafClasses.add( FlatLaf.class );
lafClasses.add( dark ? FlatDarkLaf.class : FlatLightLaf.class );
lafClasses.add( dark ? FlatDarculaLaf.class : FlatIntelliJLaf.class );
lafClasses.add( IntelliJTheme.ThemeLaf.class );
} else {
for( Class<?> lafClass = laf.getClass();
FlatLaf.class.isAssignableFrom( lafClass );
lafClass = lafClass.getSuperclass() )
{
lafClasses.add( 0, lafClass );
}
}
boolean reload = false;
for( Class<?> lafClass : lafClasses ) {
String propertiesName = '/' + lafClass.getName().replace( '.', '/' ) + ".properties";
URL url = lafClass.getResource( propertiesName );
if( url != null && "file".equals( url.getProtocol() ) ) {
try {
File file = new File( url.toURI() );
if( file.lastModified() > lastLafChangeTime ) {
reload = true;
break;
}
} catch( URISyntaxException ex ) {
// ignore
}
}
}
if( reload )
setTheme( themesList.getSelectedValue() );
}
}
}
private void selectedCurrentLookAndFeel() {
@@ -488,11 +536,13 @@ public class IJThemesPanel
//---- saveButton ----
saveButton.setToolTipText("Save .theme.json of selected IntelliJ theme to file.");
saveButton.setIcon(new FlatSVGIcon("com/formdev/flatlaf/demo/icons/download.svg"));
saveButton.addActionListener(e -> saveTheme());
toolBar.add(saveButton);
//---- sourceCodeButton ----
sourceCodeButton.setToolTipText("Opens the source code repository of selected IntelliJ theme in the browser.");
sourceCodeButton.setIcon(new FlatSVGIcon("com/formdev/flatlaf/demo/icons/github.svg"));
sourceCodeButton.addActionListener(e -> browseSourceCode());
toolBar.add(sourceCodeButton);
}

View File

@@ -1,4 +1,4 @@
JFDML JFormDesigner: "7.0.2.0.298" Java: "14" encoding: "UTF-8"
JFDML JFormDesigner: "8.1.0.0.283" Java: "19.0.2" encoding: "UTF-8"
new FormModel {
contentType: "form/swing"
@@ -24,11 +24,13 @@ new FormModel {
add( new FormComponent( "javax.swing.JButton" ) {
name: "saveButton"
"toolTipText": "Save .theme.json of selected IntelliJ theme to file."
"icon": new com.jformdesigner.model.SwingIcon( 0, "/com/formdev/flatlaf/demo/icons/download.svg" )
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "saveTheme", false ) )
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "sourceCodeButton"
"toolTipText": "Opens the source code repository of selected IntelliJ theme in the browser."
"icon": new com.jformdesigner.model.SwingIcon( 0, "/com/formdev/flatlaf/demo/icons/github.svg" )
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "browseSourceCode", false ) )
} )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {

View File

@@ -38,8 +38,10 @@ public class IJThemesUpdater
themesManager.loadBundledThemes();
for( IJThemeInfo ti : themesManager.bundledThemes ) {
if( ti.sourceCodeUrl == null || ti.sourceCodePath == null )
if( ti.sourceCodeUrl == null || ti.sourceCodePath == null ) {
System.out.println( " " + ti.name + " NOT downloaded. Needs manual update from release on JetBrains Plugin portal." );
continue;
}
String fromUrl = ti.sourceCodeUrl + "/" + ti.sourceCodePath;
if( fromUrl.contains( "github.com" ) )

View File

@@ -145,7 +145,7 @@
"license": "MIT",
"licenseFile": "Hiberbee.LICENSE.txt",
"sourceCodeUrl": "https://github.com/Hiberbee/themes",
"sourceCodePath": "blob/latest/src/main/resources/themes/HiberbeeDark.theme.json"
"sourceCodePath": "blob/latest/src/intellij/src/main/resources/themes/HiberbeeDark.theme.json"
},
"HighContrast.theme.json": {
"name": "High contrast",
@@ -249,14 +249,6 @@
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/regular/Arc Dark.theme.json"
},
"material-theme-ui-lite/Arc Dark Contrast.theme.json": {
"name": "Material Theme UI Lite / Arc Dark Contrast",
"dark": true,
"license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/contrast/Arc Dark Contrast.theme.json"
},
"material-theme-ui-lite/Atom One Dark.theme.json": {
"name": "Material Theme UI Lite / Atom One Dark",
"dark": true,
@@ -265,14 +257,6 @@
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/regular/Atom One Dark.theme.json"
},
"material-theme-ui-lite/Atom One Dark Contrast.theme.json": {
"name": "Material Theme UI Lite / Atom One Dark Contrast",
"dark": true,
"license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/contrast/Atom One Dark Contrast.theme.json"
},
"material-theme-ui-lite/Atom One Light.theme.json": {
"name": "Material Theme UI Lite / Atom One Light",
"license": "MIT",
@@ -280,13 +264,6 @@
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/regular/Atom One Light.theme.json"
},
"material-theme-ui-lite/Atom One Light Contrast.theme.json": {
"name": "Material Theme UI Lite / Atom One Light Contrast",
"license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/contrast/Atom One Light Contrast.theme.json"
},
"material-theme-ui-lite/Dracula.theme.json": {
"name": "Material Theme UI Lite / Dracula",
"dark": true,
@@ -295,14 +272,6 @@
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/regular/Dracula.theme.json"
},
"material-theme-ui-lite/Dracula Contrast.theme.json": {
"name": "Material Theme UI Lite / Dracula Contrast",
"dark": true,
"license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/contrast/Dracula Contrast.theme.json"
},
"material-theme-ui-lite/GitHub.theme.json": {
"name": "Material Theme UI Lite / GitHub",
"license": "MIT",
@@ -310,13 +279,6 @@
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/regular/GitHub.theme.json"
},
"material-theme-ui-lite/GitHub Contrast.theme.json": {
"name": "Material Theme UI Lite / GitHub Contrast",
"license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/contrast/GitHub Contrast.theme.json"
},
"material-theme-ui-lite/GitHub Dark.theme.json": {
"name": "Material Theme UI Lite / GitHub Dark",
"dark": true,
@@ -325,14 +287,6 @@
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/regular/GitHub Dark.theme.json"
},
"material-theme-ui-lite/GitHub Dark Contrast.theme.json": {
"name": "Material Theme UI Lite / GitHub Dark Contrast",
"dark": true,
"license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/contrast/GitHub Dark Contrast.theme.json"
},
"material-theme-ui-lite/Light Owl.theme.json": {
"name": "Material Theme UI Lite / Light Owl",
"license": "MIT",
@@ -340,13 +294,6 @@
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/regular/Light Owl.theme.json"
},
"material-theme-ui-lite/Light Owl Contrast.theme.json": {
"name": "Material Theme UI Lite / Light Owl Contrast",
"license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/contrast/Light Owl Contrast.theme.json"
},
"material-theme-ui-lite/Material Darker.theme.json": {
"name": "Material Theme UI Lite / Material Darker",
"dark": true,
@@ -355,14 +302,6 @@
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/regular/Material Darker.theme.json"
},
"material-theme-ui-lite/Material Darker Contrast.theme.json": {
"name": "Material Theme UI Lite / Material Darker Contrast",
"dark": true,
"license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/contrast/Material Darker Contrast.theme.json"
},
"material-theme-ui-lite/Material Deep Ocean.theme.json": {
"name": "Material Theme UI Lite / Material Deep Ocean",
"dark": true,
@@ -371,14 +310,6 @@
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/regular/Material Deep Ocean.theme.json"
},
"material-theme-ui-lite/Material Deep Ocean Contrast.theme.json": {
"name": "Material Theme UI Lite / Material Deep Ocean Contrast",
"dark": true,
"license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/contrast/Material Deep Ocean Contrast.theme.json"
},
"material-theme-ui-lite/Material Lighter.theme.json": {
"name": "Material Theme UI Lite / Material Lighter",
"license": "MIT",
@@ -386,13 +317,6 @@
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/regular/Material Lighter.theme.json"
},
"material-theme-ui-lite/Material Lighter Contrast.theme.json": {
"name": "Material Theme UI Lite / Material Lighter Contrast",
"license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/contrast/Material Lighter Contrast.theme.json"
},
"material-theme-ui-lite/Material Oceanic.theme.json": {
"name": "Material Theme UI Lite / Material Oceanic",
"dark": true,
@@ -401,14 +325,6 @@
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/regular/Material Oceanic.theme.json"
},
"material-theme-ui-lite/Material Oceanic Contrast.theme.json": {
"name": "Material Theme UI Lite / Material Oceanic Contrast",
"dark": true,
"license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/contrast/Material Oceanic Contrast.theme.json"
},
"material-theme-ui-lite/Material Palenight.theme.json": {
"name": "Material Theme UI Lite / Material Palenight",
"dark": true,
@@ -417,14 +333,6 @@
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/regular/Material Palenight.theme.json"
},
"material-theme-ui-lite/Material Palenight Contrast.theme.json": {
"name": "Material Theme UI Lite / Material Palenight Contrast",
"dark": true,
"license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/contrast/Material Palenight Contrast.theme.json"
},
"material-theme-ui-lite/Monokai Pro.theme.json": {
"name": "Material Theme UI Lite / Monokai Pro",
"dark": true,
@@ -433,14 +341,6 @@
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/regular/Monokai Pro.theme.json"
},
"material-theme-ui-lite/Monokai Pro Contrast.theme.json": {
"name": "Material Theme UI Lite / Monokai Pro Contrast",
"dark": true,
"license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/contrast/Monokai Pro Contrast.theme.json"
},
"material-theme-ui-lite/Moonlight.theme.json": {
"name": "Material Theme UI Lite / Moonlight",
"dark": true,
@@ -449,14 +349,6 @@
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/regular/Moonlight.theme.json"
},
"material-theme-ui-lite/Moonlight Contrast.theme.json": {
"name": "Material Theme UI Lite / Moonlight Contrast",
"dark": true,
"license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/contrast/Moonlight Contrast.theme.json"
},
"material-theme-ui-lite/Night Owl.theme.json": {
"name": "Material Theme UI Lite / Night Owl",
"dark": true,
@@ -465,14 +357,6 @@
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/regular/Night Owl.theme.json"
},
"material-theme-ui-lite/Night Owl Contrast.theme.json": {
"name": "Material Theme UI Lite / Night Owl Contrast",
"dark": true,
"license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/contrast/Night Owl Contrast.theme.json"
},
"material-theme-ui-lite/Solarized Dark.theme.json": {
"name": "Material Theme UI Lite / Solarized Dark",
"dark": true,
@@ -481,26 +365,11 @@
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/regular/Solarized Dark.theme.json"
},
"material-theme-ui-lite/Solarized Dark Contrast.theme.json": {
"name": "Material Theme UI Lite / Solarized Dark Contrast",
"dark": true,
"license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/contrast/Solarized Dark Contrast.theme.json"
},
"material-theme-ui-lite/Solarized Light.theme.json": {
"name": "Material Theme UI Lite / Solarized Light",
"license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/regular/Solarized Light.theme.json"
},
"material-theme-ui-lite/Solarized Light Contrast.theme.json": {
"name": "Material Theme UI Lite / Solarized Light Contrast",
"license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/contrast/Solarized Light Contrast.theme.json"
}
}

View File

@@ -0,0 +1,2 @@
eclipse.preferences.version=1
encoding/<project>=ISO-8859-1

View File

@@ -4,8 +4,7 @@ FlatLaf Extras
This sub-project provides some additional components and classes:
- [FlatSVGIcon](https://www.javadoc.io/doc/com.formdev/flatlaf-extras/latest/com/formdev/flatlaf/extras/FlatSVGIcon.html):
An icon that displays SVG using
[svgSalamander](https://github.com/JFormDesigner/svgSalamander).\
An icon that displays SVG using [JSVG](https://github.com/weisJ/jsvg).\
![FlatSVGIcon.png](../images/extras-FlatSVGIcon.png)
- [FlatTriStateCheckBox](https://www.javadoc.io/doc/com.formdev/flatlaf-extras/latest/com/formdev/flatlaf/extras/components/FlatTriStateCheckBox.html):
A tri-state check box.\
@@ -38,9 +37,9 @@ Otherwise download `flatlaf-extras-<version>.jar` here:
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.formdev/flatlaf-extras/badge.svg?style=flat-square&color=007ec6)](https://maven-badges.herokuapp.com/maven-central/com.formdev/flatlaf-extras)
If SVG classes are used, `svgSalamander-<version>.jar` is also required:
If SVG classes are used, `jsvg-<version>.jar` is also required:
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.formdev/svgSalamander/badge.svg?style=flat-square&color=007ec6)](https://maven-badges.herokuapp.com/maven-central/com.formdev/svgSalamander)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.weisj/jsvg/badge.svg?style=flat-square&color=007ec6)](https://maven-badges.herokuapp.com/maven-central/com.github.weisj/jsvg)
Tools

View File

@@ -23,7 +23,7 @@ plugins {
dependencies {
implementation( project( ":flatlaf-core" ) )
implementation( "com.formdev:svgSalamander:1.1.3" )
implementation( libs.jsvg )
}
flatlafModuleInfo {

View File

@@ -30,8 +30,8 @@ import java.awt.image.RGBImageFilter;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
@@ -49,9 +49,9 @@ import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.MultiResolutionImageSupport;
import com.formdev.flatlaf.util.SoftCache;
import com.formdev.flatlaf.util.UIScale;
import com.kitfox.svg.SVGDiagram;
import com.kitfox.svg.SVGException;
import com.kitfox.svg.SVGUniverse;
import com.github.weisj.jsvg.SVGDocument;
import com.github.weisj.jsvg.geometry.size.FloatSize;
import com.github.weisj.jsvg.parser.SVGLoader;
/**
* An icon that loads and paints SVG.
@@ -62,12 +62,9 @@ public class FlatSVGIcon
extends ImageIcon
implements DisabledIconProvider
{
// cache that uses soft references for values, which allows freeing SVG diagrams if no longer used
private static final SoftCache<URI, SVGDiagram> svgCache = new SoftCache<>();
// use own SVG universe so that it can not be cleared from anywhere
private static final SVGUniverse svgUniverse = new SVGUniverse();
private static int streamNumber;
// cache that uses soft references for values, which allows freeing SVG documents if no longer used
private static final SoftCache<String, SVGDocument> svgCache = new SoftCache<>();
private static final SVGLoader svgLoader = new SVGLoader();
private final String name;
private final int width;
@@ -75,11 +72,11 @@ public class FlatSVGIcon
private final float scale;
private final boolean disabled;
private final ClassLoader classLoader;
private final URI uri;
private final URL url;
private ColorFilter colorFilter;
private SVGDiagram diagram;
private SVGDocument document;
private boolean dark;
private boolean loadFailed;
@@ -220,7 +217,7 @@ public class FlatSVGIcon
* @since 2
*/
public FlatSVGIcon( URL url ) {
this( null, -1, -1, 1, false, null, url2uri( url ) );
this( null, -1, -1, 1, false, null, url );
}
/**
@@ -236,7 +233,7 @@ public class FlatSVGIcon
* @since 2
*/
public FlatSVGIcon( URI uri ) {
this( null, -1, -1, 1, false, null, uri );
this( null, -1, -1, 1, false, null, uri2url( uri ) );
}
/**
@@ -251,7 +248,7 @@ public class FlatSVGIcon
* @since 2
*/
public FlatSVGIcon( File file ) {
this( null, -1, -1, 1, false, null, file.toURI() );
this( null, -1, -1, 1, false, null, uri2url( file.toURI() ) );
}
/**
@@ -267,19 +264,15 @@ public class FlatSVGIcon
* @since 2
*/
public FlatSVGIcon( InputStream in ) throws IOException {
this( null, -1, -1, 1, false, null, loadFromStream( in ) );
this( null, -1, -1, 1, false, null, null );
// since the input stream is already loaded and parsed,
// get diagram here and remove it from cache
update();
synchronized( FlatSVGIcon.class ) {
svgCache.remove( uri );
}
}
private static synchronized URI loadFromStream( InputStream in ) throws IOException {
try( InputStream in2 = in ) {
return svgUniverse.loadSVG( in2, "/flatlaf-stream-" + (streamNumber++) );
document = svgLoader.load( in2 );
if( document == null ) {
loadFailed = true;
LoggingFacade.INSTANCE.logSevere( "FlatSVGIcon: failed to load SVG icon from input stream", null );
}
}
}
@@ -291,20 +284,22 @@ public class FlatSVGIcon
* @since 2.0.1
*/
public FlatSVGIcon( FlatSVGIcon icon ) {
this( icon.name, icon.width, icon.height, icon.scale, icon.disabled, icon.classLoader, icon.uri );
this( icon.name, icon.width, icon.height, icon.scale, icon.disabled, icon.classLoader, icon.url );
colorFilter = icon.colorFilter;
diagram = icon.diagram;
document = icon.document;
dark = icon.dark;
}
protected FlatSVGIcon( String name, int width, int height, float scale, boolean disabled, ClassLoader classLoader, URI uri ) {
protected FlatSVGIcon( String name, int width, int height, float scale,
boolean disabled, ClassLoader classLoader, URL url )
{
this.name = name;
this.width = width;
this.height = height;
this.scale = scale;
this.disabled = disabled;
this.classLoader = classLoader;
this.uri = uri;
this.url = url;
}
/**
@@ -383,9 +378,9 @@ public class FlatSVGIcon
if( width == this.width && height == this.height )
return this;
FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, disabled, classLoader, uri );
FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, disabled, classLoader, url );
icon.colorFilter = colorFilter;
icon.diagram = diagram;
icon.document = document;
icon.dark = dark;
return icon;
}
@@ -402,9 +397,9 @@ public class FlatSVGIcon
if( scale == this.scale )
return this;
FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, disabled, classLoader, uri );
FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, disabled, classLoader, url );
icon.colorFilter = colorFilter;
icon.diagram = diagram;
icon.document = document;
icon.dark = dark;
return icon;
}
@@ -421,9 +416,9 @@ public class FlatSVGIcon
if( disabled )
return this;
FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, true, classLoader, uri );
FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, true, classLoader, url );
icon.colorFilter = colorFilter;
icon.diagram = diagram;
icon.document = document;
icon.dark = dark;
return icon;
}
@@ -462,19 +457,19 @@ public class FlatSVGIcon
if( loadFailed )
return;
if( dark == isDarkLaf() && diagram != null )
if( dark == isDarkLaf() && document != null )
return;
dark = isDarkLaf();
// SVGs already loaded via url or input stream can not have light/dark variants
if( uri != null && diagram != null )
// SVGs already loaded via url, file or input stream can not have light/dark variants
if( document != null && name == null )
return;
URI uri = this.uri;
if( uri == null ) {
URL url = getIconURL( name, dark );
if( url == null & dark )
URL url = this.url;
if( url == null ) {
url = getIconURL( name, dark );
if( url == null && dark )
url = getIconURL( name, false );
if( url == null ) {
@@ -482,33 +477,30 @@ public class FlatSVGIcon
LoggingFacade.INSTANCE.logConfig( "FlatSVGIcon: resource '" + name + "' not found (if using Java modules, check whether icon package is opened in module-info.java)", null );
return;
}
uri = url2uri( url );
}
diagram = loadSVG( uri );
loadFailed = (diagram == null);
document = loadSVG( url );
loadFailed = (document == null);
}
static synchronized SVGDiagram loadSVG( URI uri ) {
static synchronized SVGDocument loadSVG( URL url ) {
// get from our cache
SVGDiagram diagram = svgCache.get( uri );
if( diagram != null )
return diagram;
String cacheKey = url.toString();
SVGDocument document = svgCache.get( cacheKey );
if( document != null )
return document;
// load/get SVG diagram
diagram = svgUniverse.getDiagram( uri );
// load SVG document
document = svgLoader.load( url );
if( diagram == null ) {
LoggingFacade.INSTANCE.logSevere( "FlatSVGIcon: failed to load '" + uri + "'", null );
if( document == null ) {
LoggingFacade.INSTANCE.logSevere( "FlatSVGIcon: failed to load '" + url + "'", null );
return null;
}
// add to our (soft) cache and remove from SVGUniverse (hard) cache
svgCache.put( uri, diagram );
svgUniverse.removeDocument( uri );
svgCache.put( cacheKey, document );
return diagram;
return document;
}
private URL getIconURL( String name, boolean dark ) {
@@ -528,7 +520,7 @@ public class FlatSVGIcon
*/
public boolean hasFound() {
update();
return diagram != null;
return document != null;
}
/**
@@ -540,7 +532,7 @@ public class FlatSVGIcon
return scaleSize( width );
update();
return scaleSize( (diagram != null) ? Math.round( diagram.getWidth() ) : 16 );
return scaleSize( (document != null) ? Math.round( document.size().width ) : 16 );
}
/**
@@ -552,7 +544,7 @@ public class FlatSVGIcon
return scaleSize( height );
update();
return scaleSize( (diagram != null) ? Math.round( diagram.getHeight() ) : 16 );
return scaleSize( (document != null) ? Math.round( document.size().height ) : 16 );
}
private int scaleSize( int size ) {
@@ -583,12 +575,7 @@ public class FlatSVGIcon
Graphics2D g2 = new GraphicsFilter( (Graphics2D) g.create(), colorFilter, ColorFilter.getInstance(), grayFilter );
try {
// same hints as in FlatUIUtils.setRenderingHints()
g2.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
g2.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE );
// enable better image scaling
g2.setRenderingHint( RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR );
setRenderingHints( g2 );
paintSvg( g2, x, y );
} finally {
@@ -597,7 +584,7 @@ public class FlatSVGIcon
}
private void paintSvg( Graphics2D g, int x, int y ) {
if( diagram == null ) {
if( document == null ) {
paintSvgError( g, x, y );
return;
}
@@ -607,19 +594,18 @@ public class FlatSVGIcon
UIScale.scaleGraphics( g );
if( width > 0 || height > 0 ) {
double sx = (width > 0) ? width / diagram.getWidth() : 1;
double sy = (height > 0) ? height / diagram.getHeight() : 1;
FloatSize svgSize = document.size();
double sx = (width > 0) ? width / svgSize.width : 1;
double sy = (height > 0) ? height / svgSize.height : 1;
if( sx != 1 || sy != 1 )
g.scale( sx, sy );
}
if( scale != 1 )
g.scale( scale, scale );
diagram.setIgnoringClipHeuristic( true );
try {
diagram.render( g );
} catch( SVGException ex ) {
document.render( null, g );
} catch( Exception ex ) {
paintSvgError( g, 0, 0 );
}
}
@@ -662,10 +648,21 @@ public class FlatSVGIcon
return MultiResolutionImageSupport.create( 0, dimensions, producer );
}
static URI url2uri( URL url ) {
static void setRenderingHints( Graphics2D g ) {
// enable anti-aliasing
g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
// disable coordinate normalization for correct line rendering
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE );
// enable better image scaling
g.setRenderingHint( RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR );
}
static URL uri2url( URI uri ) {
try {
return url.toURI();
} catch( URISyntaxException ex ) {
return uri.toURL();
} catch( MalformedURLException ex ) {
throw new IllegalArgumentException( ex );
}
}
@@ -964,6 +961,18 @@ public class FlatSVGIcon
this.grayFilter = grayFilter;
}
@Override
public Graphics create() {
return new GraphicsFilter( (Graphics2D) super.create(),
colorFilter, globalColorFilter, grayFilter );
}
@Override
public Graphics create( int x, int y, int width, int height ) {
return new GraphicsFilter( (Graphics2D) super.create( x, y, width, height ),
colorFilter, globalColorFilter, grayFilter );
}
@Override
public void setColor( Color c ) {
super.setColor( filterColor( c ) );

View File

@@ -19,7 +19,6 @@ package com.formdev.flatlaf.extras;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.util.Arrays;
@@ -28,8 +27,8 @@ import java.util.List;
import javax.swing.JWindow;
import com.formdev.flatlaf.util.MultiResolutionImageSupport;
import com.formdev.flatlaf.util.SystemInfo;
import com.kitfox.svg.SVGDiagram;
import com.kitfox.svg.SVGException;
import com.github.weisj.jsvg.SVGDocument;
import com.github.weisj.jsvg.geometry.size.FloatSize;
/**
* Utility methods for SVG.
@@ -83,7 +82,7 @@ public class FlatSVGUtils
* @since 2
*/
public static List<Image> createWindowIconImages( URL svgUrl ) {
SVGDiagram diagram = loadSVG( svgUrl );
SVGDocument document = FlatSVGIcon.loadSVG( svgUrl );
if( SystemInfo.isWindows && MultiResolutionImageSupport.isAvailable() ) {
// use a multi-resolution image that creates images on demand for requested sizes
@@ -102,17 +101,17 @@ public class FlatSVGUtils
new Dimension( 48, 48 ), // 300%
new Dimension( 64, 64 ), // 400%
}, dim -> {
return svg2image( diagram, dim.width, dim.height );
return svg2image( document, dim.width, dim.height );
} ) );
} else {
return Arrays.asList(
svg2image( diagram, 16, 16 ), // 100%
svg2image( diagram, 20, 20 ), // 125%
svg2image( diagram, 24, 24 ), // 150%
svg2image( diagram, 28, 28 ), // 175%
svg2image( diagram, 32, 32 ), // 200%
svg2image( diagram, 48, 48 ), // 300%
svg2image( diagram, 64, 64 ) // 400%
svg2image( document, 16, 16 ), // 100%
svg2image( document, 20, 20 ), // 125%
svg2image( document, 24, 24 ), // 150%
svg2image( document, 28, 28 ), // 175%
svg2image( document, 32, 32 ), // 200%
svg2image( document, 48, 48 ), // 300%
svg2image( document, 64, 64 ) // 400%
);
}
}
@@ -148,7 +147,7 @@ public class FlatSVGUtils
* @since 2
*/
public static BufferedImage svg2image( URL svgUrl, int width, int height ) {
return svg2image( loadSVG( svgUrl ), width, height );
return svg2image( FlatSVGIcon.loadSVG( svgUrl ), width, height );
}
/**
@@ -180,53 +179,43 @@ public class FlatSVGUtils
* @since 2
*/
public static BufferedImage svg2image( URL svgUrl, float scaleFactor ) {
SVGDiagram diagram = loadSVG( svgUrl );
int width = (int) (diagram.getWidth() * scaleFactor);
int height = (int) (diagram.getHeight() * scaleFactor);
return svg2image( diagram, width, height );
SVGDocument document = FlatSVGIcon.loadSVG( svgUrl );
FloatSize size = document.size();
int width = (int) (size.width * scaleFactor);
int height = (int) (size.height * scaleFactor);
return svg2image( document, width, height );
}
/**
* Creates a buffered image and renders the given SVGDiagram into it.
* Creates a buffered image and renders the given SVGDocument into it.
*
* @param diagram the SVG diagram
* @param document the SVG document
* @param width the width of the image
* @param height the height of the image
* @return the image
* @throws RuntimeException if failed to render SVG file
*/
public static BufferedImage svg2image( SVGDiagram diagram, int width, int height ) {
private static BufferedImage svg2image( SVGDocument document, int width, int height ) {
BufferedImage image = new BufferedImage( width, height, BufferedImage.TYPE_INT_ARGB );
Graphics2D g = image.createGraphics();
try {
BufferedImage image = new BufferedImage( width, height, BufferedImage.TYPE_INT_ARGB );
FlatSVGIcon.setRenderingHints( g );
Graphics2D g = image.createGraphics();
try {
g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
g.setRenderingHint( RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR );
FloatSize size = document.size();
double sx = width / size.width;
double sy = height / size.height;
if( sx != 1 || sy != 1 )
g.scale( sx, sy );
double sx = width / diagram.getWidth();
double sy = height / diagram.getHeight();
if( sx != 1 || sy != 1 )
g.scale( sx, sy );
diagram.setIgnoringClipHeuristic( true );
diagram.render( g );
} finally {
g.dispose();
}
return image;
} catch( SVGException ex ) {
throw new RuntimeException( ex );
document.render( null, g );
} finally {
g.dispose();
}
return image;
}
private static URL getResource( String svgName ) {
return FlatSVGUtils.class.getResource( svgName );
}
private static SVGDiagram loadSVG( URL url ) {
return FlatSVGIcon.loadSVG( FlatSVGIcon.url2uri( url ) );
}
}

View File

@@ -770,6 +770,7 @@ public class FlatUIDefaultsInspector
return String.valueOf( value );
}
@SuppressWarnings( "FormatString" ) // Error Prone
private static String color2hex( Color color ) {
int rgb = color.getRGB();
boolean hasAlpha = color.getAlpha() != 255;

View File

@@ -14,13 +14,13 @@
* limitations under the License.
*/
/**
/*
* @author Karl Tauber
*/
module com.formdev.flatlaf.extras {
requires java.desktop;
requires java.prefs;
requires static com.kitfox.svg; // optional at runtime
requires static com.github.weisj.jsvg; // optional at runtime
requires com.formdev.flatlaf;
exports com.formdev.flatlaf.extras;

View File

@@ -0,0 +1,2 @@
eclipse.preferences.version=1
encoding/<project>=ISO-8859-1

View File

@@ -33,9 +33,8 @@ plugins {
dependencies {
implementation( project( ":flatlaf-core" ) )
testImplementation( "org.junit.jupiter:junit-jupiter-api:5.7.2" )
testImplementation( "org.junit.jupiter:junit-jupiter-params" )
testRuntimeOnly( "org.junit.jupiter:junit-jupiter-engine" )
testImplementation( libs.bundles.junit )
testRuntimeOnly( libs.junit.engine )
}
flatlafModuleInfo {

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
/**
/*
* @author Karl Tauber
*/
module com.formdev.flatlaf.fonts.inter {

View File

@@ -0,0 +1,2 @@
eclipse.preferences.version=1
encoding/<project>=ISO-8859-1

View File

@@ -33,9 +33,8 @@ plugins {
dependencies {
implementation( project( ":flatlaf-core" ) )
testImplementation( "org.junit.jupiter:junit-jupiter-api:5.7.2" )
testImplementation( "org.junit.jupiter:junit-jupiter-params" )
testRuntimeOnly( "org.junit.jupiter:junit-jupiter-engine" )
testImplementation( libs.bundles.junit )
testRuntimeOnly( libs.junit.engine )
}
flatlafModuleInfo {

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
/**
/*
* @author Karl Tauber
*/
module com.formdev.flatlaf.fonts.jetbrains_mono {

View File

@@ -0,0 +1,2 @@
eclipse.preferences.version=1
encoding/<project>=ISO-8859-1

View File

@@ -33,9 +33,8 @@ plugins {
dependencies {
implementation( project( ":flatlaf-core" ) )
testImplementation( "org.junit.jupiter:junit-jupiter-api:5.7.2" )
testImplementation( "org.junit.jupiter:junit-jupiter-params" )
testRuntimeOnly( "org.junit.jupiter:junit-jupiter-engine" )
testImplementation( libs.bundles.junit )
testRuntimeOnly( libs.junit.engine )
}
flatlafModuleInfo {

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
/**
/*
* @author Karl Tauber
*/
module com.formdev.flatlaf.fonts.roboto_mono {

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