mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2026-02-11 06:27:13 -06:00
Compare commits
107 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
97d290795e | ||
|
|
2a237ff5fc | ||
|
|
13a418f74e | ||
|
|
5c56dbfed6 | ||
|
|
0d2f37e1da | ||
|
|
0494c2161c | ||
|
|
635a620439 | ||
|
|
0a7c76ec72 | ||
|
|
9ad8fb38e8 | ||
|
|
1dbe968952 | ||
|
|
460b6492cb | ||
|
|
67b0faa9ae | ||
|
|
5553425a1a | ||
|
|
8ff516e43a | ||
|
|
b6207bafde | ||
|
|
b9f43fd560 | ||
|
|
c617d9f569 | ||
|
|
9efb9761c6 | ||
|
|
03f9115fbf | ||
|
|
a2859cedb5 | ||
|
|
cdee0594f8 | ||
|
|
808833d749 | ||
|
|
581c64b601 | ||
|
|
c953ff84d0 | ||
|
|
96cd207df3 | ||
|
|
7a75f62a6a | ||
|
|
61e5fe58c2 | ||
|
|
1a3baba702 | ||
|
|
58dc14bb46 | ||
|
|
a5b7e04943 | ||
|
|
22f2aa5475 | ||
|
|
d4e9cb12be | ||
|
|
75da361480 | ||
|
|
7488bcb7b0 | ||
|
|
1b1a9be107 | ||
|
|
db2f94aa53 | ||
|
|
810146b993 | ||
|
|
93091662ab | ||
|
|
d349227fbf | ||
|
|
c9423e3aa8 | ||
|
|
b9737ca4f1 | ||
|
|
4b4990635d | ||
|
|
afaa2c8c78 | ||
|
|
f506ef0d4f | ||
|
|
d30fe66cac | ||
|
|
270e998e86 | ||
|
|
c395386c05 | ||
|
|
4f1207b0db | ||
|
|
dc3878e290 | ||
|
|
be2876149d | ||
|
|
52bae9dfb0 | ||
|
|
bb636bac3f | ||
|
|
502b18fa86 | ||
|
|
e0a5450264 | ||
|
|
5ffb23c37f | ||
|
|
b75f22b7bd | ||
|
|
35fa3197c8 | ||
|
|
f03725ae36 | ||
|
|
2b640e2129 | ||
|
|
2a983f5c03 | ||
|
|
cacc5daa14 | ||
|
|
593502287d | ||
|
|
7a9bdf9be0 | ||
|
|
170c22c5ed | ||
|
|
7e8fa58bd7 | ||
|
|
046200625c | ||
|
|
710ed55152 | ||
|
|
ce527329a6 | ||
|
|
b455dd41ab | ||
|
|
b47ed94f40 | ||
|
|
f1351a2093 | ||
|
|
c1c5e81df0 | ||
|
|
8e3c8ba6c5 | ||
|
|
dfe4404a17 | ||
|
|
b3fb63c9f5 | ||
|
|
9db3dfff26 | ||
|
|
3c9051e7de | ||
|
|
798a6d061c | ||
|
|
19afbe99d9 | ||
|
|
4715d8d16c | ||
|
|
193da2bc4d | ||
|
|
799f8efe22 | ||
|
|
f6062e1ec4 | ||
|
|
c790778a46 | ||
|
|
4344f1b3a0 | ||
|
|
d520b30500 | ||
|
|
11c02e5f50 | ||
|
|
aa4c6ee9da | ||
|
|
98f8557392 | ||
|
|
6f6a860887 | ||
|
|
38695e9e16 | ||
|
|
242c478cb3 | ||
|
|
f003e835bd | ||
|
|
267defb321 | ||
|
|
4392c7627b | ||
|
|
fde65b2730 | ||
|
|
e908362f0a | ||
|
|
a40b837634 | ||
|
|
b391465fbf | ||
|
|
bad0428f5b | ||
|
|
97018df2f9 | ||
|
|
9d84501bc8 | ||
|
|
e9fb2b3fdc | ||
|
|
f60250fd8a | ||
|
|
5fc3cae28a | ||
|
|
e7935be85b | ||
|
|
89363b2ea1 |
21
.github/workflows/ci.yml
vendored
21
.github/workflows/ci.yml
vendored
@@ -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 }}
|
||||
|
||||
2
.github/workflows/fonts.yml
vendored
2
.github/workflows/fonts.yml
vendored
@@ -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
|
||||
|
||||
2
.github/workflows/natives.yml
vendored
2
.github/workflows/natives.yml
vendored
@@ -33,7 +33,7 @@ jobs:
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: 11
|
||||
distribution: adopt
|
||||
distribution: temurin
|
||||
cache: gradle
|
||||
|
||||
- name: Build with Gradle
|
||||
|
||||
127
CHANGELOG.md
127
CHANGELOG.md
@@ -1,6 +1,133 @@
|
||||
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:
|
||||
|
||||
273
README.md
273
README.md
@@ -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.
|
||||
@@ -142,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/)
|
||||
|
||||
@@ -149,121 +150,193 @@ Buzz
|
||||
Applications using FlatLaf
|
||||
--------------------------
|
||||
|
||||
- 
|
||||
### Featured
|
||||
|
||||
-  [JFormDesigner](https://www.formdev.com/)
|
||||
(**commercial**) - Java/Swing GUI Designer (from the FlatLaf creators)
|
||||
- 
|
||||
[JProfiler](https://www.ej-technologies.com/products/jprofiler/overview.html)
|
||||
12 (**commercial**) - the award-winning all-in-one Java profiler
|
||||
-  [JFormDesigner](https://www.formdev.com/) 8
|
||||
(**commercial**) - Java/Swing GUI Designer
|
||||
-  [Jeyla Studio](https://www.jeylastudio.com/) - Salon
|
||||
Software
|
||||
-  [Fanurio](https://www.fanuriotimetracking.com/) 3.3.2
|
||||
(**commercial**) - time tracking and billing for freelancers and teams
|
||||
-  [Antares](https://www.antarescircuit.io/) - a free,
|
||||
powerful platform for designing, simulating and explaining digital circuits
|
||||
- 
|
||||
[Logisim-evolution](https://github.com/logisim-evolution/logisim-evolution)
|
||||
3.6 - Digital logic design tool and simulator
|
||||
-  [Cinecred](https://loadingbyte.com/cinecred/) - create
|
||||
beautiful film credit sequences
|
||||
-  [tinyMediaManager](https://www.tinymediamanager.org/)
|
||||
v4 (**commercial**) - a media management tool
|
||||
-  [Weasis](https://nroduit.github.io/) - medical DICOM
|
||||
viewer used in healthcare by hospitals, health networks, etc
|
||||
- 
|
||||
[Makelangelo Software](https://github.com/MarginallyClever/Makelangelo-software)
|
||||
7.3.0 - for plotters, especially the wall-hanging polargraph
|
||||
-  [Ultorg](https://www.ultorg.com/) (**commercial**) - a
|
||||
visual query system for relational databases
|
||||
- [MooInfo](https://github.com/rememberber/MooInfo) - visual implementation of
|
||||
OSHI, to view information about the system and hardware
|
||||
- [Jailer](https://github.com/Wisser/Jailer) 11.2 - database subsetting and
|
||||
relational data browsing tool
|
||||
-  [Apache NetBeans](https://netbeans.apache.org/) 11.3 -
|
||||
IDE for Java, PHP, HTML and much more
|
||||
- [jclasslib bytecode viewer](https://github.com/ingokegel/jclasslib) 5.5
|
||||
- [KeyStore Explorer](https://keystore-explorer.org/) 5.4.3
|
||||
- 
|
||||
(**commercial**) - the award-winning all-in-one Java profiler
|
||||
- 
|
||||
[install4j](https://www.ej-technologies.com/products/install4j/overview.html)
|
||||
9.0 (**commercial**) - the powerful multi-platform Java installer builder
|
||||
-  [DbVisualizer](https://www.dbvis.com/) 12.0
|
||||
(**commercial**) - the powerful multi-platform Java installer builder
|
||||
-  [DbVisualizer](https://www.dbvis.com/)
|
||||
(**commercial**) - the universal database tool for developers, analysts and
|
||||
DBAs
|
||||
-  [MagicPlot](https://magicplot.com/) 3.0
|
||||
(**commercial**) - Software for nonlinear fitting, plotting and data analysis
|
||||
- 
|
||||
[Thermo-Calc](https://thermocalc.com/products/thermo-calc/) 2021a
|
||||
(**commercial**) - Thermodynamics and Properties Software
|
||||
-  [OWASP ZAP](https://www.zaproxy.org/) 2.10 - the worlds
|
||||
most widely used web app scanner
|
||||
-  [Apache NetBeans](https://netbeans.apache.org/) - IDE
|
||||
for Java, PHP, HTML and much more
|
||||
- 
|
||||
[Thermo-Calc](https://thermocalc.com/products/thermo-calc/) (**commercial**) -
|
||||
Thermodynamics and Properties Software
|
||||
|
||||
### Data
|
||||
|
||||
-  [Ultorg](https://www.ultorg.com/) (**commercial**) - a
|
||||
visual query system for relational databases
|
||||
- [Jailer](https://github.com/Wisser/Jailer) - database subsetting and
|
||||
relational data browsing tool
|
||||
-  [MagicPlot](https://magicplot.com/) (**commercial**) -
|
||||
Software for nonlinear fitting, plotting and data analysis
|
||||
-  [Constellation](https://www.constellation-app.com/) -
|
||||
Data Visualization and Analytics (based on NetBeans platform)
|
||||
- 
|
||||
[Kafka Visualizer](https://github.com/kumait/kafkavisualizer) - Kafka GUI
|
||||
client
|
||||
|
||||
### Security
|
||||
|
||||
-  [ZAP](https://www.zaproxy.org/) - the world's most
|
||||
widely used web app scanner
|
||||
- 
|
||||
[Burp Suite Professional and Community Edition](https://portswigger.net/burp/pro)
|
||||
2020.11.2 (**commercial**) - the leading software for web security testing
|
||||
(**commercial**) - the leading software for web security testing
|
||||
- 
|
||||
[Ghidra](https://github.com/NationalSecurityAgency/ghidra) - a software
|
||||
reverse engineering (SRE) framework
|
||||
-  [jadx](https://github.com/skylot/jadx) - Dex to Java
|
||||
decompiler
|
||||
- [BurpCustomizer](https://github.com/CoreyD97/BurpCustomizer) - adds more
|
||||
FlatLaf themes to Burp Suite
|
||||
- [Total Validator](https://www.totalvalidator.com/) (**commercial**) - checks
|
||||
your website
|
||||
- [JPass](https://github.com/gaborbata/jpass) - password manager with strong
|
||||
encryption
|
||||
|
||||
### Software Development
|
||||
|
||||
- [jclasslib bytecode viewer](https://github.com/ingokegel/jclasslib)
|
||||
- [KeyStore Explorer](https://keystore-explorer.org/)
|
||||
- 
|
||||
[muCommander](https://github.com/mucommander/mucommander) - lightweight
|
||||
cross-platform file manager
|
||||
-  [Guiffy](https://www.guiffy.com/) (**commercial**) -
|
||||
advanced cross-platform Diff/Merge
|
||||
-  [HashGarten](https://github.com/jonelo/HashGarten) -
|
||||
cross-platform Swing GUI for Jacksum
|
||||
- [Pseudo Assembler IDE](https://github.com/tomasz-herman/PseudoAssemblerIDE) -
|
||||
IDE for Pseudo-Assembler
|
||||
- [Linotte](https://github.com/cpc6128/LangageLinotte) - French programming
|
||||
language created to learn programming
|
||||
- [lsfusion platform](https://github.com/lsfusion/platform) - information
|
||||
systems development platform
|
||||
|
||||
### Electrical
|
||||
|
||||
- [Antares](https://www.antarescircuit.io/) - a free, powerful platform for
|
||||
designing, simulating and explaining digital circuits
|
||||
- [Logisim-evolution](https://github.com/logisim-evolution/logisim-evolution) -
|
||||
Digital logic design tool and simulator
|
||||
- [Makelangelo Software](https://github.com/MarginallyClever/Makelangelo-software) -
|
||||
for plotters, especially the wall-hanging polargraph
|
||||
- [GUIslice Builder](https://github.com/ImpulseAdventure/GUIslice-Builder) - GUI
|
||||
builder for [GUIslice](https://github.com/ImpulseAdventure/GUIslice), a
|
||||
lightweight GUI framework for embedded displays
|
||||
- [ThunderFocus](https://github.com/marcocipriani01/ThunderFocus) -
|
||||
Arduino-based telescope focuser
|
||||
- [RemoteLight](https://github.com/Drumber/RemoteLight) - multifunctional LED
|
||||
control software
|
||||
|
||||
### Media
|
||||
|
||||
-  [jAlbum](https://jalbum.net/) (**commercial**) -
|
||||
creates photo album websites
|
||||
-  [MediathekView](https://mediathekview.de/) - search in
|
||||
media libraries of various German broadcasters
|
||||
- [Cinecred](https://loadingbyte.com/cinecred/) - create beautiful film credit
|
||||
sequences
|
||||
- [tinyMediaManager](https://www.tinymediamanager.org/) (**commercial**) - a
|
||||
media management tool
|
||||
- [Weasis](https://nroduit.github.io/) - medical DICOM viewer used in healthcare
|
||||
by hospitals, health networks, etc
|
||||
- [Shutter Encoder](https://www.shutterencoder.com/)
|
||||
([source code](https://github.com/paulpacifico/shutter-encoder)) -
|
||||
professional video converter and compression tool
|
||||
- [Sound Analysis](https://github.com/tomasz-herman/SoundAnalysis) - analyze
|
||||
sound files in time or frequency domain
|
||||
- [Novel-Grabber](https://github.com/Flameish/Novel-Grabber) - download novels
|
||||
from any webnovel and lightnovel site
|
||||
- [lectureStudio](https://www.lecturestudio.org/) - digitize your lectures with
|
||||
ease
|
||||
|
||||
### Modelling
|
||||
|
||||
-  [Astah](https://astah.net/) (**commercial**) - create
|
||||
UML, ER Diagram, Flowchart, Data Flow Diagram, Requirement Diagram, SysML
|
||||
diagrams and more
|
||||
- [IGMAS+](https://www.gfz-potsdam.de/igmas) - Interactive Gravity and Magnetic
|
||||
Application System
|
||||
|
||||
### Documents
|
||||
|
||||
-  [Big Faceless (BFO) PDF Viewer](https://bfo.com/)
|
||||
(**commercial**) - Swing PDF Viewer
|
||||
- [PDF Studio](https://www.qoppa.com/pdfstudio/) (**commercial**) - create,
|
||||
review and edit PDF documents
|
||||
- [XMLmind XML Editor](https://www.xmlmind.com/xmleditor/) (**commercial**)
|
||||
|
||||
### Geo
|
||||
|
||||
-  [JOSM](https://josm.openstreetmap.de/) - an extensible
|
||||
editor for [OpenStreetMap](https://www.openstreetmap.org/) (requires FlatLaf
|
||||
JOSM plugin)
|
||||
-  [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
|
||||
|
||||
- 
|
||||
[j-lawyer](https://github.com/jlawyerorg/j-lawyer-org) - Kanzleisoftware
|
||||
-  [Jeyla Studio](https://www.jeylastudio.com/) -
|
||||
Salon Software
|
||||
- [Fanurio](https://www.fanuriotimetracking.com/) (**commercial**) - time
|
||||
tracking and billing for freelancers and teams
|
||||
- [Jes](https://www.jes-eur.de) - Die Java-EÜR
|
||||
- [mendelson AS2](https://sourceforge.net/projects/mec-as2/),
|
||||
[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
|
||||
|
||||
-  [Spark](https://github.com/igniterealtime/Spark) -
|
||||
cross-platform IM client optimized for businesses and organizations
|
||||
-  [Chatty](https://github.com/chatty/chatty) - Twitch
|
||||
Chat Client
|
||||
|
||||
### Gaming
|
||||
|
||||
-  
|
||||
[BGBlitz](https://www.bgblitz.com/) (**commercial**) - professional Backgammon
|
||||
-  [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
|
||||
- 
|
||||
[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
|
||||
|
||||
@@ -14,10 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
val releaseVersion = "3.1.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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>(
|
||||
|
||||
@@ -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'." )
|
||||
}
|
||||
}
|
||||
|
||||
2
flatlaf-core/.settings/org.eclipse.core.resources.prefs
Normal file
2
flatlaf-core/.settings/org.eclipse.core.resources.prefs
Normal file
@@ -0,0 +1,2 @@
|
||||
eclipse.preferences.version=1
|
||||
encoding/<project>=ISO-8859-1
|
||||
@@ -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" ),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#Signature file v4.1
|
||||
#Version 3.1
|
||||
#Version 3.2.4
|
||||
|
||||
CLSS public abstract interface com.formdev.flatlaf.FlatClientProperties
|
||||
fld public final static java.lang.String BUTTON_TYPE = "JButton.buttonType"
|
||||
@@ -96,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)
|
||||
@@ -280,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"
|
||||
@@ -298,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
|
||||
|
||||
@@ -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 -----------------------------------------------------
|
||||
|
||||
/**
|
||||
|
||||
@@ -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" ),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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,8 +399,6 @@ public class IntelliJTheme
|
||||
if( "".equals( value ) )
|
||||
return; // ignore empty value
|
||||
|
||||
uiKeys.add( key );
|
||||
|
||||
// ignore some properties that affect sizes
|
||||
if( key.endsWith( ".border" ) ||
|
||||
key.endsWith( ".rowHeight" ) ||
|
||||
@@ -350,6 +413,16 @@ public class IntelliJTheme
|
||||
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
|
||||
@@ -395,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 ) {
|
||||
@@ -466,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 ) {
|
||||
@@ -486,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" );
|
||||
|
||||
@@ -511,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
|
||||
@@ -575,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" );
|
||||
@@ -643,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" );
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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,12 +642,28 @@ 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 {
|
||||
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 );
|
||||
@@ -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 + "'" );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() );
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,9 +555,11 @@ 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 ) {
|
||||
// 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 );
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ import com.formdev.flatlaf.util.SystemInfo;
|
||||
*/
|
||||
class FlatNativeLibrary
|
||||
{
|
||||
private static boolean initialized;
|
||||
private static NativeLibrary nativeLibrary;
|
||||
|
||||
/**
|
||||
@@ -45,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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 ------------------------------------------
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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 ) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 + "'" );
|
||||
|
||||
@@ -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,9 +1200,40 @@ 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() ) );
|
||||
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 );
|
||||
}
|
||||
|
||||
@@ -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
|
||||
/** @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:
|
||||
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;
|
||||
}
|
||||
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 ) {
|
||||
// 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;
|
||||
|
||||
if( c instanceof JTabbedPane )
|
||||
repaintSelectedTab( (JTabbedPane) c );
|
||||
|
||||
while( (c = SwingUtilities.getAncestorOfClass( JTabbedPane.class, c )) != null )
|
||||
repaintSelectedTab( (JTabbedPane) c );
|
||||
Component c2 = c;
|
||||
while( (c2 = SwingUtilities.getAncestorOfClass( JTabbedPane.class, c2 )) != null )
|
||||
repaintSelectedTab( (JTabbedPane) c2 );
|
||||
} );
|
||||
}
|
||||
|
||||
private void repaintSelectedTab( JTabbedPane tabbedPane ) {
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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 );
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
/*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
module com.formdev.flatlaf {
|
||||
|
||||
@@ -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 ----
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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" );
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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 ) {
|
||||
|
||||
2
flatlaf-demo/.settings/org.eclipse.core.resources.prefs
Normal file
2
flatlaf-demo/.settings/org.eclipse.core.resources.prefs
Normal file
@@ -0,0 +1,2 @@
|
||||
eclipse.preferences.version=1
|
||||
encoding/<project>=ISO-8859-1
|
||||
@@ -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" ) )
|
||||
}
|
||||
|
||||
|
||||
@@ -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() );
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 ) {
|
||||
|
||||
@@ -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" ) )
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
eclipse.preferences.version=1
|
||||
encoding/<project>=ISO-8859-1
|
||||
@@ -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).\
|
||||

|
||||
- [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:
|
||||
|
||||
[](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:
|
||||
|
||||
[](https://maven-badges.herokuapp.com/maven-central/com.formdev/svgSalamander)
|
||||
[](https://maven-badges.herokuapp.com/maven-central/com.github.weisj/jsvg)
|
||||
|
||||
|
||||
Tools
|
||||
|
||||
@@ -23,7 +23,7 @@ plugins {
|
||||
|
||||
dependencies {
|
||||
implementation( project( ":flatlaf-core" ) )
|
||||
implementation( "com.formdev:svgSalamander:1.1.3" )
|
||||
implementation( libs.jsvg )
|
||||
}
|
||||
|
||||
flatlafModuleInfo {
|
||||
|
||||
@@ -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 ) );
|
||||
|
||||
@@ -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 ) {
|
||||
try {
|
||||
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 {
|
||||
g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
|
||||
g.setRenderingHint( RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR );
|
||||
FlatSVGIcon.setRenderingHints( g );
|
||||
|
||||
double sx = width / diagram.getWidth();
|
||||
double sy = height / diagram.getHeight();
|
||||
FloatSize size = document.size();
|
||||
double sx = width / size.width;
|
||||
double sy = height / size.height;
|
||||
if( sx != 1 || sy != 1 )
|
||||
g.scale( sx, sy );
|
||||
|
||||
diagram.setIgnoringClipHeuristic( true );
|
||||
|
||||
diagram.render( g );
|
||||
document.render( null, g );
|
||||
} finally {
|
||||
g.dispose();
|
||||
}
|
||||
return image;
|
||||
|
||||
} catch( SVGException ex ) {
|
||||
throw new RuntimeException( ex );
|
||||
}
|
||||
}
|
||||
|
||||
private static URL getResource( String svgName ) {
|
||||
return FlatSVGUtils.class.getResource( svgName );
|
||||
}
|
||||
|
||||
private static SVGDiagram loadSVG( URL url ) {
|
||||
return FlatSVGIcon.loadSVG( FlatSVGIcon.url2uri( url ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
eclipse.preferences.version=1
|
||||
encoding/<project>=ISO-8859-1
|
||||
@@ -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 {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
/*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
module com.formdev.flatlaf.fonts.inter {
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
eclipse.preferences.version=1
|
||||
encoding/<project>=ISO-8859-1
|
||||
@@ -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 {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
/*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
module com.formdev.flatlaf.fonts.jetbrains_mono {
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
eclipse.preferences.version=1
|
||||
encoding/<project>=ISO-8859-1
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user