Compare commits

...

118 Commits

Author SHA1 Message Date
Karl Tauber
e34b5eafe1 Merge PR #639: Fonts: Roboto Mono 2023-01-12 15:28:06 +01:00
Karl Tauber
4e1e749094 Fonts: added Roboto Mono (issue #638) 2023-01-12 14:08:08 +01:00
Karl Tauber
ede9293377 README.md: added macOS theme screenshots 2023-01-03 20:11:55 +01:00
Karl Tauber
9101324a1f Window decorations: glass pane no longer overlaps the FlatLaf window title bar (issue #630) 2023-01-03 19:48:21 +01:00
Karl Tauber
4b844353ee Window decorations: fixed broken window resizing on Linux multi-screen setups (issue #632) 2023-01-02 19:54:05 +01:00
Karl Tauber
2134c19c58 IntelliJ Themes: avoid that accent color affect some colors in some IntelliJ themes (issue #625) 2023-01-02 18:58:18 +01:00
Karl Tauber
c974784ebb IntelliJ Themes: fixed default button hover background in "Solarized Light" theme (issue #628) 2023-01-02 18:43:12 +01:00
Karl Tauber
5eb6961023 updated sigtest for FlatLaf 3.0
(generated in clean workspace with gradle task `sigtestGenerate`)
2022-12-16 01:30:50 +01:00
Karl Tauber
07cbd8b97b Fonts: enabled "Download" section in README.md 2022-12-16 01:29:11 +01:00
Karl Tauber
09c7f15364 Fonts: added missing description in POM (required for Maven Central) 2022-12-16 00:51:35 +01:00
Karl Tauber
b879b393ad release 3.0 2022-12-16 00:19:03 +01:00
Karl Tauber
e4503c2a54 Native window decorations: signed Windows DLLs with FormDev Software GmbH code signing certificate (issue #624) 2022-12-14 17:08:29 +01:00
Karl Tauber
7e2d02b997 added DSC Software AG as Platinum sponsor; added Jeyla Studio 2022-12-14 15:29:03 +01:00
Karl Tauber
d286550572 Merge PR #613: Window decorations: Title bar customizing 2022-12-03 19:33:05 +01:00
Karl Tauber
4e44e25d30 macOS themes: fix horizontal centering of combobox arrows (issue #497; PR #533) 2022-12-03 19:17:10 +01:00
Karl Tauber
9fef2f9d05 SwingX: update fonts in JXHeader, JXMonthView, JXTaskPane and JXTitledPanel when changing default font 2022-12-01 12:51:19 +01:00
Karl Tauber
04f1f5921d Native window decorations: updated DLLs (issue #591)
built by GitHub Actions:
https://github.com/JFormDesigner/FlatLaf/actions/runs/3554848392
2022-11-26 19:34:40 +01:00
Karl Tauber
f9ecffb850 flatlaf-natives-windows: fixed memory allocation error handling (issue #591) 2022-11-26 19:14:24 +01:00
Karl Tauber
c9b5274ccf flatlaf-natives-windows: reworked memory allocation error handling 2022-11-26 19:05:24 +01:00
Karl Tauber
d209d47b9e Testing: added FlatPaintingArrowsTest (extracted from FlatPaintingTest and used parts of FlatPaintingIconsTest) 2022-11-26 18:04:29 +01:00
Karl Tauber
21baaf810c CHANGELOG.md: added changelog for merged PRs 2022-11-26 17:11:35 +01:00
Karl Tauber
95b4366270 Merge PR #615: Fonts: lazy loading 2022-11-26 16:24:54 +01:00
Karl Tauber
c3adadfe2f flatlaf-natives-windows: fixed compile and link errors 2022-11-23 21:27:55 +01:00
Karl Tauber
adf7753617 Fonts: fixed gradle build error and javadoc warnings 2022-11-21 12:55:55 +01:00
Karl Tauber
d491847754 Fonts: support lazy font file loading (extends PRs #545 and #614) 2022-11-21 11:51:27 +01:00
Karl Tauber
6afc747790 Merge PR #614: Fonts: Roboto 2022-11-20 14:08:58 +01:00
Karl Tauber
ff46935448 Demo: "Data components" tab: demonstrate rounded selection for JList and JTree 2022-11-20 14:07:02 +01:00
Karl Tauber
78c2f98f1f Fonts: added Roboto 2022-11-19 16:49:26 +01:00
Karl Tauber
91be9aa2fe Fonts: do not publish font snapshots/releases in CI 2022-11-19 13:11:08 +01:00
Karl Tauber
13e5da584f Fonts: do not skip all gradle font tasks when building snapshots and releases because they are used in demo and theme editor 2022-11-19 12:01:14 +01:00
Karl Tauber
1762e0b7a6 Fonts: added font license to maven pom 2022-11-19 11:31:06 +01:00
Karl Tauber
05240abfe0 GitHub Actions: removed on.pull_request.* to avoid duplicate execution or actions in PRs 2022-11-19 11:28:06 +01:00
Karl Tauber
b515e8be04 Fonts: fixed GitHub Actions:
- ci.yml: skip fonts in snapshot and release jobs
- fonts.yml: build on all branches/PRs; publish snapshots
- fixed version for font snapshots
2022-11-19 10:48:07 +01:00
Karl Tauber
24bc7fb0b5 Merge PR #545: Fonts (Inter and JetBrains Mono) 2022-11-18 17:54:00 +01:00
Karl Tauber
0d2e1e6d18 Fonts: HiDPIUtils: improved vertical position correction of text (on Windows) for various fonts 2022-11-18 17:35:59 +01:00
Karl Tauber
f23c523baf GitHub Actions: ci.yml: include font JARs in build artifacts 2022-11-17 23:01:56 +01:00
Karl Tauber
76fee29f5b Demo: install Inter font only when used; removed JetBrains Mono 2022-11-17 23:01:17 +01:00
Karl Tauber
ec77746a43 Fonts: support specifying preferred font family for easy using another font (e.g. Inter) for all components 2022-11-17 23:01:03 +01:00
Karl Tauber
92cd6f8f34 Theme Editor:
- use JetBrains Mono font for editor area
- added Inter font to allow using it in preview (Java 11+)
2022-11-17 23:00:07 +01:00
Karl Tauber
e7d2b5cbb6 Fonts: added Inter and JetBrains Mono 2022-11-17 22:59:31 +01:00
Karl Tauber
4d175da3a0 Window decorations: added debug option to paint title bar rectangles that are used by Windows 10/11 in WM_NCHITTEST to identify special areas 2022-11-16 20:07:11 +01:00
Karl Tauber
5f047ddda9 Window decorations: added client properties to hide title, iconify, maximize/restore and close buttons (issue #608) 2022-11-16 11:08:31 +01:00
Karl Tauber
ccca6fe88e Merge PR #612: macOS themes: make spinner look like macOS stepper 2022-11-16 10:59:10 +01:00
Karl Tauber
a1f18e1ec9 macOS themes: fixed spinner arrow hover/pressed colors (issue #497; PR #533) 2022-11-16 10:51:38 +01:00
Karl Tauber
afdaf7a0a5 Merge PR #609: Tree: hide default closed/opened/leaf icons by default 2022-11-16 10:29:24 +01:00
Karl Tauber
62f0ef19f4 macOS themes: make spinner look like macOS stepper (issue #497; PR #533) 2022-11-15 14:29:47 +01:00
Karl Tauber
b736502c27 Tree: hide default closed/opened/leaf icons by default 2022-11-14 14:59:47 +01:00
Karl Tauber
2be2dae3d6 macOS themes: updated UI defaults dumps (PR #533) 2022-11-14 14:19:49 +01:00
Karl Tauber
aefe104ca4 FlatSVGIcon: no longer use classes from package com.formdev.flatlaf.ui to allow using FlatSVGIcon (and flatlaf-extras.jar) in NetBeans plugin (NetBeans ships with FlatLaf, but does not export that package) 2022-11-14 14:02:27 +01:00
Karl Tauber
3e6bce9cec no longer check for system property apple.awt.graphics.UseQuartz because openjdk seems not support it
not found `apple.awt.graphics.UseQuartz` in:
- https://github.com/openjdk/jdk8u-dev
- https://github.com/openjdk/jdk
2022-11-14 13:48:54 +01:00
Karl Tauber
a6394cac38 minor code cleanup:
- remove redundant semicolon
- create array with curly
2022-11-14 12:25:29 +01:00
Karl Tauber
1e09ddfc93 Merge PR #607: systemColor() function and support changing accent color in macOS themes 2022-11-14 12:05:47 +01:00
Karl Tauber
664f5c98e9 macOS themes: support changing accent and highlight colors (issue #497) 2022-11-02 21:59:45 +01:00
Karl Tauber
c7bfd2ea82 UIDefaultsLoader: added systemColor() color function that can be used to change accent color (preparation for getting accent color from operating system) 2022-11-02 21:59:07 +01:00
Karl Tauber
9ce7ddd088 UIDefaultsLoader: reworked error handling when parsing colors to support null as result (preparation for systemColor() function) 2022-11-02 21:57:57 +01:00
Karl Tauber
cca8d427d2 Merge PR #533: macOS light and dark themes 2022-11-01 12:23:57 +01:00
Karl Tauber
aa9263a2e7 macOS themes: use rounded selection for menus and combo boxes; fixed menus and combo box selection colors (issue #497) 2022-11-01 12:00:11 +01:00
Karl Tauber
5eaebde437 macOS themes: added some ScrollBar UI properties so that themes look the same on Windows or Linux as on macOS (issue #497) 2022-11-01 11:52:36 +01:00
Karl Tauber
7f15f557a5 ComboBox: for style "mac", place popup over combobox (issue #497) 2022-11-01 11:52:36 +01:00
Karl Tauber
b459715cb5 macOS light and dark themes (issue #497) 2022-11-01 11:37:29 +01:00
Karl Tauber
bfede219d0 added DbVisualizer as Platinum sponsor 2022-11-01 10:13:37 +01:00
Karl Tauber
ef21efecf5 Tree:
- Fixed missing tree lines (if enabled) for wide-selected rows. (issue #598)
- Fixed scaling of tree lines and fixed alignment to expand/collapse arrows.
- Removed support for dashed tree lines. `Tree.lineTypeDashed` is now ignored.
2022-11-01 10:12:49 +01:00
Karl Tauber
2bfbc9dc12 Merge PR #577: Rounded outlined icons 2022-10-30 10:39:09 +01:00
Karl Tauber
c3a1b45546 Merge PR #548: ComboBox: support rounded selection 2022-10-30 10:28:48 +01:00
Karl Tauber
b72508f920 Merge PR #547: List: Support rounded selection
# Conflicts:
#	flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatComponents2Test.java
2022-10-30 10:24:16 +01:00
Karl Tauber
22bb80218d Merge PR #546: Tree: rounded selection 2022-10-30 10:16:07 +01:00
Karl Tauber
873a7e8572 Menu: fixed missing background on hover if top-level JMenu is opaque and selectionInsets or selectionArc are set (PR #536) 2022-10-30 10:10:22 +01:00
Karl Tauber
0c5016fe89 Merge PR #536: Menus: rounded selection
# Conflicts:
#	flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatMenuBarUI.java
#	flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatMenuUI.java
#	flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties
#	flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/FlatLafUIKeys.txt
2022-10-30 09:55:09 +01:00
Karl Tauber
607b084697 Merge PR #534: ToolBar: hover effect for button groups 2022-10-29 19:51:37 +02:00
Karl Tauber
9d8ffec276 Merge PR #605: FlatInspector: add/remove mouse listener in setEnabled 2022-10-29 14:41:24 +02:00
Max Weber
15f08e9b7c FlatInspector: add/remove mouse listener in setEnabled 2022-10-29 05:16:29 -06:00
Karl Tauber
08aa6b1894 added ej-technologies (creator of JProfiler and install4j) as Platinum sponsor 2022-10-28 22:44:02 +02:00
Karl Tauber
06b02c4f7c README.md: new applications using FlatLaf:
- JProfiler
- JFormDesigner
- Fanurio
- Antares
- Logisim-evolution
- Cinecred
- tinyMediaManager
- Weasis
- Makelangelo Software

(changed "New" to "Hot")
2022-10-28 22:22:10 +02:00
Karl Tauber
b56acd271f added Sponsor button 2022-10-26 18:09:28 +02:00
Karl Tauber
b24e2db59e FileChooser: fixed layout of (optional) accessory component and fixed too large right margin (issue #604; regression since implementing PR #522 in FlatLaf 2.3) 2022-10-21 13:12:52 +02:00
Karl Tauber
f215356629 updated sigtest for FlatLaf 2.6
(generated in clean workspace with gradle task `sigtestGenerate`)
2022-10-18 11:26:38 +02:00
Karl Tauber
069a7c809c release 2.6 2022-10-18 11:11:24 +02:00
Karl Tauber
883b4d735a changed "since 3" to "since 2.6" 2022-10-18 11:08:14 +02:00
Karl Tauber
9f39b269bb CHANGELOG.md: moved PR #595 from "Fixed bugs" to "New features and improvements" 2022-10-17 18:15:19 +02:00
Karl Tauber
36c405c708 fixed NPE in FlatUIUtils.isCellEditor() (issue #601) 2022-10-17 18:09:12 +02:00
Karl Tauber
bc7c68ebe4 MenuBar: fixed NPE in FlatMenuItemRenderer.getTopLevelFont() if menu item does not have a parent (issue #600; regression since implementing #589 in FlatLaf 2.5; commit f6c5db07f2) 2022-10-17 17:08:12 +02:00
Karl Tauber
6c502ad4c5 2.6-SNAPSHOT 2022-10-17 16:31:54 +02:00
Karl Tauber
100aa0b621 Native libraries: load jawt.dll also on Windows when running in Java 9 and later (to be on the safe side) 2022-10-06 10:58:32 +02:00
Karl Tauber
8e42b19934 Native libraries: support loading via System.loadLibrary()
(for pre-extracted native libs in NetBeans)
2022-10-06 10:49:55 +02:00
Karl Tauber
1a456d5d68 ScaledImageIcon: do not throw exceptions if image has invalid size (e.g. not found); instead paint a red rectangle (similar to FlatSVGIcon) 2022-10-01 20:12:32 +02:00
Karl Tauber
e83c26a76a - ScrollBar: show "pressed" feedback on track/thumb only for left mouse button; if absolute positioning is enabled (the default), then also for middle mouse button
- Arrow buttons in ComboBox, Spinner, ScrollBar and TabbedPane: show "pressed" feedback only for left mouse button
2022-09-30 19:55:42 +02:00
Karl Tauber
6e7c2a616b updated CHANGELOG.md for PR #595 and added tab context menu test 2022-09-30 15:33:37 +02:00
Karl Tauber
0699454df8 Merge PR #595: Switch and close tabs on left mouse click only 2022-09-30 15:10:45 +02:00
Karl Tauber
92c110548a ComboBox and Spinner: no longer use preferred height for arrow button width, because preferred height may be zero, which would hide arrow button (see https://github.com/scijava/scijava-ui-swing/issues/77#issuecomment-1261452712)
- arrow button width depends on combobox/spinner height
- default/max button width is height of a raw combobox/spinner (without insets)
- min button width is 3/4 of default button width
2022-09-30 12:30:46 +02:00
Karl Tauber
ca88023560 GitHub Actions: build using Java 19 (use toolchain because Gradle 7.5.1 does not support running on Java 19) 2022-09-28 19:15:59 +02:00
Karl Tauber
12fc2299ec update to Gradle 7.5.1
./gradlew wrapper --gradle-version=7.5.1
2022-09-28 15:44:16 +02:00
Karl Tauber
2089c77b84 updated sigtest for FlatLaf 2.5
(generated in clean workspace with gradle task `sigtestGenerate`)
2022-09-27 16:50:34 +02:00
ShadelessFox
95522846ac Switch and close tabs on left mouse click only 2022-09-25 21:52:44 +03:00
John Platts
f7be12df67 Add AllocRoutines.h include 2022-09-19 14:23:51 -05:00
John Platts
a1d1e221ae Remove operator new and operator delete overloads from Runtime.cpp
The ```operator new``` and ```operator delete``` overloads in Runtime.cpp are replaced by placement ```operator new``` and ```operator delete``` operators in AllocRoutines.h that take a const FlatLafNoThrowT& placement parameter.

Using ```new (FlatLafNoThrow) FlatWndProc``` instead of ```new FlatWndProc``` also allows for inlining by the C++ compiler.
2022-09-19 14:23:16 -05:00
John Platts
0a4dc54fb9 Update put and ensureCapacity routines 2022-09-19 14:17:37 -05:00
John Platts
b8c7801365 Change ensureCapacity method to return a bool 2022-09-19 14:06:26 -05:00
John Platts
a7099c039f Rename allocation functions 2022-09-19 13:57:25 -05:00
John Platts
a4d2d347e3 Change put method to return a bool 2022-09-19 13:56:28 -05:00
John Platts
829c537fd3 Add checks for allocation failure 2022-09-19 13:55:33 -05:00
John Platts
28437f99cf Update new and delete FlatWndProc.cpp 2022-09-19 13:53:33 -05:00
John Platts
c1402d85e1 Update HWNDMap.h 2022-09-19 13:39:47 -05:00
John Platts
32e071ab89 Update AllocRoutines.h 2022-09-19 13:36:10 -05:00
John Platts
01125e030e Create AllocRoutines.h 2022-09-19 13:26:33 -05:00
John Platts
b43278439a Delete AllocRoutines.h 2022-09-19 13:26:01 -05:00
John Platts
7a445aabd7 Create AllocRoutines.h 2022-09-19 13:25:26 -05:00
Karl Tauber
380dae1017 Icons: cache paths for (complex) immutable icons that may be painted often (e.g. Tree icons or FileView icons) 2022-08-11 22:26:48 +02:00
Karl Tauber
fb15cdc546 Icons:
- reduced temporary memory usage by specifying optimal initial capacity to `new Path2D.Float()`
- replaced `path.append( new Line2D.Float(...) )` with `path.moveTo(...); path.lineTo(...);`, which does the same, but does not use temporary objects
2022-08-11 18:09:47 +02:00
Karl Tauber
a525fe29db Icons: changed icons for FileChooser, OptionPane and Tree to rounded outlined style (issue #543) 2022-08-11 17:02:24 +02:00
Karl Tauber
bf0685cee2 ComboBox: support rounded selection 2022-06-05 00:53:22 +02:00
Karl Tauber
8262793751 List: support rounded selection for layout orientations VERTICAL_WRAP and HORIZONTAL_WRAP 2022-06-04 11:16:04 +02:00
Karl Tauber
5ec7848fb0 List: fixed endless loop rounded selection painting 2022-06-03 17:32:55 +02:00
Karl Tauber
450fc123ff List: support rounded selection 2022-06-03 16:12:02 +02:00
Karl Tauber
3802c64be3 Tree: better support for non-wide rounded selection 2022-06-03 09:33:19 +02:00
Karl Tauber
7bf1b26812 Tree: support rounded selection 2022-06-02 12:03:20 +02:00
Karl Tauber
f1792e46c6 Menus:
- support different selection colors for top-level JMenus
- fixed styling of underline selection properties for top-level JMenus
2022-05-15 16:39:11 +02:00
Karl Tauber
84e9c36280 Menus: support rounded selection 2022-05-15 14:24:38 +02:00
Karl Tauber
2ef6a2c3c9 ToolBar: add hover effect to button groups 2022-05-14 13:59:47 +02:00
243 changed files with 11811 additions and 1673 deletions

2
.gitattributes vendored
View File

@@ -20,7 +20,9 @@
*.gif binary
*.jar binary
*.lib binary
*.otf binary
*.png binary
*.sketch binary
*.so binary
*.ttf binary
*.zip binary

1
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1 @@
custom: https://www.formdev.com/flatlaf/sponsor/

View File

@@ -1,4 +1,5 @@
# https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions
# https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle
name: CI
@@ -8,9 +9,6 @@ on:
- '*'
tags:
- '[0-9]*'
pull_request:
branches:
- '*'
jobs:
build:
@@ -26,6 +24,10 @@ jobs:
- 8
- 11 # LTS
- 17 # LTS
toolchain: [""]
include:
- java: 17
toolchain: 19 # latest
steps:
- uses: actions/checkout@v3
@@ -41,7 +43,7 @@ jobs:
cache: gradle
- name: Build with Gradle
run: ./gradlew build
run: ./gradlew build -Dtoolchain=${{ matrix.toolchain }}
- name: Upload artifacts
uses: actions/upload-artifact@v3
@@ -50,6 +52,7 @@ jobs:
name: FlatLaf-build-artifacts
path: |
flatlaf-*/build/libs
flatlaf-*/flatlaf-*/build/libs
!**/*-javadoc.jar
!**/*-sources.jar
@@ -73,7 +76,7 @@ jobs:
cache: gradle
- name: Publish snapshot to oss.sonatype.org
run: ./gradlew publish :flatlaf-theme-editor:build -Dorg.gradle.internal.publish.checksums.insecure=true
run: ./gradlew publish :flatlaf-theme-editor:build -PskipFonts -Dorg.gradle.internal.publish.checksums.insecure=true
env:
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
@@ -109,7 +112,7 @@ jobs:
cache: gradle
- name: Release a new stable version to Maven Central
run: ./gradlew publish :flatlaf-demo:build :flatlaf-theme-editor:build -Drelease=true
run: ./gradlew publish :flatlaf-demo:build :flatlaf-theme-editor:build -PskipFonts -Prelease
env:
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}

60
.github/workflows/fonts.yml vendored Normal file
View File

@@ -0,0 +1,60 @@
# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions
# https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle
name: Fonts
on:
push:
branches:
- '*'
tags:
- 'fonts/*-[0-9]*'
paths:
- 'flatlaf-fonts/**'
- '.github/workflows/fonts.yml'
- 'gradle/wrapper/gradle-wrapper.properties'
jobs:
Fonts:
strategy:
matrix:
font:
- inter
- jetbrains-mono
- roboto
- roboto-mono
runs-on: ubuntu-latest
if: |
github.event_name == 'push' &&
github.repository == 'JFormDesigner/FlatLaf'
steps:
- uses: actions/checkout@v3
- name: Setup Java 11
uses: actions/setup-java@v3
with:
java-version: 11
distribution: adopt # pre-installed on ubuntu-latest
cache: gradle
- name: Build with Gradle
run: ./gradlew :flatlaf-fonts-${{ matrix.font }}:build
if: startsWith( github.ref, format( 'refs/tags/fonts/{0}-', matrix.font ) ) != true
- name: Publish snapshot to oss.sonatype.org
run: ./gradlew :flatlaf-fonts-${{ matrix.font }}:publish -Dorg.gradle.internal.publish.checksums.insecure=true
env:
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
if: github.ref == 'refs/heads/main' || startsWith( github.ref, 'refs/heads/develop-' )
- name: Release a new stable version to Maven Central
run: ./gradlew :flatlaf-fonts-${{ matrix.font }}:build :flatlaf-fonts-${{ matrix.font }}:publish -Prelease
env:
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
SIGNING_KEY: ${{ secrets.SIGNING_KEY }}
SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }}
if: startsWith( github.ref, format( 'refs/tags/fonts/{0}-', matrix.font ) )

View File

@@ -1,4 +1,5 @@
# https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions
# https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle
name: Native Libraries
@@ -12,13 +13,6 @@ on:
- 'flatlaf-natives/**'
- '.github/workflows/natives.yml'
- 'gradle/wrapper/gradle-wrapper.properties'
pull_request:
branches:
- '*'
paths:
- 'flatlaf-natives/**'
- '.github/workflows/natives.yml'
- 'gradle/wrapper/gradle-wrapper.properties'
jobs:
Natives:

2
.gitignore vendored
View File

@@ -9,5 +9,7 @@ out/
*.iml
*.ipr
*.iws
*.xcuserstate
*.xcworkspacedata
.vs/
.vscode/

View File

@@ -1,6 +1,90 @@
FlatLaf Change Log
==================
## 3.1-SNAPSHOT
#### New features and improvements
- Fonts: Added **Roboto
Mono** (https://fonts.google.com/specimen/Roboto+Mono). (PR #639, issue #638)
#### Fixed bugs
- FlatLaf window decorations:
- Fixed inconsistent size of glass pane depending on whether FlatLaf window
decorations are used (e.g. Windows 10/11) or not (e.g. macOS). Now the glass
pane no longer overlaps the FlatLaf window title bar. (issue #630)
- Linux: Fixed broken window resizing on multi-screen setups. (issue #632)
- IntelliJ Themes:
- Fixed default button hover background in "Solarized Light" theme. (issue
#628)
- Avoid that accent color affect some colors in some IntelliJ themes. (issue
#625)
## 3.0
#### New features and improvements
- **macOS light and dark themes**: The two new themes `FlatMacLightLaf` and
`FlatMacDarkLaf` use macOS colors and look similar to native macOS controls.
(PRs #533, #612 and #607)
- **Fonts**: Packaged some fonts into JARs and provide an easy way to use them
with FlatLaf. (PRs #545, #614 and #615) At the moment there are three fonts:
- **Inter** (https://rsms.me/inter/) - a typeface carefully crafted & designed
for computer screens
- **Roboto** (https://fonts.google.com/specimen/Roboto) - default font on
Android and recommended for Material Design
- **JetBrains Mono** (https://www.jetbrains.com/mono) - a monospaced typeface
- **Rounded selection**: Optionally use rounded selection in:
- Menus (PR #536)
- ComboBox (PR #548)
- List (PR #547)
- Tree (PR #546)
- Tree: Hide default closed/opened/leaf icons by default. Set UI value
`Tree.showDefaultIcons` to `true` to show them.
- ToolBar: Hover effect for button groups. (PR #534)
- Icons: New modern **rounded outlined icons** for `JFileChooser`,
`JOptionPane`, `JPasswordField` and `JTree`. (PR #577)
#### Fixed bugs
- FileChooser: Fixed layout of (optional) accessory component and fixed too
large right margin. (issue #604; regression since implementing PR #522 in
FlatLaf 2.3)
- Tree:
- Fixed missing tree lines (if enabled) for wide-selected rows. (issue #598)
- Fixed scaling of tree lines and fixed alignment to expand/collapse arrows.
- Removed support for dashed tree lines. `Tree.lineTypeDashed` is now ignored.
- SwingX: Fonts in `JXHeader`, `JXMonthView`, `JXTaskPane` and `JXTitledPanel`
were not updated when changing default font.
## 2.6
#### New features and improvements
- If value of system property `flatlaf.nativeLibraryPath` is `system`, then
`System.loadLibrary(String)` is used to load the native library.
- TabbedPane: Switch and close tabs on left mouse click only. (PR #595)
#### Fixed bugs
- ComboBox and Spinner: Fixed missing arrow buttons if preferred height is zero.
Minimum width of arrow buttons is 3/4 of default width.
- MenuBar: Fixed NPE in `FlatMenuItemRenderer.getTopLevelFont()` if menu item
does not have a parent. (issue #600; regression since implementing #589 in
FlatLaf 2.5)
- ScrollBar: Show "pressed" feedback on track/thumb only for left mouse button.
If absolute positioning is enabled (the default), then also for middle mouse
button.
- Arrow buttons in ComboBox, Spinner, ScrollBar and TabbedPane: Show "pressed"
feedback only for left mouse button.
- ScaledImageIcon: Do not throw exceptions if image was has invalid size (e.g.
not found). Instead, paint a red rectangle (similar to `FlatSVGIcon`).
- Fixed NPE in `FlatUIUtils.isCellEditor()`. (issue #601)
## 2.5
#### New features and improvements

View File

@@ -15,6 +15,11 @@ IntelliJ IDEA 2019.2+ and uses almost the same colors and icons.
![FlatLaf Dark](images/flat_dark.png)
macOS Themes
------------
![FlatLaf macOS themes](images/flat_macos_themes.png)
IntelliJ Platform Themes
------------------------
@@ -25,6 +30,17 @@ FlatLaf can use 3rd party themes created for IntelliJ Platform (see
![IntelliJ Platform Themes](images/intellij_platform_themes.png)
Sponsors
--------
<a href="https://www.ej-technologies.com/"><img src="https://www.formdev.com/flatlaf/sponsor/ej-technologies.png" width="200" alt="ej-technologies" title="ej-technologies - Java APM, Java Profiler, Java Installer Builder"></a>
&nbsp; &nbsp; &nbsp; &nbsp;
<a href="https://www.dbvis.com/"><img src="https://www.formdev.com/flatlaf/sponsor/dbvisualizer.svg" width="200" alt="DbVisualizer" title="DbVisualizer - SQL Client and Editor"></a>
&nbsp; &nbsp; &nbsp; &nbsp;
<a href="https://www.dscsag.com/"><img src="https://www.formdev.com/flatlaf/sponsor/DSC.png" height="48" alt="DSC Software AG" title="DSC Software AG - Your Companion for Integrative PLM"></a>
[Become a Sponsor](https://www.formdev.com/flatlaf/sponsor/)
Demo
----
@@ -74,6 +90,8 @@ Addons
- [SwingX](flatlaf-swingx) - support for SwingX components
- [JIDE Common Layer](flatlaf-jide-oss) - support for JIDE Common Layer
components
- [Fonts](flatlaf-fonts) - some font families bundled in easy-to-use and
redistributable JARs
Getting started
@@ -126,42 +144,64 @@ Buzz
Applications using FlatLaf
--------------------------
- ![New](images/new.svg) [Ultorg](https://www.ultorg.com/) (**commercial**) - a
- ![New](images/new.svg)
[JProfiler](https://www.ej-technologies.com/products/jprofiler/overview.html)
12 (**commercial**) - the award-winning all-in-one Java profiler
- ![New](images/new.svg) [JFormDesigner](https://www.formdev.com/) 8
(**commercial**) - Java/Swing GUI Designer
- ![New](images/new.svg) [Jeyla Studio](https://www.jeylastudio.com/) - Salon
Software
- ![New](images/new.svg) [Fanurio](https://www.fanuriotimetracking.com/) 3.3.2
(**commercial**) - time tracking and billing for freelancers and teams
- ![New](images/new.svg) [Antares](https://www.antarescircuit.io/) - a free,
powerful platform for designing, simulating and explaining digital circuits
- ![New](images/new.svg)
[Logisim-evolution](https://github.com/logisim-evolution/logisim-evolution)
3.6 - Digital logic design tool and simulator
- ![New](images/new.svg) [Cinecred](https://loadingbyte.com/cinecred/) - create
beautiful film credit sequences
- ![New](images/new.svg) [tinyMediaManager](https://www.tinymediamanager.org/)
v4 (**commercial**) - a media management tool
- ![New](images/new.svg) [Weasis](https://nroduit.github.io/) - medical DICOM
viewer used in healthcare by hospitals, health networks, etc
- ![New](images/new.svg)
[Makelangelo Software](https://github.com/MarginallyClever/Makelangelo-software)
7.3.0 - for plotters, especially the wall-hanging polargraph
- ![Hot](images/hot.svg) [Ultorg](https://www.ultorg.com/) (**commercial**) - a
visual query system for relational databases
- ![New](images/new.svg) [MooInfo](https://github.com/rememberber/MooInfo) -
visual implementation of OSHI, to view information about the system and
hardware
- ![New](images/new.svg) [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
- [MooInfo](https://github.com/rememberber/MooInfo) - visual implementation of
OSHI, to view information about the system and hardware
- [Jailer](https://github.com/Wisser/Jailer) 11.2 - database subsetting and
relational data browsing tool
- ![Hot](images/hot.svg) [Apache NetBeans](https://netbeans.apache.org/) 11.3 -
IDE for Java, PHP, HTML and much more
- [jclasslib bytecode viewer](https://github.com/ingokegel/jclasslib) 5.5
- [KeyStore Explorer](https://keystore-explorer.org/) 5.4.3
- ![New](images/new.svg)
- ![Hot](images/hot.svg)
[install4j](https://www.ej-technologies.com/products/install4j/overview.html)
9.0 (**commercial**) - the powerful multi-platform Java installer builder
- ![New](images/new.svg) [DbVisualizer](https://www.dbvis.com/) 12.0
- ![Hot](images/hot.svg) [DbVisualizer](https://www.dbvis.com/) 12.0
(**commercial**) - the universal database tool for developers, analysts and
DBAs
- ![New](images/new.svg) [MagicPlot](https://magicplot.com/) 3.0
- ![Hot](images/hot.svg) [MagicPlot](https://magicplot.com/) 3.0
(**commercial**) - Software for nonlinear fitting, plotting and data analysis
- ![New](images/new.svg)
- ![Hot](images/hot.svg)
[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
- ![New](images/new.svg)
- ![Hot](images/hot.svg) [OWASP ZAP](https://www.zaproxy.org/) 2.10 - the worlds
most widely used web app scanner
- ![Hot](images/hot.svg)
[Burp Suite Professional and Community Edition](https://portswigger.net/burp/pro)
2020.11.2 (**commercial**) - the leading software for web security testing
- ![New](images/new.svg)
[BurpCustomizer](https://github.com/CoreyD97/BurpCustomizer) - adds more
- [BurpCustomizer](https://github.com/CoreyD97/BurpCustomizer) - adds more
FlatLaf themes to Burp Suite
- [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
- ![New](images/new.svg) [PDF Studio](https://www.qoppa.com/pdfstudio/) 2021
(**commercial**) - create, review and edit PDF documents
- ![Hot](images/hot.svg) [JOSM](https://josm.openstreetmap.de/) - an extensible
editor for [OpenStreetMap](https://www.openstreetmap.org/) (requires FlatLaf
JOSM plugin)
- ![Hot](images/hot.svg) [jAlbum](https://jalbum.net/) 21 (**commercial**) -
creates photo album websites
- [PDF Studio](https://www.qoppa.com/pdfstudio/) 2021 (**commercial**) - create,
review and edit PDF documents
- [XMLmind XML Editor](https://www.xmlmind.com/xmleditor/) 9.3 (**commercial**)
- [Total Validator](https://www.totalvalidator.com/) 15 (**commercial**) -
checks your website
@@ -187,8 +227,8 @@ Applications using FlatLaf
[mendelson AS2](https://mendelson-e-c.com/as2/),
[AS4](https://mendelson-e-c.com/as4/) and
[OFTP2](https://mendelson-e-c.com/oftp2) (**commercial**)
- ![New](images/new.svg) [IGMAS+](https://www.gfz-potsdam.de/igmas) -
Interactive Gravity and Magnetic Application System
- [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

View File

@@ -14,10 +14,10 @@
* limitations under the License.
*/
val releaseVersion = "2.5"
val developmentVersion = "3.0-SNAPSHOT"
val releaseVersion = "3.0"
val developmentVersion = "3.1-SNAPSHOT"
version = if( java.lang.Boolean.getBoolean( "release" ) ) releaseVersion else developmentVersion
version = if( rootProject.hasProperty( "release" ) ) releaseVersion else developmentVersion
allprojects {
version = rootProject.version
@@ -37,6 +37,9 @@ println( "----------------------------------------------------------------------
println( "FlatLaf Version: ${version}" )
println( "Gradle ${gradle.gradleVersion} at ${gradle.gradleHomeDir}" )
println( "Java ${System.getProperty( "java.version" )}" )
val toolchainJavaVersion = System.getProperty( "toolchain" )
if( !toolchainJavaVersion.isNullOrEmpty() )
println( "Java toolchain ${toolchainJavaVersion}" )
println()

View File

@@ -80,7 +80,7 @@ publishing {
val releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
val snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots/"
url = uri( if( java.lang.Boolean.getBoolean( "release" ) ) releasesRepoUrl else snapshotsRepoUrl )
url = uri( if( rootProject.hasProperty( "release" ) ) releasesRepoUrl else snapshotsRepoUrl )
credentials {
// get from gradle.properties
@@ -108,5 +108,5 @@ signing {
// disable signing of snapshots
tasks.withType<Sign>().configureEach {
onlyIf { java.lang.Boolean.getBoolean( "release" ) }
onlyIf { rootProject.hasProperty( "release" ) }
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright 2022 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
plugins {
java
}
val toolchainJavaVersion = System.getProperty( "toolchain" )
if( !toolchainJavaVersion.isNullOrEmpty() ) {
java.toolchain {
languageVersion.set( JavaLanguageVersion.of( toolchainJavaVersion ) )
}
}

View File

@@ -16,6 +16,7 @@
plugins {
`java-library`
`flatlaf-toolchain`
`flatlaf-module-info`
`flatlaf-java9`
`flatlaf-publish`
@@ -86,7 +87,7 @@ tasks {
"action" to "generate",
"fileName" to "${project.name}-sigtest.txt",
"classpath" to jar.get().outputs.files.asPath,
"packages" to "com.formdev.flatlaf,com.formdev.flatlaf.util",
"packages" to "com.formdev.flatlaf,com.formdev.flatlaf.themes,com.formdev.flatlaf.util",
"version" to version,
"release" to "1.8", // Java version
"failonerror" to "true" )

View File

@@ -1,5 +1,5 @@
#Signature file v4.1
#Version 2.4
#Version 3.0
CLSS public abstract interface com.formdev.flatlaf.FlatClientProperties
fld public final static java.lang.String BUTTON_TYPE = "JButton.buttonType"
@@ -11,6 +11,7 @@ fld public final static java.lang.String BUTTON_TYPE_TAB = "tab"
fld public final static java.lang.String BUTTON_TYPE_TOOLBAR_BUTTON = "toolBarButton"
fld public final static java.lang.String COMPONENT_FOCUS_OWNER = "JComponent.focusOwner"
fld public final static java.lang.String COMPONENT_ROUND_RECT = "JComponent.roundRect"
fld public final static java.lang.String COMPONENT_TITLE_BAR_CAPTION = "JComponent.titleBarCaption"
fld public final static java.lang.String MENU_BAR_EMBEDDED = "JRootPane.menuBarEmbedded"
fld public final static java.lang.String MINIMUM_HEIGHT = "JComponent.minimumHeight"
fld public final static java.lang.String MINIMUM_WIDTH = "JComponent.minimumWidth"
@@ -85,7 +86,11 @@ fld public final static java.lang.String TEXT_FIELD_TRAILING_COMPONENT = "JTextF
fld public final static java.lang.String TEXT_FIELD_TRAILING_ICON = "JTextField.trailingIcon"
fld public final static java.lang.String TITLE_BAR_BACKGROUND = "JRootPane.titleBarBackground"
fld public final static java.lang.String TITLE_BAR_FOREGROUND = "JRootPane.titleBarForeground"
fld public final static java.lang.String TITLE_BAR_SHOW_CLOSE = "JRootPane.titleBarShowClose"
fld public final static java.lang.String TITLE_BAR_SHOW_ICON = "JRootPane.titleBarShowIcon"
fld public final static java.lang.String TITLE_BAR_SHOW_ICONIFFY = "JRootPane.titleBarShowIconify"
fld public final static java.lang.String TITLE_BAR_SHOW_MAXIMIZE = "JRootPane.titleBarShowMaximize"
fld public final static java.lang.String TITLE_BAR_SHOW_TITLE = "JRootPane.titleBarShowTitle"
fld public final static java.lang.String TREE_PAINT_SELECTION = "JTree.paintSelection"
fld public final static java.lang.String TREE_WIDE_SELECTION = "JTree.wideSelection"
fld public final static java.lang.String USE_WINDOW_DECORATIONS = "JRootPane.useWindowDecorations"
@@ -185,6 +190,7 @@ meth public java.lang.String getID()
meth public java.util.Map<java.lang.String,java.lang.String> getExtraDefaults()
meth public javax.swing.Icon getDisabledIcon(javax.swing.JComponent,javax.swing.Icon)
meth public javax.swing.UIDefaults getDefaults()
meth public static <%0 extends java.lang.Object> {%%0} getStyleableValue(javax.swing.JComponent,java.lang.String)
meth public static boolean install(javax.swing.LookAndFeel)
anno 0 java.lang.Deprecated()
meth public static boolean isLafDark()
@@ -193,7 +199,13 @@ meth public static boolean isUseNativeWindowDecorations()
meth public static boolean setup(javax.swing.LookAndFeel)
meth public static boolean supportsNativeWindowDecorations()
meth public static java.lang.Object parseDefaultsValue(java.lang.String,java.lang.String,java.lang.Class<?>)
meth public static java.lang.String getPreferredFontFamily()
meth public static java.lang.String getPreferredLightFontFamily()
meth public static java.lang.String getPreferredMonospacedFontFamily()
meth public static java.lang.String getPreferredSemiboldFontFamily()
meth public static java.util.Map<java.lang.String,java.lang.Class<?>> getStyleableInfos(javax.swing.JComponent)
meth public static java.util.Map<java.lang.String,java.lang.String> getGlobalExtraDefaults()
meth public static java.util.function.Function<java.lang.String,java.awt.Color> getSystemColorGetter()
meth public static javax.swing.UIDefaults$ActiveValue createActiveFontValue(float)
meth public static void hideMnemonics()
meth public static void initIconColors(javax.swing.UIDefaults,boolean)
@@ -206,6 +218,11 @@ meth public static void repaintAllFramesAndDialogs()
meth public static void revalidateAndRepaintAllFramesAndDialogs()
meth public static void runWithUIDefaultsGetter(java.util.function.Function<java.lang.Object,java.lang.Object>,java.lang.Runnable)
meth public static void setGlobalExtraDefaults(java.util.Map<java.lang.String,java.lang.String>)
meth public static void setPreferredFontFamily(java.lang.String)
meth public static void setPreferredLightFontFamily(java.lang.String)
meth public static void setPreferredMonospacedFontFamily(java.lang.String)
meth public static void setPreferredSemiboldFontFamily(java.lang.String)
meth public static void setSystemColorGetter(java.util.function.Function<java.lang.String,java.awt.Color>)
meth public static void setUseNativeWindowDecorations(boolean)
meth public static void showMnemonics(java.awt.Component)
meth public static void unregisterCustomDefaultsSource(java.io.File)
@@ -220,7 +237,7 @@ meth public void setExtraDefaults(java.util.Map<java.lang.String,java.lang.Strin
meth public void uninitialize()
meth public void unregisterUIDefaultsGetter(java.util.function.Function<java.lang.Object,java.lang.Object>)
supr javax.swing.plaf.basic.BasicLookAndFeel
hfds DESKTOPFONTHINTS,aquaLoaded,customDefaultsSources,desktopPropertyListener,desktopPropertyName,desktopPropertyName2,extraDefaults,globalExtraDefaults,mnemonicHandler,oldPopupFactory,postInitialization,subMenuUsabilityHelperInstalled,uiDefaultsGetters,updateUIPending
hfds DESKTOPFONTHINTS,aquaLoaded,customDefaultsSources,desktopPropertyListener,desktopPropertyName,desktopPropertyName2,extraDefaults,getUIMethod,getUIMethodInitialized,globalExtraDefaults,mnemonicHandler,oldPopupFactory,postInitialization,preferredFontFamily,preferredLightFontFamily,preferredMonospacedFontFamily,preferredSemiboldFontFamily,subMenuUsabilityHelperInstalled,systemColorGetter,uiDefaultsGetters,updateUIPending
hcls ActiveFont,FlatUIDefaults,ImageIconUIResource
CLSS public abstract interface static com.formdev.flatlaf.FlatLaf$DisabledIconProvider
@@ -259,6 +276,7 @@ fld public final static java.lang.String NATIVE_LIBRARY_PATH = "flatlaf.nativeLi
fld public final static java.lang.String UI_SCALE = "flatlaf.uiScale"
fld public final static java.lang.String UI_SCALE_ALLOW_SCALE_DOWN = "flatlaf.uiScale.allowScaleDown"
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_TEXT_Y_CORRECTION = "flatlaf.useTextYCorrection"
fld public final static java.lang.String USE_UBUNTU_FONT = "flatlaf.useUbuntuFont"
@@ -291,6 +309,26 @@ meth public java.lang.String getName()
supr com.formdev.flatlaf.FlatLaf
hfds theme
CLSS public com.formdev.flatlaf.themes.FlatMacDarkLaf
cons public init()
fld public final static java.lang.String NAME = "FlatLaf macOS Dark"
meth public boolean isDark()
meth public java.lang.String getDescription()
meth public java.lang.String getName()
meth public static boolean setup()
meth public static void installLafInfo()
supr com.formdev.flatlaf.FlatDarkLaf
CLSS public com.formdev.flatlaf.themes.FlatMacLightLaf
cons public init()
fld public final static java.lang.String NAME = "FlatLaf macOS Light"
meth public boolean isDark()
meth public java.lang.String getDescription()
meth public java.lang.String getName()
meth public static boolean setup()
meth public static void installLafInfo()
supr com.formdev.flatlaf.FlatLightLaf
CLSS public abstract interface com.formdev.flatlaf.util.AnimatedIcon
innr public static AnimationSupport
intf javax.swing.Icon
@@ -358,6 +396,7 @@ meth public static float clamp(float)
meth public static float luma(java.awt.Color)
meth public static java.awt.Color darken(java.awt.Color,float)
meth public static java.awt.Color desaturate(java.awt.Color,float)
meth public static java.awt.Color fade(java.awt.Color,float)
meth public static java.awt.Color lighten(java.awt.Color,float)
meth public static java.awt.Color mix(java.awt.Color,java.awt.Color,float)
meth public static java.awt.Color saturate(java.awt.Color,float)
@@ -433,6 +472,17 @@ meth public java.lang.String toString()
supr javax.swing.plaf.ColorUIResource
hfds baseOfDefaultColorRGB,functions,hasBaseOfDefaultColor
CLSS public com.formdev.flatlaf.util.FontUtils
cons public init()
meth public static boolean installFont(java.net.URL)
meth public static java.awt.Font getCompositeFont(java.lang.String,int,int)
meth public static java.awt.Font[] getAllFonts()
meth public static java.lang.String[] getAvailableFontFamilyNames()
meth public static void loadFontFamily(java.lang.String)
meth public static void registerFontFamilyLoader(java.lang.String,java.lang.Runnable)
supr java.lang.Object
hfds loadersMap
CLSS public com.formdev.flatlaf.util.Graphics2DProxy
cons public init(java.awt.Graphics2D)
meth public boolean drawImage(java.awt.Image,int,int,int,int,int,int,int,int,java.awt.Color,java.awt.image.ImageObserver)
@@ -569,7 +619,7 @@ meth public static void drawStringWithYCorrection(javax.swing.JComponent,java.aw
meth public static void paintAtScale1x(java.awt.Graphics2D,int,int,int,int,com.formdev.flatlaf.util.HiDPIUtils$Painter)
meth public static void paintAtScale1x(java.awt.Graphics2D,javax.swing.JComponent,com.formdev.flatlaf.util.HiDPIUtils$Painter)
supr java.lang.Object
hfds useTextYCorrection
hfds CORRECTION_INTER,CORRECTION_OPEN_SANS,CORRECTION_SEGOE_UI,CORRECTION_TAHOMA,SCALE_FACTORS,useDebugScaleFactor,useTextYCorrection
CLSS public abstract interface static com.formdev.flatlaf.util.HiDPIUtils$Painter
outer com.formdev.flatlaf.util.HiDPIUtils
@@ -600,6 +650,7 @@ supr java.lang.Object
CLSS public com.formdev.flatlaf.util.NativeLibrary
cons public init(java.io.File,boolean)
cons public init(java.lang.String,boolean)
cons public init(java.lang.String,java.lang.ClassLoader,boolean)
meth public boolean isLoaded()
supr java.lang.Object

View File

@@ -346,7 +346,7 @@ public interface FlatClientProperties
/**
* Specifies whether the window icon should be shown in the window title bar
* (requires enabled window decorations).
* (requires enabled window decorations). Default is UI property {@code TitlePane.showIcon}.
* <p>
* Setting this shows/hides the windows icon
* for the {@code JFrame} or {@code JDialog} that contains the root pane.
@@ -362,6 +362,62 @@ public interface FlatClientProperties
*/
String TITLE_BAR_SHOW_ICON = "JRootPane.titleBarShowIcon";
/**
* Specifies whether the window title should be shown in the window title bar
* (requires enabled window decorations). Default is {@code true}.
* <p>
* Setting this shows/hides the windows title
* for the {@code JFrame} or {@code JDialog} that contains the root pane.
* <p>
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
*
* @since 3
*/
String TITLE_BAR_SHOW_TITLE = "JRootPane.titleBarShowTitle";
/**
* Specifies whether the "iconfify" button should be shown in the window title bar
* (requires enabled window decorations). Default is {@code true}.
* <p>
* Setting this shows/hides the "iconfify" button
* for the {@code JFrame} that contains the root pane.
* <p>
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
*
* @since 3
*/
String TITLE_BAR_SHOW_ICONIFFY = "JRootPane.titleBarShowIconify";
/**
* Specifies whether the "maximize/restore" button should be shown in the window title bar
* (requires enabled window decorations). Default is {@code true}.
* <p>
* Setting this shows/hides the "maximize/restore" button
* for the {@code JFrame} that contains the root pane.
* <p>
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
*
* @since 3
*/
String TITLE_BAR_SHOW_MAXIMIZE = "JRootPane.titleBarShowMaximize";
/**
* Specifies whether the "close" button should be shown in the window title bar
* (requires enabled window decorations). Default is {@code true}.
* <p>
* Setting this shows/hides the "close" button
* for the {@code JFrame} or {@code JDialog} that contains the root pane.
* <p>
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
*
* @since 3
*/
String TITLE_BAR_SHOW_CLOSE = "JRootPane.titleBarShowClose";
/**
* Background color of window title bar (requires enabled window decorations).
* <p>
@@ -386,6 +442,17 @@ public interface FlatClientProperties
*/
String TITLE_BAR_FOREGROUND = "JRootPane.titleBarForeground";
/**
* Specifies whether the glass pane should have full height and overlap the title bar,
* if FlatLaf window decorations are enabled. Default is {@code false}.
* <p>
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
*
* @since 3.1
*/
String GLASS_PANE_FULL_HEIGHT = "JRootPane.glassPaneFullHeight";
//---- JScrollBar / JScrollPane -------------------------------------------
/**

View File

@@ -78,6 +78,7 @@ import com.formdev.flatlaf.ui.FlatPopupFactory;
import com.formdev.flatlaf.ui.FlatRootPaneUI;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.util.FontUtils;
import com.formdev.flatlaf.util.GrayFilter;
import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.MultiResolutionImageSupport;
@@ -98,6 +99,7 @@ public abstract class FlatLaf
private static List<Object> customDefaultsSources;
private static Map<String, String> globalExtraDefaults;
private Map<String, String> extraDefaults;
private static Function<String, Color> systemColorGetter;
private String desktopPropertyName;
private String desktopPropertyName2;
@@ -113,6 +115,11 @@ public abstract class FlatLaf
private Consumer<UIDefaults> postInitialization;
private List<Function<Object, Object>> uiDefaultsGetters;
private static String preferredFontFamily;
private static String preferredLightFontFamily;
private static String preferredSemiboldFontFamily;
private static String preferredMonospacedFontFamily;
/**
* Sets the application look and feel to the given LaF
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
@@ -630,6 +637,13 @@ public abstract class FlatLaf
if( uiFont == null )
uiFont = createCompositeFont( Font.SANS_SERIF, Font.PLAIN, 12 );
// use preferred font family (if specified)
if( preferredFontFamily != null ) {
FontUIResource preferredFont = createCompositeFont( preferredFontFamily, uiFont.getStyle(), uiFont.getSize() );
if( !ActiveFont.isFallbackFont( preferredFont ) || ActiveFont.isDialogFamily( preferredFontFamily ) )
uiFont = preferredFont;
}
// get/remove "defaultFont" from defaults if set in properties files
// (use remove() to avoid that ActiveFont.createValue() gets invoked)
Object defaultFont = defaults.remove( "defaultFont" );
@@ -650,6 +664,9 @@ public abstract class FlatLaf
}
static FontUIResource createCompositeFont( String family, int style, int size ) {
// load lazy font family
FontUtils.loadFontFamily( family );
// using StyleContext.getFont() here because it uses
// sun.font.FontUtilities.getCompositeFontUIResource()
// and creates a composite font that is able to display all Unicode characters
@@ -897,14 +914,14 @@ public abstract class FlatLaf
* E.g. using {@link UIManager#setLookAndFeel(LookAndFeel)} or {@link #setup(LookAndFeel)}.
* <p>
* The global extra defaults are useful for smaller additional defaults that may change.
* E.g. accent color. Otherwise, FlatLaf properties files should be used.
* Otherwise, FlatLaf properties files should be used.
* See {@link #registerCustomDefaultsSource(String)}.
* <p>
* The keys and values are strings in same format as in FlatLaf properties files.
* <p>
* Sample that setups "FlatLaf Light" theme with red accent color:
* Sample that setups "FlatLaf Light" theme with white background color:
* <pre>{@code
* FlatLaf.setGlobalExtraDefaults( Collections.singletonMap( "@accentColor", "#f00" ) );
* FlatLaf.setGlobalExtraDefaults( Collections.singletonMap( "@background", "#fff" ) );
* FlatLightLaf.setup();
* }</pre>
*
@@ -929,15 +946,15 @@ public abstract class FlatLaf
* E.g. using {@link UIManager#setLookAndFeel(LookAndFeel)} or {@link #setup(LookAndFeel)}.
* <p>
* The extra defaults are useful for smaller additional defaults that may change.
* E.g. accent color. Otherwise, FlatLaf properties files should be used.
* Otherwise, FlatLaf properties files should be used.
* See {@link #registerCustomDefaultsSource(String)}.
* <p>
* The keys and values are strings in same format as in FlatLaf properties files.
* <p>
* Sample that setups "FlatLaf Light" theme with red accent color:
* Sample that setups "FlatLaf Light" theme with white background color:
* <pre>{@code
* FlatLaf laf = new FlatLightLaf();
* laf.setExtraDefaults( Collections.singletonMap( "@accentColor", "#f00" ) );
* laf.setExtraDefaults( Collections.singletonMap( "@background", "#fff" ) );
* FlatLaf.setup( laf );
* }</pre>
*
@@ -979,6 +996,36 @@ public abstract class FlatLaf
return val;
}
/**
* Returns the system color getter function, or {@code null}.
*
* @since 3
*/
public static Function<String, Color> getSystemColorGetter() {
return systemColorGetter;
}
/**
* Sets a system color getter function that is invoked when function
* {@code systemColor()} is used in FlatLaf properties files.
* <p>
* The name of the system color is passed as parameter to the function.
* The function should return {@code null} for unknown system colors.
* <p>
* Can be used to change the accent color:
* <pre>{@code
* FlatLaf.setSystemColorGetter( name -> {
* return name.equals( "accent" ) ? Color.red : null;
* } );
* FlatLightLaf.setup();
* }</pre>
*
* @since 3
*/
public static void setSystemColorGetter( Function<String, Color> systemColorGetter ) {
FlatLaf.systemColorGetter = systemColorGetter;
}
private static void reSetLookAndFeel() {
EventQueue.invokeLater( () -> {
LookAndFeel lookAndFeel = UIManager.getLookAndFeel();
@@ -1292,6 +1339,90 @@ public abstract class FlatLaf
private static boolean getUIMethodInitialized;
private static MethodHandle getUIMethod;
/**
* Returns the preferred font family to be used for (nearly) all fonts; or {@code null}.
*
* @since 3
*/
public static String getPreferredFontFamily() {
return preferredFontFamily;
}
/**
* Sets the preferred font family to be used for (nearly) all fonts.
* <p>
* <strong>Note</strong>: This must be invoked <strong>before</strong> setting
* the application look and feel.
*
* @since 3
*/
public static void setPreferredFontFamily( String preferredFontFamily ) {
FlatLaf.preferredFontFamily = preferredFontFamily;
}
/**
* Returns the preferred font family to be used for "light" fonts; or {@code null}.
*
* @since 3
*/
public static String getPreferredLightFontFamily() {
return preferredLightFontFamily;
}
/**
* Sets the preferred font family to be used for "light" fonts.
* <p>
* <strong>Note</strong>: This must be invoked <strong>before</strong> setting
* the application look and feel.
*
* @since 3
*/
public static void setPreferredLightFontFamily( String preferredLightFontFamily ) {
FlatLaf.preferredLightFontFamily = preferredLightFontFamily;
}
/**
* Returns the preferred font family to be used for "semibold" fonts; or {@code null}.
*
* @since 3
*/
public static String getPreferredSemiboldFontFamily() {
return preferredSemiboldFontFamily;
}
/**
* Sets the preferred font family to be used for "semibold" fonts.
* <p>
* <strong>Note</strong>: This must be invoked <strong>before</strong> setting
* the application look and feel.
*
* @since 3
*/
public static void setPreferredSemiboldFontFamily( String preferredSemiboldFontFamily ) {
FlatLaf.preferredSemiboldFontFamily = preferredSemiboldFontFamily;
}
/**
* Returns the preferred font family to be used for monospaced fonts; or {@code null}.
*
* @since 3
*/
public static String getPreferredMonospacedFontFamily() {
return preferredMonospacedFontFamily;
}
/**
* Sets the preferred font family to be used for monospaced fonts.
* <p>
* <strong>Note</strong>: This must be invoked <strong>before</strong> setting
* the application look and feel.
*
* @since 3
*/
public static void setPreferredMonospacedFontFamily( String preferredMonospacedFontFamily ) {
FlatLaf.preferredMonospacedFontFamily = preferredMonospacedFontFamily;
}
//---- class FlatUIDefaults -----------------------------------------------
private class FlatUIDefaults
@@ -1426,9 +1557,16 @@ public abstract class FlatLaf
// create font for family
if( families != null && !families.isEmpty() ) {
String preferredFamily = preferredFamily( families );
if( preferredFamily != null ) {
Font font = createCompositeFont( preferredFamily, newStyle, newSize );
if( !isFallbackFont( font ) || isDialogFamily( preferredFamily ) )
return toUIResource( font );
}
for( String family : families ) {
Font font = createCompositeFont( family, newStyle, newSize );
if( !isFallbackFont( font ) || family.equalsIgnoreCase( Font.DIALOG ) )
if( !isFallbackFont( font ) || isDialogFamily( family ) )
return toUIResource( font );
}
}
@@ -1457,9 +1595,26 @@ public abstract class FlatLaf
: new FontUIResource( font );
}
private boolean isFallbackFont( Font font ) {
private static boolean isFallbackFont( Font font ) {
return Font.DIALOG.equalsIgnoreCase( font.getFamily() );
}
private static boolean isDialogFamily( String family ) {
return family.equalsIgnoreCase( Font.DIALOG );
}
private static String preferredFamily( List<String> families ) {
for( String family : families ) {
family = family.toLowerCase( Locale.ENGLISH );
if( family.endsWith( " light" ) || family.endsWith( "-thin" ) )
return preferredLightFontFamily;
if( family.endsWith( " semibold" ) || family.endsWith( "-medium" ) )
return preferredSemiboldFontFamily;
if( family.equals( "monospaced" ) )
return preferredMonospacedFontFamily;
}
return null;
}
}
//---- class ImageIconUIResource ------------------------------------------

View File

@@ -155,9 +155,19 @@ public interface FlatSystemProperties
String UPDATE_UI_ON_SYSTEM_FONT_CHANGE = "flatlaf.updateUIOnSystemFontChange";
/**
* Specifies a directory in which the native FlatLaf library have been extracted.
* Specifies a directory in which the native FlatLaf libraries have been extracted.
* The path can be absolute or relative to current application working directory.
* This can be used to avoid extraction of the native libraries to the temporary directory at runtime.
* <p>
* If the value is {@code "system"}, then {@link System#loadLibrary(String)} is
* used to load the native library.
* Searches for the native library in classloader of caller
* (using {@link ClassLoader#findLibrary(String)}) and in paths specified
* in system properties {@code sun.boot.library.path} and {@code java.library.path}.
* (supported since FlatLaf 2.6)
* <p>
* If the native library can not loaded from the given path (or via {@link System#loadLibrary(String)}),
* then the embedded native library is extracted to the temporary directory and loaded from there.
*
* @since 2
*/

View File

@@ -302,7 +302,7 @@ public class IntelliJTheme
for( Map.Entry<String, String> e : colors.entrySet() ) {
String value = e.getValue();
ColorUIResource color = UIDefaultsLoader.parseColor( value );
ColorUIResource color = parseColor( value );
if( color != null ) {
String key = e.getKey();
namedColors.put( key, color );
@@ -448,7 +448,15 @@ public class IntelliJTheme
ColorUIResource color = namedColors.get( value );
// parse color
return (color != null) ? color : UIDefaultsLoader.parseColor( value );
return (color != null) ? color : parseColor( value );
}
private ColorUIResource parseColor( String value ) {
try {
return UIDefaultsLoader.parseColor( value );
} catch( IllegalArgumentException ex ) {
return null;
}
}
/**
@@ -540,7 +548,7 @@ public class IntelliJTheme
// radioFocused.svg and radioSelectedFocused.svg
// use opacity=".65" for the border
// --> add alpha to focused border colors
String[] focusedBorderColorKeys = new String[] {
String[] focusedBorderColorKeys = {
"CheckBox.icon.focusedBorderColor",
"CheckBox.icon.focusedSelectedBorderColor",
"CheckBox.icon[filled].focusedBorderColor",

View File

@@ -84,6 +84,7 @@ class UIDefaultsLoader
private static int parseColorDepth;
private static Map<String, ColorUIResource> systemColorCache;
private static final SoftCache<String, Object> fontCache = new SoftCache<>();
static void loadDefaultsFromProperties( Class<?> lookAndFeelClass, List<FlatDefaultsAddon> addons,
@@ -105,6 +106,10 @@ class UIDefaultsLoader
Properties additionalDefaults, boolean dark, UIDefaults defaults )
{
try {
// temporary cache system colors while loading defaults,
// which avoids that system color getter is invoked multiple times
systemColorCache = (FlatLaf.getSystemColorGetter() != null) ? new HashMap<>() : null;
// load core properties files
Properties properties = new Properties();
for( Class<?> lafClass : lafClasses ) {
@@ -276,6 +281,9 @@ class UIDefaultsLoader
// remember variables in defaults to allow using them in styles
defaults.put( KEY_VARIABLES, variables );
// clear/disable system color cache
systemColorCache = null;
} catch( IOException ex ) {
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to load properties files.", ex );
}
@@ -525,14 +533,14 @@ class UIDefaultsLoader
case STRING: return value;
case BOOLEAN: return parseBoolean( value );
case CHARACTER: return parseCharacter( value );
case INTEGER: return parseInteger( value, true );
case INTEGERORFLOAT:return parseIntegerOrFloat( value, true );
case FLOAT: return parseFloat( value, true );
case INTEGER: return parseInteger( value );
case INTEGERORFLOAT:return parseIntegerOrFloat( value );
case FLOAT: return parseFloat( value );
case BORDER: return parseBorder( value, resolver, addonClassLoaders );
case ICON: return parseInstance( value, addonClassLoaders );
case INSETS: return parseInsets( value );
case DIMENSION: return parseDimension( value );
case COLOR: return parseColorOrFunction( value, resolver, true );
case COLOR: return parseColorOrFunction( value, resolver );
case FONT: return parseFont( value );
case SCALEDINTEGER: return parseScaledInteger( value );
case SCALEDFLOAT: return parseScaledFloat( value );
@@ -550,24 +558,34 @@ class UIDefaultsLoader
}
// colors
Object color = parseColorOrFunction( value, resolver, false );
if( color != null ) {
resultValueType[0] = ValueType.COLOR;
if( value.startsWith( "#" ) || value.endsWith( ")" ) ) {
Object color = parseColorOrFunction( value, resolver );
resultValueType[0] = (color != null) ? ValueType.COLOR : ValueType.NULL;
return color;
}
// integer
Integer integer = parseInteger( value, false );
if( integer != null ) {
resultValueType[0] = ValueType.INTEGER;
return integer;
}
// integer or float
char firstChar = value.charAt( 0 );
if( (firstChar >= '0' && firstChar <= '9') ||
firstChar == '-' || firstChar == '+' || firstChar == '.' )
{
// integer
try {
Integer integer = parseInteger( value );
resultValueType[0] = ValueType.INTEGER;
return integer;
} catch( NumberFormatException ex ) {
// ignore
}
// float
Float f = parseFloat( value, false );
if( f != null ) {
resultValueType[0] = ValueType.FLOAT;
return f;
// float
try {
Float f = parseFloat( value );
resultValueType[0] = ValueType.FLOAT;
return f;
} catch( NumberFormatException ex ) {
// ignore
}
}
// string
@@ -596,10 +614,10 @@ class UIDefaultsLoader
List<String> parts = splitFunctionParams( value, ',' );
Insets insets = parseInsets( value );
ColorUIResource lineColor = (parts.size() >= 5)
? (ColorUIResource) parseColorOrFunction( resolver.apply( parts.get( 4 ) ), resolver, true )
? (ColorUIResource) parseColorOrFunction( resolver.apply( parts.get( 4 ) ), resolver )
: null;
float lineThickness = (parts.size() >= 6 && !parts.get( 5 ).isEmpty()) ? parseFloat( parts.get( 5 ), true ) : 1f;
int arc = (parts.size() >= 7) ? parseInteger( parts.get( 6 ), true ) : 0;
float lineThickness = (parts.size() >= 6 && !parts.get( 5 ).isEmpty()) ? parseFloat( parts.get( 5 ) ) : 1f;
int arc = (parts.size() >= 7) ? parseInteger( parts.get( 6 ) ) : 0;
return (LazyValue) t -> {
return (lineColor != null)
@@ -674,30 +692,24 @@ class UIDefaultsLoader
}
}
private static Object parseColorOrFunction( String value, Function<String, String> resolver, boolean reportError ) {
private static Object parseColorOrFunction( String value, Function<String, String> resolver ) {
if( value.endsWith( ")" ) )
return parseColorFunctions( value, resolver, reportError );
return parseColorFunctions( value, resolver );
return parseColor( value, reportError );
return parseColor( value );
}
/**
* 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 ) {
return parseColor( value, false );
}
private static ColorUIResource parseColor( String value, boolean reportError ) {
try {
int rgba = parseColorRGBA( value );
return ((rgba & 0xff000000) == 0xff000000)
? new ColorUIResource( rgba )
: new ColorUIResource( new Color( rgba, true ) );
} catch( IllegalArgumentException ex ) {
if( reportError )
throw new IllegalArgumentException( "invalid color '" + value + "'" );
// not a color --> ignore
}
return null;
int rgba = parseColorRGBA( value );
return ((rgba & 0xff000000) == 0xff000000)
? new ColorUIResource( rgba )
: new ColorUIResource( new Color( rgba, true ) );
}
/**
@@ -710,7 +722,7 @@ class UIDefaultsLoader
static int parseColorRGBA( String value ) {
int len = value.length();
if( (len != 4 && len != 5 && len != 7 && len != 9) || value.charAt( 0 ) != '#' )
throw new IllegalArgumentException();
throw newInvalidColorException( value );
// parse hex
int n = 0;
@@ -725,7 +737,7 @@ class UIDefaultsLoader
else if( ch >= 'A' && ch <= 'F' )
digit = ch - 'A' + 10;
else
throw new IllegalArgumentException();
throw newInvalidColorException( value );
n = (n << 4) | digit;
}
@@ -744,13 +756,14 @@ class UIDefaultsLoader
: (((n >> 8) & 0xffffff) | ((n & 0xff) << 24)); // move alpha from lowest to highest byte
}
private static Object parseColorFunctions( String value, Function<String, String> resolver, boolean reportError ) {
private static IllegalArgumentException newInvalidColorException( String value ) {
return new IllegalArgumentException( "invalid color '" + value + "'" );
}
private static Object parseColorFunctions( String value, Function<String, String> resolver ) {
int paramsStart = value.indexOf( '(' );
if( paramsStart < 0 ) {
if( reportError )
throw new IllegalArgumentException( "missing opening parenthesis in function '" + value + "'" );
return null;
}
if( paramsStart < 0 )
throw new IllegalArgumentException( "missing opening parenthesis in function '" + value + "'" );
String function = StringUtils.substringTrimmed( value, 0, paramsStart );
List<String> params = splitFunctionParams( value.substring( paramsStart + 1, value.length() - 1 ), ',' );
@@ -763,28 +776,29 @@ class UIDefaultsLoader
parseColorDepth++;
try {
switch( function ) {
case "if": return parseColorIf( value, params, resolver, reportError );
case "rgb": return parseColorRgbOrRgba( false, params, resolver, reportError );
case "rgba": return parseColorRgbOrRgba( true, params, resolver, reportError );
case "if": return parseColorIf( value, params, resolver );
case "systemColor": return parseColorSystemColor( value, params, resolver );
case "rgb": return parseColorRgbOrRgba( false, params, resolver );
case "rgba": return parseColorRgbOrRgba( true, params, resolver );
case "hsl": return parseColorHslOrHsla( false, params );
case "hsla": return parseColorHslOrHsla( true, params );
case "lighten": return parseColorHSLIncreaseDecrease( 2, true, params, resolver, reportError );
case "darken": return parseColorHSLIncreaseDecrease( 2, false, params, resolver, reportError );
case "saturate": return parseColorHSLIncreaseDecrease( 1, true, params, resolver, reportError );
case "desaturate": return parseColorHSLIncreaseDecrease( 1, false, params, resolver, reportError );
case "fadein": return parseColorHSLIncreaseDecrease( 3, true, params, resolver, reportError );
case "fadeout": return parseColorHSLIncreaseDecrease( 3, false, params, resolver, reportError );
case "fade": return parseColorFade( params, resolver, reportError );
case "spin": return parseColorSpin( params, resolver, reportError );
case "changeHue": return parseColorChange( 0, params, resolver, reportError );
case "changeSaturation":return parseColorChange( 1, params, resolver, reportError );
case "changeLightness": return parseColorChange( 2, params, resolver, reportError );
case "changeAlpha": return parseColorChange( 3, params, resolver, reportError );
case "mix": return parseColorMix( null, params, resolver, reportError );
case "tint": return parseColorMix( "#fff", params, resolver, reportError );
case "shade": return parseColorMix( "#000", params, resolver, reportError );
case "contrast": return parseColorContrast( params, resolver, reportError );
case "over": return parseColorOver( params, resolver, reportError );
case "lighten": return parseColorHSLIncreaseDecrease( 2, true, params, resolver );
case "darken": return parseColorHSLIncreaseDecrease( 2, false, params, resolver );
case "saturate": return parseColorHSLIncreaseDecrease( 1, true, params, resolver );
case "desaturate": return parseColorHSLIncreaseDecrease( 1, false, params, resolver );
case "fadein": return parseColorHSLIncreaseDecrease( 3, true, params, resolver );
case "fadeout": return parseColorHSLIncreaseDecrease( 3, false, params, resolver );
case "fade": return parseColorFade( params, resolver );
case "spin": return parseColorSpin( params, resolver );
case "changeHue": return parseColorChange( 0, params, resolver );
case "changeSaturation":return parseColorChange( 1, params, resolver );
case "changeLightness": return parseColorChange( 2, params, resolver );
case "changeAlpha": return parseColorChange( 3, params, resolver );
case "mix": return parseColorMix( null, params, resolver );
case "tint": return parseColorMix( "#fff", params, resolver );
case "shade": return parseColorMix( "#000", params, resolver );
case "contrast": return parseColorContrast( params, resolver );
case "over": return parseColorOver( params, resolver );
}
} finally {
parseColorDepth--;
@@ -799,13 +813,51 @@ 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, boolean reportError ) {
private static Object parseColorIf( String value, List<String> params, Function<String, String> resolver ) {
if( params.size() != 3 )
throwMissingParametersException( value );
boolean ifCondition = parseCondition( params.get( 0 ), resolver, Collections.emptyList() );
String ifValue = params.get( ifCondition ? 1 : 2 );
return parseColorOrFunction( resolver.apply( ifValue ), resolver, reportError );
return parseColorOrFunction( resolver.apply( ifValue ), resolver );
}
/**
* Syntax: systemColor(name[,defaultValue])
* - name: system color name
* - defaultValue: default color value used if system color is not available
*/
private static Object parseColorSystemColor( String value, List<String> params, Function<String, String> resolver ) {
if( params.size() < 1 )
throwMissingParametersException( value );
ColorUIResource systemColor = getSystemColor( params.get( 0 ) );
if( systemColor != null )
return systemColor;
String defaultValue = (params.size() > 1) ? params.get( 1 ) : "";
if( defaultValue.equals( "null" ) || defaultValue.isEmpty() )
return null;
return parseColorOrFunction( resolver.apply( defaultValue ), resolver );
}
private static ColorUIResource getSystemColor( String name ) {
Function<String, Color> systemColorGetter = FlatLaf.getSystemColorGetter();
if( systemColorGetter == null )
return null;
// use containsKey() because value may be null
if( systemColorCache != null && systemColorCache.containsKey( name ) )
return systemColorCache.get( name );
Color color = systemColorGetter.apply( name );
ColorUIResource uiColor = (color != null) ? new ColorUIResource( color ) : null;
if( systemColorCache != null )
systemColorCache.put( name, uiColor );
return uiColor;
}
/**
@@ -816,7 +868,7 @@ class UIDefaultsLoader
* - alpha: an integer 0-255 or a percentage 0-100%
*/
private static ColorUIResource parseColorRgbOrRgba( boolean hasAlpha, List<String> params,
Function<String, String> resolver, boolean reportError )
Function<String, String> resolver )
{
if( hasAlpha && params.size() == 2 ) {
// syntax rgba(color,alpha), which allows adding alpha to any color
@@ -825,7 +877,7 @@ class UIDefaultsLoader
String colorStr = params.get( 0 );
int alpha = parseInteger( params.get( 1 ), 0, 255, true );
ColorUIResource color = (ColorUIResource) parseColorOrFunction( resolver.apply( colorStr ), resolver, reportError );
ColorUIResource color = (ColorUIResource) parseColorOrFunction( resolver.apply( colorStr ), resolver );
return new ColorUIResource( new Color( ((alpha & 0xff) << 24) | (color.getRGB() & 0xffffff), true ) );
}
@@ -865,7 +917,7 @@ class UIDefaultsLoader
* - options: [relative] [autoInverse] [noAutoInverse] [lazy] [derived]
*/
private static Object parseColorHSLIncreaseDecrease( int hslIndex, boolean increase,
List<String> params, Function<String, String> resolver, boolean reportError )
List<String> params, Function<String, String> resolver )
{
String colorStr = params.get( 0 );
int amount = parsePercentage( params.get( 1 ) );
@@ -900,7 +952,7 @@ class UIDefaultsLoader
}
// parse base color, apply function and create derived color
return parseFunctionBaseColor( colorStr, function, derived, resolver, reportError );
return parseFunctionBaseColor( colorStr, function, derived, resolver );
}
/**
@@ -909,7 +961,7 @@ class UIDefaultsLoader
* - amount: percentage 0-100%
* - options: [derived] [lazy]
*/
private static Object parseColorFade( List<String> params, Function<String, String> resolver, boolean reportError ) {
private static Object parseColorFade( List<String> params, Function<String, String> resolver ) {
String colorStr = params.get( 0 );
int amount = parsePercentage( params.get( 1 ) );
boolean derived = false;
@@ -934,7 +986,7 @@ class UIDefaultsLoader
}
// parse base color, apply function and create derived color
return parseFunctionBaseColor( colorStr, function, derived, resolver, reportError );
return parseFunctionBaseColor( colorStr, function, derived, resolver );
}
/**
@@ -943,9 +995,9 @@ class UIDefaultsLoader
* - angle: number of degrees to rotate
* - options: [derived]
*/
private static Object parseColorSpin( List<String> params, Function<String, String> resolver, boolean reportError ) {
private static Object parseColorSpin( List<String> params, Function<String, String> resolver ) {
String colorStr = params.get( 0 );
int amount = parseInteger( params.get( 1 ), true );
int amount = parseInteger( params.get( 1 ) );
boolean derived = false;
if( params.size() > 2 ) {
@@ -957,7 +1009,7 @@ class UIDefaultsLoader
ColorFunction function = new ColorFunctions.HSLIncreaseDecrease( 0, true, amount, false, false );
// parse base color, apply function and create derived color
return parseFunctionBaseColor( colorStr, function, derived, resolver, reportError );
return parseFunctionBaseColor( colorStr, function, derived, resolver );
}
/**
@@ -970,11 +1022,11 @@ class UIDefaultsLoader
* - options: [derived]
*/
private static Object parseColorChange( int hslIndex,
List<String> params, Function<String, String> resolver, boolean reportError )
List<String> params, Function<String, String> resolver )
{
String colorStr = params.get( 0 );
int value = (hslIndex == 0)
? parseInteger( params.get( 1 ), true )
? parseInteger( params.get( 1 ) )
: parsePercentage( params.get( 1 ) );
boolean derived = false;
@@ -987,7 +1039,7 @@ class UIDefaultsLoader
ColorFunction function = new ColorFunctions.HSLChange( hslIndex, value );
// parse base color, apply function and create derived color
return parseFunctionBaseColor( colorStr, function, derived, resolver, reportError );
return parseFunctionBaseColor( colorStr, function, derived, resolver );
}
/**
@@ -999,7 +1051,7 @@ 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, boolean reportError ) {
private static Object parseColorMix( String color1Str, List<String> params, Function<String, String> resolver ) {
int i = 0;
if( color1Str == null )
color1Str = params.get( i++ );
@@ -1007,7 +1059,7 @@ class UIDefaultsLoader
int weight = (params.size() > i) ? parsePercentage( params.get( i ) ) : 50;
// parse second color
ColorUIResource color2 = (ColorUIResource) parseColorOrFunction( resolver.apply( color2Str ), resolver, reportError );
ColorUIResource color2 = (ColorUIResource) parseColorOrFunction( resolver.apply( color2Str ), resolver );
if( color2 == null )
return null;
@@ -1015,7 +1067,7 @@ class UIDefaultsLoader
ColorFunction function = new ColorFunctions.Mix( color2, weight );
// parse first color, apply function and create mixed color
return parseFunctionBaseColor( color1Str, function, false, resolver, reportError );
return parseFunctionBaseColor( color1Str, function, false, resolver );
}
/**
@@ -1026,14 +1078,14 @@ 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, boolean reportError ) {
private static Object parseColorContrast( List<String> params, Function<String, String> resolver ) {
String colorStr = params.get( 0 );
String darkStr = params.get( 1 );
String lightStr = params.get( 2 );
int threshold = (params.size() > 3) ? parsePercentage( params.get( 3 ) ) : 43;
// parse color to compare against
ColorUIResource color = (ColorUIResource) parseColorOrFunction( resolver.apply( colorStr ), resolver, reportError );
ColorUIResource color = (ColorUIResource) parseColorOrFunction( resolver.apply( colorStr ), resolver );
if( color == null )
return null;
@@ -1043,7 +1095,7 @@ class UIDefaultsLoader
: darkStr;
// parse dark or light color
return parseColorOrFunction( resolver.apply( darkOrLightColor ), resolver, reportError );
return parseColorOrFunction( resolver.apply( darkOrLightColor ), resolver );
}
/**
@@ -1052,12 +1104,12 @@ 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, boolean reportError ) {
private static ColorUIResource parseColorOver( List<String> params, Function<String, String> resolver ) {
String foregroundStr = params.get( 0 );
String backgroundStr = params.get( 1 );
// parse foreground color
ColorUIResource foreground = (ColorUIResource) parseColorOrFunction( resolver.apply( foregroundStr ), resolver, reportError );
ColorUIResource foreground = (ColorUIResource) parseColorOrFunction( resolver.apply( foregroundStr ), resolver );
if( foreground == null || foreground.getAlpha() == 255 )
return foreground;
@@ -1065,7 +1117,7 @@ class UIDefaultsLoader
ColorUIResource foreground2 = new ColorUIResource( foreground.getRGB() );
// parse background color
ColorUIResource background = (ColorUIResource) parseColorOrFunction( resolver.apply( backgroundStr ), resolver, reportError );
ColorUIResource background = (ColorUIResource) parseColorOrFunction( resolver.apply( backgroundStr ), resolver );
if( background == null )
return foreground2;
@@ -1075,11 +1127,11 @@ class UIDefaultsLoader
}
private static Object parseFunctionBaseColor( String colorStr, ColorFunction function,
boolean derived, Function<String, String> resolver, boolean reportError )
boolean derived, Function<String, String> resolver )
{
// parse base color
String resolvedColorStr = resolver.apply( colorStr );
ColorUIResource baseColor = (ColorUIResource) parseColorOrFunction( resolvedColorStr, resolver, reportError );
ColorUIResource baseColor = (ColorUIResource) parseColorOrFunction( resolvedColorStr, resolver );
if( baseColor == null )
return null;
@@ -1163,11 +1215,11 @@ class UIDefaultsLoader
throw new IllegalArgumentException( "size specified more than once in '" + value + "'" );
if( firstChar == '+' || firstChar == '-' )
relativeSize = parseInteger( param, true );
relativeSize = parseInteger( param );
else if( param.endsWith( "%" ) )
scaleSize = parseInteger( param.substring( 0, param.length() - 1 ), true ) / 100f;
scaleSize = parseInteger( param.substring( 0, param.length() - 1 ) ) / 100f;
else
absoluteSize = parseInteger( param, true );
absoluteSize = parseInteger( param );
} else if( firstChar == '$' ) {
// reference to base font
if( baseFontKey != null )
@@ -1241,55 +1293,49 @@ class UIDefaultsLoader
return (max * percent) / 100;
}
Integer integer = parseInteger( value, true );
Integer integer = parseInteger( value );
if( integer < min || integer > max )
throw new NumberFormatException( "integer '" + value + "' out of range (" + min + '-' + max + ')' );
return integer;
}
private static Integer parseInteger( String value, boolean reportError ) {
private static Integer parseInteger( String value ) {
try {
return Integer.parseInt( value );
} catch( NumberFormatException ex ) {
if( reportError )
throw new NumberFormatException( "invalid integer '" + value + "'" );
throw new NumberFormatException( "invalid integer '" + value + "'" );
}
return null;
}
private static Number parseIntegerOrFloat( String value, boolean reportError ) {
private static Number parseIntegerOrFloat( String value ) {
try {
return Integer.parseInt( value );
} catch( NumberFormatException ex ) {
try {
return Float.parseFloat( value );
} catch( NumberFormatException ex2 ) {
if( reportError )
throw new NumberFormatException( "invalid integer or float '" + value + "'" );
throw new NumberFormatException( "invalid integer or float '" + value + "'" );
}
}
return null;
}
private static Float parseFloat( String value, boolean reportError ) {
private static Float parseFloat( String value ) {
try {
return Float.parseFloat( value );
} catch( NumberFormatException ex ) {
if( reportError )
throw new NumberFormatException( "invalid float '" + value + "'" );
throw new NumberFormatException( "invalid float '" + value + "'" );
}
return null;
}
private static ActiveValue parseScaledInteger( String value ) {
int val = parseInteger( value, true );
int val = parseInteger( value );
return t -> {
return UIScale.scale( val );
};
}
private static ActiveValue parseScaledFloat( String value ) {
float val = parseFloat( value, true );
float val = parseFloat( value );
return t -> {
return UIScale.scale( val );
};
@@ -1344,7 +1390,11 @@ class UIDefaultsLoader
start = i + 1;
}
}
strs.add( StringUtils.substringTrimmed( str, start ) );
// last param
String s = StringUtils.substringTrimmed( str, start );
if( !s.isEmpty() || !strs.isEmpty() )
strs.add( s );
return strs;
}

View File

@@ -16,9 +16,12 @@
package com.formdev.flatlaf.icons;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Area;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
@@ -36,6 +39,8 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
public class FlatCapsLockIcon
extends FlatAbstractIcon
{
private Path2D path;
public FlatCapsLockIcon() {
super( 16, 16, UIManager.getColor( "PasswordField.capsLockIconColor" ) );
}
@@ -63,16 +68,22 @@ public class FlatCapsLockIcon
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd">
<rect width="16" height="16" fill="#6E6E6E" rx="3"/>
<rect width="6" height="2" x="5" y="11.5" fill="#FFF"/>
<path fill="#FFF" d="M2,8 L8,2 L14,8 L11,8 L11,10 L5,10 L5,8 L2,8 Z"/>
<rect width="5" height="2" x="5.5" y="11.5" stroke="#FFF" stroke-linejoin="round"/>
<path stroke="#FFF" stroke-linejoin="round" d="M2.5,7.5 L8,2 L13.5,7.5 L10.5,7.5 L10.5,9.5 L5.5,9.5 L5.5,7.5 L2.5,7.5 Z"/>
</g>
</svg>
*/
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
path.append( new RoundRectangle2D.Float( 0, 0, 16, 16, 6, 6 ), false );
path.append( new Rectangle2D.Float( 5, 11.5f, 6, 2 ), false );
path.append( FlatUIUtils.createPath( 2,8, 8,2, 14,8, 11,8, 11,10, 5,10, 5,8 ), false );
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE );
BasicStroke stroke = new BasicStroke( 1, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND );
if( path == null ) {
path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
path.append( new RoundRectangle2D.Float( 0, 0, 16, 16, 6, 6 ), false );
path.append( new Area( stroke.createStrokedShape( new Rectangle2D.Float( 5.5f, 11.5f, 5, 2 ) ) ), false );
path.append( new Area( stroke.createStrokedShape( FlatUIUtils.createPath(
2.5,7.5, 8,2, 13.5,7.5, 10.5,7.5, 10.5,9.5, 5.5,9.5, 5.5,7.5, 2.5,7.5 ) ) ), false );
}
g.fill( path );
}
}

View File

@@ -242,7 +242,7 @@ public class FlatCheckBoxIcon
}
protected void paintCheckmark( Component c, Graphics2D g ) {
Path2D.Float path = new Path2D.Float();
Path2D.Float path = new Path2D.Float( Path2D.WIND_NON_ZERO, 3 );
path.moveTo( 4.5f, 7.5f );
path.lineTo( 6.6f, 10f );
path.lineTo( 11.25f, 3.5f );

View File

@@ -76,7 +76,7 @@ public class FlatCheckBoxMenuItemIcon
}
protected void paintCheckmark( Graphics2D g2 ) {
Path2D.Float path = new Path2D.Float();
Path2D.Float path = new Path2D.Float( Path2D.WIND_NON_ZERO, 3 );
path.moveTo( 4.5f, 7.5f );
path.lineTo( 6.6f, 10f );
path.lineTo( 11.25f, 3.5f );

View File

@@ -20,7 +20,6 @@ import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
import java.util.Map;
import javax.swing.AbstractButton;
@@ -103,9 +102,11 @@ public class FlatClearIcon
// paint cross
g.setColor( clearIconColor );
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
path.append( new Line2D.Float( 5,5, 11,11 ), false );
path.append( new Line2D.Float( 5,11, 11,5 ), false );
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD, 4 );
path.moveTo( 5, 5 );
path.lineTo( 11, 11 );
path.moveTo( 5, 11 );
path.lineTo( 11, 5 );
g.draw( path );
}
}

View File

@@ -39,21 +39,25 @@ public class FlatFileChooserDetailsViewIcon
/*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd">
<rect width="2" height="2" x="2" y="3" fill="#6E6E6E"/>
<rect width="2" height="2" x="2" y="7" fill="#6E6E6E"/>
<rect width="2" height="2" x="2" y="11" fill="#6E6E6E"/>
<rect width="8" height="2" x="6" y="3" fill="#6E6E6E"/>
<rect width="8" height="2" x="6" y="7" fill="#6E6E6E"/>
<rect width="8" height="2" x="6" y="11" fill="#6E6E6E"/>
<rect width="2" height="1" x="2" y="3" fill="#6E6E6E" rx=".5"/>
<rect width="2" height="1" x="2" y="6" fill="#6E6E6E" rx=".5"/>
<rect width="2" height="1" x="2" y="9" fill="#6E6E6E" rx=".5"/>
<rect width="2" height="1" x="2" y="12" fill="#6E6E6E" rx=".5"/>
<rect width="8" height="1" x="6" y="3" fill="#6E6E6E" rx=".5"/>
<rect width="8" height="1" x="6" y="6" fill="#6E6E6E" rx=".5"/>
<rect width="8" height="1" x="6" y="9" fill="#6E6E6E" rx=".5"/>
<rect width="8" height="1" x="6" y="12" fill="#6E6E6E" rx=".5"/>
</g>
</svg>
*/
g.fillRect( 2, 3, 2, 2 );
g.fillRect( 2, 7, 2, 2 );
g.fillRect( 2, 11, 2, 2 );
g.fillRect( 6, 3, 8, 2 );
g.fillRect( 6, 7, 8, 2 );
g.fillRect( 6, 11, 8, 2 );
g.fillRoundRect( 2, 3, 2, 1, 1, 1 );
g.fillRoundRect( 2, 6, 2, 1, 1, 1 );
g.fillRoundRect( 2, 9, 2, 1, 1, 1 );
g.fillRoundRect( 2, 12, 2, 1, 1, 1 );
g.fillRoundRect( 6, 3, 8, 1, 1, 1 );
g.fillRoundRect( 6, 6, 8, 1, 1, 1 );
g.fillRoundRect( 6, 9, 8, 1, 1, 1 );
g.fillRoundRect( 6, 12, 8, 1, 1, 1 );
}
}

View File

@@ -16,8 +16,10 @@
package com.formdev.flatlaf.icons;
import java.awt.BasicStroke;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatUIUtils;
@@ -39,10 +41,22 @@ public class FlatFileChooserHomeFolderIcon
protected void paintIcon( Component c, Graphics2D g ) {
/*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<polygon fill="#6E6E6E" fill-rule="evenodd" points="2 8 8 2 14 8 12 8 12 13 9 13 9 10 7 10 7 13 4 13 4 8"/>
<g fill="none" fill-rule="evenodd">
<polyline stroke="#6E6E6E" stroke-linejoin="round" points="6.5 13 6.5 9.5 9.5 9.5 9.5 13"/>
<path stroke="#6E6E6E" d="M3.5,6.5 L3.5,12.5 C3.5,13.0522847 3.94771525,13.5 4.5,13.5 L11.5,13.5 C12.0522847,13.5 12.5,13.0522847 12.5,12.5 L12.5,6.5 L12.5,6.5"/>
<polyline stroke="#6E6E6E" stroke-linecap="round" stroke-linejoin="round" points="1.5 8.5 8 2 14.5 8.5"/>
</g>
</svg>
*/
g.fill( FlatUIUtils.createPath( 2,8, 8,2, 14,8, 12,8, 12,13, 9,13, 9,10, 7,10, 7,13, 4,13, 4,8 ) );
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE );
g.setStroke( new BasicStroke( 1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) );
g.draw( FlatUIUtils.createPath( false, 6.5,13, 6.5,9.5, 9.5,9.5, 9.5,13 ) );
g.draw( FlatUIUtils.createPath( false, 3.5,6.5,
3.5,12.5, FlatUIUtils.QUAD_TO, 3.5,13.5, 4.5,13.5,
11.5,13.5, FlatUIUtils.QUAD_TO, 12.5,13.5, 12.5,12.5,
12.5,6.5 ) );
g.draw( FlatUIUtils.createPath( false, 1.5,8.5, 8,2, 14.5,8.5 ) );
}
}

View File

@@ -16,8 +16,11 @@
package com.formdev.flatlaf.icons;
import java.awt.BasicStroke;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.RoundRectangle2D;
import javax.swing.UIManager;
/**
@@ -39,17 +42,20 @@ public class FlatFileChooserListViewIcon
/*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd">
<rect width="4" height="4" x="3" y="3" fill="#6E6E6E"/>
<rect width="4" height="4" x="3" y="9" fill="#6E6E6E"/>
<rect width="4" height="4" x="9" y="9" fill="#6E6E6E"/>
<rect width="4" height="4" x="9" y="3" fill="#6E6E6E"/>
<rect width="4" height="4" x="2.5" y="2.5" stroke="#6E6E6E" rx="1.5"/>
<rect width="4" height="4" x="2.5" y="9.5" stroke="#6E6E6E" rx="1.5"/>
<rect width="4" height="4" x="9.5" y="9.5" stroke="#6E6E6E" rx="1.5"/>
<rect width="4" height="4" x="9.5" y="2.5" stroke="#6E6E6E" rx="1.5"/>
</g>
</svg>
*/
g.fillRect( 3, 3, 4, 4 );
g.fillRect( 3, 9, 4, 4 );
g.fillRect( 9, 9, 4, 4 );
g.fillRect( 9, 3, 4, 4 );
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE );
g.setStroke( new BasicStroke( 1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) );
g.draw( new RoundRectangle2D.Float( 2.5f, 2.5f, 4, 4, 2, 2 ) );
g.draw( new RoundRectangle2D.Float( 2.5f, 9.5f, 4, 4, 2, 2 ) );
g.draw( new RoundRectangle2D.Float( 9.5f, 9.5f, 4, 4, 2, 2 ) );
g.draw( new RoundRectangle2D.Float( 9.5f, 2.5f, 4, 4, 2, 2 ) );
}
}

View File

@@ -16,10 +16,13 @@
package com.formdev.flatlaf.icons;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Line2D;
import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatUIUtils;
/**
* "new folder" icon for {@link javax.swing.JFileChooser}.
@@ -31,6 +34,8 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
public class FlatFileChooserNewFolderIcon
extends FlatAbstractIcon
{
private final Color greenColor = UIManager.getColor( "Actions.Green" );
public FlatFileChooserNewFolderIcon() {
super( 16, 16, UIManager.getColor( "Actions.Grey" ) );
}
@@ -40,13 +45,20 @@ public class FlatFileChooserNewFolderIcon
/*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd">
<polygon fill="#6E6E6E" points="2 3 5.5 3 7 5 14 5 14 8 11 8 11 10 9 10 9 13 2 13"/>
<path fill="#59A869" d="M14,11 L16,11 L16,13 L14,13 L14,15 L12,15 L12,13 L10,13 L10,11 L12,11 L12,9 L14,9 L14,11 Z"/>
<path stroke="#6E6E6E" d="M13,13.5 L3,13.5 C2.17157288,13.5 1.5,12.8284271 1.5,12 L1.5,4 C1.5,3.17157288 2.17157288,2.5 3,2.5 L6.29289322,2.5 C6.42550146,2.5 6.55267842,2.55267842 6.64644661,2.64644661 L8.5,4.5 L8.5,4.5 L13,4.5 C13.8284271,4.5 14.5,5.17157288 14.5,6 L14.5,12 C14.5,12.8284271 13.8284271,13.5 13,13.5 Z"/>
<line x1="5.5" x2="10.5" y1="9" y2="9" stroke="#59A869" stroke-linecap="round"/>
<line x1="8" x2="8" y1="6.5" y2="11.5" stroke="#59A869" stroke-linecap="round"/>
</g>
</svg>
*/
g.fill( FlatUIUtils.createPath( 2,3, 5.5,3, 7,5, 14,5, 14,8, 11,8, 11,10, 9,10, 9,13, 2,13 ) );
g.fill( FlatUIUtils.createPath( 14,11, 16,11, 16,13, 14,13, 14,15, 12,15, 12,13, 10,13, 10,11, 12,11, 12,9, 14,9, 14,11 ) );
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE );
g.setStroke( new BasicStroke( 1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) );
g.draw( FlatFileViewDirectoryIcon.createFolderPath() );
g.setColor( greenColor );
g.draw( new Line2D.Float( 5.5f, 9, 10.5f, 9 ) );
g.draw( new Line2D.Float( 8, 6.5f, 8, 11.5f ) );
}
}

View File

@@ -16,9 +16,12 @@
package com.formdev.flatlaf.icons;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Line2D;
import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatUIUtils;
@@ -44,15 +47,20 @@ public class FlatFileChooserUpFolderIcon
/*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd">
<polygon fill="#6E6E6E" points="2 3 5.5 3 7 5 9 5 9 9 13 9 13 5 14 5 14 13 2 13"/>
<path fill="#389FD6" d="M12,4 L12,8 L10,8 L10,4 L8,4 L11,1 L14,4 L12,4 Z"/>
<path stroke="#6E6E6E" d="M13,13.5 L3,13.5 C2.17157288,13.5 1.5,12.8284271 1.5,12 L1.5,4 C1.5,3.17157288 2.17157288,2.5 3,2.5 L6.29289322,2.5 C6.42550146,2.5 6.55267842,2.55267842 6.64644661,2.64644661 L8.5,4.5 L8.5,4.5 L13,4.5 C13.8284271,4.5 14.5,5.17157288 14.5,6 L14.5,12 C14.5,12.8284271 13.8284271,13.5 13,13.5 Z"/>
<line x1="8" x2="8" y1="6.5" y2="11.5" stroke="#389FD6" stroke-linecap="round"/>
<polyline stroke="#389FD6" stroke-linecap="round" stroke-linejoin="round" points="5.5 9 8 6.5 10.5 9"/>
</g>
</svg>
*/
g.fill( FlatUIUtils.createPath( 2,3, 5.5,3, 7,5, 9,5, 9,9, 13,9, 13,5, 14,5, 14,13, 2,13 ) );
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE );
g.setStroke( new BasicStroke( 1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) );
g.draw( FlatFileViewDirectoryIcon.createFolderPath() );
g.setColor( blueColor );
g.fill( FlatUIUtils.createPath( 12,4, 12,8, 10,8, 10,4, 8,4, 11,1, 14,4, 12,4 ) );
g.draw( new Line2D.Float( 8, 6.5f, 8, 11.5f ) );
g.draw( FlatUIUtils.createPath( false, 5.5,9, 8,6.5, 10.5,9 ) );
}
}

View File

@@ -16,10 +16,12 @@
package com.formdev.flatlaf.icons;
import java.awt.BasicStroke;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.awt.RenderingHints;
import java.awt.geom.Line2D;
import java.awt.geom.RoundRectangle2D;
import javax.swing.UIManager;
/**
@@ -41,17 +43,18 @@ public class FlatFileViewComputerIcon
/*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd">
<path fill="#6E6E6E" d="M2,3 L14,3 L14,11 L2,11 L2,3 Z M4,5 L4,9 L12,9 L12,5 L4,5 Z"/>
<rect width="12" height="2" x="2" y="12" fill="#6E6E6E"/>
<rect width="11" height="7" x="2.5" y="3.5" stroke="#6E6E6E" rx="1"/>
<line x1="8" x2="8" y1="11" y2="12" stroke="#6E6E6E"/>
<line x1="4.5" x2="11.5" y1="12.5" y2="12.5" stroke="#6E6E6E" stroke-linecap="round"/>
</g>
</svg>
*/
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
path.append( new Rectangle2D.Float( 2, 3, 12, 8 ), false );
path.append( new Rectangle2D.Float( 4, 5, 8, 4 ), false );
g.fill( path );
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE );
g.setStroke( new BasicStroke( 1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) );
g.fillRect( 2, 12, 12, 2 );
g.draw( new RoundRectangle2D.Float( 2.5f, 3.5f, 11, 7, 2, 2 ) );
g.drawLine( 8, 11, 8, 12 );
g.draw( new Line2D.Float( 4.5f, 12.5f, 11.5f, 12.5f ) );
}
}

View File

@@ -18,6 +18,8 @@ package com.formdev.flatlaf.icons;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Path2D;
import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatUIUtils;
@@ -31,6 +33,8 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
public class FlatFileViewDirectoryIcon
extends FlatAbstractIcon
{
private Path2D path;
public FlatFileViewDirectoryIcon() {
super( 16, 16, UIManager.getColor( "Objects.Grey" ) );
}
@@ -39,10 +43,32 @@ public class FlatFileViewDirectoryIcon
protected void paintIcon( Component c, Graphics2D g ) {
/*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<polygon fill="#6E6E6E" fill-rule="evenodd" points="1 2 6 2 8 4 15 4 15 13 1 13"/>
<path fill="none" stroke="#6E6E6E" d="M13,13.5 L3,13.5 C2.17157288,13.5 1.5,12.8284271 1.5,12 L1.5,4 C1.5,3.17157288 2.17157288,2.5 3,2.5 L6.29289322,2.5 C6.42550146,2.5 6.55267842,2.55267842 6.64644661,2.64644661 L8.5,4.5 L8.5,4.5 L13,4.5 C13.8284271,4.5 14.5,5.17157288 14.5,6 L14.5,12 C14.5,12.8284271 13.8284271,13.5 13,13.5 Z"/>
</svg>
*/
g.fill( FlatUIUtils.createPath( 1,2, 6,2, 8,4, 15,4, 15,13, 1,13 ) );
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE );
if( path == null )
path = createFolderPath();
g.draw( path );
}
static Path2D createFolderPath() {
double arc = 1.5;
double arc2 = 0.5;
return FlatUIUtils.createPath(
// bottom-right
14.5,13.5-arc, FlatUIUtils.QUAD_TO, 14.5,13.5, 14.5-arc,13.5,
// bottom-left
1.5+arc,13.5, FlatUIUtils.QUAD_TO, 1.5,13.5, 1.5,13.5-arc,
// top-left
1.5,2.5+arc, FlatUIUtils.QUAD_TO, 1.5,2.5, 1.5+arc,2.5,
// top-mid-left
6.5-arc2,2.5, FlatUIUtils.QUAD_TO, 6.5,2.5, 6.5+arc2,2.5+arc2,
// top-mid-right
8.5,4.5,
// top-right
14.5-arc,4.5, FlatUIUtils.QUAD_TO, 14.5,4.5, 14.5,4.5+arc );
}
}

View File

@@ -16,8 +16,11 @@
package com.formdev.flatlaf.icons;
import java.awt.BasicStroke;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Path2D;
import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatUIUtils;
@@ -31,6 +34,8 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
public class FlatFileViewFileIcon
extends FlatAbstractIcon
{
private Path2D path;
public FlatFileViewFileIcon() {
super( 16, 16, UIManager.getColor( "Objects.Grey" ) );
}
@@ -39,14 +44,33 @@ public class FlatFileViewFileIcon
protected void paintIcon( Component c, Graphics2D g ) {
/*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd">
<polygon fill="#6E6E6E" points="8 6 8 1 13 1 13 15 3 15 3 6"/>
<polygon fill="#6E6E6E" points="3 5 7 5 7 1"/>
<g fill="none" fill-rule="evenodd" stroke-linejoin="round">
<path stroke="#6E6E6E" d="M4,1.5 L8.8,1.5 L8.8,1.5 L13.5,6.2 L13.5,13 C13.5,13.8284271 12.8284271,14.5 12,14.5 L4,14.5 C3.17157288,14.5 2.5,13.8284271 2.5,13 L2.5,3 C2.5,2.17157288 3.17157288,1.5 4,1.5 Z"/>
<path stroke="#6E6E6E" d="M8.5,2 L8.5,5 C8.5,5.82842712 9.17157288,6.5 10,6.5 L13,6.5 L13,6.5"/>
</g>
</svg>
*/
g.fill( FlatUIUtils.createPath( 8,6, 8,1, 13,1, 13,15, 3,15, 3,6 ) );
g.fill( FlatUIUtils.createPath( 3,5, 7,5, 7,1 ) );
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE );
g.setStroke( new BasicStroke( 1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) );
if( path == null ) {
double arc = 1.5;
path = FlatUIUtils.createPath( false,
// top-left
2.5,1.5+arc, FlatUIUtils.QUAD_TO, 2.5,1.5, 2.5+arc,1.5,
// top-right
8.8,1.5, 13.5,6.2,
// bottom-right
13.5,14.5-arc, FlatUIUtils.QUAD_TO, 13.5,14.5, 13.5-arc,14.5,
// bottom-left
2.5+arc,14.5, FlatUIUtils.QUAD_TO, 2.5,14.5, 2.5,14.5-arc,
FlatUIUtils.CLOSE_PATH,
FlatUIUtils.MOVE_TO, 8.5,2,
8.5,6.5-arc, FlatUIUtils.QUAD_TO, 8.5,6.5, 8.5+arc,6.5,
13,6.5 );
}
g.draw( path );
}
}

View File

@@ -16,9 +16,10 @@
package com.formdev.flatlaf.icons;
import java.awt.BasicStroke;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.geom.Path2D;
import java.awt.RenderingHints;
import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatUIUtils;
@@ -40,18 +41,22 @@ public class FlatFileViewFloppyDriveIcon
protected void paintIcon( Component c, Graphics2D g ) {
/*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd">
<path fill="#6E6E6E" d="M11,14 L11,11 L5,11 L5,14 L2,14 L2,2 L14,2 L14,14 L11,14 Z M4,4 L4,8 L12,8 L12,4 L4,4 Z"/>
<rect width="4" height="2" x="6" y="12" fill="#6E6E6E"/>
<g fill="none" fill-rule="evenodd" stroke-linejoin="round">
<path stroke="#6E6E6E" d="M3.5,2.5 L11.5,2.5 L11.5,2.5 L13.5,4.5 L13.5,12.5 C13.5,13.0522847 13.0522847,13.5 12.5,13.5 L3.5,13.5 C2.94771525,13.5 2.5,13.0522847 2.5,12.5 L2.5,3.5 C2.5,2.94771525 2.94771525,2.5 3.5,2.5 Z"/>
<polyline stroke="#6E6E6E" points="4.5 13 4.5 9.5 11.5 9.5 11.5 13"/>
<polyline stroke="#6E6E6E" points="5.5 3 5.5 5.5 10.5 5.5 10.5 3"/>
</g>
</svg>
*/
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
path.append( FlatUIUtils.createPath( 11,14, 11,11, 5,11, 5,14, 2,14, 2,2, 14,2, 14,14, 11,14 ), false );
path.append( FlatUIUtils.createPath( 4,4, 4,8, 12,8, 12,4, 4,4 ), false );
g.fill( path );
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE );
g.setStroke( new BasicStroke( 1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) );
g.fillRect( 6, 12, 4, 2 );
g.draw( FlatUIUtils.createPath( 3.5,2.5, 11.5,2.5, 11.5,2.5, 13.5,4.5,
13.5,12.5, FlatUIUtils.QUAD_TO, 13.5,13.5, 12.5,13.5,
3.5,13.5, FlatUIUtils.QUAD_TO, 2.5,13.5, 2.5,12.5,
2.5,3.5, FlatUIUtils.QUAD_TO, 2.5,2.5, 3.5,2.5 ) );
g.draw( FlatUIUtils.createPath( false, 4.5,13, 4.5,9.5, 11.5,9.5, 11.5,13 ) );
g.draw( FlatUIUtils.createPath( false, 5.5,3, 5.5,5.5, 10.5,5.5, 10.5,3 ) );
}
}

View File

@@ -16,10 +16,12 @@
package com.formdev.flatlaf.icons;
import java.awt.BasicStroke;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.awt.RenderingHints;
import java.awt.geom.Ellipse2D;
import java.awt.geom.RoundRectangle2D;
import javax.swing.UIManager;
/**
@@ -40,14 +42,19 @@ public class FlatFileViewHardDriveIcon
protected void paintIcon( Component c, Graphics2D g ) {
/*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="#6E6E6E" fill-rule="evenodd" d="M2,6 L14,6 L14,10 L2,10 L2,6 Z M12,8 L12,9 L13,9 L13,8 L12,8 Z M10,8 L10,9 L11,9 L11,8 L10,8 Z"/>
<g fill="none" fill-rule="evenodd">
<rect width="11" height="5" x="2.5" y="5.5" stroke="#6E6E6E" rx="1"/>
<circle cx="11.5" cy="8.5" r="1" fill="#6E6E6E"/>
<circle cx="9.5" cy="8.5" r="1" fill="#6E6E6E"/>
</g>
</svg>
*/
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
path.append( new Rectangle2D.Float( 2, 6, 12, 4 ), false );
path.append( new Rectangle2D.Float( 12, 8, 1, 1 ), false );
path.append( new Rectangle2D.Float( 10, 8, 1, 1 ), false );
g.fill( path );
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE );
g.setStroke( new BasicStroke( 1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) );
g.draw( new RoundRectangle2D.Float( 2.5f, 5.5f, 11, 5, 2, 2 ) );
g.fill( new Ellipse2D.Float( 10.8f, 7.8f, 1.4f, 1.4f ) );
g.fill( new Ellipse2D.Float( 8.8f, 7.8f, 1.4f, 1.4f ) );
}
}

View File

@@ -17,9 +17,11 @@
package com.formdev.flatlaf.icons;
import static com.formdev.flatlaf.util.UIScale.*;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D;
import java.util.Map;
@@ -96,7 +98,8 @@ public class FlatHelpButtonIcon
<g fill="none" fill-rule="evenodd">
<circle cx="11" cy="11" r="10.5" fill="#6E6E6E"/>
<circle cx="11" cy="11" r="9.5" fill="#FFF"/>
<path fill="#6E6E6E" d="M10,17 L12,17 L12,15 L10,15 L10,17 Z M11,5 C8.8,5 7,6.8 7,9 L9,9 C9,7.9 9.9,7 11,7 C12.1,7 13,7.9 13,9 C13,11 10,10.75 10,14 L12,14 C12,11.75 15,11.5 15,9 C15,6.8 13.2,5 11,5 Z"/>
<path stroke="#6E6E6E" stroke-linecap="round" stroke-width="2" d="M8,8.5 C8.25,7 9.66585007,6 11,6 C12.5,6 14,7 14,8.5 C14,10.5 11,11 11,13"/>
<circle cx="11" cy="16" r="1.2" fill="#6E6E6E"/>
</g>
</svg>
*/
@@ -147,22 +150,19 @@ public class FlatHelpButtonIcon
g2.fill( new Ellipse2D.Float( xy, xy, wh, wh ) );
// paint question mark
Path2D q = new Path2D.Float();
q.moveTo( 11, 5 );
q.curveTo( 8.8,5, 7,6.8, 7,9 );
q.lineTo( 9, 9 );
q.curveTo( 9,7.9, 9.9,7, 11,7 );
q.curveTo( 12.1,7, 13,7.9, 13,9 );
q.curveTo( 13,11, 10,10.75, 10,14 );
q.lineTo( 12, 14 );
q.curveTo( 12,11.75, 15,11.5, 15,9 );
q.curveTo( 15,6.8, 13.2,5, 11,5 );
q.closePath();
Path2D q = new Path2D.Float( Path2D.WIND_NON_ZERO, 10 );
q.moveTo( 8,8.5 );
q.curveTo( 8.25,7, 9.66585007,6, 11,6 );
q.curveTo( 12.5,6, 14,7, 14,8.5 );
q.curveTo( 14,10.5, 11,11, 11,13 );
g2.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE );
g2.setStroke( new BasicStroke( 2, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) );
g2.translate( focusWidth, focusWidth );
g2.setColor( enabled ? questionMarkColor : disabledQuestionMarkColor );
g2.fill( q );
g2.fillRect( 10, 15, 2, 2 );
g2.draw( q );
g2.fill( new Ellipse2D.Float( 9.8f, 14.8f, 2.4f, 2.4f ) );
}
@Override

View File

@@ -20,7 +20,6 @@ import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatButtonUI;
@@ -58,9 +57,11 @@ public class FlatInternalFrameCloseIcon
float my = height / 2;
float r = 3.25f;
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
path.append( new Line2D.Float( mx - r, my - r, mx + r, my + r ), false );
path.append( new Line2D.Float( mx - r, my + r, mx + r, my - r ), false );
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD, 4 );
path.moveTo( mx - r, my - r );
path.lineTo( mx + r, my + r );
path.moveTo( mx - r, my + r );
path.lineTo( mx + r, my - r );
g.setStroke( new BasicStroke( 1f ) );
g.draw( path );
}

View File

@@ -19,7 +19,7 @@ package com.formdev.flatlaf.icons;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
/**
* "Error" icon for {@link javax.swing.JOptionPane}.
@@ -40,8 +40,8 @@ public class FlatOptionPaneErrorIcon
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
<g fill="none" fill-rule="evenodd">
<circle cx="16" cy="16" r="14" fill="#DB5860"/>
<rect width="4" height="11" x="14" y="7" fill="#FFF"/>
<rect width="4" height="4" x="14" y="21" fill="#FFF"/>
<rect width="4" height="12" x="14" y="7" fill="#FFF" rx="2"/>
<circle cx="16" cy="23" r="2" fill="#FFF"/>
</g>
</svg>
*/
@@ -54,8 +54,8 @@ public class FlatOptionPaneErrorIcon
@Override
protected Shape createInside() {
Path2D inside = new Path2D.Float( Path2D.WIND_EVEN_ODD );
inside.append( new Rectangle2D.Float( 14, 7, 4, 11 ), false );
inside.append( new Rectangle2D.Float( 14, 21, 4, 4 ), false );
inside.append( new RoundRectangle2D.Float( 14, 7, 4, 12, 4, 4 ), false );
inside.append( new Ellipse2D.Float( 14, 21, 4, 4 ), false );
return inside;
}
}

View File

@@ -19,7 +19,7 @@ package com.formdev.flatlaf.icons;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
/**
* "Information" icon for {@link javax.swing.JOptionPane}.
@@ -40,8 +40,8 @@ public class FlatOptionPaneInformationIcon
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
<g fill="none" fill-rule="evenodd">
<circle cx="16" cy="16" r="14" fill="#389FD6"/>
<rect width="4" height="11" x="14" y="14" fill="#FFF"/>
<rect width="4" height="4" x="14" y="7" fill="#FFF"/>
<rect width="4" height="12" x="14" y="13" fill="#FFF" rx="2"/>
<circle cx="16" cy="9" r="2" fill="#FFF"/>
</g>
</svg>
*/
@@ -54,8 +54,8 @@ public class FlatOptionPaneInformationIcon
@Override
protected Shape createInside() {
Path2D inside = new Path2D.Float( Path2D.WIND_EVEN_ODD );
inside.append( new Rectangle2D.Float( 14, 14, 4, 11 ), false );
inside.append( new Rectangle2D.Float( 14, 7, 4, 4 ), false );
inside.append( new RoundRectangle2D.Float( 14, 13, 4, 12, 4, 4 ), false );
inside.append( new Ellipse2D.Float( 14, 7, 4, 4 ), false );
return inside;
}
}

View File

@@ -16,10 +16,10 @@
package com.formdev.flatlaf.icons;
import java.awt.BasicStroke;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
/**
* "Question" icon for {@link javax.swing.JOptionPane}.
@@ -40,8 +40,8 @@ public class FlatOptionPaneQuestionIcon
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
<g fill="none" fill-rule="evenodd">
<circle cx="16" cy="16" r="14" fill="#389FD6"/>
<rect width="4" height="4" x="14" y="22" fill="#FFF"/>
<path fill="#FFF" d="M14,20 C14,20 18,20 18,20 C18,16 23,16 23,12 C23,8 20,6 16,6 C12,6 9,8 9,12 C9,12 13,12 13,12 C13,10 14,9 16,9 C18,9 19,10 19,12 C19,15 14,15 14,20 Z"/>
<circle cx="16" cy="24" r="1.7" fill="#FFF"/>
<path stroke="#FFF" stroke-linecap="round" stroke-width="3" d="M11.5,11.75 C11.75,9.5 13.75,8 16,8 C18.25,8 20.5,9.5 20.5,11.75 C20.5,14.75 16,15.5 16,19"/>
</g>
</svg>
*/
@@ -53,21 +53,17 @@ public class FlatOptionPaneQuestionIcon
@Override
protected Shape createInside() {
Path2D q = new Path2D.Float();
q.moveTo( 14, 20 );
q.lineTo( 18, 20 );
q.curveTo( 18, 16, 23, 16, 23, 12 );
q.curveTo( 23, 8, 20, 6, 16, 6 );
q.curveTo( 12, 6, 9, 8, 9, 12 );
q.curveTo( 9, 12, 13, 12, 13, 12 );
q.curveTo( 13, 10, 14, 9, 16, 9 );
q.curveTo( 18, 9, 19, 10, 19, 12 );
q.curveTo( 19, 15, 14, 15, 14, 20 );
q.closePath();
Path2D q = new Path2D.Float( Path2D.WIND_NON_ZERO, 10 );
q.moveTo( 11.5,11.75 );
q.curveTo( 11.75,9.5, 13.75,8, 16,8 );
q.curveTo( 18.25,8, 20.5,9.5, 20.5,11.75 );
q.curveTo( 20.5,14.75, 16,15.5, 16,19 );
BasicStroke stroke = new BasicStroke( 3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER );
Path2D inside = new Path2D.Float( Path2D.WIND_EVEN_ODD );
inside.append( new Rectangle2D.Float( 14, 22, 4, 4 ), false );
inside.append( q, false );
inside.append( new Ellipse2D.Float( 14.3f, 22.3f, 3.4f, 3.4f ), false );
inside.append( stroke.createStrokedShape( q ), false );
return inside;
}
}

View File

@@ -17,8 +17,9 @@
package com.formdev.flatlaf.icons;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import com.formdev.flatlaf.ui.FlatUIUtils;
/**
@@ -39,23 +40,24 @@ public class FlatOptionPaneWarningIcon
/*
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
<g fill="none" fill-rule="evenodd">
<polygon fill="#EDA200" points="16 2 31 28 1 28"/>
<rect width="4" height="8" x="14" y="10" fill="#FFF"/>
<rect width="4" height="4" x="14" y="21" fill="#FFF"/>
<path fill="#EDA200" d="M17.7364863,3.038851 L30.2901269,25.0077221 C30.8381469,25.966757 30.5049534,27.1884663 29.5459185,27.7364863 C29.2437231,27.9091694 28.9016945,28 28.5536406,28 L3.44635936,28 C2.34178986,28 1.44635936,27.1045695 1.44635936,26 C1.44635936,25.6519461 1.53718999,25.3099175 1.70987307,25.0077221 L14.2635137,3.038851 C14.8115337,2.0798161 16.033243,1.74662265 16.9922779,2.29464259 C17.3023404,2.47182119 17.5593077,2.72878844 17.7364863,3.038851 Z"/>
<rect width="4" height="11" x="14" y="8" fill="#FFF" rx="2"/>
<circle cx="16" cy="23" r="2" fill="#FFF"/>
</g>
</svg>
*/
@Override
protected Shape createOutside() {
return FlatUIUtils.createPath( 16,2, 31,28, 1,28 );
return FlatUIUtils.createRoundTrianglePath( 16,0, 32,28, 0,28, 4 );
}
@Override
protected Shape createInside() {
Path2D inside = new Path2D.Float( Path2D.WIND_EVEN_ODD );
inside.append( new Rectangle2D.Float( 14, 10, 4, 8 ), false );
inside.append( new Rectangle2D.Float( 14, 21, 4, 4 ), false );
inside.append( new RoundRectangle2D.Float( 14, 8, 4, 11, 4, 4 ), false );
inside.append( new Ellipse2D.Float( 14, 21, 4, 4 ), false );
return inside;
}
}

View File

@@ -46,6 +46,7 @@ public class FlatSearchIcon
@Styleable protected Color searchIconPressedColor = UIManager.getColor( "SearchField.searchIconPressedColor" );
private final boolean ignoreButtonState;
private Area area;
public FlatSearchIcon() {
this( false );
@@ -89,9 +90,11 @@ public class FlatSearchIcon
null, searchIconHoverColor, searchIconPressedColor ) );
// paint magnifier
Area area = new Area( new Ellipse2D.Float( 2, 2, 10, 10 ) );
area.subtract( new Area( new Ellipse2D.Float( 3, 3, 8, 8 ) ) );
area.add( new Area( FlatUIUtils.createPath( 10.813,9.75, 14,12.938, 12.938,14, 9.75,10.813 ) ) );
if( area == null ) {
area = new Area( new Ellipse2D.Float( 2, 2, 10, 10 ) );
area.subtract( new Area( new Ellipse2D.Float( 3, 3, 8, 8 ) ) );
area.add( new Area( FlatUIUtils.createPath( 10.813,9.75, 14,12.938, 12.938,14, 9.75,10.813 ) ) );
}
g.fill( area );
}
}

View File

@@ -21,7 +21,6 @@ import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
import java.util.Map;
import javax.swing.UIManager;
@@ -100,9 +99,11 @@ public class FlatTabbedPaneCloseIcon
float r = ((bg != null) ? closeCrossFilledSize : closeCrossPlainSize) / 2;
// paint cross
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
path.append( new Line2D.Float( mx - r, my - r, mx + r, my + r ), false );
path.append( new Line2D.Float( mx - r, my + r, mx + r, my - r ), false );
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD, 4 );
path.moveTo( mx - r, my - r );
path.lineTo( mx + r, my + r );
path.moveTo( mx - r, my + r );
path.lineTo( mx + r, my - r );
g.setStroke( new BasicStroke( closeCrossLineWidth ) );
g.draw( path );
}

View File

@@ -18,8 +18,9 @@ package com.formdev.flatlaf.icons;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Path2D;
import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatUIUtils;
/**
* "closed" icon for {@link javax.swing.JTree} used by {@link javax.swing.tree.DefaultTreeCellRenderer}.
@@ -31,6 +32,8 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
public class FlatTreeClosedIcon
extends FlatAbstractIcon
{
private Path2D path;
public FlatTreeClosedIcon() {
super( 16, 16, UIManager.getColor( "Tree.icon.closedColor" ) );
}
@@ -41,10 +44,14 @@ public class FlatTreeClosedIcon
/*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<polygon fill="#6E6E6E" fill-rule="evenodd" points="1 2 6 2 8 4 15 4 15 13 1 13"/>
<path fill="none" stroke="#6E6E6E" d="M13,13.5 L3,13.5 C2.17157288,13.5 1.5,12.8284271 1.5,12 L1.5,4 C1.5,3.17157288 2.17157288,2.5 3,2.5 L6.29289322,2.5 C6.42550146,2.5 6.55267842,2.55267842 6.64644661,2.64644661 L8.5,4.5 L8.5,4.5 L13,4.5 C13.8284271,4.5 14.5,5.17157288 14.5,6 L14.5,12 C14.5,12.8284271 13.8284271,13.5 13,13.5 Z"/>
</svg>
*/
g.fill( FlatUIUtils.createPath( 1,2, 6,2, 8,4, 15,4, 15,13, 1,13 ) );
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE );
if( path == null )
path = FlatFileViewDirectoryIcon.createFolderPath();
g.draw( path );
}
}

View File

@@ -16,9 +16,11 @@
package com.formdev.flatlaf.icons;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.geom.Path2D;
import java.util.function.Function;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
@@ -39,6 +41,7 @@ public class FlatTreeCollapsedIcon
extends FlatAbstractIcon
{
private final boolean chevron;
private Path2D path;
public FlatTreeCollapsedIcon() {
this( UIManager.getColor( "Tree.icon.collapsedColor" ) );
@@ -59,10 +62,15 @@ public class FlatTreeCollapsedIcon
if( chevron ) {
// chevron arrow
g.fill( FlatUIUtils.createPath( 3,1, 3,2.5, 6,5.5, 3,8.5, 3,10, 4.5,10, 9,5.5, 4.5,1 ) );
g.setStroke( new BasicStroke( 1f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER ) );
if( path == null )
path = FlatUIUtils.createPath( false, 3.5,1.5, 7.5,5.5, 3.5,9.5 );
g.draw( path );
} else {
// triangle arrow
g.fill( FlatUIUtils.createPath( 2,1, 2,10, 10,5.5 ) );
if( path == null )
path = FlatUIUtils.createPath( 2,1, 2,10, 10,5.5 );
g.fill( path );
}
}

View File

@@ -16,10 +16,14 @@
package com.formdev.flatlaf.icons;
import java.awt.BasicStroke;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Line2D;
import java.awt.geom.RoundRectangle2D;
import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.util.ColorFunctions;
/**
* "leaf" icon for {@link javax.swing.JTree} used by {@link javax.swing.tree.DefaultTreeCellRenderer}.
@@ -42,13 +46,22 @@ public class FlatTreeLeafIcon
/*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd">
<polygon fill="#6E6E6E" points="8 6 8 1 13 1 13 15 3 15 3 6"/>
<polygon fill="#6E6E6E" points="3 5 7 5 7 1"/>
<rect width="11" height="13" x="2.5" y="1.5" stroke="#6E6E6E" rx="1.5"/>
<line x1="5.5" x2="10.5" y1="5.5" y2="5.5" stroke="#6E6E6E" stroke-linecap="round" stroke-opacity=".6"/>
<line x1="5.5" x2="10.5" y1="8" y2="8" stroke="#6E6E6E" stroke-linecap="round" stroke-opacity=".6"/>
<line x1="5.5" x2="10.5" y1="10.5" y2="10.5" stroke="#6E6E6E" stroke-linecap="round" stroke-opacity=".6"/>
</g>
</svg>
*/
g.fill( FlatUIUtils.createPath( 8,6, 8,1, 13,1, 13,15, 3,15, 3,6 ) );
g.fill( FlatUIUtils.createPath( 3,5, 7,5, 7,1 ) );
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE );
g.setStroke( new BasicStroke( 1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) );
g.draw( new RoundRectangle2D.Float( 2.5f, 1.5f, 11, 13, 3, 3 ) );
g.setColor( ColorFunctions.fade( g.getColor(), 0.6f ) );
g.draw( new Line2D.Float( 5.5f, 5.5f, 10.5f, 5.5f ) );
g.draw( new Line2D.Float( 5.5f, 8, 10.5f, 8 ) );
g.draw( new Line2D.Float( 5.5f, 10.5f, 10.5f, 10.5f ) );
}
}

View File

@@ -16,8 +16,11 @@
package com.formdev.flatlaf.icons;
import java.awt.BasicStroke;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Path2D;
import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatUIUtils;
@@ -31,6 +34,8 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
public class FlatTreeOpenIcon
extends FlatAbstractIcon
{
private Path2D path;
public FlatTreeOpenIcon() {
super( 16, 16, UIManager.getColor( "Tree.icon.openColor" ) );
}
@@ -41,14 +46,38 @@ public class FlatTreeOpenIcon
/*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd">
<polygon fill="#6E6E6E" points="1 2 6 2 8 4 14 4 14 6 3.5 6 1 11"/>
<polygon fill="#6E6E6E" points="4 7 16 7 13 13 1 13"/>
</g>
<path fill="none" stroke="#6E6E6E" d="M2,13.5 L4.11538462,8.42307692 C4.34828895,7.86410651 4.89444872,7.5 5.5,7.5 L14.75,7.5 C15.0261424,7.5 15.25,7.72385763 15.25,8 C15.25,8.06601301 15.2369281,8.13137261 15.2115385,8.19230769 L13.3846154,12.5769231 C13.151711,13.1358935 12.6055513,13.5 12,13.5 L3,13.5 C2.17157288,13.5 1.5,12.8284271 1.5,12 L1.5,4 C1.5,3.17157288 2.17157288,2.5 3,2.5 L6.29289322,2.5 C6.42550146,2.5 6.55267842,2.55267842 6.64644661,2.64644661 L8.5,4.5 L8.5,4.5 L12,4.5 C12.8284271,4.5 13.5,5.17157288 13.5,6 L13.5,6.5 L13.5,6.5"/>
</svg>
*/
g.fill( FlatUIUtils.createPath( 1,2, 6,2, 8,4, 14,4, 14,6, 3.5,6, 1,11 ) );
g.fill( FlatUIUtils.createPath( 4,7, 16,7, 13,13, 1,13 ) );
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE );
g.setStroke( new BasicStroke( 1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER ) );
if( path == null ) {
double arc = 1.5;
double arc2 = 0.5;
path = FlatUIUtils.createPath( false,
// bottom-left of opend part
2,13.5,
// top-left of opend part
FlatUIUtils.ROUNDED, 4.5,7.5, arc,
// top-right of opend part
FlatUIUtils.ROUNDED, 15.5,7.5, arc2,
// bottom-right
FlatUIUtils.ROUNDED, 13,13.5, arc,
// bottom-left
1.5+arc,13.5, FlatUIUtils.QUAD_TO, 1.5,13.5, 1.5,13.5-arc,
// top-left
1.5,2.5+arc, FlatUIUtils.QUAD_TO, 1.5,2.5, 1.5+arc,2.5,
// top-mid-left
6.5-arc2,2.5, FlatUIUtils.QUAD_TO, 6.5,2.5, 6.5+arc2,2.5+arc2,
// top-mid-right
8.5,4.5,
// top-right
13.5-arc,4.5, FlatUIUtils.QUAD_TO, 13.5,4.5, 13.5,4.5+arc,
13.5,6.5 );
}
g.draw( path );
}
}

View File

@@ -20,7 +20,6 @@ import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatButtonUI;
@@ -57,9 +56,11 @@ public class FlatWindowCloseIcon
int iy2 = iy + iwh - 1;
float thickness = SystemInfo.isWindows_11_orLater ? (float) scaleFactor : (int) scaleFactor;
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
path.append( new Line2D.Float( ix, iy, ix2, iy2 ), false );
path.append( new Line2D.Float( ix, iy2, ix2, iy ), false );
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD, 4 );
path.moveTo( ix, iy );
path.lineTo( ix2, iy2 );
path.moveTo( ix, iy2 );
path.lineTo( ix2, iy );
g.setStroke( new BasicStroke( thickness ) );
g.draw( path );
}

View File

@@ -0,0 +1,68 @@
/*
* Copyright 2022 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.themes;
import javax.swing.UIManager;
import com.formdev.flatlaf.FlatDarkLaf;
/**
* A Flat LaF that imitates macOS dark look.
* <p>
* The UI defaults are loaded from {@code FlatMacDarkLaf.properties},
* {@code FlatDarkLaf.properties} and {@code FlatLaf.properties}.
*
* @author Karl Tauber
* @since 3
*/
public class FlatMacDarkLaf
extends FlatDarkLaf
{
public static final String NAME = "FlatLaf macOS Dark";
/**
* Sets the application look and feel to this LaF
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
*/
public static boolean setup() {
return setup( new FlatMacDarkLaf() );
}
/**
* Adds this look and feel to the set of available look and feels.
* <p>
* Useful if your application uses {@link UIManager#getInstalledLookAndFeels()}
* to query available LaFs and display them to the user in a combobox.
*/
public static void installLafInfo() {
installLafInfo( NAME, FlatMacDarkLaf.class );
}
@Override
public String getName() {
return NAME;
}
@Override
public String getDescription() {
return "FlatLaf macOS Dark Look and Feel";
}
@Override
public boolean isDark() {
return true;
}
}

View File

@@ -0,0 +1,68 @@
/*
* Copyright 2022 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.themes;
import javax.swing.UIManager;
import com.formdev.flatlaf.FlatLightLaf;
/**
* A Flat LaF that imitates macOS light look.
* <p>
* The UI defaults are loaded from {@code FlatMacLightLaf.properties},
* {@code FlatLightLaf.properties} and {@code FlatLaf.properties}.
*
* @author Karl Tauber
* @since 3
*/
public class FlatMacLightLaf
extends FlatLightLaf
{
public static final String NAME = "FlatLaf macOS Light";
/**
* Sets the application look and feel to this LaF
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
*/
public static boolean setup() {
return setup( new FlatMacLightLaf() );
}
/**
* Adds this look and feel to the set of available look and feels.
* <p>
* Useful if your application uses {@link UIManager#getInstalledLookAndFeels()}
* to query available LaFs and display them to the user in a combobox.
*/
public static void installLafInfo() {
installLafInfo( NAME, FlatMacLightLaf.class );
}
@Override
public String getName() {
return NAME;
}
@Override
public String getDescription() {
return "FlatLaf macOS Light Look and Feel";
}
@Override
public boolean isDark() {
return false;
}
}

View File

@@ -25,6 +25,7 @@ import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JComponent;
import javax.swing.SwingUtilities;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicArrowButton;
@@ -48,8 +49,10 @@ public class FlatArrowButton
protected Color pressedBackground;
private int arrowWidth = DEFAULT_ARROW_WIDTH;
private float arrowThickness = 1;
private float xOffset = 0;
private float yOffset = 0;
private boolean roundBorderAutoXOffset = true;
private boolean hover;
private boolean pressed;
@@ -82,14 +85,18 @@ public class FlatArrowButton
@Override
public void mousePressed( MouseEvent e ) {
pressed = true;
repaint();
if( SwingUtilities.isLeftMouseButton( e ) ) {
pressed = true;
repaint();
}
}
@Override
public void mouseReleased( MouseEvent e ) {
pressed = false;
repaint();
if( SwingUtilities.isLeftMouseButton( e ) ) {
pressed = false;
repaint();
}
}
} );
}
@@ -116,6 +123,16 @@ public class FlatArrowButton
this.arrowWidth = arrowWidth;
}
/** @since 3 */
public float getArrowThickness() {
return arrowThickness;
}
/** @since 3 */
public void setArrowThickness( float arrowThickness ) {
this.arrowThickness = arrowThickness;
}
protected boolean isHover() {
return hover;
}
@@ -140,6 +157,16 @@ public class FlatArrowButton
this.yOffset = yOffset;
}
/** @since 3 */
public boolean isRoundBorderAutoXOffset() {
return roundBorderAutoXOffset;
}
/** @since 3 */
public void setRoundBorderAutoXOffset( boolean roundBorderAutoXOffset ) {
this.roundBorderAutoXOffset = roundBorderAutoXOffset;
}
protected Color deriveBackground( Color background ) {
return background;
}
@@ -203,14 +230,17 @@ public class FlatArrowButton
}
protected void paintArrow( Graphics2D g ) {
boolean vert = (direction == NORTH || direction == SOUTH);
int x = 0;
// move arrow for round borders
Container parent = getParent();
if( vert && parent instanceof JComponent && FlatUIUtils.hasRoundBorder( (JComponent) parent ) )
x -= scale( parent.getComponentOrientation().isLeftToRight() ? 1 : -1 );
if( isRoundBorderAutoXOffset() ) {
Container parent = getParent();
boolean vert = (direction == NORTH || direction == SOUTH);
if( vert && parent instanceof JComponent && FlatUIUtils.hasRoundBorder( (JComponent) parent ) )
x -= scale( parent.getComponentOrientation().isLeftToRight() ? 1 : -1 );
}
FlatUIUtils.paintArrow( g, x, 0, getWidth(), getHeight(), getDirection(), chevron, getArrowWidth(), getXOffset(), getYOffset() );
FlatUIUtils.paintArrow( g, x, 0, getWidth(), getHeight(), getDirection(), chevron,
getArrowWidth(), getArrowThickness(), getXOffset(), getYOffset() );
}
}

View File

@@ -20,6 +20,7 @@ import static com.formdev.flatlaf.FlatClientProperties.*;
import static com.formdev.flatlaf.util.UIScale.scale;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
@@ -45,8 +46,10 @@ import javax.swing.LookAndFeel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.plaf.ButtonUI;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.ToolBarUI;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicButtonListener;
import javax.swing.plaf.basic.BasicButtonUI;
@@ -797,5 +800,20 @@ public class FlatButtonUI
super.propertyChange( e );
FlatButtonUI.this.propertyChange( b, e );
}
@Override
public void stateChanged( ChangeEvent e ) {
super.stateChanged( e );
// if button is in toolbar, repaint button groups
AbstractButton b = (AbstractButton) e.getSource();
Container parent = b.getParent();
if( parent instanceof JToolBar ) {
JToolBar toolBar = (JToolBar) parent;
ToolBarUI ui = toolBar.getUI();
if( ui instanceof FlatToolBarUI )
((FlatToolBarUI)ui).repaintButtonGroup( b );
}
}
}
}

View File

@@ -70,6 +70,7 @@ import javax.swing.plaf.basic.BasicComboBoxUI;
import javax.swing.plaf.basic.BasicComboPopup;
import javax.swing.plaf.basic.ComboPopup;
import javax.swing.text.JTextComponent;
import com.formdev.flatlaf.icons.FlatCheckBoxMenuItemIcon;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableField;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableLookupProvider;
@@ -99,7 +100,7 @@ import com.formdev.flatlaf.util.SystemInfo;
* @uiDefault ComboBox.minimumWidth int
* @uiDefault ComboBox.editorColumns int
* @uiDefault ComboBox.maximumRowCount int
* @uiDefault ComboBox.buttonStyle String auto (default), button or none
* @uiDefault ComboBox.buttonStyle String auto (default), button, mac or none
* @uiDefault Component.arrowType String chevron (default) or triangle
* @uiDefault Component.isIntelliJTheme boolean
* @uiDefault ComboBox.editableBackground Color optional; defaults to ComboBox.background
@@ -117,6 +118,9 @@ import com.formdev.flatlaf.util.SystemInfo;
* @uiDefault ComboBox.buttonHoverArrowColor Color
* @uiDefault ComboBox.buttonPressedArrowColor Color
* @uiDefault ComboBox.popupBackground Color optional
* @uiDefault ComboBox.popupInsets Insets
* @uiDefault ComboBox.selectionInsets Insets
* @uiDefault ComboBox.selectionArc int
*
* @author Karl Tauber
*/
@@ -150,6 +154,9 @@ public class FlatComboBoxUI
@Styleable protected Color buttonPressedArrowColor;
@Styleable protected Color popupBackground;
/** @since 3 */ @Styleable protected Insets popupInsets;
/** @since 3 */ @Styleable protected Insets selectionInsets;
/** @since 3 */ @Styleable protected int selectionArc;
private MouseListener hoverListener;
protected boolean hover;
@@ -253,6 +260,9 @@ public class FlatComboBoxUI
buttonPressedArrowColor = UIManager.getColor( "ComboBox.buttonPressedArrowColor" );
popupBackground = UIManager.getColor( "ComboBox.popupBackground" );
popupInsets = UIManager.getInsets( "ComboBox.popupInsets" );
selectionInsets = UIManager.getInsets( "ComboBox.selectionInsets" );
selectionArc = UIManager.getInt( "ComboBox.selectionArc" );
// set maximumRowCount
int maximumRowCount = UIManager.getInt( "ComboBox.maximumRowCount" );
@@ -308,11 +318,14 @@ public class FlatComboBoxUI
// limit button width to height of a raw combobox (without insets)
FontMetrics fm = comboBox.getFontMetrics( comboBox.getFont() );
int maxButtonWidth = fm.getHeight() + scale( padding.top ) + scale( padding.bottom );
int minButtonWidth = (maxButtonWidth * 3) / 4;
// make button square (except if width is limited)
Insets insets = getInsets();
int buttonWidth = Math.min( parent.getPreferredSize().height - insets.top - insets.bottom, maxButtonWidth );
int buttonWidth = Math.min( Math.max( parent.getHeight() - insets.top - insets.bottom, minButtonWidth ), maxButtonWidth );
if( buttonWidth != arrowButton.getWidth() ) {
// set width of arrow button to preferred height of combobox
// set width of arrow button
int xOffset = comboBox.getComponentOrientation().isLeftToRight()
? arrowButton.getWidth() - buttonWidth
: 0;
@@ -556,7 +569,9 @@ public class FlatComboBoxUI
int height = c.getHeight();
int arrowX = arrowButton.getX();
int arrowWidth = arrowButton.getWidth();
boolean paintButton = (comboBox.isEditable() || "button".equals( buttonStyle )) && !"none".equals( buttonStyle );
boolean paintButton = (comboBox.isEditable() || "button".equals( buttonStyle )) &&
!"none".equals( buttonStyle ) &&
!isMacStyle();
boolean enabled = comboBox.isEnabled();
boolean isLeftToRight = comboBox.getComponentOrientation().isLeftToRight();
@@ -574,13 +589,21 @@ public class FlatComboBoxUI
: buttonBackground;
if( buttonColor != null ) {
g2.setColor( buttonColor );
Shape oldClip = g2.getClip();
if( isLeftToRight )
g2.clipRect( arrowX, 0, width - arrowX, height );
else
g2.clipRect( 0, 0, arrowX + arrowWidth, height );
FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc );
g2.setClip( oldClip );
if( isMacStyle() ) {
Insets insets = comboBox.getInsets();
int gap = scale( 2 );
FlatUIUtils.paintComponentBackground( g2, arrowX + gap, insets.top + gap,
arrowWidth - (gap * 2), height - insets.top - insets.bottom - (gap * 2),
0, arc - focusWidth );
} else {
Shape oldClip = g2.getClip();
if( isLeftToRight )
g2.clipRect( arrowX, 0, width - arrowX, height );
else
g2.clipRect( 0, 0, arrowX + arrowWidth, height );
FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc );
g2.setClip( oldClip );
}
}
}
@@ -719,6 +742,10 @@ public class FlatComboBoxUI
return parentParent != null && !comboBox.getBackground().equals( parentParent.getBackground() );
}
private boolean isMacStyle() {
return "mac".equals( buttonStyle );
}
/** @since 1.3 */
public static boolean isPermanentFocusOwner( JComboBox<?> comboBox ) {
if( comboBox.isEditable() ) {
@@ -753,6 +780,21 @@ public class FlatComboBoxUI
buttonHoverArrowColor, null, buttonPressedArrowColor, null );
}
@Override
public int getArrowWidth() {
return isMacStyle() ? (getWidth() % 2 == 0 ? 6 : 7) : super.getArrowWidth();
}
@Override
public float getArrowThickness() {
return isMacStyle() ? 1.5f : super.getArrowThickness();
}
@Override
public boolean isRoundBorderAutoXOffset() {
return isMacStyle() ? false : super.isRoundBorderAutoXOffset();
}
@Override
protected boolean isHover() {
return super.isHover() || (!comboBox.isEditable() ? hover : false);
@@ -770,6 +812,20 @@ public class FlatComboBoxUI
return super.getArrowColor();
}
@Override
protected void paintArrow( Graphics2D g ) {
if( isMacStyle() && !comboBox.isEditable() ) {
// for style "mac", paint up and down arrows if combobox is not editable
int height = getHeight();
int h = Math.round( height / 2f );
FlatUIUtils.paintArrow( g, 0, 0, getWidth(), h, SwingConstants.NORTH, chevron,
getArrowWidth(), getArrowThickness(), getXOffset(), getYOffset() + 1.25f );
FlatUIUtils.paintArrow( g, 0, height - h, getWidth(), h, SwingConstants.SOUTH, chevron,
getArrowWidth(), getArrowThickness(), getXOffset(), getYOffset() - 1.25f );
} else
super.paintArrow( g );
}
}
//---- class FlatComboPopup -----------------------------------------------
@@ -804,12 +860,19 @@ public class FlatComboBoxUI
}
}
// for style "mac", add width of "checked item" icon
boolean isPopupOverComboBox = isPopupOverComboBox();
int selectedIndex = -1;
if( isPopupOverComboBox && (selectedIndex = comboBox.getSelectedIndex()) >= 0 )
displayWidth += MacCheckedItemIcon.INSTANCE.getIconWidth() + scale( CellPaddingBorder.MAC_STYLE_GAP );
// add width of vertical scroll bar
JScrollBar verticalScrollBar = scroller.getVerticalScrollBar();
if( verticalScrollBar != null )
displayWidth += verticalScrollBar.getPreferredSize().width;
// make popup wider if necessary
int pw0 = pw;
if( displayWidth > pw ) {
// limit popup width to screen width
GraphicsConfiguration gc = comboBox.getGraphicsConfiguration();
@@ -829,6 +892,30 @@ public class FlatComboBoxUI
px -= diff;
}
// for style "mac", place popup over combobox
Rectangle cellBounds;
if( isPopupOverComboBox && selectedIndex >= 0 &&
(cellBounds = list.getCellBounds( 0, 0 )) != null )
{
Insets comboBoxInsets = comboBox.getInsets();
Insets listInsets = list.getInsets();
Insets popupInsets = getInsets();
// position popup so that selected item is at same Y position as combobox
py -= (cellBounds.height * (selectedIndex + 1)) + comboBoxInsets.top + listInsets.top + popupInsets.top;
// position popup slightly to the left so that a small part of the right side of the combobox stays visible
int offset = Math.min( pw - pw0, MacCheckedItemIcon.INSTANCE.getIconWidth() ) + scale( 4 );
if( comboBox.getComponentOrientation().isLeftToRight() )
px -= offset + comboBoxInsets.right + listInsets.right;
else
px += offset + comboBoxInsets.left + listInsets.left;
// not invoking super.computePopupBounds() here to let
// JPopupMenu.adjustPopupLocationToFitScreen() fix the location if necessary
return new Rectangle( px, py, pw, ph );
}
return super.computePopupBounds( px, py, pw, ph );
}
@@ -839,17 +926,12 @@ public class FlatComboBoxUI
// make opaque to avoid that background shines thru border (e.g. at 150% scaling)
setOpaque( true );
// set popup border
// use non-UIResource to avoid that it is overwritten when making
// popup visible (see JPopupMenu.setInvoker()) in theme editor preview
// set popup border
// use non-UIResource to avoid that it is overwritten when making
// popup visible (see JPopupMenu.setInvoker()) in theme editor preview
Border border = UIManager.getBorder( "PopupMenu.border" );
if( border != null )
setBorder( FlatUIUtils.nonUIResource( border ) );
}
@Override
protected void configureList() {
super.configureList();
list.setCellRenderer( new PopupListCellRenderer() );
updateStyle();
@@ -857,12 +939,21 @@ public class FlatComboBoxUI
void updateStyle() {
if( popupBackground != null )
list.setBackground( popupBackground );
list.setBackground( popupBackground );
// set popup background because it may shine thru when scaled (e.g. at 150%)
// use non-UIResource to avoid that it is overwritten when making
// popup visible (see JPopupMenu.setInvoker()) in theme editor preview
setBackground( FlatUIUtils.nonUIResource( list.getBackground() ) );
// set popup background because it may shine thru when scaled (e.g. at 150%)
// use non-UIResource to avoid that it is overwritten when making
// popup visible (see JPopupMenu.setInvoker()) in theme editor preview
setBackground( FlatUIUtils.nonUIResource( list.getBackground() ) );
scroller.setViewportBorder( (popupInsets != null) ? new FlatEmptyBorder( popupInsets ) : null );
scroller.setOpaque( false );
if( list.getUI() instanceof FlatListUI ) {
FlatListUI ui = (FlatListUI) list.getUI();
ui.selectionInsets = selectionInsets;
ui.selectionArc = selectionArc;
}
}
@Override
@@ -904,6 +995,15 @@ public class FlatComboBoxUI
paddingBorder.uninstall();
}
private boolean isPopupOverComboBox() {
return isMacStyle() &&
!comboBox.isEditable() &&
comboBox.getItemCount() > 0 &&
comboBox.getItemCount() <= comboBox.getMaximumRowCount() &&
// for compatibility with Aqua Laf
!clientPropertyBoolean( comboBox, "JComboBox.isPopDown", false );
}
//---- class PopupListCellRenderer -----
private class PopupListCellRenderer
@@ -921,6 +1021,13 @@ public class FlatComboBoxUI
Component c = renderer.getListCellRendererComponent( list, value, index, isSelected, cellHasFocus );
c.applyComponentOrientation( comboBox.getComponentOrientation() );
// style "mac"
if( isPopupOverComboBox() && c instanceof JComponent ) {
int selectedIndex = comboBox.getSelectedIndex();
((JComponent)c).putClientProperty( CellPaddingBorder.KEY_MAC_STYLE_HINT,
(selectedIndex >= 0) ? (index == selectedIndex) : null );
}
paddingBorder.install( c, Math.round( FlatUIUtils.getBorderFocusWidth( comboBox ) ) );
return c;
@@ -937,10 +1044,16 @@ public class FlatComboBoxUI
* which vertically aligns text in popup list with text in combobox.
* <p>
* The renderer border is painted on the outer side of this border.
* <p>
* For button style "mac", also used to increase insets on left side for
* "checked item" icon and to paint "checked item" icon for selected combobox item.
*/
private static class CellPaddingBorder
extends AbstractBorder
{
static final String KEY_MAC_STYLE_HINT = "FlatLaf.internal.FlatComboBoxUI.macStyleHint";
static final int MAC_STYLE_GAP = 4;
private Insets padding;
private JComponent rendererComponent;
private Border rendererBorder;
@@ -990,6 +1103,8 @@ public class FlatComboBoxUI
if( rendererComponent == null )
return;
rendererComponent.putClientProperty( KEY_MAC_STYLE_HINT, null );
if( rendererComponent.getBorder() == this )
rendererComponent.setBorder( rendererBorder );
rendererComponent = null;
@@ -1017,6 +1132,18 @@ public class FlatComboBoxUI
insets.left += focusWidth;
insets.right += focusWidth;
// style "mac"
if( c instanceof JComponent ) {
Boolean macStyleHint = clientPropertyBooleanStrict( (JComponent) c, KEY_MAC_STYLE_HINT, null );
if( macStyleHint != null ) {
int indent = MacCheckedItemIcon.INSTANCE.getIconWidth() + scale( MAC_STYLE_GAP );
if( c.getComponentOrientation().isLeftToRight() )
insets.left += indent;
else
insets.right += indent;
}
}
return insets;
}
@@ -1024,6 +1151,35 @@ public class FlatComboBoxUI
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
if( rendererBorder != null )
rendererBorder.paintBorder( c, g, x, y, width, height );
// style "mac"
if( c instanceof JComponent ) {
Boolean macStyleHint = clientPropertyBooleanStrict( (JComponent) c, KEY_MAC_STYLE_HINT, null );
if( macStyleHint == Boolean.TRUE ) {
// paint "checked item" icon
int ix = c.getComponentOrientation().isLeftToRight()
? x + scale( padding.left )
: x + width - scale( padding.right ) - MacCheckedItemIcon.INSTANCE.getIconWidth();
MacCheckedItemIcon.INSTANCE.paintIcon( c, g, ix, y + ((height - MacCheckedItemIcon.INSTANCE.getIconHeight()) / 2) );
}
}
}
}
//---- class MacCheckedItemIcon -------------------------------------------
/**
* Use for style "mac" to mark checked item.
*/
private static class MacCheckedItemIcon
extends FlatCheckBoxMenuItemIcon
{
static MacCheckedItemIcon INSTANCE = new MacCheckedItemIcon();
@Override
protected void paintIcon( Component c, Graphics2D g2 ) {
g2.setColor( c.getForeground() );
paintCheckmark( g2 );
}
}

View File

@@ -243,11 +243,13 @@ public class FlatFileChooserUI
borderLayout.setHgap( 8 );
Component north = borderLayout.getLayoutComponent( BorderLayout.NORTH );
Component lineEnd = borderLayout.getLayoutComponent( BorderLayout.LINE_END );
Component center = borderLayout.getLayoutComponent( BorderLayout.CENTER );
Component south = borderLayout.getLayoutComponent( BorderLayout.SOUTH );
if( north != null && center != null && south != null ) {
if( north != null && lineEnd != null && center != null && south != null ) {
JPanel p = new JPanel( new BorderLayout( 0, 11 ) );
p.add( north, BorderLayout.NORTH );
p.add( lineEnd, BorderLayout.LINE_END );
p.add( center, BorderLayout.CENTER );
p.add( south, BorderLayout.SOUTH );
fc.add( p, BorderLayout.CENTER );

View File

@@ -17,20 +17,34 @@
package com.formdev.flatlaf.ui;
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.beans.PropertyChangeListener;
import java.util.Map;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JComponent;
import javax.swing.JList;
import javax.swing.ListCellRenderer;
import javax.swing.ListModel;
import javax.swing.ListSelectionModel;
import javax.swing.UIManager;
import javax.swing.event.ListSelectionListener;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicComboBoxRenderer;
import javax.swing.plaf.basic.BasicListUI;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.util.Graphics2DProxy;
import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.UIScale;
/**
* Provides the Flat LaF UI delegate for {@link javax.swing.JList}.
@@ -59,6 +73,8 @@ import com.formdev.flatlaf.util.LoggingFacade;
*
* @uiDefault List.selectionInactiveBackground Color
* @uiDefault List.selectionInactiveForeground Color
* @uiDefault List.selectionInsets Insets
* @uiDefault List.selectionArc int
*
* <!-- FlatListCellBorder -->
*
@@ -76,6 +92,8 @@ public class FlatListUI
@Styleable protected Color selectionForeground;
@Styleable protected Color selectionInactiveBackground;
@Styleable protected Color selectionInactiveForeground;
/** @since 3 */ @Styleable protected Insets selectionInsets;
/** @since 3 */ @Styleable protected int selectionArc;
// for FlatListCellBorder
/** @since 2 */ @Styleable protected Insets cellMargins;
@@ -110,6 +128,8 @@ public class FlatListUI
selectionForeground = UIManager.getColor( "List.selectionForeground" );
selectionInactiveBackground = UIManager.getColor( "List.selectionInactiveBackground" );
selectionInactiveForeground = UIManager.getColor( "List.selectionInactiveForeground" );
selectionInsets = UIManager.getInsets( "List.selectionInsets" );
selectionArc = UIManager.getInt( "List.selectionArc" );
toggleSelectionColors();
}
@@ -168,6 +188,29 @@ public class FlatListUI
};
}
@Override
protected ListSelectionListener createListSelectionListener() {
ListSelectionListener superListener = super.createListSelectionListener();
return e -> {
superListener.valueChanged( e );
// for united rounded selection, repaint parts of the rows/columns that adjoin to the changed rows/columns
if( useUnitedRoundedSelection( true, true ) &&
!list.isSelectionEmpty() &&
(list.getMaxSelectionIndex() - list.getMinSelectionIndex()) >= 1 )
{
int size = list.getModel().getSize();
int firstIndex = Math.min( Math.max( e.getFirstIndex(), 0 ), size - 1 );
int lastIndex = Math.min( Math.max( e.getLastIndex(), 0 ), size - 1 );
Rectangle r = getCellBounds( list, firstIndex, lastIndex );
if( r != null ) {
int arc = (int) Math.ceil( UIScale.scale( selectionArc / 2f ) );
list.repaint( r.x - arc, r.y - arc, r.width + (arc * 2), r.height + (arc * 2) );
}
}
};
}
/** @since 2 */
protected void installStyle() {
try {
@@ -247,4 +290,164 @@ public class FlatListUI
list.setSelectionForeground( selectionInactiveForeground );
}
}
@SuppressWarnings( "rawtypes" )
@Override
protected void paintCell( Graphics g, int row, Rectangle rowBounds, ListCellRenderer cellRenderer,
ListModel dataModel, ListSelectionModel selModel, int leadIndex )
{
boolean isSelected = selModel.isSelectedIndex( row );
// get renderer component
@SuppressWarnings( "unchecked" )
Component rendererComponent = cellRenderer.getListCellRendererComponent( list,
dataModel.getElementAt( row ), row, isSelected, list.hasFocus() && (row == leadIndex) );
//
boolean isFileList = Boolean.TRUE.equals( list.getClientProperty( "List.isFileList" ) );
int cx, cw;
if( isFileList ) {
// see BasicListUI.paintCell()
cw = Math.min( rowBounds.width, rendererComponent.getPreferredSize().width + 4 );
cx = list.getComponentOrientation().isLeftToRight()
? rowBounds.x
: rowBounds.x + (rowBounds.width - cw);
} else {
cx = rowBounds.x;
cw = rowBounds.width;
}
// rounded selection or selection insets
if( isSelected &&
!isFileList && // rounded selection is not supported for file list
(rendererComponent instanceof DefaultListCellRenderer ||
rendererComponent instanceof BasicComboBoxRenderer) &&
(selectionArc > 0 ||
(selectionInsets != null &&
(selectionInsets.top != 0 || selectionInsets.left != 0 || selectionInsets.bottom != 0 || selectionInsets.right != 0))) )
{
// Because selection painting is done in the cell renderer, it would be
// necessary to require a FlatLaf specific renderer to implement rounded selection.
// Using a LaF specific renderer was avoided because often a custom renderer is
// already used in applications. Then either the rounded selection is not used,
// or the application has to be changed to extend a FlatLaf renderer.
//
// To solve this, a graphics proxy is used that paints rounded selection
// if row is selected and the renderer wants to fill the background.
class RoundedSelectionGraphics extends Graphics2DProxy {
// used to avoid endless loop in case that paintCellSelection() invokes
// g.fillRect() with full bounds (selectionInsets is 0,0,0,0)
private boolean inPaintSelection;
RoundedSelectionGraphics( Graphics delegate ) {
super( (Graphics2D) delegate );
}
@Override
public Graphics create() {
return new RoundedSelectionGraphics( super.create() );
}
@Override
public Graphics create( int x, int y, int width, int height ) {
return new RoundedSelectionGraphics( super.create( x, y, width, height ) );
}
@Override
public void fillRect( int x, int y, int width, int height ) {
if( !inPaintSelection &&
x == 0 && y == 0 && width == rowBounds.width && height == rowBounds.height &&
this.getColor() == rendererComponent.getBackground() )
{
inPaintSelection = true;
paintCellSelection( this, row, x, y, width, height );
inPaintSelection = false;
} else
super.fillRect( x, y, width, height );
}
}
g = new RoundedSelectionGraphics( g );
}
// paint renderer
rendererPane.paintComponent( g, rendererComponent, list, cx, rowBounds.y, cw, rowBounds.height, true );
}
/** @since 3 */
protected void paintCellSelection( Graphics g, int row, int x, int y, int width, int height ) {
float arcTopLeft, arcTopRight, arcBottomLeft, arcBottomRight;
arcTopLeft = arcTopRight = arcBottomLeft = arcBottomRight = UIScale.scale( selectionArc / 2f );
if( list.getLayoutOrientation() == JList.VERTICAL ) {
// layout orientation: VERTICAL
if( useUnitedRoundedSelection( true, false ) ) {
if( row > 0 && list.isSelectedIndex( row - 1 ) )
arcTopLeft = arcTopRight = 0;
if( row < list.getModel().getSize() - 1 && list.isSelectedIndex( row + 1 ) )
arcBottomLeft = arcBottomRight = 0;
}
} else {
// layout orientation: VERTICAL_WRAP or HORIZONTAL_WRAP
Rectangle r = null;
if( useUnitedRoundedSelection( true, false ) ) {
// vertical: check whether cells above or below are selected
r = getCellBounds( list, row, row );
int topIndex = locationToIndex( list, new Point( r.x, r.y - 1 ) );
int bottomIndex = locationToIndex( list, new Point( r.x, r.y + r.height ) );
if( topIndex >= 0 && topIndex != row && list.isSelectedIndex( topIndex ) )
arcTopLeft = arcTopRight = 0;
if( bottomIndex >= 0 && bottomIndex != row && list.isSelectedIndex( bottomIndex ) )
arcBottomLeft = arcBottomRight = 0;
}
if( useUnitedRoundedSelection( false, true ) ) {
// horizontal: check whether cells left or right are selected
if( r == null )
r = getCellBounds( list, row, row );
int leftIndex = locationToIndex( list, new Point( r.x - 1, r.y ) );
int rightIndex = locationToIndex( list, new Point( r.x + r.width, r.y ) );
// special handling for the case that last column contains less cells than the other columns
boolean ltr = list.getComponentOrientation().isLeftToRight();
if( !ltr && leftIndex >= 0 && leftIndex != row && leftIndex == locationToIndex( list, new Point( r.x - 1, r.y - 1 ) ) )
leftIndex = -1;
if( ltr && rightIndex >= 0 && rightIndex != row && rightIndex == locationToIndex( list, new Point( r.x + r.width, r.y - 1 ) ) )
rightIndex = -1;
if( leftIndex >= 0 && leftIndex != row && list.isSelectedIndex( leftIndex ) )
arcTopLeft = arcBottomLeft = 0;
if( rightIndex >= 0 && rightIndex != row && list.isSelectedIndex( rightIndex ) )
arcTopRight = arcBottomRight = 0;
}
}
FlatUIUtils.paintSelection( (Graphics2D) g, x, y, width, height,
UIScale.scale( selectionInsets ), arcTopLeft, arcTopRight, arcBottomLeft, arcBottomRight, 0 );
}
private boolean useUnitedRoundedSelection( boolean vertical, boolean horizontal ) {
return selectionArc > 0 &&
(selectionInsets == null ||
(vertical && selectionInsets.top == 0 && selectionInsets.bottom == 0) ||
(horizontal && selectionInsets.left == 0 && selectionInsets.right == 0));
}
/**
* Paints a cell selection at the given coordinates.
* The selection color must be set on the graphics context.
* <p>
* This method is intended for use in custom cell renderers.
*
* @since 3
*/
public static void paintCellSelection( JList<?> list, Graphics g, int row, int x, int y, int width, int height ) {
if( !(list.getUI() instanceof FlatListUI) )
return;
FlatListUI ui = (FlatListUI) list.getUI();
ui.paintCellSelection( g, row, x, y, width, height );
}
}

View File

@@ -75,6 +75,9 @@ public class FlatMenuBarUI
/** @since 2 */ @Styleable protected Insets itemMargins;
// used in FlatMenuUI
/** @since 3 */ @Styleable protected Insets selectionInsets;
/** @since 3 */ @Styleable protected Insets selectionEmbeddedInsets;
/** @since 3 */ @Styleable protected int selectionArc = -1;
/** @since 2 */ @Styleable protected Color hoverBackground;
/** @since 2.5 */ @Styleable protected Color selectionBackground;
/** @since 2.5 */ @Styleable protected Color selectionForeground;

View File

@@ -63,6 +63,8 @@ import com.formdev.flatlaf.util.SystemInfo;
* @uiDefault MenuItem.acceleratorArrowGap int
* @uiDefault MenuItem.checkBackground Color
* @uiDefault MenuItem.checkMargins Insets
* @uiDefault MenuItem.selectionInsets Insets
* @uiDefault MenuItem.selectionArc int
* @uiDefault MenuItem.selectionType String null (default) or underline
* @uiDefault MenuItem.underlineSelectionBackground Color
* @uiDefault MenuItem.underlineSelectionCheckBackground Color
@@ -91,6 +93,9 @@ public class FlatMenuItemRenderer
@Styleable protected Color checkBackground = UIManager.getColor( "MenuItem.checkBackground" );
@Styleable protected Insets checkMargins = UIManager.getInsets( "MenuItem.checkMargins" );
/** @since 3 */ @Styleable protected Insets selectionInsets = UIManager.getInsets( "MenuItem.selectionInsets" );
/** @since 3 */ @Styleable protected int selectionArc = UIManager.getInt( "MenuItem.selectionArc" );
@Styleable protected Color underlineSelectionBackground = UIManager.getColor( "MenuItem.underlineSelectionBackground" );
@Styleable protected Color underlineSelectionCheckBackground = UIManager.getColor( "MenuItem.underlineSelectionCheckBackground" );
@Styleable protected Color underlineSelectionColor = UIManager.getColor( "MenuItem.underlineSelectionColor" );
@@ -337,10 +342,16 @@ public class FlatMenuItemRenderer
g.setColor( Color.orange ); g.drawRect( arrowRect.x, arrowRect.y, arrowRect.width - 1, arrowRect.height - 1 );
debug*/
boolean armedOrSelected = isArmedOrSelected( menuItem );
boolean underlineSelection = isUnderlineSelection();
paintBackground( g, underlineSelection ? underlineSelectionBackground : selectionBackground );
if( underlineSelection && isArmedOrSelected( menuItem ) )
paintUnderlineSelection( g, underlineSelectionColor, underlineSelectionHeight );
paintBackground( g );
if( armedOrSelected ) {
if( underlineSelection )
paintUnderlineSelection( g, underlineSelectionBackground, underlineSelectionColor, underlineSelectionHeight );
else
paintSelection( g, selectionBackground, selectionInsets, selectionArc );
}
paintIcon( g, iconRect, getIconForPainting(), underlineSelection ? underlineSelectionCheckBackground : checkBackground, selectionBackground );
paintText( g, textRect, menuItem.getText(), selectionForeground, disabledForeground );
paintAccelerator( g, accelRect, getAcceleratorText(), acceleratorForeground, acceleratorSelectionForeground, disabledForeground );
@@ -348,21 +359,35 @@ debug*/
paintArrowIcon( g, arrowRect, arrowIcon );
}
protected void paintBackground( Graphics g, Color selectionBackground ) {
boolean armedOrSelected = isArmedOrSelected( menuItem );
if( menuItem.isOpaque() || armedOrSelected ) {
// paint background
g.setColor( armedOrSelected
? deriveBackground( selectionBackground )
: menuItem.getBackground() );
/** @since 3 */
protected void paintBackground( Graphics g ) {
if( menuItem.isOpaque() ) {
g.setColor( menuItem.getBackground() );
g.fillRect( 0, 0, menuItem.getWidth(), menuItem.getHeight() );
}
}
protected void paintUnderlineSelection( Graphics g, Color underlineSelectionColor, int underlineSelectionHeight ) {
/** @since 3 */
protected void paintSelection( Graphics g, Color selectionBackground, Insets selectionInsets, int selectionArc ) {
float arc = scale( selectionArc / 2f );
g.setColor( deriveBackground( selectionBackground ) );
FlatUIUtils.paintSelection( (Graphics2D) g, 0, 0, menuItem.getWidth(), menuItem.getHeight(),
scale( selectionInsets ), arc, arc, arc, arc, 0 );
}
/** @since 3 */
protected void paintUnderlineSelection( Graphics g, Color underlineSelectionBackground,
Color underlineSelectionColor, int underlineSelectionHeight )
{
int width = menuItem.getWidth();
int height = menuItem.getHeight();
// paint background
g.setColor( deriveBackground( underlineSelectionBackground ) );
g.fillRect( 0, 0, width, height );
// paint underline
int underlineHeight = scale( underlineSelectionHeight );
g.setColor( underlineSelectionColor );
if( isTopLevelMenu( menuItem ) ) {
@@ -500,7 +525,11 @@ debug*/
private Font getTopLevelFont() {
Font font = menuItem.getFont();
return (font != menuFont) ? font : menuItem.getParent().getFont();
// menu item parent may be null if JMenu.isTopLevelMenu() is overridden
// and does not check parent (e.g. com.jidesoft.swing.JideMenu.isTopLevelMenu())
return (font != menuFont || menuItem.getParent() == null)
? font
: menuItem.getParent().getFont();
}
private Icon getIconForPainting() {

View File

@@ -20,7 +20,9 @@ import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeListener;
import java.lang.invoke.MethodHandles;
@@ -32,7 +34,9 @@ import javax.swing.JComponent;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JRootPane;
import javax.swing.LookAndFeel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.event.MouseInputListener;
import javax.swing.plaf.ComponentUI;
@@ -75,9 +79,12 @@ import com.formdev.flatlaf.util.LoggingFacade;
*
* <!-- FlatMenuRenderer -->
*
* @uiDefault MenuBar.selectionInsets Insets
* @uiDefault MenuBar.selectionEmbeddedInsets Insets
* @uiDefault MenuBar.selectionArc int
* @uiDefault MenuBar.hoverBackground Color
* @uiDefault MenuBar.selectionBackground Color
* @uiDefault MenuBar.selectionForeground Color
* @uiDefault MenuBar.selectionBackground Color optional; defaults to Menu.selectionBackground
* @uiDefault MenuBar.selectionForeground Color optional; defaults to Menu.selectionForeground
* @uiDefault MenuBar.underlineSelectionBackground Color
* @uiDefault MenuBar.underlineSelectionColor Color
* @uiDefault MenuBar.underlineSelectionHeight int
@@ -225,12 +232,15 @@ public class FlatMenuUI
protected class FlatMenuRenderer
extends FlatMenuItemRenderer
{
/** @since 3 */ protected Insets menuBarSelectionInsets = UIManager.getInsets( "MenuBar.selectionInsets" );
/** @since 3 */ protected Insets menuBarSelectionEmbeddedInsets = UIManager.getInsets( "MenuBar.selectionEmbeddedInsets" );
/** @since 3 */ protected int menuBarSelectionArc = UIManager.getInt( "MenuBar.selectionArc" );
protected Color hoverBackground = UIManager.getColor( "MenuBar.hoverBackground" );
protected Color menuBarSelectionBackground = UIManager.getColor( "MenuBar.selectionBackground" );
protected Color menuBarSelectionForeground = UIManager.getColor( "MenuBar.selectionForeground" );
protected Color menuBarUnderlineSelectionBackground = FlatUIUtils.getUIColor( "MenuBar.underlineSelectionBackground", underlineSelectionBackground );
protected Color menuBarUnderlineSelectionColor = FlatUIUtils.getUIColor( "MenuBar.underlineSelectionColor", underlineSelectionColor );
protected int menuBarUnderlineSelectionHeight = FlatUIUtils.getUIInt( "MenuBar.underlineSelectionHeight", underlineSelectionHeight );
/** @since 2.5 */ protected Color menuBarSelectionBackground = UIManager.getColor( "MenuBar.selectionBackground" );
/** @since 2.5 */ protected Color menuBarSelectionForeground = UIManager.getColor( "MenuBar.selectionForeground" );
protected Color menuBarUnderlineSelectionBackground = UIManager.getColor( "MenuBar.underlineSelectionBackground" );
protected Color menuBarUnderlineSelectionColor = UIManager.getColor( "MenuBar.underlineSelectionColor" );
protected int menuBarUnderlineSelectionHeight = FlatUIUtils.getUIInt( "MenuBar.underlineSelectionHeight", -1 );
protected FlatMenuRenderer( JMenuItem menuItem, Icon checkIcon, Icon arrowIcon,
Font acceleratorFont, String acceleratorDelimiter )
@@ -238,46 +248,76 @@ public class FlatMenuUI
super( menuItem, checkIcon, arrowIcon, acceleratorFont, acceleratorDelimiter );
}
/** @since 3 */
@Override
protected void paintBackground( Graphics g, Color selectionBackground ) {
if( ((JMenu)menuItem).isTopLevelMenu() ) {
if( isUnderlineSelection() )
selectionBackground = getStyleFromMenuBarUI( ui -> ui.underlineSelectionBackground, menuBarUnderlineSelectionBackground );
else {
selectionBackground = getStyleFromMenuBarUI( ui -> ui.selectionBackground,
menuBarSelectionBackground != null ? menuBarSelectionBackground : selectionBackground );
}
protected void paintBackground( Graphics g ) {
super.paintBackground( g );
ButtonModel model = menuItem.getModel();
if( model.isRollover() && !model.isArmed() && !model.isSelected() && model.isEnabled() ) {
g.setColor( deriveBackground( getStyleFromMenuBarUI( ui -> ui.hoverBackground, hoverBackground ) ) );
if( ((JMenu)menuItem).isTopLevelMenu() && isHover() ) {
// paint hover background
Color color = deriveBackground( getStyleFromMenuBarUI( ui -> ui.hoverBackground, hoverBackground ) );
if( isUnderlineSelection() ) {
g.setColor( color );
g.fillRect( 0, 0, menuItem.getWidth(), menuItem.getHeight() );
return;
}
} else
paintSelection( g, color, selectionInsets, selectionArc );
}
}
/** @since 3 */
@Override
protected void paintSelection( Graphics g, Color selectionBackground, Insets selectionInsets, int selectionArc ) {
if( ((JMenu)menuItem).isTopLevelMenu() ) {
if( !isHover() )
selectionBackground = getStyleFromMenuBarUI( ui -> ui.selectionBackground, menuBarSelectionBackground, selectionBackground );
JMenuBar menuBar = (JMenuBar) menuItem.getParent();
JRootPane rootPane = SwingUtilities.getRootPane( menuBar );
if( rootPane != null && rootPane.getParent() instanceof Window &&
rootPane.getJMenuBar() == menuBar &&
FlatRootPaneUI.isMenuBarEmbedded( rootPane ) )
{
selectionInsets = getStyleFromMenuBarUI( ui -> ui.selectionEmbeddedInsets, menuBarSelectionEmbeddedInsets );
} else
selectionInsets = getStyleFromMenuBarUI( ui -> ui.selectionInsets, menuBarSelectionInsets );
selectionArc = getStyleFromMenuBarUI( ui -> (ui.selectionArc != -1)
? ui.selectionArc : null, menuBarSelectionArc );
}
super.paintBackground( g, selectionBackground );
super.paintSelection( g, selectionBackground, selectionInsets, selectionArc );
}
/** @since 3 */
@Override
protected void paintUnderlineSelection( Graphics g, Color underlineSelectionBackground,
Color underlineSelectionColor, int underlineSelectionHeight )
{
if( ((JMenu)menuItem).isTopLevelMenu() ) {
underlineSelectionBackground = getStyleFromMenuBarUI( ui -> ui.underlineSelectionBackground, menuBarUnderlineSelectionBackground, underlineSelectionBackground );
underlineSelectionColor = getStyleFromMenuBarUI( ui -> ui.underlineSelectionColor, menuBarUnderlineSelectionColor, underlineSelectionColor );
underlineSelectionHeight = getStyleFromMenuBarUI( ui -> (ui.underlineSelectionHeight != -1) ? ui.underlineSelectionHeight : null,
(menuBarUnderlineSelectionHeight != -1) ? menuBarUnderlineSelectionHeight : underlineSelectionHeight );
}
super.paintUnderlineSelection( g, underlineSelectionBackground, underlineSelectionColor, underlineSelectionHeight );
}
@Override
protected void paintText( Graphics g, Rectangle textRect, String text, Color selectionForeground, Color disabledForeground ) {
if( ((JMenu)menuItem).isTopLevelMenu() && !isUnderlineSelection() ) {
selectionForeground = getStyleFromMenuBarUI( ui -> ui.selectionForeground,
menuBarSelectionForeground != null ? menuBarSelectionForeground : selectionForeground );
}
if( ((JMenu)menuItem).isTopLevelMenu() && !isUnderlineSelection() )
selectionForeground = getStyleFromMenuBarUI( ui -> ui.selectionForeground, menuBarSelectionForeground, selectionForeground );
super.paintText( g, textRect, text, selectionForeground, disabledForeground );
}
@Override
protected void paintUnderlineSelection( Graphics g, Color underlineSelectionColor, int underlineSelectionHeight ) {
if( ((JMenu)menuItem).isTopLevelMenu() ) {
underlineSelectionColor = getStyleFromMenuBarUI( ui -> ui.underlineSelectionColor, menuBarUnderlineSelectionColor );
underlineSelectionHeight = getStyleFromMenuBarUI( ui -> (ui.underlineSelectionHeight != -1)
? ui.underlineSelectionHeight : null, menuBarUnderlineSelectionHeight );
}
private boolean isHover() {
ButtonModel model = menuItem.getModel();
return model.isRollover() && !model.isArmed() && !model.isSelected() && model.isEnabled();
}
super.paintUnderlineSelection( g, underlineSelectionColor, underlineSelectionHeight );
private <T> T getStyleFromMenuBarUI( Function<FlatMenuBarUI, T> f, T defaultValue, T defaultValue2 ) {
return getStyleFromMenuBarUI( f, (defaultValue != null) ? defaultValue : defaultValue2 );
}
private <T> T getStyleFromMenuBarUI( Function<FlatMenuBarUI, T> f, T defaultValue ) {

View File

@@ -48,27 +48,25 @@ class FlatNativeLibrary
String libraryName;
if( SystemInfo.isWindows_10_orLater && (SystemInfo.isX86 || SystemInfo.isX86_64) ) {
// Windows: requires Windows 10 (x86 or x86_64)
// Windows: requires Windows 10/11 (x86 or x86_64)
libraryName = "flatlaf-windows-x86";
if( SystemInfo.isX86_64 )
libraryName += "_64";
// load jawt native library
if( !SystemInfo.isJava_9_orLater ) {
// 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.
loadJAWT();
}
// In Java 8, load jawt.dll (part of JRE) explicitly because it
// is not found when running application with <jdk>/bin/java.exe.
// When using <jdk>/jre/bin/java.exe, it is found.
// jawt.dll is located in <jdk>/jre/bin/.
// Java 9 and later do not have this problem,
// but load jawt.dll anyway to be on the safe side.
loadJAWT();
} else if( SystemInfo.isLinux && SystemInfo.isX86_64 ) {
// Linux: requires x86_64
libraryName = "flatlaf-linux-x86_64";
// Load jawt.so (part of JRE) explicitly because it is not found
// Load libjawt.so (part of JRE) explicitly because it is not found
// in all Java versions/distributions.
// E.g. not found in Java 13 and later from openjdk.java.net.
// There seems to be also differences between distributions.
@@ -84,11 +82,19 @@ class FlatNativeLibrary
private static NativeLibrary createNativeLibrary( String libraryName ) {
String libraryPath = System.getProperty( FlatSystemProperties.NATIVE_LIBRARY_PATH );
if( libraryPath != null ) {
File libraryFile = new File( libraryPath, System.mapLibraryName( libraryName ) );
if( libraryFile.exists() )
return new NativeLibrary( libraryFile, true );
else
if( "system".equals( libraryPath ) ) {
NativeLibrary library = new NativeLibrary( libraryName, true );
if( library.isLoaded() )
return library;
LoggingFacade.INSTANCE.logSevere( "Did not find library " + libraryName + " in java.library.path, using extracted library instead", null );
} else {
File libraryFile = new File( libraryPath, System.mapLibraryName( libraryName ) );
if( libraryFile.exists() )
return new NativeLibrary( libraryFile, true );
LoggingFacade.INSTANCE.logSevere( "Did not find external library " + libraryFile + ", using extracted library instead", null );
}
}
return new NativeLibrary( "com/formdev/flatlaf/natives/" + libraryName, null, true );
@@ -101,9 +107,9 @@ class FlatNativeLibrary
// log error only if native library jawt.dll not already loaded
String message = ex.getMessage();
if( message == null || !message.contains( "already loaded in another classloader" ) )
LoggingFacade.INSTANCE.logSevere( null, ex );
LoggingFacade.INSTANCE.logSevere( message, ex );
} catch( Exception ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex );
LoggingFacade.INSTANCE.logSevere( ex.getMessage(), ex );
}
}
}

View File

@@ -349,11 +349,23 @@ public class FlatRootPaneUI
titlePane.updateIcon();
break;
case FlatClientProperties.TITLE_BAR_SHOW_TITLE:
case FlatClientProperties.TITLE_BAR_SHOW_ICONIFFY:
case FlatClientProperties.TITLE_BAR_SHOW_MAXIMIZE:
case FlatClientProperties.TITLE_BAR_SHOW_CLOSE:
if( titlePane != null )
titlePane.updateVisibility();
break;
case FlatClientProperties.TITLE_BAR_BACKGROUND:
case FlatClientProperties.TITLE_BAR_FOREGROUND:
if( titlePane != null )
titlePane.titleBarColorsChanged();
break;
case FlatClientProperties.GLASS_PANE_FULL_HEIGHT:
rootPane.revalidate();
break;
}
}
@@ -434,11 +446,11 @@ public class FlatRootPaneUI
int width = rootPane.getWidth() - insets.left - insets.right;
int height = rootPane.getHeight() - insets.top - insets.bottom;
// layered pane
if( rootPane.getLayeredPane() != null )
rootPane.getLayeredPane().setBounds( x, y, width, height );
if( rootPane.getGlassPane() != null )
rootPane.getGlassPane().setBounds( x, y, width, height );
// title pane
int nextY = 0;
if( titlePane != null ) {
int prefHeight = !isFullScreen ? titlePane.getPreferredSize().height : 0;
@@ -446,6 +458,15 @@ public class FlatRootPaneUI
nextY += prefHeight;
}
// glass pane
if( rootPane.getGlassPane() != null ) {
boolean fullHeight = FlatClientProperties.clientPropertyBoolean(
rootPane, FlatClientProperties.GLASS_PANE_FULL_HEIGHT, false );
int offset = fullHeight ? 0 : nextY;
rootPane.getGlassPane().setBounds( x, y + offset, width, height - offset );
}
// menu bar
JMenuBar menuBar = rootPane.getJMenuBar();
if( menuBar != null && menuBar.isVisible() ) {
boolean embedded = !isFullScreen && titlePane != null && titlePane.isMenuBarEmbedded();
@@ -459,10 +480,12 @@ public class FlatRootPaneUI
}
}
// content pane
Container contentPane = rootPane.getContentPane();
if( contentPane != null )
contentPane.setBounds( 0, nextY, width, Math.max( height - nextY, 0 ) );
// title pane
if( titlePane != null )
titlePane.menuBarLayouted();
}

View File

@@ -17,7 +17,10 @@
package com.formdev.flatlaf.ui;
import java.awt.Component;
import java.awt.Graphics;
import javax.swing.JSpinner;
import javax.swing.UIManager;
import javax.swing.plaf.SpinnerUI;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
/**
@@ -35,6 +38,19 @@ public class FlatRoundBorder
// only used via styling (not in UI defaults, but has likewise client properties)
/** @since 2 */ @Styleable protected Boolean roundRect;
@Override
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
// make mac style spinner border smaller (border does not surround arrow buttons)
if( isMacStyleSpinner( c ) ) {
int macStyleButtonsWidth = ((FlatSpinnerUI)((JSpinner)c).getUI()).getMacStyleButtonsWidth();
width -= macStyleButtonsWidth;
if( !c.getComponentOrientation().isLeftToRight() )
x += macStyleButtonsWidth;
}
super.paintBorder( c, g, x, y, width, height );
}
@Override
protected int getArc( Component c ) {
if( isCellEditor( c ) )
@@ -43,6 +59,17 @@ public class FlatRoundBorder
Boolean roundRect = FlatUIUtils.isRoundRect( c );
if( roundRect == null )
roundRect = this.roundRect;
return roundRect != null ? (roundRect ? Short.MAX_VALUE : 0) : arc;
return roundRect != null
? (roundRect ? Short.MAX_VALUE : 0)
: (isMacStyleSpinner( c ) ? 0 : arc);
}
private boolean isMacStyleSpinner( Component c ) {
if( c instanceof JSpinner ) {
SpinnerUI ui = ((JSpinner)c).getUI();
if( ui instanceof FlatSpinnerUI )
return ((FlatSpinnerUI)ui).isMacStyle();
}
return false;
}
}

View File

@@ -352,6 +352,9 @@ public class FlatScrollBarUI
@Override
protected void paintTrack( Graphics g, JComponent c, Rectangle trackBounds ) {
if( trackBounds.isEmpty() || !scrollbar.isEnabled() )
return;
g.setColor( getTrackColor( c, hoverTrack, isPressed && hoverTrack && !hoverThumb ) );
paintTrackOrThumb( g, c, trackBounds, trackInsets, trackArc );
}
@@ -452,18 +455,31 @@ public class FlatScrollBarUI
@Override
public void mousePressed( MouseEvent e ) {
isPressed = true;
repaint();
if( SwingUtilities.isLeftMouseButton( e ) || isAbsolutePositioning( e ) ) {
isPressed = true;
repaint();
// update hover because BasicScrollBarUI.TrackListener.mousePressed()
// moves the track on middle-click (if absolute positioning is enabled)
if( isAbsolutePositioning( e ) )
update( e.getX(), e.getY() );
}
}
@Override
public void mouseReleased( MouseEvent e ) {
isPressed = false;
repaint();
if( SwingUtilities.isLeftMouseButton( e ) || isAbsolutePositioning( e ) ) {
isPressed = false;
repaint();
}
update( e.getX(), e.getY() );
}
private boolean isAbsolutePositioning( MouseEvent e ) {
return getSupportsAbsolutePositioning() && SwingUtilities.isMiddleMouseButton( e );
}
private void update( int x, int y ) {
boolean inTrack = getTrackBounds().contains( x, y );
boolean inThumb = getThumbBounds().contains( x, y );

View File

@@ -531,7 +531,7 @@ debug*/
public static Shape createDirectionalThumbShape( float x, float y, float w, float h, float arc ) {
float wh = w / 2;
Path2D path = new Path2D.Float();
Path2D path = new Path2D.Float( Path2D.WIND_NON_ZERO, 9 );
path.moveTo( x + wh, y + h );
path.lineTo( x, y + (h - wh) );
path.lineTo( x, y + arc );

View File

@@ -65,7 +65,7 @@ import com.formdev.flatlaf.util.LoggingFacade;
* <!-- FlatSpinnerUI -->
*
* @uiDefault Component.minimumWidth int
* @uiDefault Spinner.buttonStyle String button (default) or none
* @uiDefault Spinner.buttonStyle String button (default), mac or none
* @uiDefault Component.arrowType String chevron (default) or triangle
* @uiDefault Component.isIntelliJTheme boolean
* @uiDefault Spinner.disabledBackground Color
@@ -340,7 +340,25 @@ public class FlatSpinnerUI
private Component createArrowButton( int direction, String name ) {
FlatArrowButton button = new FlatArrowButton( direction, arrowType, buttonArrowColor,
buttonDisabledArrowColor, buttonHoverArrowColor, null, buttonPressedArrowColor, null );
buttonDisabledArrowColor, buttonHoverArrowColor, null, buttonPressedArrowColor, null )
{
@Override
public int getArrowWidth() {
return isMacStyle() ? 7 : super.getArrowWidth();
}
@Override
public float getArrowThickness() {
return isMacStyle() ? 1.5f : super.getArrowThickness();
}
@Override
public float getYOffset() {
return isMacStyle() ? 0 : super.getYOffset();
}
@Override
public boolean isRoundBorderAutoXOffset() {
return isMacStyle() ? false : super.isRoundBorderAutoXOffset();
}
};
button.setName( name );
button.setYOffset( (direction == SwingConstants.NORTH) ? 1.25f : -1.25f );
if( direction == SwingConstants.NORTH )
@@ -374,10 +392,13 @@ public class FlatSpinnerUI
int width = c.getWidth();
int height = c.getHeight();
boolean enabled = spinner.isEnabled();
boolean ltr = spinner.getComponentOrientation().isLeftToRight();
boolean isMacStyle = isMacStyle();
int macStyleButtonsWidth = isMacStyle ? getMacStyleButtonsWidth() : 0;
// paint background
g2.setColor( getBackground( enabled ) );
FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc );
FlatUIUtils.paintComponentBackground( g2, ltr ? 0 : macStyleButtonsWidth, 0, width - macStyleButtonsWidth, height, focusWidth, arc );
// paint button background and separator
boolean paintButton = !"none".equals( buttonStyle );
@@ -386,27 +407,49 @@ public class FlatSpinnerUI
Component button = (handler.nextButton != null) ? handler.nextButton : handler.previousButton;
int arrowX = button.getX();
int arrowWidth = button.getWidth();
boolean isLeftToRight = spinner.getComponentOrientation().isLeftToRight();
// paint arrow buttons background
if( enabled && buttonBackground != null ) {
g2.setColor( buttonBackground );
Shape oldClip = g2.getClip();
if( isLeftToRight )
g2.clipRect( arrowX, 0, width - arrowX, height );
else
g2.clipRect( 0, 0, arrowX + arrowWidth, height );
FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc );
g2.setClip( oldClip );
}
// paint vertical line between value and arrow buttons
Color separatorColor = enabled ? buttonSeparatorColor : buttonDisabledSeparatorColor;
if( separatorColor != null && buttonSeparatorWidth > 0 ) {
g2.setColor( separatorColor );
if( isMacStyle ) {
Insets insets = spinner.getInsets();
int lineWidth = Math.round( FlatUIUtils.getBorderLineWidth( spinner ) );
int bx = arrowX;
int by = insets.top - lineWidth;
int bw = arrowWidth;
int bh = height - insets.top - insets.bottom + (lineWidth * 2);
float lw = scale( buttonSeparatorWidth );
float lx = isLeftToRight ? arrowX : arrowX + arrowWidth - lw;
g2.fill( new Rectangle2D.Float( lx, focusWidth, lw, height - 1 - (focusWidth * 2) ) );
// buttons border
FlatUIUtils.paintOutlinedComponent( g2, bx, by, bw, bh,
0, 0, 0, lw, scale( 12 ),
null, separatorColor, buttonBackground );
// separator between buttons
if( separatorColor != null ) {
int thickness = scale( 1 );
g2.setColor( separatorColor );
g2.fill( new Rectangle2D.Float( bx + lw, by + ((bh - thickness) / 2f),
bw - (lw * 2), thickness ) );
}
} else {
// paint arrow buttons background
if( enabled && buttonBackground != null ) {
g2.setColor( buttonBackground );
Shape oldClip = g2.getClip();
if( ltr )
g2.clipRect( arrowX, 0, width - arrowX, height );
else
g2.clipRect( 0, 0, arrowX + arrowWidth, height );
FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc );
g2.setClip( oldClip );
}
// paint vertical line between value and arrow buttons
if( separatorColor != null && buttonSeparatorWidth > 0 ) {
g2.setColor( separatorColor );
float lw = scale( buttonSeparatorWidth );
float lx = ltr ? arrowX : arrowX + arrowWidth - lw;
g2.fill( new Rectangle2D.Float( lx, focusWidth, lw, height - 1 - (focusWidth * 2) ) );
}
}
}
@@ -415,6 +458,19 @@ public class FlatSpinnerUI
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
}
boolean isMacStyle() {
return "mac".equals( buttonStyle );
}
int getMacStyleButtonsWidth() {
return (handler.nextButton != null || handler.previousButton != null)
? scale( MAC_STEPPER_GAP ) + scale( MAC_STEPPER_WIDTH )
: 0;
}
private static final int MAC_STEPPER_WIDTH = 15;
private static final int MAC_STEPPER_GAP = 3;
//---- class Handler ------------------------------------------------------
private class Handler
@@ -471,6 +527,7 @@ public class FlatSpinnerUI
Insets insets = parent.getInsets();
Rectangle r = FlatUIUtils.subtractInsets( new Rectangle( size ), insets );
// editor gets all space if there are no buttons
if( nextButton == null && previousButton == null ) {
if( editor != null )
editor.setBounds( r );
@@ -483,22 +540,39 @@ public class FlatSpinnerUI
// limit buttons width to height of a raw spinner (without insets)
FontMetrics fm = spinner.getFontMetrics( spinner.getFont() );
int maxButtonWidth = fm.getHeight() + scale( padding.top ) + scale( padding.bottom );
int minButtonWidth = (maxButtonWidth * 3) / 4;
// make button area square (if spinner has preferred height)
int buttonsWidth = Math.min( parent.getPreferredSize().height - insets.top - insets.bottom, maxButtonWidth );
// make button area square (except if width is limited)
boolean isMacStyle = isMacStyle();
int buttonsGap = isMacStyle ? scale( MAC_STEPPER_GAP ) : 0;
int prefButtonWidth = isMacStyle ? scale( MAC_STEPPER_WIDTH ) : buttonsRect.height;
int buttonsWidth = Math.min( Math.max( prefButtonWidth, minButtonWidth ), maxButtonWidth );
// update editor and buttons bounds
buttonsRect.width = buttonsWidth;
editorRect.width -= buttonsWidth + buttonsGap;
boolean ltr = parent.getComponentOrientation().isLeftToRight();
if( ltr )
buttonsRect.x += editorRect.width + buttonsGap;
else
editorRect.x += buttonsWidth + buttonsGap;
if( parent.getComponentOrientation().isLeftToRight() ) {
editorRect.width -= buttonsWidth;
buttonsRect.x += editorRect.width;
} else {
editorRect.x += buttonsWidth;
editorRect.width -= buttonsWidth;
// in mac button style increase buttons height and move to the right
// for exact alignment with border
if( isMacStyle ) {
int lineWidth = Math.round( FlatUIUtils.getBorderLineWidth( spinner ) );
if( lineWidth > 0 ) {
buttonsRect.x += ltr ? lineWidth : -lineWidth;
buttonsRect.y -= lineWidth;
buttonsRect.height += lineWidth * 2;
}
}
// set editor bounds
if( editor != null )
editor.setBounds( editorRect );
// set buttons bounds
int nextHeight = (buttonsRect.height / 2) + (buttonsRect.height % 2); // round up
if( nextButton != null )
nextButton.setBounds( buttonsRect.x, buttonsRect.y, buttonsRect.width, nextHeight );

View File

@@ -2589,7 +2589,7 @@ public class FlatTabbedPaneUI
public void mousePressed( MouseEvent e ) {
updateRollover( e );
if( !isPressedTabClose() )
if( !isPressedTabClose() && SwingUtilities.isLeftMouseButton( e ) )
mouseDelegate.mousePressed( e );
}
@@ -2644,7 +2644,7 @@ public class FlatTabbedPaneUI
// check whether mouse hit tab close area
boolean hitClose = isTabClosable( tabIndex ) && getTabCloseHitArea( tabIndex ).contains( x, y );
if( e.getID() == MouseEvent.MOUSE_PRESSED )
if( e.getID() == MouseEvent.MOUSE_PRESSED && SwingUtilities.isLeftMouseButton( e ) )
pressedTabIndex = hitClose ? tabIndex : -1;
setRolloverTabClose( hitClose );
setPressedTabClose( hitClose && tabIndex == pressedTabIndex );

View File

@@ -107,6 +107,8 @@ import com.formdev.flatlaf.util.UIScale;
public class FlatTitlePane
extends JComponent
{
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" );
@@ -354,15 +356,12 @@ public class FlatTitlePane
if( window == null || rootPane.getWindowDecorationStyle() != JRootPane.FRAME )
return;
updateVisibility();
if( window instanceof Frame ) {
Frame frame = (Frame) window;
boolean resizable = frame.isResizable();
boolean maximized = ((frame.getExtendedState() & Frame.MAXIMIZED_BOTH) != 0);
iconifyButton.setVisible( true );
maximizeButton.setVisible( resizable && !maximized );
restoreButton.setVisible( resizable && maximized );
if( maximized &&
!(SystemInfo.isLinux && FlatNativeLinuxLibrary.isWMUtilsSupported( window )) &&
rootPane.getClientProperty( "_flatlaf.maximizedBoundsUpToDate" ) == null )
@@ -383,14 +382,27 @@ public class FlatTitlePane
frame.setExtendedState( oldExtendedState );
}
}
}
}
/** @since 3 */
protected void updateVisibility() {
titleLabel.setVisible( clientPropertyBoolean( rootPane, TITLE_BAR_SHOW_TITLE, true ) );
closeButton.setVisible( clientPropertyBoolean( rootPane, TITLE_BAR_SHOW_CLOSE, true ) );
if( window instanceof Frame ) {
Frame frame = (Frame) window;
boolean maximizable = frame.isResizable() && clientPropertyBoolean( rootPane, TITLE_BAR_SHOW_MAXIMIZE, true );
boolean maximized = ((frame.getExtendedState() & Frame.MAXIMIZED_BOTH) != 0);
iconifyButton.setVisible( clientPropertyBoolean( rootPane, TITLE_BAR_SHOW_ICONIFFY, true ) );
maximizeButton.setVisible( maximizable && !maximized );
restoreButton.setVisible( maximizable && maximized );
} else {
// hide buttons because they are only supported in frames
iconifyButton.setVisible( false );
maximizeButton.setVisible( false );
restoreButton.setVisible( false );
revalidate();
repaint();
}
}
@@ -566,11 +578,13 @@ public class FlatTitlePane
doLayout();
}
/*debug
@Override
public void paint( Graphics g ) {
super.paint( g );
if( !UIManager.getBoolean( KEY_DEBUG_SHOW_RECTANGLES ) )
return;
if( debugTitleBarHeight > 0 ) {
g.setColor( Color.green );
g.drawLine( 0, debugTitleBarHeight, getWidth(), debugTitleBarHeight );
@@ -594,7 +608,6 @@ public class FlatTitlePane
Point offset = SwingUtilities.convertPoint( this, 0, 0, window );
g.drawRect( r.x - offset.x, r.y - offset.y, r.width - 1, r.height - 1 );
}
debug*/
@Override
protected void paintComponent( Graphics g ) {
@@ -923,15 +936,14 @@ debug*/
FlatNativeWindowBorder.setTitleBarHeightAndHitTestSpots( window, titleBarHeight,
hitTestSpots, appIconBounds, minimizeButtonBounds, maximizeButtonBounds, closeButtonBounds );
/*debug
debugTitleBarHeight = titleBarHeight;
debugHitTestSpots = hitTestSpots;
debugAppIconBounds = appIconBounds;
debugMinimizeButtonBounds = minimizeButtonBounds;
debugMaximizeButtonBounds = maximizeButtonBounds;
debugCloseButtonBounds = closeButtonBounds;
repaint();
debug*/
if( UIManager.getBoolean( KEY_DEBUG_SHOW_RECTANGLES ) )
repaint();
}
private Rectangle boundsInWindow( JComponent c ) {
@@ -950,14 +962,12 @@ debug*/
return r;
}
/*debug
private int debugTitleBarHeight;
private List<Rectangle> debugHitTestSpots;
private Rectangle debugAppIconBounds;
private Rectangle debugMinimizeButtonBounds;
private Rectangle debugMaximizeButtonBounds;
private Rectangle debugCloseButtonBounds;
debug*/
//---- class FlatTitlePaneBorder ------------------------------------------

View File

@@ -20,15 +20,24 @@ import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.FocusTraversalPolicy;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.ContainerEvent;
import java.awt.event.ContainerListener;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Map;
import javax.swing.AbstractButton;
import javax.swing.ButtonGroup;
import javax.swing.ButtonModel;
import javax.swing.DefaultButtonModel;
import javax.swing.InputMap;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JToolBar;
import javax.swing.LayoutFocusTraversalPolicy;
import javax.swing.UIManager;
import javax.swing.border.Border;
@@ -37,6 +46,7 @@ import javax.swing.plaf.basic.BasicToolBarUI;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.UIScale;
/**
* Provides the Flat LaF UI delegate for {@link javax.swing.JToolBar}.
@@ -58,6 +68,8 @@ import com.formdev.flatlaf.util.LoggingFacade;
* @uiDefault ToolBar.focusableButtons boolean
* @uiDefault ToolBar.arrowKeysOnlyNavigation boolean
* @uiDefault ToolBar.floatable boolean
* @uiDefault ToolBar.hoverButtonGroupArc int
* @uiDefault ToolBar.hoverButtonGroupBackground Color
*
* <!-- FlatToolBarBorder -->
*
@@ -72,6 +84,8 @@ public class FlatToolBarUI
{
/** @since 1.4 */ @Styleable protected boolean focusableButtons;
/** @since 2 */ @Styleable protected boolean arrowKeysOnlyNavigation;
/** @since 3 */ @Styleable protected int hoverButtonGroupArc;
/** @since 3 */ @Styleable protected Color hoverButtonGroupBackground;
// for FlatToolBarBorder
@Styleable protected Insets borderMargins;
@@ -119,6 +133,8 @@ public class FlatToolBarUI
focusableButtons = UIManager.getBoolean( "ToolBar.focusableButtons" );
arrowKeysOnlyNavigation = UIManager.getBoolean( "ToolBar.arrowKeysOnlyNavigation" );
hoverButtonGroupArc = UIManager.getInt( "ToolBar.hoverButtonGroupArc" );
hoverButtonGroupBackground = UIManager.getColor( "ToolBar.hoverButtonGroupBackground" );
// floatable
if( !UIManager.getBoolean( "ToolBar.floatable" ) ) {
@@ -132,6 +148,8 @@ public class FlatToolBarUI
protected void uninstallDefaults() {
super.uninstallDefaults();
hoverButtonGroupBackground = null;
if( oldFloatable != null ) {
toolBar.setFloatable( oldFloatable );
oldFloatable = null;
@@ -329,6 +347,99 @@ public class FlatToolBarUI
super.setOrientation( orientation );
}
@Override
public void paint( Graphics g, JComponent c ) {
super.paint( g, c );
paintButtonGroup( g );
}
/**@since 3 */
protected void paintButtonGroup( Graphics g ) {
if( hoverButtonGroupBackground == null )
return;
// find hovered button that is part of a button group
ButtonGroup group = null;
for( Component b : toolBar.getComponents() ) {
if( b instanceof AbstractButton && ((AbstractButton)b).getModel().isRollover() ) {
group = getButtonGroup( (AbstractButton) b );
if( group != null )
break;
}
}
if( group == null )
return;
// get bounds of buttons in group
ArrayList<Rectangle> rects = new ArrayList<>();
Enumeration<AbstractButton> e = group.getElements();
while( e.hasMoreElements() ) {
AbstractButton gb = e.nextElement();
if( gb.getParent() == toolBar )
rects.add( gb.getBounds() );
}
// sort button bounds
boolean horizontal = (toolBar.getOrientation() == JToolBar.HORIZONTAL);
rects.sort( (r1, r2) -> horizontal ? r1.x - r2.x : r1.y - r2.y );
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g );
g.setColor( FlatUIUtils.deriveColor( hoverButtonGroupBackground, toolBar.getBackground() ) );
// paint button group hover background
int maxSepWidth = UIScale.scale( 10 );
Rectangle gr = null;
for( Rectangle r : rects ) {
if( gr == null ) {
// first button
gr = r;
} else if( horizontal ? (gr.x + gr.width + maxSepWidth >= r.x) : (gr.y + gr.height + maxSepWidth >= r.y) ) {
// button joins previous button
gr = gr.union( r );
} else {
// paint group
FlatUIUtils.paintComponentBackground( (Graphics2D) g, gr.x, gr.y, gr.width, gr.height, 0, UIScale.scale( hoverButtonGroupArc ) );
gr = r;
}
}
if( gr != null )
FlatUIUtils.paintComponentBackground( (Graphics2D) g, gr.x, gr.y, gr.width, gr.height, 0, UIScale.scale( hoverButtonGroupArc ) );
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
}
/**@since 3 */
protected void repaintButtonGroup( AbstractButton b ) {
if( hoverButtonGroupBackground == null )
return;
ButtonGroup group = getButtonGroup( b );
if( group == null )
return;
// compute union bounds of all buttons in group (including separators)
Rectangle gr = null;
Enumeration<AbstractButton> e = group.getElements();
while( e.hasMoreElements() ) {
AbstractButton gb = e.nextElement();
Container parent = gb.getParent();
if( parent == toolBar )
gr = (gr != null) ? gr.union( gb.getBounds() ) : gb.getBounds();
}
// repaint button group
if( gr != null )
toolBar.repaint( gr );
}
private ButtonGroup getButtonGroup( AbstractButton b ) {
ButtonModel model = b.getModel();
return (model instanceof DefaultButtonModel)
? ((DefaultButtonModel)model).getGroup()
: null;
}
//---- class FlatToolBarFocusTraversalPolicy ------------------------------
/**

View File

@@ -17,15 +17,19 @@
package com.formdev.flatlaf.ui;
import static com.formdev.flatlaf.FlatClientProperties.*;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Map;
import javax.swing.CellRendererPane;
import javax.swing.Icon;
@@ -36,6 +40,7 @@ import javax.swing.LookAndFeel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.JTree.DropLocation;
import javax.swing.event.TreeSelectionListener;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicTreeUI;
import javax.swing.tree.DefaultTreeCellRenderer;
@@ -96,8 +101,11 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault Tree.selectionForeground Color
* @uiDefault Tree.selectionInactiveBackground Color
* @uiDefault Tree.selectionInactiveForeground Color
* @uiDefault Tree.selectionInsets Insets
* @uiDefault Tree.selectionArc int
* @uiDefault Tree.wideSelection boolean
* @uiDefault Tree.showCellFocusIndicator boolean
* @uiDefault Tree.showDefaultIcons boolean
*
* <!-- FlatTreeExpandedIcon -->
*
@@ -132,8 +140,11 @@ public class FlatTreeUI
@Styleable protected Color selectionInactiveBackground;
@Styleable protected Color selectionInactiveForeground;
@Styleable protected Color selectionBorderColor;
/** @since 3 */ @Styleable protected Insets selectionInsets;
/** @since 3 */ @Styleable protected int selectionArc;
@Styleable protected boolean wideSelection;
@Styleable protected boolean showCellFocusIndicator;
/** @since 3 */ protected boolean showDefaultIcons;
// for icons
// (needs to be public because icon classes are in another package)
@@ -147,6 +158,7 @@ public class FlatTreeUI
// only used via styling (not in UI defaults, but has likewise client properties)
/** @since 2 */ @Styleable protected boolean paintSelection = true;
private boolean paintLines;
private Color defaultCellNonSelectionBackground;
private Color defaultSelectionBackground;
private Color defaultSelectionForeground;
@@ -175,9 +187,13 @@ public class FlatTreeUI
selectionInactiveBackground = UIManager.getColor( "Tree.selectionInactiveBackground" );
selectionInactiveForeground = UIManager.getColor( "Tree.selectionInactiveForeground" );
selectionBorderColor = UIManager.getColor( "Tree.selectionBorderColor" );
selectionInsets = UIManager.getInsets( "Tree.selectionInsets" );
selectionArc = UIManager.getInt( "Tree.selectionArc" );
wideSelection = UIManager.getBoolean( "Tree.wideSelection" );
showCellFocusIndicator = UIManager.getBoolean( "Tree.showCellFocusIndicator" );
showDefaultIcons = UIManager.getBoolean( "Tree.showDefaultIcons" );
paintLines = UIManager.getBoolean( "Tree.paintLines" );
defaultCellNonSelectionBackground = UIManager.getColor( "Tree.textBackground" );
defaultSelectionBackground = selectionBackground;
defaultSelectionForeground = selectionForeground;
@@ -210,6 +226,19 @@ public class FlatTreeUI
oldStyleValues = null;
}
@Override
protected void updateRenderer() {
super.updateRenderer();
// remove default leaf/closed/opened icons
if( !showDefaultIcons && currentCellRenderer instanceof DefaultTreeCellRenderer ) {
DefaultTreeCellRenderer renderer = (DefaultTreeCellRenderer) currentCellRenderer;
renderer.setLeafIcon( null );
renderer.setClosedIcon( null );
renderer.setOpenIcon( null );
}
}
@Override
protected MouseListener createMouseListener() {
return new BasicTreeUI.MouseHandler() {
@@ -295,6 +324,34 @@ public class FlatTreeUI
tree.repaint( 0, r.y, tree.getWidth(), r.height );
}
@Override
protected TreeSelectionListener createTreeSelectionListener() {
TreeSelectionListener superListener = super.createTreeSelectionListener();
return e -> {
superListener.valueChanged( e );
// for united rounded selection, repaint parts of the rows that adjoin to the changed rows
TreePath[] changedPaths;
if( useUnitedRoundedSelection() &&
tree.getSelectionCount() > 1 &&
(changedPaths = e.getPaths()) != null )
{
if( changedPaths.length > 4 ) {
// same is done in BasicTreeUI.Handler.valueChanged()
tree.repaint();
} else {
int arc = (int) Math.ceil( UIScale.scale( selectionArc / 2f ) );
for( TreePath path : changedPaths ) {
Rectangle r = getPathBounds( tree, path );
if( r != null )
tree.repaint( r.x, r.y - arc, r.width, r.height + (arc * 2) );
}
}
}
};
}
@Override
public Rectangle getPathBounds( JTree tree, TreePath path ) {
Rectangle bounds = super.getPathBounds( tree, path );
@@ -346,8 +403,127 @@ public class FlatTreeUI
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
}
@Override
public void paint( Graphics g, JComponent c ) {
if( treeState == null )
return;
// use clip bounds to limit painting to needed rows
Rectangle clipBounds = g.getClipBounds();
TreePath firstPath = getClosestPathForLocation( tree, 0, clipBounds.y );
Enumeration<TreePath> visiblePaths = treeState.getVisiblePathsFrom( firstPath );
if( visiblePaths != null ) {
Insets insets = tree.getInsets();
HashSet<TreePath> verticalLinePaths = paintLines ? new HashSet<>() : null;
ArrayList<Runnable> paintLinesLater = paintLines ? new ArrayList<>() : null;
ArrayList<Runnable> paintExpandControlsLater = paintLines ? new ArrayList<>() : null;
// add parents for later painting of vertical lines
if( paintLines ) {
for( TreePath path = firstPath.getParentPath(); path != null; path = path.getParentPath() )
verticalLinePaths.add( path );
}
Rectangle boundsBuffer = new Rectangle();
boolean rootVisible = isRootVisible();
int row = treeState.getRowForPath( firstPath );
boolean leftToRight = tree.getComponentOrientation().isLeftToRight();
int treeWidth = tree.getWidth();
// iterate over visible rows and paint rows, expand control and lines
while( visiblePaths.hasMoreElements() ) {
TreePath path = visiblePaths.nextElement();
if( path == null )
break;
// compute path bounds
Rectangle bounds = treeState.getBounds( path, boundsBuffer );
if( bounds == null )
break;
// add tree insets to path bounds
if( leftToRight )
bounds.x += insets.left;
else
bounds.x = treeWidth - insets.right - (bounds.x + bounds.width);
bounds.y += insets.top;
boolean isLeaf = treeModel.isLeaf( path.getLastPathComponent() );
boolean isExpanded = isLeaf ? false : treeState.getExpandedState( path );
boolean hasBeenExpanded = isLeaf ? false : tree.hasBeenExpanded( path );
// paint row (including selection)
paintRow( g, clipBounds, insets, bounds, path, row, isExpanded, hasBeenExpanded, isLeaf );
// collect lines for later painting
if( paintLines ) {
TreePath parentPath = path.getParentPath();
// add parent for later painting of vertical lines
if( parentPath != null )
verticalLinePaths.add( parentPath );
// paint horizontal line later (for using rendering hints)
if( parentPath != null || (rootVisible && row == 0) ) {
Rectangle bounds2 = new Rectangle( bounds );
int row2 = row;
paintLinesLater.add( () -> {
paintHorizontalPartOfLeg( g, clipBounds, insets, bounds2, path, row2, isExpanded, hasBeenExpanded, isLeaf );
} );
}
}
// paint expand control
if( shouldPaintExpandControl( path, row, isExpanded, hasBeenExpanded, isLeaf ) ) {
if( paintLines ) {
// need to paint after painting lines
Rectangle bounds2 = new Rectangle( bounds );
int row2 = row;
paintExpandControlsLater.add( () -> {
paintExpandControl( g, clipBounds, insets, bounds2, path, row2, isExpanded, hasBeenExpanded, isLeaf );
} );
} else
paintExpandControl( g, clipBounds, insets, bounds, path, row, isExpanded, hasBeenExpanded, isLeaf );
}
if( bounds.y + bounds.height >= clipBounds.y + clipBounds.height )
break;
row++;
}
if( paintLines ) {
// enable antialiasing for line painting
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g );
// paint horizontal lines
for( Runnable r : paintLinesLater )
r.run();
// paint vertical lines
g.setColor( Color.green );
for( TreePath path : verticalLinePaths )
paintVerticalPartOfLeg( g, clipBounds, insets, path );
// restore rendering hints
if( oldRenderingHints != null )
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
// paint expand controls
for( Runnable r : paintExpandControlsLater )
r.run();
}
}
paintDropLine( g );
rendererPane.removeAll();
}
/**
* Same as super.paintRow(), but supports wide selection and uses
* Similar to super.paintRow(), but supports wide selection and uses
* inactive selection background/foreground if tree is not focused.
*/
@Override
@@ -428,7 +604,7 @@ public class FlatTreeUI
paintWideSelection( g, clipBounds, insets, bounds, path, row, isExpanded, hasBeenExpanded, isLeaf );
} else {
// non-wide selection
paintCellBackground( g, rendererComponent, bounds );
paintCellBackground( g, rendererComponent, bounds, row, true );
}
// this is actually not necessary because renderer should always set color
@@ -442,7 +618,7 @@ public class FlatTreeUI
if( bg != null && !bg.equals( defaultCellNonSelectionBackground ) ) {
Color oldColor = g.getColor();
g.setColor( bg );
paintCellBackground( g, rendererComponent, bounds );
paintCellBackground( g, rendererComponent, bounds, row, false );
g.setColor( oldColor );
}
}
@@ -497,17 +673,23 @@ public class FlatTreeUI
private void paintWideSelection( Graphics g, Rectangle clipBounds, Insets insets, Rectangle bounds,
TreePath path, int row, boolean isExpanded, boolean hasBeenExpanded, boolean isLeaf )
{
g.fillRect( 0, bounds.y, tree.getWidth(), bounds.height );
float arcTop, arcBottom;
arcTop = arcBottom = UIScale.scale( selectionArc / 2f );
// paint expand/collapse icon
// (was already painted before, but painted over with wide selection)
if( shouldPaintExpandControl( path, row, isExpanded, hasBeenExpanded, isLeaf ) ) {
paintExpandControl( g, clipBounds, insets, bounds,
path, row, isExpanded, hasBeenExpanded, isLeaf );
if( useUnitedRoundedSelection() ) {
if( row > 0 && tree.isRowSelected( row - 1 ) )
arcTop = 0;
if( row < tree.getRowCount() - 1 && tree.isRowSelected( row + 1 ) )
arcBottom = 0;
}
FlatUIUtils.paintSelection( (Graphics2D) g, 0, bounds.y, tree.getWidth(), bounds.height,
UIScale.scale( selectionInsets ), arcTop, arcTop, arcBottom, arcBottom, 0 );
}
private void paintCellBackground( Graphics g, Component rendererComponent, Rectangle bounds ) {
private void paintCellBackground( Graphics g, Component rendererComponent, Rectangle bounds,
int row, boolean paintSelection )
{
int xOffset = 0;
int imageOffset = 0;
@@ -520,7 +702,42 @@ public class FlatTreeUI
xOffset = label.getComponentOrientation().isLeftToRight() ? imageOffset : 0;
}
g.fillRect( bounds.x + xOffset, bounds.y, bounds.width - imageOffset, bounds.height );
if( paintSelection ) {
float arcTopLeft, arcTopRight, arcBottomLeft, arcBottomRight;
arcTopLeft = arcTopRight = arcBottomLeft = arcBottomRight = UIScale.scale( selectionArc / 2f );
if( useUnitedRoundedSelection() ) {
if( row > 0 && tree.isRowSelected( row - 1 ) ) {
Rectangle r = getPathBounds( tree, tree.getPathForRow( row - 1 ) );
arcTopLeft = Math.min( arcTopLeft, r.x - bounds.x );
arcTopRight = Math.min( arcTopRight, (bounds.x + bounds.width) - (r.x + r.width) );
}
if( row < tree.getRowCount() - 1 && tree.isRowSelected( row + 1 ) ) {
Rectangle r = getPathBounds( tree, tree.getPathForRow( row + 1 ) );
arcBottomLeft = Math.min( arcBottomLeft, r.x - bounds.x );
arcBottomRight = Math.min( arcBottomRight, (bounds.x + bounds.width) - (r.x + r.width) );
}
}
FlatUIUtils.paintSelection( (Graphics2D) g, bounds.x + xOffset, bounds.y, bounds.width - imageOffset, bounds.height,
UIScale.scale( selectionInsets ), arcTopLeft, arcTopRight, arcBottomLeft, arcBottomRight, 0 );
} else
g.fillRect( bounds.x + xOffset, bounds.y, bounds.width - imageOffset, bounds.height );
}
private boolean useUnitedRoundedSelection() {
return selectionArc > 0 &&
(selectionInsets == null || (selectionInsets.top == 0 && selectionInsets.bottom == 0));
}
@Override
protected void paintVerticalLine( Graphics g, JComponent c, int x, int top, int bottom ) {
((Graphics2D)g).fill( new Rectangle2D.Float( x, top, UIScale.scale( 1f ), bottom - top ) );
}
@Override
protected void paintHorizontalLine( Graphics g, JComponent c, int y, int left, int right ) {
((Graphics2D)g).fill( new Rectangle2D.Float( left, y, right - left, UIScale.scale( 1f ) ) );
}
/**

View File

@@ -39,6 +39,7 @@ import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import java.util.IdentityHashMap;
@@ -76,8 +77,6 @@ import com.formdev.flatlaf.util.UIScale;
*/
public class FlatUIUtils
{
public static final boolean MAC_USE_QUARTZ = Boolean.getBoolean( "apple.awt.graphics.UseQuartz" );
private static boolean useSharedUIs = true;
private static final WeakHashMap<LookAndFeel, IdentityHashMap<Object, ComponentUI>> sharedUIinstances = new WeakHashMap<>();
@@ -210,6 +209,9 @@ public class FlatUIUtils
}
public static boolean isCellEditor( Component c ) {
if( c == null )
return false;
// check whether used in cell editor (check 3 levels up)
Component c2 = c;
for( int i = 0; i <= 2 && c2 != null; i++ ) {
@@ -386,8 +388,7 @@ public class FlatUIUtils
};
g2.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
g2.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL,
MAC_USE_QUARTZ ? RenderingHints.VALUE_STROKE_PURE : RenderingHints.VALUE_STROKE_NORMALIZE );
g2.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE );
return oldRenderingHints;
}
@@ -440,9 +441,9 @@ public class FlatUIUtils
}
/**
* Fills the background of a component with a round rectangle.
* Fills the background of a component with a rounded rectangle.
* <p>
* The bounds of the painted round rectangle are
* The bounds of the painted rounded rectangle are
* {@code x + focusWidth, y + focusWidth, width - (focusWidth * 2), height - (focusWidth * 2)}.
* The given arc diameter refers to the painted rectangle (and not to {@code x,y,width,height}).
*
@@ -473,7 +474,7 @@ public class FlatUIUtils
* <p>
*
* <strong>Background</strong>:
* The bounds of the filled round rectangle are
* The bounds of the filled rounded rectangle are
* {@code [x + focusWidth, y + focusWidth, width - (focusWidth * 2), height - (focusWidth * 2)]}.
* The focus border and the border may paint over the background.
* <p>
@@ -671,6 +672,50 @@ public class FlatUIUtils
}
}
/**
* Paints a selection.
* <p>
* The bounds of the painted selection (rounded) rectangle are
* {@code x + insets.left, y + insets.top, width - insets.left - insets.right, height - insets.top - insets.bottom}.
* The given arc radius refers to the painted rectangle (and not to {@code x,y,width,height}).
*
* @since 3
*/
public static void paintSelection( Graphics2D g, int x, int y, int width, int height, Insets insets,
float arcTopLeft, float arcTopRight, float arcBottomLeft, float arcBottomRight, int flags )
{
if( insets != null ) {
x += insets.left;
y += insets.top;
width -= insets.left + insets.right;
height -= insets.top + insets.bottom;
}
if( arcTopLeft > 0 || arcTopRight > 0 || arcBottomLeft > 0 || arcBottomRight > 0 ) {
double systemScaleFactor = UIScale.getSystemScaleFactor( g );
if( systemScaleFactor != 1 && systemScaleFactor != 2 ) {
// paint at scale 1x to avoid clipping on right and bottom edges at 125%, 150% or 175%
HiDPIUtils.paintAtScale1x( g, x, y, width, height,
(g2d, x2, y2, width2, height2, scaleFactor) -> {
paintRoundedSelectionImpl( g2d, x2, y2, width2, height2,
(float) (arcTopLeft * scaleFactor), (float) (arcTopRight * scaleFactor),
(float) (arcBottomLeft * scaleFactor), (float) (arcBottomRight * scaleFactor) );
} );
} else
paintRoundedSelectionImpl( g, x, y, width, height, arcTopLeft, arcTopRight, arcBottomLeft, arcBottomRight );
} else
g.fillRect( x, y, width, height );
}
private static void paintRoundedSelectionImpl( Graphics2D g, int x, int y, int width, int height,
float arcTopLeft, float arcTopRight, float arcBottomLeft, float arcBottomRight )
{
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g );
g.fill( FlatUIUtils.createRoundRectanglePath( x, y, width, height, arcTopLeft, arcTopRight, arcBottomLeft, arcBottomRight ) );
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
}
public static void paintGrip( Graphics g, int x, int y, int width, int height,
boolean horizontal, int dotCount, int dotSize, int gap, boolean centerPrecise )
{
@@ -762,7 +807,7 @@ public class FlatUIUtils
}
/**
* Creates a not-filled rounded rectangle shape and allows specifying the line width and the radius or each corner.
* Creates a not-filled rounded rectangle shape and allows specifying the line width and the radius of each corner.
*/
public static Path2D createRoundRectangle( float x, float y, float width, float height,
float lineWidth, float arcTopLeft, float arcTopRight, float arcBottomLeft, float arcBottomRight )
@@ -801,7 +846,7 @@ public class FlatUIUtils
double ciBottomLeft = arcBottomLeft * ci;
double ciBottomRight = arcBottomRight * ci;
Path2D rect = new Path2D.Float();
Path2D rect = new Path2D.Float( Path2D.WIND_NON_ZERO, 16 );
rect.moveTo( x2 - arcTopRight, y );
rect.curveTo( x2 - ciTopRight, y,
x2, y + ciTopRight,
@@ -823,6 +868,27 @@ public class FlatUIUtils
return rect;
}
/**
* Creates a rounded triangle shape for the given points and arc radius.
*
* @since 3
*/
public static Shape createRoundTrianglePath( float x1, float y1, float x2, float y2,
float x3, float y3, float arc )
{
double averageSideLength = (distance( x1,y1, x2,y2 ) + distance( x2,y2, x3,y3 ) + distance( x3,y3, x1,y1 )) / 3;
double t1 = (1 / averageSideLength) * arc;
double t2 = 1 - t1;
return createPath(
lerp( x3, x1, t2 ), lerp( y3, y1, t2 ),
QUAD_TO, x1, y1, lerp( x1, x2, t1 ), lerp( y1, y2, t1 ),
lerp( x1, x2, t2 ), lerp( y1, y2, t2 ),
QUAD_TO, x2, y2, lerp( x2, x3, t1 ), lerp( y2, y3, t1 ),
lerp( x2, x3, t2 ), lerp( y2, y3, t2 ),
QUAD_TO, x3, y3, lerp( x3, x1, t1 ), lerp( y3, y1, t1 ) );
}
/**
* Paints a chevron or triangle arrow in the center of the given rectangle.
*
@@ -835,13 +901,15 @@ public class FlatUIUtils
* {@link SwingConstants#WEST} or {@link SwingConstants#EAST})
* @param chevron {@code true} for chevron arrow, {@code false} for triangle arrow
* @param arrowSize the width of the painted arrow (for vertical direction) (will be scaled)
* @param arrowThickness the thickness of the painted chevron arrow (will be scaled)
* @param xOffset an offset added to the x coordinate of the arrow to paint it out-of-center. Usually zero. (will be scaled)
* @param yOffset an offset added to the y coordinate of the arrow to paint it out-of-center. Usually zero. (will be scaled)
*
* @since 1.1
* @since 3
*/
public static void paintArrow( Graphics2D g, int x, int y, int width, int height,
int direction, boolean chevron, int arrowSize, float xOffset, float yOffset )
int direction, boolean chevron, int arrowSize, float arrowThickness,
float xOffset, float yOffset )
{
// compute arrow width/height
// - make chevron arrows one pixel smaller because coordinates are based on center of pixels (0.5/0.5)
@@ -875,7 +943,7 @@ debug*/
Shape arrowShape = createArrowShape( direction, chevron, aw, ah );
if( chevron ) {
Stroke oldStroke = g.getStroke();
g.setStroke( new BasicStroke( UIScale.scale( 1f ) ) );
g.setStroke( new BasicStroke( UIScale.scale( arrowThickness ) ) );
drawShapePure( g, arrowShape );
g.setStroke( oldStroke );
} else {
@@ -932,6 +1000,12 @@ debug*/
}
debug*/
/** @since 3 */ public static final double MOVE_TO = -1_000_000_000_001.;
/** @since 3 */ public static final double QUAD_TO = -1_000_000_000_002.;
/** @since 3 */ public static final double CURVE_TO = -1_000_000_000_003.;
/** @since 3 */ public static final double ROUNDED = -1_000_000_000_004.;
/** @since 3 */ public static final double CLOSE_PATH = -1_000_000_000_005.;
/**
* Creates a closed path for the given points.
*/
@@ -943,15 +1017,88 @@ debug*/
* Creates an open or closed path for the given points.
*/
public static Path2D createPath( boolean close, double... points ) {
Path2D path = new Path2D.Float();
Path2D path = new Path2D.Float( Path2D.WIND_NON_ZERO, points.length / 2 + (close ? 1 : 0) );
path.moveTo( points[0], points[1] );
for( int i = 2; i < points.length; i += 2 )
path.lineTo( points[i], points[i + 1] );
for( int i = 2; i < points.length; ) {
double p = points[i];
if( p == MOVE_TO ) {
// move pointer to
// params: x, y
path.moveTo( points[i + 1], points[i + 2] );
i += 3;
} else if( p == QUAD_TO ) {
// add quadratic curve
// params: x1, y1, x2, y2
path.quadTo( points[i + 1], points[i + 2], points[i + 3], points[i + 4] );
i += 5;
} else if( p == CURVE_TO ) {
// add bezier curve
// params: x1, y1, x2, y2, x3, y3
path.curveTo( points[i + 1], points[i + 2], points[i + 3], points[i + 4], points[i + 5], points[i + 6] );
i += 7;
} else if( p == ROUNDED ) {
// add rounded corner
// params: x, y, arc
double x = points[i + 1];
double y = points[i + 2];
double arc = points[i + 3];
// index of next point
int ip2 = i + 4;
if( points[ip2] == QUAD_TO || points[ip2] == ROUNDED )
ip2++;
// previous and next points
Point2D p1 = path.getCurrentPoint();
double x1 = p1.getX();
double y1 = p1.getY();
double x2 = points[ip2];
double y2 = points[ip2 + 1];
double d1 = distance( x, y, x1, y1 );
double d2 = distance( x, y, x2, y2 );
double t1 = 1 - ((1 / d1) * arc);
double t2 = (1 / d2) * arc;
path.lineTo( lerp( x1, x, t1 ), lerp( y1, y, t1 ) );
path.quadTo( x, y, lerp( x, x2, t2 ), lerp( y, y2, t2 ) );
i += 4;
} else if( p == CLOSE_PATH ) {
// close path
// params: -
path.closePath();
i += 1;
} else {
// add line to
// params: x, y
path.lineTo( p, points[i + 1] );
i += 2;
}
}
if( close )
path.closePath();
return path;
}
/**
* Calculates linear interpolation between two values.
*
* https://en.wikipedia.org/wiki/Linear_interpolation#Programming_language_support
*/
private static double lerp( double v1, double v2, double t ) {
return (v1 * (1 - t)) + (v2 * t);
}
/**
* Calculates the distance between two points.
*/
private static double distance( double x1, double y1, double x2, double y2 ) {
double dx = x2 - x1;
double dy = y2 - y1;
return Math.sqrt( (dx * dx) + (dy * dy) );
}
/**
* Draws the given shape with disabled stroke normalization.
* The x/y coordinates of the shape are translated by a half pixel.

View File

@@ -606,9 +606,10 @@ debug*/
if( resizeDir == S_RESIZE_CURSOR || resizeDir == SW_RESIZE_CURSOR || resizeDir == SE_RESIZE_CURSOR ) {
newBounds.height = (yOnScreen + dragBottomOffset) - newBounds.y;
if( limitToParentBounds() ) {
int parentHeight = getParentBounds().height;
if( newBounds.y + newBounds.height > parentHeight )
newBounds.height = parentHeight - newBounds.y;
Rectangle parentBounds = getParentBounds();
int parentBottomY = parentBounds.y + parentBounds.height;
if( newBounds.y + newBounds.height > parentBottomY )
newBounds.height = parentBottomY - newBounds.y;
}
}
@@ -624,9 +625,10 @@ debug*/
if( resizeDir == E_RESIZE_CURSOR || resizeDir == NE_RESIZE_CURSOR || resizeDir == SE_RESIZE_CURSOR ) {
newBounds.width = (xOnScreen + dragRightOffset) - newBounds.x;
if( limitToParentBounds() ) {
int parentWidth = getParentBounds().width;
if( newBounds.x + newBounds.width > parentWidth )
newBounds.width = parentWidth - newBounds.x;
Rectangle parentBounds = getParentBounds();
int parentRightX = parentBounds.x + parentBounds.width;
if( newBounds.x + newBounds.width > parentRightX )
newBounds.width = parentRightX - newBounds.x;
}
}

View File

@@ -105,6 +105,19 @@ public class ColorFunctions
return HSLColor.toRGB( hsl[0], hsl[1], hsl[2], alpha );
}
/**
* Set the opacity (alpha) of a color.
*
* @param color base color
* @param amount the amount (in range 0-1) of the new opacity
* @return new color
* @since 3
*/
public static Color fade( Color color, float amount ) {
int newAlpha = Math.round( 255 * amount );
return new Color( (color.getRGB() & 0xffffff) | (newAlpha << 24), true );
}
/**
* Returns a color that is a mixture of two colors.
* <p>

View File

@@ -0,0 +1,153 @@
/*
* Copyright 2022 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.util;
import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.GraphicsEnvironment;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import javax.swing.plaf.UIResource;
import javax.swing.text.StyleContext;
/**
* Utility methods for fonts.
*
* @author Karl Tauber
* @since 3
*/
public class FontUtils
{
private static Map<String, Runnable> loadersMap;
/**
* Gets a composite font for the given family, style and size.
* A composite font that is able to display all Unicode characters.
* The font family is loaded if necessary via {@link #loadFontFamily(String)}.
* <p>
* To get fonts derived from returned fonts, it is recommended to use one of the
* {@link Font#deriveFont} methods instead of invoking this method.
*/
public static Font getCompositeFont( String family, int style, int size ) {
loadFontFamily( family );
// using StyleContext.getFont() here because it uses
// sun.font.FontUtilities.getCompositeFontUIResource()
// and creates a composite font that is able to display all Unicode characters
Font font = StyleContext.getDefaultStyleContext().getFont( family, style, size );
// always return non-UIResource font to avoid side effects when using font
// because Swing uninstalls UIResource fonts when switching L&F
// (StyleContext.getFont() may return a UIResource)
if( font instanceof UIResource )
font = font.deriveFont( font.getStyle() );
return font;
}
/**
* Registers a font family for lazy loading via {@link #loadFontFamily(String)}.
* <p>
* The given runnable is invoked when the given font family should be loaded.
* The runnable should invoke {@link #installFont(URL)} to load and register font(s)
* for the family.
* A family may consist of up to four font files for the supported font styles:
* regular (plain), italic, bold and bold-italic.
*/
public static void registerFontFamilyLoader( String family, Runnable loader ) {
if( loadersMap == null )
loadersMap = new HashMap<>();
loadersMap.put( family, loader );
}
/**
* Loads a font family previously registered via {@link #registerFontFamilyLoader(String, Runnable)}.
* If the family is already loaded or no londer is registered for that family, nothing happens.
*/
public static void loadFontFamily( String family ) {
if( !hasLoaders() )
return;
Runnable loader = loadersMap.remove( family );
if( loader != null )
loader.run();
if( loadersMap.isEmpty() )
loadersMap = null;
}
/**
* Loads a font file from the given url and registers it in the graphics environment.
* Uses {@link Font#createFont(int, InputStream)} and {@link GraphicsEnvironment#registerFont(Font)}.
*/
public static boolean installFont( URL url ) {
try( InputStream in = url.openStream() ) {
Font font = Font.createFont( Font.TRUETYPE_FONT, in );
return GraphicsEnvironment.getLocalGraphicsEnvironment().registerFont( font );
} catch( FontFormatException | IOException ex ) {
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to install font " + url, ex );
return false;
}
}
/**
* Returns all font familiy names available in the graphics environment.
* This invokes {@link GraphicsEnvironment#getAvailableFontFamilyNames()} and
* appends families registered for lazy loading via {@link #registerFontFamilyLoader(String, Runnable)}
* to the result.
*/
public static String[] getAvailableFontFamilyNames() {
String[] availableFontFamilyNames = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
if( !hasLoaders() )
return availableFontFamilyNames;
// append families that are not yet loaded
ArrayList<String> result = new ArrayList<>( availableFontFamilyNames.length + loadersMap.size() );
for( String name : availableFontFamilyNames )
result.add( name );
for( String name : loadersMap.keySet() ) {
if( !result.contains( name ) )
result.add( name );
}
return result.toArray( new String[result.size()] );
}
/**
* Returns all fonts available in the graphics environment.
* This first loads all families registered for lazy loading via {@link #registerFontFamilyLoader(String, Runnable)}
* and then invokes {@link GraphicsEnvironment#getAllFonts()}.
*/
public static Font[] getAllFonts() {
if( hasLoaders() ) {
// load all registered families
String[] families = loadersMap.keySet().toArray( new String[loadersMap.size()] );
for( String family : families )
loadFontFamily( family );
}
return GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
}
private static boolean hasLoaders() {
return loadersMap != null && !loadersMap.isEmpty();
}
}

View File

@@ -16,6 +16,7 @@
package com.formdev.flatlaf.util;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.font.GlyphVector;
@@ -141,37 +142,103 @@ public class HiDPIUtils
if( !useTextYCorrection() || !SystemInfo.isWindows )
return 0;
if( !SystemInfo.isJava_9_orLater )
return UIScale.getUserScaleFactor() > 1 ? -UIScale.scale( 0.625f ) : 0;
if( !SystemInfo.isJava_9_orLater ) {
// Java 8
float scaleFactor = getUserScaleFactor();
if( scaleFactor > 1 ) {
switch( g.getFont().getFamily() ) {
case "Segoe UI":
case "Segoe UI Light":
case "Segoe UI Semibold":
return -((scaleFactor == 2.25f || scaleFactor == 4f ? 0.875f : 0.625f) * scaleFactor);
AffineTransform t = g.getTransform();
double scaleY = t.getScaleY();
if( scaleY < 1.25 )
return 0;
case "Noto Sans":
case "Open Sans":
return -(0.3f * scaleFactor);
// Text is painted at slightly different Y positions depending on scale factor
// and Y position of component.
// The exact reason is not yet known (to me), but there are several factors:
// - fractional scale factors result in fractional component Y device coordinates
// - fractional text Y device coordinates are rounded for horizontal lines of characters
// - maybe different rounding methods for drawing primitives (e.g. rectangle) and text
// - Java adds 0.5 to X/Y positions before drawing string in BufferedTextPipe.enqueueGlyphList()
case "Verdana":
return -((scaleFactor < 2 ? 0.4f : 0.3f) * scaleFactor);
}
}
} else {
// Java 9 and later
// this is not the optimal solution, but works very good in most cases
// (tested with class FlatPaintingStringTest on Windows 10 with font "Segoe UI")
if( scaleY <= 1.25 )
return -0.875f;
if( scaleY <= 1.5 )
return -0.625f;
if( scaleY <= 1.75 )
return -0.875f;
if( scaleY <= 2.0 )
return -0.75f;
if( scaleY <= 2.25 )
return -0.875f;
if( scaleY <= 3.5 )
return -0.75f;
return -0.875f;
// Text is painted at slightly different Y positions depending on scale factor
// and Y position of component.
// The exact reason is not yet known (to me), but there are several factors:
// - fractional scale factors result in fractional component Y device coordinates
// - fractional text Y device coordinates are rounded for horizontal lines of characters
// - maybe different rounding methods for drawing primitives (e.g. rectangle) and text
// - Java adds 0.5 to X/Y positions before drawing string in BufferedTextPipe.enqueueGlyphList()
// this is not the optimal solution, but works very good in most cases
// (tested with class FlatPaintingStringTest on Windows 11)
switch( g.getFont().getFamily() ) {
case "Segoe UI":
case "Segoe UI Light":
case "Segoe UI Semibold":
case "Verdana":
case Font.DIALOG:
case Font.SANS_SERIF:
return correctionForScaleY( g, CORRECTION_SEGOE_UI );
case "Tahoma":
return correctionForScaleY( g, CORRECTION_TAHOMA );
case "Inter":
case "Inter Light":
case "Inter Semi Bold":
case "Roboto":
case "Roboto Light":
case "Roboto Medium":
return correctionForScaleY( g, CORRECTION_INTER );
case "Noto Sans":
case "Open Sans":
return correctionForScaleY( g, CORRECTION_OPEN_SANS );
}
}
return 0;
}
private static final float[]
SCALE_FACTORS = { 1.25f, 1.5f, 1.75f, 2f, 2.25f, 2.5f, 3f, 3.5f, 4f },
CORRECTION_SEGOE_UI = { -0.5f, -0.5f, -0.625f, -0.75f, -0.75f, -0.75f, -0.75f, -0.75f, -0.875f },
CORRECTION_TAHOMA = { -0.25f, -0.25f, -0.25f, -0f, -0.125f, -0.125f, -0.125f, -0.125f, -0f },
CORRECTION_INTER = { -0.25f, -0.25f, -0.25f, -0f, -0.125f, -0.125f, -0f, -0.25f, -0f },
CORRECTION_OPEN_SANS = { -0.5f, -0.25f, -0.25f, -0f, -0.25f, -0.25f, -0f, -0.25f, -0.25f };
private static float correctionForScaleY( Graphics2D g, float[] correction ) {
if( correction.length != 9 )
throw new IllegalArgumentException();
double scaleY = g.getTransform().getScaleY();
return (scaleY < 1.25) ? 0 : correction[scaleFactor2index( (float) scaleY )];
}
private static int scaleFactor2index( float scaleFactor ) {
for( int i = 0; i < SCALE_FACTORS.length; i++ ) {
if( scaleFactor <= SCALE_FACTORS[i] )
return i;
}
return SCALE_FACTORS.length - 1;
}
private static Boolean useDebugScaleFactor;
private static boolean useDebugScaleFactor() {
if( useDebugScaleFactor == null )
useDebugScaleFactor = FlatSystemProperties.getBoolean( "FlatLaf.debug.HiDPIUtils.useDebugScaleFactor", false );
return useDebugScaleFactor;
}
private static float getUserScaleFactor() {
return !useDebugScaleFactor()
? UIScale.getUserScaleFactor()
: Float.parseFloat( System.getProperty( "FlatLaf.debug.HiDPIUtils.debugScaleFactor", "1" ) );
}
/**

View File

@@ -73,6 +73,22 @@ public class NativeLibrary
: false;
}
/**
* Load native library using {@link System#loadLibrary(String)}.
* Searches for the library in classloader of caller
* (using {@link ClassLoader#findLibrary(String)}) and in paths specified
* in system properties {@code sun.boot.library.path} and {@code java.library.path}.
*
* @param libraryName name of the native library (without "lib" prefix and without extension)
* @param supported whether the native library is supported on the current platform
* @since 2.6
*/
public NativeLibrary( String libraryName, boolean supported ) {
this.loaded = supported
? loadLibraryFromSystem( libraryName )
: false;
}
/**
* Returns whether the native library is loaded.
* <p>
@@ -92,7 +108,7 @@ public class NativeLibrary
? classLoader.getResource( libraryName )
: NativeLibrary.class.getResource( "/" + libraryName );
if( libraryUrl == null ) {
log( "Library '" + libraryName + "' not found", null );
LoggingFacade.INSTANCE.logSevere( "Library '" + libraryName + "' not found", null );
return false;
}
@@ -125,7 +141,7 @@ public class NativeLibrary
return true;
} catch( Throwable ex ) {
log( null, ex );
LoggingFacade.INSTANCE.logSevere( ex.getMessage(), ex );
if( tempFile != null )
deleteOrMarkForDeletion( tempFile );
@@ -138,7 +154,24 @@ public class NativeLibrary
System.load( libraryFile.getAbsolutePath() );
return true;
} catch( Throwable ex ) {
log( ex.getMessage(), ex );
LoggingFacade.INSTANCE.logSevere( ex.getMessage(), ex );
return false;
}
}
private boolean loadLibraryFromSystem( String libraryName ) {
try {
System.loadLibrary( libraryName );
return true;
} catch( Throwable ex ) {
String message = ex.getMessage();
// do not log error if library was not found
// thrown in ClassLoader.loadLibrary(Class<?> fromClass, String name, boolean isAbsolute)
if( ex instanceof UnsatisfiedLinkError && message != null && message.contains( "java.library.path" ) )
return false;
LoggingFacade.INSTANCE.logSevere( message, ex );
return false;
}
}
@@ -158,10 +191,6 @@ public class NativeLibrary
: System.mapLibraryName( libraryName );
}
private static void log( String msg, Throwable thrown ) {
LoggingFacade.INSTANCE.logSevere( msg, thrown );
}
private static Path createTempFile( String libraryName ) throws IOException {
int sep = libraryName.lastIndexOf( '/' );
String name = (sep >= 0) ? libraryName.substring( sep + 1 ) : libraryName;

View File

@@ -16,6 +16,7 @@
package com.formdev.flatlaf.util;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
@@ -102,6 +103,13 @@ debug*/
int imageWidth = image.getWidth( null );
int imageHeight = image.getHeight( null );
// paint red rectangle if image has invalid size (e.g. not found)
if( imageWidth < 0 || imageHeight < 0 ) {
g.setColor( Color.red );
g.fillRect( x, y, getIconWidth(), getIconHeight() );
return;
}
// scale image if necessary to destination size
if( imageWidth != destImageWidth || imageHeight != destImageHeight ) {
// determine scaling method; default is "quality"

View File

@@ -22,6 +22,7 @@ module com.formdev.flatlaf {
exports com.formdev.flatlaf;
exports com.formdev.flatlaf.icons;
exports com.formdev.flatlaf.themes;
exports com.formdev.flatlaf.ui;
exports com.formdev.flatlaf.util;

View File

@@ -50,8 +50,9 @@
@selectionInactiveForeground = @foreground
# menu
@menuSelectionBackground = @selectionBackground
@menuHoverBackground = lighten(@menuBackground,10%,derived)
@menuCheckBackground = darken(@selectionBackground,10%,derived noAutoInverse)
@menuCheckBackground = darken(@menuSelectionBackground,10%,derived noAutoInverse)
@menuAcceleratorForeground = darken(@foreground,15%)
@menuAcceleratorSelectionForeground = @selectionForeground
@@ -62,7 +63,7 @@
# accent colors (blueish)
# set @accentColor to use single accent color or
# modify @accentBaseColor to use variations of accent base color
@accentColor = null
@accentColor = systemColor(accent,null)
@accentBaseColor = #4B6EAF
@accentBase2Color = lighten(saturate(spin(@accentBaseColor,-8),13%),5%)
# accent color variations
@@ -349,6 +350,11 @@ ToggleButton.disabledSelectedBackground = lighten($ToggleButton.background,3%,de
ToggleButton.toolbar.selectedBackground = lighten($ToggleButton.background,7%,derived)
#---- ToolBar ----
ToolBar.hoverButtonGroupBackground = lighten($ToolBar.background,3%,derived)
#---- ToolTip ----
ToolTip.border = 4,6,4,6

View File

@@ -285,6 +285,10 @@ ComboBox.buttonDisabledArrowColor = @buttonDisabledArrowColor
ComboBox.buttonHoverArrowColor = @buttonHoverArrowColor
ComboBox.buttonPressedArrowColor = @buttonPressedArrowColor
ComboBox.popupInsets = 0,0,0,0
ComboBox.selectionInsets = 0,0,0,0
ComboBox.selectionArc = 0
#---- Component ----
@@ -390,6 +394,8 @@ InternalFrameTitlePane.border = 0,8,0,0
List.border = 0,0,0,0
List.cellMargins = 1,6,1,6
List.selectionInsets = 0,0,0,0
List.selectionArc = 0
List.cellFocusColor = @cellFocusColor
List.cellNoFocusBorder = com.formdev.flatlaf.ui.FlatListCellBorder$Default
List.focusCellHighlightBorder = com.formdev.flatlaf.ui.FlatListCellBorder$Focused
@@ -422,6 +428,9 @@ MenuBar.border = com.formdev.flatlaf.ui.FlatMenuBarBorder
MenuBar.background = @menuBackground
MenuBar.hoverBackground = @menuHoverBackground
MenuBar.itemMargins = 3,8,3,8
MenuBar.selectionInsets = $MenuItem.selectionInsets
MenuBar.selectionEmbeddedInsets = $MenuItem.selectionInsets
MenuBar.selectionArc = $MenuItem.selectionArc
#---- MenuItem ----
@@ -444,6 +453,8 @@ MenuItem.textNoAcceleratorGap = 6
MenuItem.acceleratorArrowGap = 2
MenuItem.acceleratorDelimiter = "+"
[mac]MenuItem.acceleratorDelimiter = ""
MenuItem.selectionInsets = 0,0,0,0
MenuItem.selectionArc = 0
# for MenuItem.selectionType = underline
MenuItem.underlineSelectionBackground = @menuHoverBackground
@@ -847,6 +858,7 @@ ToolBar.borderMargins = 2,2,2,2
ToolBar.isRollover = true
ToolBar.focusableButtons = false
ToolBar.arrowKeysOnlyNavigation = true
ToolBar.hoverButtonGroupArc = 8
ToolBar.floatable = false
ToolBar.gripColor = @icon
ToolBar.dockingBackground = darken($ToolBar.background,5%)
@@ -883,10 +895,13 @@ Tree.dropCellForeground = @dropCellForeground
Tree.dropLineColor = @dropLineColor
Tree.rendererFillBackground = false
Tree.rendererMargins = 1,2,1,2
Tree.selectionInsets = 0,0,0,0
Tree.selectionArc = 0
Tree.wideSelection = true
Tree.repaintWholeRow = true
Tree.paintLines = false
Tree.showCellFocusIndicator = false
Tree.showDefaultIcons = false
Tree.leftChildIndent = 7
Tree.rightChildIndent = 11
Tree.rowHeight = 0
@@ -904,7 +919,6 @@ Tree.icon.closedColor = @icon
Tree.icon.openColor = @icon
#---- Styles ------------------------------------------------------------------
#---- inTextField ----

View File

@@ -50,8 +50,9 @@
@selectionInactiveForeground = @foreground
# menu
@menuSelectionBackground = @selectionBackground
@menuHoverBackground = darken(@menuBackground,10%,derived)
@menuCheckBackground = lighten(@selectionBackground,40%,derived noAutoInverse)
@menuCheckBackground = lighten(@menuSelectionBackground,40%,derived noAutoInverse)
@menuAcceleratorForeground = lighten(@foreground,30%)
@menuAcceleratorSelectionForeground = @selectionForeground
@@ -62,7 +63,7 @@
# accent colors (blueish)
# set @accentColor to use single accent color or
# modify @accentBaseColor to use variations of accent base color
@accentColor = null
@accentColor = systemColor(accent,null)
@accentBaseColor = #2675BF
@accentBase2Color = lighten(saturate(@accentBaseColor,10%),6%)
# accent color variations
@@ -356,6 +357,11 @@ ToggleButton.disabledSelectedBackground = darken($ToggleButton.background,13%,de
ToggleButton.toolbar.selectedBackground = $ToggleButton.selectedBackground
#---- ToolBar ----
ToolBar.hoverButtonGroupBackground = darken($ToolBar.background,3%,derived)
#---- ToolTip ----
ToolTip.border = 4,6,4,6,shade(@background,40%)

View File

@@ -44,6 +44,12 @@ info = lazy(ToolTip.background)
infoText = lazy(ToolTip.foreground)
#---- variables ----
# make sure that accent color (set via FlatLaf.setSystemColorGetter()) is ignored
@accentColor = null
#---- Button ----
Button.startBackground = $Button.background
@@ -213,6 +219,7 @@ ToggleButton.endBackground = $ToggleButton.background
[Solarized_Dark---4lex4]Component.accentColor = lazy(TabbedPane.underlineColor)
[Solarized_Dark---4lex4]Slider.focusedColor = fade($Component.focusColor,80%,derived)
[Solarized_Light---4lex4]Button.default.hoverBackground = darken($Button.default.background,3%,derived)
[Solarized_Light---4lex4]Component.accentColor = lazy(TabbedPane.underlineColor)
[vuesion-theme]Component.accentColor = lazy(Button.default.endBackground)

View File

@@ -0,0 +1,288 @@
#
# Copyright 2022 FormDev Software GmbH
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# base theme (light, dark, intellij or darcula); only used by theme editor
@baseTheme = dark
#---- macOS NSColor system colors (in NSColorSpace.deviceRGB) ----
# generated on macOS 12.2 using Xcode and flatlaf-testing/misc/MacOSColorDump.playground
@nsLabelColor = #ffffffd8
@nsSecondaryLabelColor = #ffffff8c
@nsTertiaryLabelColor = #ffffff3f
@nsQuaternaryLabelColor = #ffffff19
@nsSystemRedColor = #ff453a
@nsSystemGreenColor = #32d74b
@nsSystemBlueColor = #0a84ff
@nsSystemOrangeColor = #ff9f0a
@nsSystemYellowColor = #ffd60a
@nsSystemBrownColor = #ac8e68
@nsSystemPinkColor = #ff375f
@nsSystemPurpleColor = #bf5af2
@nsSystemTealColor = #6ac4dc
@nsSystemIndigoColor = #5e5ce6
@nsSystemMintColor = #63e6e2
@nsSystemCyanColor = #5ac8f5
@nsSystemGrayColor = #98989d
@nsLinkColor = #419cff
@nsPlaceholderTextColor = #ffffff3f
@nsWindowFrameTextColor = #ffffffd8
@nsSelectedMenuItemTextColor = #ffffff
@nsAlternateSelectedControlTextColor = #ffffff
@nsHeaderTextColor = #ffffff
@nsSeparatorColor = #ffffff19
@nsGridColor = #1a1a1a
@nsTextColor = #ffffff
@nsTextBackgroundColor = #1e1e1e
@nsSelectedTextColor = #ffffff
@nsSelectedTextBackgroundColor = #3f638b
@nsUnemphasizedSelectedTextBackgroundColor = #464646
@nsUnemphasizedSelectedTextColor = #ffffff
@nsWindowBackgroundColor = #323232
@nsUnderPageBackgroundColor = #282828
@nsControlBackgroundColor = #1e1e1e
@nsSelectedContentBackgroundColor = #0058d0
@nsUnemphasizedSelectedContentBackgroundColor = #464646
@nsFindHighlightColor = #ffff00
@nsControlColor = #ffffff3f
@nsControlTextColor = #ffffffd8
@nsSelectedControlColor = #3f638b
@nsSelectedControlTextColor = #ffffffd8
@nsDisabledControlTextColor = #ffffff3f
@nsKeyboardFocusIndicatorColor = #1aa9ff7f
@nsControlAccentColor = #007aff
# accent colors are:
# @nsSelectedTextBackgroundColor
# @nsSelectedContentBackgroundColor
# @nsSelectedControlColor
# @nsKeyboardFocusIndicatorColor
# @nsControlAccentColor
#---- variables ----
# general background and foreground (text color)
@background = @nsControlBackgroundColor
@foreground = over(@nsControlTextColor,@background)
@disabledForeground = over(@nsSecondaryLabelColor,@background)
# component background
@buttonBackground = over(@nsControlColor,@background)
@componentBackground = darken(over(@nsControlColor,@background),18%)
@disabledComponentBackground = darken(@componentBackground,2%)
@menuBackground = lighten(@background,8%)
# selection
@selectionBackground = if(systemColor(accent), shade(spin(systemColor(accent),4),20%), @nsSelectedContentBackgroundColor)
@selectionForeground = @nsSelectedMenuItemTextColor
@selectionInactiveBackground = @nsUnemphasizedSelectedContentBackgroundColor
# text selection
@textSelectionBackground = systemColor(highlight,if(systemColor(accent), darken(desaturate(systemColor(accent),60%),10%), @nsSelectedTextBackgroundColor))
@textSelectionForeground = @nsSelectedTextColor
# menu
@menuSelectionBackground = desaturate(@selectionBackground,20%)
@menuItemMargin = 3,11,3,11
# accent colors (blueish)
@accentColor = systemColor(accent,@nsControlAccentColor)
@accentFocusColor = if(systemColor(accent), fade(spin(systemColor(accent),-10),50%), @nsKeyboardFocusIndicatorColor)
#---- Button ----
Button.arc = 12
Button.borderWidth = 0
Button.disabledBackground = darken($Button.background,10%)
Button.default.borderWidth = 0
Button.toolbar.hoverBackground = #fff1
Button.toolbar.pressedBackground = #fff2
Button.toolbar.selectedBackground = #fff3
#---- CheckBox ----
CheckBox.iconTextGap = 6
CheckBox.arc = 7
CheckBox.icon.focusWidth = null
CheckBox.icon.style = filled
CheckBox.icon[filled].borderWidth = 0
CheckBox.icon[filled].selectedBorderWidth = 0
CheckBox.icon[filled].background = darken(over(@nsControlColor,@background),3%)
CheckBox.icon[filled].disabledBackground = darken($CheckBox.icon[filled].background,10%)
CheckBox.icon[filled].selectedBackground = @accentColor
CheckBox.icon[filled].checkmarkColor = fadeout(@nsSelectedMenuItemTextColor,15%)
CheckBox.icon[filled].disabledCheckmarkColor = darken($CheckBox.icon[filled].checkmarkColor,45%)
CheckBox.icon.focusedBackground = null
#---- ComboBox ----
ComboBox.buttonStyle = mac
ComboBox.background = over(@nsControlColor,@background)
ComboBox.editableBackground = @componentBackground
ComboBox.disabledBackground = @disabledComponentBackground
ComboBox.buttonBackground = @accentColor
ComboBox.buttonArrowColor = @nsSelectedMenuItemTextColor
ComboBox.buttonHoverArrowColor = darken($ComboBox.buttonArrowColor,15%,derived noAutoInverse)
ComboBox.buttonPressedArrowColor = darken($ComboBox.buttonArrowColor,25%,derived noAutoInverse)
ComboBox.popupBackground = @menuBackground
ComboBox.selectionBackground = @menuSelectionBackground
ComboBox.popupInsets = 5,0,5,0
ComboBox.selectionInsets = 0,5,0,5
ComboBox.selectionArc = 8
#---- Component ----
Component.focusWidth = 2
Component.innerFocusWidth = 0
Component.innerOutlineWidth = 0
Component.arc = 12
Component.borderColor = @nsSeparatorColor
Component.disabledBorderColor = fadeout(@nsSeparatorColor,5%)
#---- EditorPane ---
EditorPane.disabledBackground = @disabledComponentBackground
EditorPane.selectionBackground = @textSelectionBackground
EditorPane.selectionForeground = @textSelectionForeground
#---- FormattedTextField ---
FormattedTextField.disabledBackground = @disabledComponentBackground
FormattedTextField.selectionBackground = @textSelectionBackground
FormattedTextField.selectionForeground = @textSelectionForeground
#---- MenuBar ----
MenuBar.selectionInsets = 0,0,0,0
MenuBar.selectionEmbeddedInsets = 3,0,3,0
MenuBar.selectionArc = 8
MenuBar.selectionBackground = lighten(@menuBackground,15%,derived)
MenuBar.selectionForeground = @foreground
#---- MenuItem ----
MenuItem.selectionInsets = 0,5,0,5
MenuItem.selectionArc = 8
Menu.selectionBackground = @menuSelectionBackground
MenuItem.selectionBackground = @menuSelectionBackground
CheckBoxMenuItem.selectionBackground = @menuSelectionBackground
RadioButtonMenuItem.selectionBackground = @menuSelectionBackground
#---- PasswordField ---
PasswordField.disabledBackground = @disabledComponentBackground
PasswordField.selectionBackground = @textSelectionBackground
PasswordField.selectionForeground = @textSelectionForeground
#---- PopupMenu ----
PopupMenu.borderInsets = 6,1,6,1
#---- ProgressBar ----
ProgressBar.background = lighten(@background,8%)
#---- RadioButton ----
RadioButton.iconTextGap = 6
RadioButton.icon.style = filled
RadioButton.icon[filled].centerDiameter = 6
#---- ScrollBar ----
ScrollBar.width = 12
ScrollBar.track = @componentBackground
ScrollBar.thumb = @buttonBackground
# from FlatLaf.properties (when using not on macOS)
ScrollBar.minimumThumbSize = 18,18
ScrollBar.thumbInsets = 2,2,2,2
ScrollBar.thumbArc = 999
ScrollBar.hoverThumbWithTrack = true
#---- Separator ----
Separator.foreground = @nsSeparatorColor
#---- Slider ----
Slider.trackWidth = 3
Slider.thumbSize = 14,14
Slider.trackColor = lighten(@background,8%)
Slider.thumbColor = lighten($Slider.trackColor,35%)
Slider.disabledTrackColor = darken($Slider.trackColor,4%)
Slider.disabledThumbColor = darken($Slider.thumbColor,32%)
Slider.focusedColor = $Component.focusColor
#---- Spinner ----
Spinner.buttonStyle = mac
Spinner.disabledBackground = @disabledComponentBackground
Spinner.buttonBackground = @buttonBackground
Spinner.buttonArrowColor = @foreground
Spinner.buttonHoverArrowColor = lighten($Spinner.buttonArrowColor,10%,derived noAutoInverse)
Spinner.buttonPressedArrowColor = lighten($Spinner.buttonArrowColor,20%,derived noAutoInverse)
Spinner.buttonSeparatorWidth = 0
#---- TextArea ---
TextArea.disabledBackground = @disabledComponentBackground
TextArea.selectionBackground = @textSelectionBackground
TextArea.selectionForeground = @textSelectionForeground
#---- TextField ----
TextField.disabledBackground = @disabledComponentBackground
TextField.selectionBackground = @textSelectionBackground
TextField.selectionForeground = @textSelectionForeground
#---- TextPane ---
TextPane.disabledBackground = @disabledComponentBackground
TextPane.selectionBackground = @textSelectionBackground
TextPane.selectionForeground = @textSelectionForeground
#---- ToggleButton ----
ToggleButton.disabledBackground = $Button.disabledBackground
ToggleButton.selectedBackground = lighten($ToggleButton.background,20%,derived)
ToggleButton.toolbar.selectedBackground = #fff3

View File

@@ -0,0 +1,284 @@
#
# Copyright 2022 FormDev Software GmbH
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# base theme (light, dark, intellij or darcula); only used by theme editor
@baseTheme = light
#---- macOS NSColor system colors (in NSColorSpace.deviceRGB) ----
# generated on macOS 12.2 using Xcode and flatlaf-testing/misc/MacOSColorDump.playground
@nsLabelColor = #000000d8
@nsSecondaryLabelColor = #0000007f
@nsTertiaryLabelColor = #00000042
@nsQuaternaryLabelColor = #00000019
@nsSystemRedColor = #ff3b30
@nsSystemGreenColor = #28cd41
@nsSystemBlueColor = #007aff
@nsSystemOrangeColor = #ff9500
@nsSystemYellowColor = #ffcc00
@nsSystemBrownColor = #a2845e
@nsSystemPinkColor = #ff2d55
@nsSystemPurpleColor = #af52de
@nsSystemTealColor = #59adc4
@nsSystemIndigoColor = #5856d6
@nsSystemMintColor = #00c7be
@nsSystemCyanColor = #55bef0
@nsSystemGrayColor = #8e8e93
@nsLinkColor = #0068da
@nsPlaceholderTextColor = #0000003f
@nsWindowFrameTextColor = #000000d8
@nsSelectedMenuItemTextColor = #ffffff
@nsAlternateSelectedControlTextColor = #ffffff
@nsHeaderTextColor = #000000d8
@nsSeparatorColor = #00000019
@nsGridColor = #e6e6e6
@nsTextColor = #000000
@nsTextBackgroundColor = #ffffff
@nsSelectedTextColor = #000000
@nsSelectedTextBackgroundColor = #b3d7ff
@nsUnemphasizedSelectedTextBackgroundColor = #dcdcdc
@nsUnemphasizedSelectedTextColor = #000000
@nsWindowBackgroundColor = #ececec
@nsUnderPageBackgroundColor = #969696e5
@nsControlBackgroundColor = #ffffff
@nsSelectedContentBackgroundColor = #0063e1
@nsUnemphasizedSelectedContentBackgroundColor = #dcdcdc
@nsFindHighlightColor = #ffff00
@nsControlColor = #ffffff
@nsControlTextColor = #000000d8
@nsSelectedControlColor = #b3d7ff
@nsSelectedControlTextColor = #000000d8
@nsDisabledControlTextColor = #0000003f
@nsKeyboardFocusIndicatorColor = #0067f47f
@nsControlAccentColor = #007aff
# accent colors are:
# @nsSelectedTextBackgroundColor
# @nsSelectedContentBackgroundColor
# @nsSelectedControlColor
# @nsKeyboardFocusIndicatorColor
# @nsControlAccentColor
#---- variables ----
# general background and foreground (text color)
@background = #f6f6f6
@foreground = over(@nsControlTextColor,@background)
@disabledForeground = over(@nsTertiaryLabelColor,@background)
# component background
@buttonBackground = @nsControlColor
@componentBackground = @nsControlColor
@disabledComponentBackground = darken(@componentBackground,2%)
@menuBackground = darken(@background,4%)
# selection
@selectionBackground = if(systemColor(accent), shade(spin(systemColor(accent),4),10%), @nsSelectedContentBackgroundColor)
@selectionForeground = @nsSelectedMenuItemTextColor
@selectionInactiveBackground = @nsUnemphasizedSelectedContentBackgroundColor
# text selection
@textSelectionBackground = systemColor(highlight,if(systemColor(accent), tint(systemColor(accent),70%), @nsSelectedTextBackgroundColor))
@textSelectionForeground = @foreground
# menu
@menuSelectionBackground = lighten(@accentColor,12%)
@menuCheckBackground = lighten(@menuSelectionBackground,25%,derived noAutoInverse)
@menuItemMargin = 3,11,3,11
# accent colors (blueish)
@accentColor = systemColor(accent,@nsControlAccentColor)
@accentFocusColor = if(systemColor(accent), fade(spin(systemColor(accent),4),50%), @nsKeyboardFocusIndicatorColor)
#---- Button ----
Button.arc = 12
Button.disabledBackground = @disabledComponentBackground
Button.focusedBackground = null
Button.default.borderWidth = 1
Button.default.boldText = true
Button.default.background = @accentColor
Button.default.foreground = contrast($Button.default.background, @background, $Button.foreground, 20%)
#---- CheckBox ----
CheckBox.iconTextGap = 6
CheckBox.arc = 7
CheckBox.icon.focusWidth = null
CheckBox.icon.style = filled
CheckBox.icon[filled].borderWidth = 1
CheckBox.icon[filled].selectedBorderWidth = 0
CheckBox.icon[filled].disabledSelectedBorderWidth = 1
CheckBox.icon[filled].background = @nsControlColor
CheckBox.icon[filled].disabledBackground = @disabledComponentBackground
CheckBox.icon[filled].selectedBackground = @accentColor
CheckBox.icon[filled].borderColor = $Component.borderColor
CheckBox.icon[filled].disabledBorderColor = $Component.disabledBorderColor
CheckBox.icon[filled].checkmarkColor = @nsSelectedMenuItemTextColor
CheckBox.icon[filled].disabledCheckmarkColor = darken($CheckBox.icon[filled].checkmarkColor,25%)
CheckBox.icon.focusedBackground = null
#---- ComboBox ----
ComboBox.buttonStyle = mac
ComboBox.disabledBackground = @disabledComponentBackground
ComboBox.buttonBackground = @accentColor
ComboBox.buttonArrowColor = @nsSelectedMenuItemTextColor
ComboBox.buttonHoverArrowColor = darken($ComboBox.buttonArrowColor,15%,derived noAutoInverse)
ComboBox.buttonPressedArrowColor = darken($ComboBox.buttonArrowColor,25%,derived noAutoInverse)
ComboBox.popupBackground = @menuBackground
ComboBox.selectionBackground = @menuSelectionBackground
ComboBox.popupInsets = 5,0,5,0
ComboBox.selectionInsets = 0,5,0,5
ComboBox.selectionArc = 8
#---- Component ----
Component.focusWidth = 2
Component.innerFocusWidth = 0
Component.innerOutlineWidth = 0
Component.arc = 12
Component.borderColor = fadein(@nsSeparatorColor,5%)
Component.disabledBorderColor = @nsSeparatorColor
#---- EditorPane ---
EditorPane.disabledBackground = @disabledComponentBackground
EditorPane.selectionBackground = @textSelectionBackground
EditorPane.selectionForeground = @textSelectionForeground
#---- FormattedTextField ---
FormattedTextField.disabledBackground = @disabledComponentBackground
FormattedTextField.selectionBackground = @textSelectionBackground
FormattedTextField.selectionForeground = @textSelectionForeground
#---- MenuBar ----
MenuBar.selectionInsets = 0,0,0,0
MenuBar.selectionEmbeddedInsets = 3,0,3,0
MenuBar.selectionArc = 8
MenuBar.selectionBackground = darken(@menuBackground,15%,derived)
MenuBar.selectionForeground = @foreground
#---- MenuItem ----
MenuItem.selectionInsets = 0,5,0,5
MenuItem.selectionArc = 8
Menu.selectionBackground = @menuSelectionBackground
MenuItem.selectionBackground = @menuSelectionBackground
CheckBoxMenuItem.selectionBackground = @menuSelectionBackground
RadioButtonMenuItem.selectionBackground = @menuSelectionBackground
#---- PasswordField ---
PasswordField.disabledBackground = @disabledComponentBackground
PasswordField.selectionBackground = @textSelectionBackground
PasswordField.selectionForeground = @textSelectionForeground
#---- PopupMenu ----
PopupMenu.borderInsets = 6,1,6,1
#---- ProgressBar ----
ProgressBar.background = darken(@background,5%)
#---- RadioButton ----
RadioButton.iconTextGap = 6
RadioButton.icon.style = filled
RadioButton.icon[filled].centerDiameter = 6
#---- ScrollBar ----
ScrollBar.width = 12
ScrollBar.track = darken(@componentBackground,2%)
ScrollBar.thumb = darken(@componentBackground,24%)
# from FlatLaf.properties (when using not on macOS)
ScrollBar.minimumThumbSize = 18,18
ScrollBar.thumbInsets = 2,2,2,2
ScrollBar.thumbArc = 999
ScrollBar.hoverThumbWithTrack = true
#---- Separator ----
Separator.foreground = @nsSeparatorColor
#---- Slider ----
Slider.trackWidth = 3
Slider.thumbSize = 14,14
Slider.trackColor = darken(@background,7%)
Slider.thumbColor = @componentBackground
Slider.thumbBorderColor = $Component.borderColor
Slider.disabledTrackColor = lighten($Slider.trackColor,3%)
Slider.disabledThumbColor = darken($Slider.thumbColor,3%)
#---- Spinner ----
Spinner.buttonStyle = mac
Spinner.disabledBackground = @disabledComponentBackground
Spinner.buttonArrowColor = @foreground
Spinner.buttonHoverArrowColor = lighten($Spinner.buttonArrowColor,20%,derived noAutoInverse)
Spinner.buttonPressedArrowColor = lighten($Spinner.buttonArrowColor,30%,derived noAutoInverse)
#---- TextArea ---
TextArea.disabledBackground = @disabledComponentBackground
TextArea.selectionBackground = @textSelectionBackground
TextArea.selectionForeground = @textSelectionForeground
#---- TextField ----
TextField.disabledBackground = @disabledComponentBackground
TextField.selectionBackground = @textSelectionBackground
TextField.selectionForeground = @textSelectionForeground
#---- TextPane ---
TextPane.disabledBackground = @disabledComponentBackground
TextPane.selectionBackground = @textSelectionBackground
TextPane.selectionForeground = @textSelectionForeground
#---- ToggleButton ----
ToggleButton.disabledBackground = $Button.disabledBackground

View File

@@ -185,7 +185,10 @@ public class TestFlatStyleableInfo
"buttonHoverArrowColor", Color.class,
"buttonPressedArrowColor", Color.class,
"popupBackground", Color.class
"popupBackground", Color.class,
"popupInsets", Insets.class,
"selectionInsets", Insets.class,
"selectionArc", int.class
);
// border
@@ -266,6 +269,8 @@ public class TestFlatStyleableInfo
"selectionForeground", Color.class,
"selectionInactiveBackground", Color.class,
"selectionInactiveForeground", Color.class,
"selectionInsets", Insets.class,
"selectionArc", int.class,
// FlatListCellBorder
"cellMargins", Insets.class,
@@ -283,6 +288,9 @@ public class TestFlatStyleableInfo
Map<String, Class<?>> expected = expectedMap(
"itemMargins", Insets.class,
"selectionInsets", Insets.class,
"selectionEmbeddedInsets", Insets.class,
"selectionArc", int.class,
"hoverBackground", Color.class,
"selectionBackground", Color.class,
"selectionForeground", Color.class,
@@ -369,6 +377,9 @@ public class TestFlatStyleableInfo
"checkBackground", Color.class,
"checkMargins", Insets.class,
"selectionInsets", Insets.class,
"selectionArc", int.class,
"underlineSelectionBackground", Color.class,
"underlineSelectionCheckBackground", Color.class,
"underlineSelectionColor", Color.class,
@@ -899,6 +910,8 @@ public class TestFlatStyleableInfo
Map<String, Class<?>> expected = expectedMap(
"focusableButtons", boolean.class,
"arrowKeysOnlyNavigation", boolean.class,
"hoverButtonGroupArc", int.class,
"hoverButtonGroupBackground", Color.class,
"borderMargins", Insets.class,
"gripColor", Color.class
@@ -931,6 +944,8 @@ public class TestFlatStyleableInfo
"selectionInactiveBackground", Color.class,
"selectionInactiveForeground", Color.class,
"selectionBorderColor", Color.class,
"selectionInsets", Insets.class,
"selectionArc", int.class,
"wideSelection", boolean.class,
"showCellFocusIndicator", boolean.class,

View File

@@ -316,6 +316,9 @@ public class TestFlatStyling
ui.applyStyle( "buttonPressedArrowColor: #fff" );
ui.applyStyle( "popupBackground: #fff" );
ui.applyStyle( "popupInsets: 1,2,3,4" );
ui.applyStyle( "selectionInsets: 1,2,3,4" );
ui.applyStyle( "selectionArc: 8" );
// border
flatRoundBorder( style -> ui.applyStyle( style ) );
@@ -413,6 +416,8 @@ public class TestFlatStyling
ui.applyStyle( "selectionForeground: #fff" );
ui.applyStyle( "selectionInactiveBackground: #fff" );
ui.applyStyle( "selectionInactiveForeground: #fff" );
ui.applyStyle( "selectionInsets: 1,2,3,4" );
ui.applyStyle( "selectionArc: 8" );
// FlatListCellBorder
ui.applyStyle( "cellMargins: 1,2,3,4" );
@@ -435,6 +440,9 @@ public class TestFlatStyling
FlatMenuBarUI ui = (FlatMenuBarUI) c.getUI();
ui.applyStyle( "itemMargins: 1,2,3,4" );
ui.applyStyle( "selectionInsets: 1,2,3,4" );
ui.applyStyle( "selectionEmbeddedInsets: 1,2,3,4" );
ui.applyStyle( "selectionArc: 8" );
ui.applyStyle( "hoverBackground: #fff" );
ui.applyStyle( "selectionBackground: #fff" );
ui.applyStyle( "selectionForeground: #fff" );
@@ -523,6 +531,9 @@ public class TestFlatStyling
applyStyle.accept( "checkBackground: #fff" );
applyStyle.accept( "checkMargins: 1,2,3,4" );
applyStyle.accept( "selectionInsets: 1,2,3,4" );
applyStyle.accept( "selectionArc: 8" );
applyStyle.accept( "underlineSelectionBackground: #fff" );
applyStyle.accept( "underlineSelectionCheckBackground: #fff" );
applyStyle.accept( "underlineSelectionColor: #fff" );
@@ -1102,6 +1113,8 @@ public class TestFlatStyling
ui.applyStyle( "focusableButtons: true" );
ui.applyStyle( "arrowKeysOnlyNavigation: true" );
ui.applyStyle( "hoverButtonGroupArc: 12" );
ui.applyStyle( "hoverButtonGroupBackground: #fff" );
ui.applyStyle( "borderMargins: 1,2,3,4" );
ui.applyStyle( "gripColor: #fff" );
@@ -1137,6 +1150,8 @@ public class TestFlatStyling
ui.applyStyle( "selectionInactiveBackground: #fff" );
ui.applyStyle( "selectionInactiveForeground: #fff" );
ui.applyStyle( "selectionBorderColor: #fff" );
ui.applyStyle( "selectionInsets: 1,2,3,4" );
ui.applyStyle( "selectionArc: 8" );
ui.applyStyle( "wideSelection: true" );
ui.applyStyle( "showCellFocusIndicator: true" );

View File

@@ -30,7 +30,7 @@ import com.formdev.flatlaf.FlatSystemProperties;
*/
public class TestUtils
{
public static final float[] FACTORS = new float[] { 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 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 ) {
System.setProperty( FlatSystemProperties.UI_SCALE, "1x" );

View File

@@ -27,6 +27,7 @@ public class TestColorFunctions
{
@Test
void colorFunctions() {
// lighten, darken
assertEquals( new Color( 0xff6666 ), ColorFunctions.lighten( Color.red, 0.2f ) );
assertEquals( new Color( 0x990000 ), ColorFunctions.darken( Color.red, 0.2f ) );
@@ -38,6 +39,11 @@ public class TestColorFunctions
assertEquals( new Color( 0xffaa00 ), ColorFunctions.spin( Color.red,40 ) );
assertEquals( new Color( 0xff00aa ), ColorFunctions.spin( Color.red,-40 ) );
// fade
assertEquals( new Color( 0x33ff0000, true ), ColorFunctions.fade( Color.red, 0.2f ) );
assertEquals( new Color( 0xccff0000, true ), ColorFunctions.fade( Color.red, 0.8f ) );
assertEquals( new Color( 0xccff0000, true ), ColorFunctions.fade( new Color( 0x10ff0000, true ), 0.8f ) );
// mix
assertEquals( new Color( 0x1ae600 ), ColorFunctions.mix( Color.red, Color.green, 0.1f ) );
assertEquals( new Color( 0x40bf00 ), ColorFunctions.mix( Color.red, Color.green, 0.25f ) );

View File

@@ -1,7 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd">
<rect width="16" height="16" fill="#6E6E6E" rx="3"/>
<rect width="6" height="2" x="5" y="11.5" fill="#FFF"/>
<path fill="#FFF" d="M2,8 L8,2 L14,8 L11,8 L11,10 L5,10 L5,8 L2,8 Z"/>
<rect width="5" height="2" x="5.5" y="11.5" stroke="#FFF" stroke-linejoin="round"/>
<path stroke="#FFF" stroke-linejoin="round" d="M2.5,7.5 L8,2 L13.5,7.5 L10.5,7.5 L10.5,9.5 L5.5,9.5 L5.5,7.5 L2.5,7.5 Z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 328 B

After

Width:  |  Height:  |  Size: 408 B

View File

@@ -1,10 +1,12 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd">
<rect width="2" height="2" x="2" y="3" fill="#6E6E6E"/>
<rect width="2" height="2" x="2" y="7" fill="#6E6E6E"/>
<rect width="2" height="2" x="2" y="11" fill="#6E6E6E"/>
<rect width="8" height="2" x="6" y="3" fill="#6E6E6E"/>
<rect width="8" height="2" x="6" y="7" fill="#6E6E6E"/>
<rect width="8" height="2" x="6" y="11" fill="#6E6E6E"/>
<rect width="2" height="1" x="2" y="3" fill="#6E6E6E" rx=".5"/>
<rect width="2" height="1" x="2" y="6" fill="#6E6E6E" rx=".5"/>
<rect width="2" height="1" x="2" y="9" fill="#6E6E6E" rx=".5"/>
<rect width="2" height="1" x="2" y="12" fill="#6E6E6E" rx=".5"/>
<rect width="8" height="1" x="6" y="3" fill="#6E6E6E" rx=".5"/>
<rect width="8" height="1" x="6" y="6" fill="#6E6E6E" rx=".5"/>
<rect width="8" height="1" x="6" y="9" fill="#6E6E6E" rx=".5"/>
<rect width="8" height="1" x="6" y="12" fill="#6E6E6E" rx=".5"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 498 B

After

Width:  |  Height:  |  Size: 682 B

View File

@@ -1,3 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<polygon fill="#6E6E6E" fill-rule="evenodd" points="2 8 8 2 14 8 12 8 12 13 9 13 9 10 7 10 7 13 4 13 4 8"/>
<g fill="none" fill-rule="evenodd">
<polyline stroke="#6E6E6E" stroke-linejoin="round" points="6.5 13 6.5 9.5 9.5 9.5 9.5 13"/>
<path stroke="#6E6E6E" d="M3.5,6.5 L3.5,12.5 C3.5,13.0522847 3.94771525,13.5 4.5,13.5 L11.5,13.5 C12.0522847,13.5 12.5,13.0522847 12.5,12.5 L12.5,6.5 L12.5,6.5"/>
<polyline stroke="#6E6E6E" stroke-linecap="round" stroke-linejoin="round" points="1.5 8.5 8 2 14.5 8.5"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 201 B

After

Width:  |  Height:  |  Size: 509 B

View File

@@ -1,8 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd">
<rect width="4" height="4" x="3" y="3" fill="#6E6E6E"/>
<rect width="4" height="4" x="3" y="9" fill="#6E6E6E"/>
<rect width="4" height="4" x="9" y="9" fill="#6E6E6E"/>
<rect width="4" height="4" x="9" y="3" fill="#6E6E6E"/>
<rect width="4" height="4" x="2.5" y="2.5" stroke="#6E6E6E" rx="1.5"/>
<rect width="4" height="4" x="2.5" y="9.5" stroke="#6E6E6E" rx="1.5"/>
<rect width="4" height="4" x="9.5" y="9.5" stroke="#6E6E6E" rx="1.5"/>
<rect width="4" height="4" x="9.5" y="2.5" stroke="#6E6E6E" rx="1.5"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 376 B

After

Width:  |  Height:  |  Size: 436 B

View File

@@ -1,6 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd">
<polygon fill="#6E6E6E" points="2 3 5.5 3 7 5 14 5 14 8 11 8 11 10 9 10 9 13 2 13"/>
<path fill="#59A869" d="M14,11 L16,11 L16,13 L14,13 L14,15 L12,15 L12,13 L10,13 L10,11 L12,11 L12,9 L14,9 L14,11 Z"/>
<path stroke="#6E6E6E" d="M13,13.5 L3,13.5 C2.17157288,13.5 1.5,12.8284271 1.5,12 L1.5,4 C1.5,3.17157288 2.17157288,2.5 3,2.5 L6.29289322,2.5 C6.42550146,2.5 6.55267842,2.55267842 6.64644661,2.64644661 L8.5,4.5 L8.5,4.5 L13,4.5 C13.8284271,4.5 14.5,5.17157288 14.5,6 L14.5,12 C14.5,12.8284271 13.8284271,13.5 13,13.5 Z"/>
<line x1="5.5" x2="10.5" y1="9" y2="9" stroke="#59A869" stroke-linecap="round"/>
<line x1="8" x2="8" y1="6.5" y2="11.5" stroke="#59A869" stroke-linecap="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 347 B

After

Width:  |  Height:  |  Size: 632 B

View File

@@ -1,6 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd">
<polygon fill="#6E6E6E" points="2 3 5.5 3 7 5 9 5 9 9 13 9 13 5 14 5 14 13 2 13"/>
<path fill="#389FD6" d="M12,4 L12,8 L10,8 L10,4 L8,4 L11,1 L14,4 L12,4 Z"/>
<path stroke="#6E6E6E" d="M13,13.5 L3,13.5 C2.17157288,13.5 1.5,12.8284271 1.5,12 L1.5,4 C1.5,3.17157288 2.17157288,2.5 3,2.5 L6.29289322,2.5 C6.42550146,2.5 6.55267842,2.55267842 6.64644661,2.64644661 L8.5,4.5 L8.5,4.5 L13,4.5 C13.8284271,4.5 14.5,5.17157288 14.5,6 L14.5,12 C14.5,12.8284271 13.8284271,13.5 13,13.5 Z"/>
<line x1="8" x2="8" y1="6.5" y2="11.5" stroke="#389FD6" stroke-linecap="round"/>
<polyline stroke="#389FD6" stroke-linecap="round" stroke-linejoin="round" points="5.5 9 8 6.5 10.5 9"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 303 B

After

Width:  |  Height:  |  Size: 655 B

View File

@@ -1,6 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd">
<path fill="#6E6E6E" d="M2,3 L14,3 L14,11 L2,11 L2,3 Z M4,5 L4,9 L12,9 L12,5 L4,5 Z"/>
<rect width="12" height="2" x="2" y="12" fill="#6E6E6E"/>
<rect width="11" height="7" x="2.5" y="3.5" stroke="#6E6E6E" rx="1"/>
<line x1="8" x2="8" y1="11" y2="12" stroke="#6E6E6E"/>
<line x1="4.5" x2="11.5" y1="12.5" y2="12.5" stroke="#6E6E6E" stroke-linecap="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 289 B

After

Width:  |  Height:  |  Size: 360 B

View File

@@ -1,3 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<polygon fill="#6E6E6E" fill-rule="evenodd" points="1 2 6 2 8 4 15 4 15 13 1 13"/>
<path fill="none" stroke="#6E6E6E" d="M13,13.5 L3,13.5 C2.17157288,13.5 1.5,12.8284271 1.5,12 L1.5,4 C1.5,3.17157288 2.17157288,2.5 3,2.5 L6.29289322,2.5 C6.42550146,2.5 6.55267842,2.55267842 6.64644661,2.64644661 L8.5,4.5 L8.5,4.5 L13,4.5 C13.8284271,4.5 14.5,5.17157288 14.5,6 L14.5,12 C14.5,12.8284271 13.8284271,13.5 13,13.5 Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 176 B

After

Width:  |  Height:  |  Size: 427 B

View File

@@ -1,6 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd">
<polygon fill="#6E6E6E" points="8 6 8 1 13 1 13 15 3 15 3 6"/>
<polygon fill="#6E6E6E" points="3 5 7 5 7 1"/>
<g fill="none" fill-rule="evenodd" stroke-linejoin="round">
<path stroke="#6E6E6E" d="M4,1.5 L8.8,1.5 L8.8,1.5 L13.5,6.2 L13.5,13 C13.5,13.8284271 12.8284271,14.5 12,14.5 L4,14.5 C3.17157288,14.5 2.5,13.8284271 2.5,13 L2.5,3 C2.5,2.17157288 3.17157288,1.5 4,1.5 Z"/>
<path stroke="#6E6E6E" d="M8.5,2 L8.5,5 C8.5,5.82842712 9.17157288,6.5 10,6.5 L13,6.5 L13,6.5"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 254 B

After

Width:  |  Height:  |  Size: 472 B

View File

@@ -1,6 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd">
<path fill="#6E6E6E" d="M11,14 L11,11 L5,11 L5,14 L2,14 L2,2 L14,2 L14,14 L11,14 Z M4,4 L4,8 L12,8 L12,4 L4,4 Z"/>
<rect width="4" height="2" x="6" y="12" fill="#6E6E6E"/>
<g fill="none" fill-rule="evenodd" stroke-linejoin="round">
<path stroke="#6E6E6E" d="M3.5,2.5 L11.5,2.5 L11.5,2.5 L13.5,4.5 L13.5,12.5 C13.5,13.0522847 13.0522847,13.5 12.5,13.5 L3.5,13.5 C2.94771525,13.5 2.5,13.0522847 2.5,12.5 L2.5,3.5 C2.5,2.94771525 2.94771525,2.5 3.5,2.5 Z"/>
<polyline stroke="#6E6E6E" points="4.5 13 4.5 9.5 11.5 9.5 11.5 13"/>
<polyline stroke="#6E6E6E" points="5.5 3 5.5 5.5 10.5 5.5 10.5 3"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 316 B

After

Width:  |  Height:  |  Size: 533 B

View File

@@ -1,3 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="#6E6E6E" fill-rule="evenodd" d="M2,6 L14,6 L14,10 L2,10 L2,6 Z M12,8 L12,9 L13,9 L13,8 L12,8 Z M10,8 L10,9 L11,9 L11,8 L10,8 Z"/>
<g fill="none" fill-rule="evenodd">
<rect width="11" height="5" x="2.5" y="5.5" stroke="#6E6E6E" rx="1"/>
<circle cx="11.5" cy="8.5" r="1" fill="#6E6E6E"/>
<circle cx="9.5" cy="8.5" r="1" fill="#6E6E6E"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 235 B

After

Width:  |  Height:  |  Size: 317 B

View File

@@ -6,7 +6,7 @@
</linearGradient>
</defs>
<g fill="none" fill-rule="evenodd">
<rect width="16" height="16" fill="url(#flatlaf-a)"/>
<rect width="16" height="16" fill="url(#flatlaf-a)" rx="2"/>
<polygon fill="#FFF" points="9 13 13 13 12.5 11.5 10.5 11.5 10.5 6.5 9 6"/>
<polygon fill="#FFF" points="4 12.5 4 3 9 3 8.5 4.5 5.5 4.5 5.5 7 7.5 7 7 8.5 5.5 8.5 5.5 12"/>
</g>

Before

Width:  |  Height:  |  Size: 583 B

After

Width:  |  Height:  |  Size: 590 B

View File

@@ -2,6 +2,7 @@
<g fill="none" fill-rule="evenodd">
<circle cx="11" cy="11" r="10.5" fill="#6E6E6E"/>
<circle cx="11" cy="11" r="9.5" fill="#FFF"/>
<path fill="#6E6E6E" d="M10,17 L12,17 L12,15 L10,15 L10,17 Z M11,5 C8.8,5 7,6.8 7,9 L9,9 C9,7.9 9.9,7 11,7 C12.1,7 13,7.9 13,9 C13,11 10,10.75 10,14 L12,14 C12,11.75 15,11.5 15,9 C15,6.8 13.2,5 11,5 Z"/>
<path stroke="#6E6E6E" stroke-linecap="round" stroke-width="2" d="M8,8.5 C8.25,7 9.66585007,6 11,6 C12.5,6 14,7 14,8.5 C14,10.5 11,11 11,13"/>
<circle cx="11" cy="16" r="1.2" fill="#6E6E6E"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 448 B

After

Width:  |  Height:  |  Size: 440 B

View File

@@ -1,7 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
<g fill="none" fill-rule="evenodd">
<circle cx="16" cy="16" r="14" fill="#DB5860"/>
<rect width="4" height="11" x="14" y="7" fill="#FFF"/>
<rect width="4" height="4" x="14" y="21" fill="#FFF"/>
<rect width="4" height="12" x="14" y="7" fill="#FFF" rx="2"/>
<circle cx="16" cy="23" r="2" fill="#FFF"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 306 B

After

Width:  |  Height:  |  Size: 302 B

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