Compare commits

..

11 Commits

Author SHA1 Message Date
Karl Tauber
4d7a6ff331 AnimatedPainter:
- renamed `getValues()` to `getAnimatableValues()`
- renamed `getClientPropertyKey()` to `getAnimationClientPropertyKey()`
- AnimatedPainterSupport improvements
2025-03-13 11:46:14 +01:00
Karl Tauber
23fc3674c9 LineChartPanel:
- support "synchron" charts
- reworked to make code easier to understand/maintain
- added some JavaBean properties to make it configurable in JFormDesigner
- fixes some bugs

removed `FlatAnimatorTest.LineChartPanel` and replaced it with `LineChartPanel`
2025-03-12 18:35:56 +01:00
Karl Tauber
34a7214dd8 LineChartPanel copied from branch smooth-scrolling, commit 44a04cca2c 2025-03-11 19:33:36 +01:00
Karl Tauber
26d7008c04 AnimatedPainter: support individual animation duration, resolution and interpolator depending on value(s) 2021-11-22 22:07:45 +01:00
Karl Tauber
3b489e8e1a AnimatedPainter: support independent animation of multiple values 2021-11-22 22:07:20 +01:00
Karl Tauber
ccbf577f46 AnimatedBorder: demo for labeled material border 2021-11-21 23:20:47 +01:00
Karl Tauber
b903f18130 FlatAnimatorTest:
- support synchronized line chart
- LineChartPanel: added slider to change horizontal scaling
- FlatAnimatedIconTest: added line chart panel
- FlatAnimatedBorderTest: added line chart panel
2021-11-21 12:27:31 +01:00
Karl Tauber
9523c89c51 FlatAnimatorTest: added standard-easing and line chart
(line chart copied from `FlatSmoothScrollingTest.LineChartPanel` in branch `smooth-scrolling` commit 331ab06b0087d3a70f7c131368b88e5e7c92102f)
2021-11-20 15:14:03 +01:00
Karl Tauber
aa6fb2fcce AnimatedPainter added (refactored from AnimatedBorder and AnimatedIcon)
(checked API compatibility of AnimatedIcon with gradle task sigtestCheck)
2021-11-20 11:13:06 +01:00
Karl Tauber
e4fa2e28ea AnimatedBorder:
- support repainting only necessary region while animating
- use AbstractBorder in test app and fixed insets
2021-11-19 18:02:54 +01:00
Karl Tauber
b2245e2246 AnimatedBorder added (for future animations) (issue #66) 2021-11-19 18:02:54 +01:00
568 changed files with 39922 additions and 63758 deletions

2
.gitattributes vendored
View File

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

1
.github/FUNDING.yml vendored
View File

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

View File

@@ -1,5 +1,4 @@
# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions # https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
# https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle
name: CI name: CI
@@ -9,6 +8,9 @@ on:
- '*' - '*'
tags: tags:
- '[0-9]*' - '[0-9]*'
pull_request:
branches:
- '*'
jobs: jobs:
build: build:
@@ -17,46 +19,51 @@ jobs:
strategy: strategy:
matrix: matrix:
# test against # test against
# - Java 8 (minimum requirement) # - Java 1.8 (minimum requirement)
# - Java 9 (first version with JPMS)
# - Java LTS versions (11, 17, ...) # - Java LTS versions (11, 17, ...)
# - lastest Java version(s) # - lastest Java version(s)
java: java:
- 8 - 1.8
- 9
- 11 # LTS - 11 # LTS
- 17 # LTS - 14
toolchain: [""] - 15
include:
- java: 17
toolchain: 21 # latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v2
- uses: gradle/wrapper-validation-action@v1 - uses: gradle/wrapper-validation-action@v1
if: matrix.java == '8' if: matrix.java == '1.8'
- name: Setup Java ${{ matrix.java }} - name: Setup Java ${{ matrix.java }}
uses: actions/setup-java@v3 uses: actions/setup-java@v1
with: with:
java-version: ${{ matrix.java }} java-version: ${{ matrix.java }}
distribution: temurin # Java 8, 11 and 17 are pre-installed on ubuntu-latest
cache: gradle
- name: Check with Error Prone - name: Cache Gradle wrapper
if: matrix.java == '11' uses: actions/cache@v1
run: ./gradlew errorprone clean -Dtoolchain=${{ matrix.toolchain }} with:
path: ~/.gradle/wrapper
key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }}
- name: Cache Gradle cache
uses: actions/cache@v2
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}
restore-keys: ${{ runner.os }}-gradle
- name: Build with Gradle - name: Build with Gradle
run: ./gradlew build -Dtoolchain=${{ matrix.toolchain }} run: ./gradlew build
- name: Upload artifacts - name: Upload artifacts
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v2
if: matrix.java == '11' if: matrix.java == '11'
with: with:
name: FlatLaf-build-artifacts name: FlatLaf-build-artifacts
path: | path: |
flatlaf-*/build/libs flatlaf-*/build/libs
flatlaf-*/flatlaf-*/build/libs
!**/*-javadoc.jar !**/*-javadoc.jar
!**/*-sources.jar !**/*-sources.jar
@@ -66,21 +73,32 @@ jobs:
needs: build needs: build
if: | if: |
github.event_name == 'push' && github.event_name == 'push' &&
(github.ref == 'refs/heads/main' || startsWith( github.ref, 'refs/heads/develop-' )) && github.ref == 'refs/heads/main' &&
github.repository == 'JFormDesigner/FlatLaf' github.repository == 'JFormDesigner/FlatLaf'
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v2
- name: Setup Java 11 - name: Setup Java 11
uses: actions/setup-java@v3 uses: actions/setup-java@v1
with: with:
java-version: 11 java-version: 11
distribution: temurin # pre-installed on ubuntu-latest
cache: gradle - name: Cache Gradle wrapper
uses: actions/cache@v1
with:
path: ~/.gradle/wrapper
key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }}
- name: Cache Gradle cache
uses: actions/cache@v2
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}
restore-keys: ${{ runner.os }}-gradle
- name: Publish snapshot to oss.sonatype.org - name: Publish snapshot to oss.sonatype.org
run: ./gradlew publish :flatlaf-theme-editor:build -PskipFonts -Dorg.gradle.internal.publish.checksums.insecure=true -Dorg.gradle.parallel=false run: ./gradlew publish :flatlaf-theme-editor:build -Dorg.gradle.internal.publish.checksums.insecure=true
env: env:
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
@@ -106,17 +124,28 @@ jobs:
github.repository == 'JFormDesigner/FlatLaf' github.repository == 'JFormDesigner/FlatLaf'
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v2
- name: Setup Java 11 - name: Setup Java 11
uses: actions/setup-java@v3 uses: actions/setup-java@v1
with: with:
java-version: 11 java-version: 11
distribution: temurin # pre-installed on ubuntu-latest
cache: gradle - name: Cache Gradle wrapper
uses: actions/cache@v1
with:
path: ~/.gradle/wrapper
key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }}
- name: Cache Gradle cache
uses: actions/cache@v2
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}
restore-keys: ${{ runner.os }}-gradle
- name: Release a new stable version to Maven Central - name: Release a new stable version to Maven Central
run: ./gradlew publish :flatlaf-demo:build :flatlaf-theme-editor:build -PskipFonts -Prelease -Dorg.gradle.parallel=false run: ./gradlew publish :flatlaf-demo:build :flatlaf-theme-editor:build -Drelease=true
env: env:
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}

View File

@@ -1,60 +0,0 @@
# 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: temurin # 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,5 +1,4 @@
# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions # https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
# https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle
name: Native Libraries name: Native Libraries
@@ -10,41 +9,50 @@ on:
tags: tags:
- '[0-9]*' - '[0-9]*'
paths: paths:
- 'flatlaf-natives/**' - 'flatlaf-natives/flatlaf-natives-windows/**'
- '.github/workflows/natives.yml'
pull_request:
branches:
- '*'
paths:
- 'flatlaf-natives/flatlaf-natives-windows/**'
- '.github/workflows/natives.yml' - '.github/workflows/natives.yml'
- 'gradle/wrapper/gradle-wrapper.properties'
jobs: jobs:
Natives: Windows:
strategy: runs-on: windows-latest
matrix:
os:
- windows
- ubuntu
runs-on: ${{ matrix.os }}-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v2
- uses: gradle/wrapper-validation-action@v1 - uses: gradle/wrapper-validation-action@v1
- name: Setup Java 11 - name: Setup Java 1.8
uses: actions/setup-java@v3 uses: actions/setup-java@v1
with: with:
java-version: 11 java-version: 1.8
distribution: temurin
cache: gradle - name: Cache Gradle wrapper
uses: actions/cache@v1
with:
path: ~/.gradle/wrapper
key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }}
- name: Cache Gradle cache
uses: actions/cache@v2
with:
path: |
~/.gradle/caches
!~/.gradle/caches/modules-2/modules-2.lock
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}
restore-keys: ${{ runner.os }}-gradle
- name: Build with Gradle - name: Build with Gradle
# --no-daemon is necessary on Windows otherwise caching Gradle would fail with: run: ./gradlew :flatlaf-natives-windows:build
# tar.exe: Couldn't open ~/.gradle/caches/modules-2/modules-2.lock: Permission denied
run: ./gradlew build-natives --no-daemon
- name: Upload artifacts - name: Upload artifacts
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v2
with: with:
name: FlatLaf-natives-build-artifacts-${{ matrix.os }} name: FlatLaf-natives-windows-build-artifacts
path: | path: |
flatlaf-core/src/main/resources/com/formdev/flatlaf/natives flatlaf-natives/flatlaf-natives-windows/build
flatlaf-natives/flatlaf-natives-*/build

2
.gitignore vendored
View File

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

View File

@@ -1,472 +1,7 @@
FlatLaf Change Log FlatLaf Change Log
================== ==================
## 3.2.2 ## 2.0-SNAPSHOT
#### Fixed bugs
- Button: Fixed painting icon and text at wrong location when using HTML text,
left/right vertical alignment and running in Java 19+. (issue #746)
- CheckBox and RadioButton: Fixed cut off right side when border is removed and
horizontal alignment is set to `right`. (issue #734)
- TabbedPane: Fixed NPE when using focusable component as tab component and
switching theme. (issue #745)
## 3.2.1
#### Fixed bugs
- Fixed memory leak in
`MultiResolutionImageSupport.create(int,Dimension[],Function<Dimension,Image>)`,
which caches images created by the producer function. Used by
`FlatSVGIcon.getImage()` and `FlatSVGUtils.createWindowIconImages()`. If you
use one of these methods, it is **strongly recommended** to upgrade to this
version, because if the returned image is larger and painted very often it may
result in an out-of-memory situation. (issue #726)
- FileChooser: Fixed occasional NPE in `FlatShortcutsPanel` on Windows. (issue
#718)
- TextField: Fixed placeholder text painting, which did not respect horizontal
alignment property of `JTextField`. (issue #721)
- Popup: Fixed drop shadow if popup overlaps a heavyweight component. (Windows
10 only; issue #626)
## 3.2
#### New features and improvements
- TabbedPane: Support rounded underline selection and rounded card tabs. (PR
#703)
- FlatLaf window decorations:
- Support for Windows on ARM 64-bit. (issue #443, PR #707)
- Support toolbox-style "small" window title bar. (issue #659, PR #702)
- Extras: Class `FlatSVGIcon` now uses [JSVG](https://github.com/weisJ/jsvg)
library (instead of svgSalamander) for rendering. JSVG provides improved SVG
rendering and uses less memory compared to svgSalamander. (PR #684)
- ComboBox: Improved location of selected item in popup if list is large and
scrollable.
- FileChooser: Show localized text for all locales supported by Java's Metal
look and feel. (issue #680)
- Added system property `flatlaf.useNativeLibrary` to allow disabling loading of
FlatLaf native library. (issue #674)
- IntelliJ Themes:
- Reduced memory footprint by releasing Json data and ignoring IntelliJ UI
properties that are not used in FlatLaf.
- Updated "Hiberbee Dark" and "Gradianto" themes.
#### Fixed bugs
- Styling: Fixed scaling of some styling properties (`rowHeight` for Table and
Tree; `iconTextGap` for Button, CheckBox and RadioButton). (issue #682)
- Fixed `IllegalComponentStateException` when invoker is not showing in
`SubMenuUsabilityHelper`. (issue #692)
- macOS themes: Changing `@accentColor` variable in FlatLaf properties files did
not change all accent related colors for all components.
- IntelliJ Themes:
- "Light Owl" theme: Fixed wrong (unreadable) text color in selected menu
items, selected text in text components, and selection in ComboBox popup
list. (issue #687)
- "Gradianto Midnight Blue" theme: Fixed color of ScrollBar track, which was
not visible. (issue #686)
- "Monocai" theme: Fixed unreadable text color of default buttons. (issue
#693)
- "Vuesion" theme: Fixed foreground colors of disabled text.
- "Material UI Lite" themes: Fixed non-editable ComboBox button background.
- CheckBox and RadioButton: Fixed unselected icon colors for themes "Atom One
Light", "Cyan Light", "GitHub", "Light Owl", "Material Lighter" and
"Solarized Light".
- TabbedPane: Fixed focused tab background color for themes "Arc *", "Material
Design Dark", "Monocai", "One Dark", "Spacegray" and "Xcode-Dark". (issue
#697)
- TextComponents, ComboBox and Spinner: Fixed background colors of enabled
text components, to distinguish from disabled, for themes "Carbon", "Cobalt
2", "Gradianto *", "Gruvbox *", "Monocai", "Spacegray", "Vuesion",
"Xcode-Dark", "GitHub", and "Light Owl". (issue #528)
- Fixed wrong disabled text colors in "Dark Flat", "Hiberbee Dark", "Light
Flat", "Nord", "Solarized Dark" and "Solarized Light" themes.
- Fixed colors for selection background/foreground, Separator, Slider track
and ProgressBar background in various themes.
- Native Windows libraries: Fixed crash when running in Java 8 and newer Java
version is installed in `PATH` environment variable and using class
`SystemInfo` before AWT initialization. (issue #673)
- ComboBox: Fixed search in item list for text with spaces. (issue #691)
- FormattedTextField: On Linux, fixed `IllegalArgumentException: Invalid
location` if `JFormattedTextField.setDocument()` is invoked in a focus gained
listener on that formatted text field. (issue #698)
- PopupMenu: Make sure that popup menu does not overlap any operating system
task bar. (issue #701)
- FileChooser: Use system icons on Windows with Java 17.0.3 (and later) 32-bit.
Only Java 17 - 17.0.2 32-bit do not use system icons because of a bug in Java
32-bit that crashes the application. (PR #709)
- FileChooser: Fixed crash on Windows with Java 17 to 17.0.2 32-bit. Java 17
64-bit is not affected. (regression since FlatLaf 2.3; PR #522, see also issue
#403)
#### Incompatibilities
- Extras: Class `FlatSVGIcon` now uses [JSVG](https://github.com/weisJ/jsvg)
library for SVG rendering. You need to replace svgSalamander with JSVG in your
build scripts and distribute `jsvg.jar` with your application. Also replace
`com.kitfox.svg` with `com.github.weisj.jsvg` in `module-info.java` files.
- IntelliJ Themes: Removed all "Contrast" themes from "Material UI Lite".
## 3.1.1
- IntelliJ Themes:
- Fixed too large menu item paddings and too large table/tree row heights (all
"Material Theme UI Lite" themes; issue #667; regression in FlatLaf 3.1).
- Fixed too large tree row height in "Carbon", "Dark Purple", "Gray",
"Material Design Dark", "Monokai Pro", "One Dark" and "Spacegray" themes.
- Native libraries: Fixed `IllegalArgumentException: URI scheme is not "file"`
when using FlatLaf in WebStart. (issue #668; regression in FlatLaf 3.1)
## 3.1
#### New features and improvements
- Windows 11: Popups (`JPopupMenu`, `JComboBox`, `JToolTip`, etc.) now use
native Windows 11 rounded borders and drop shadows. (PR #643)
- Fonts:
- Added **Roboto Mono** (https://fonts.google.com/specimen/Roboto+Mono). (PR
#639, issue #638)
- Updated **JetBrains Mono** to
[v2.304](https://github.com/JetBrains/JetBrainsMono/releases/tag/v2.304).
- Theme Editor: Support macOS light and dark themes.
- TabbedPane: Support hover and focused tab foreground colors. (issue #627)
- TabbedPane: `tabbedPane.getBackgroundAt(tabIndex)` now has higher priority
than `TabbedPane.focusColor` and `TabbedPane.selectedBackground`. If
`tabbedPane.setBackgroundAt(tabIndex)` is used to set a color for a single
tab, then this color is now used even if the tab is focused or selected.
- TableHeader: Support column hover and pressed background and foreground
colors. (issue #636)
- Native libraries: Made it easier to distribute FlatLaf native libraries
(Windows `.dll` and Linux `.so`) to avoid problems on operating systems with
enabled execution restrictions.
See https://www.formdev.com/flatlaf/native-libraries/ for more details. (issue #624)
- Published native libraries to Maven Central for easy using them as
dependencies in Gradle and Maven.
- If available, native libraries are now loaded from same location as
`flatlaf.jar`, otherwise they are extract from `flatlaf.jar` to temporary
folder and loaded from there.
- Windows DLLs are now digitally signed with FormDev Software GmbH
certificate.
#### Fixed bugs
- FlatLaf window decorations:
- Fixed inconsistent size of glass pane depending on whether FlatLaf window
decorations are used (e.g. Windows 10/11) or not (e.g. macOS). Now the glass
pane no longer overlaps the FlatLaf window title bar. (issue #630)
- Linux: Fixed broken window resizing on multi-screen setups. (issue #632)
- Linux: Fixed behavior of maximize/restore button when tiling window to left
or right half of screen. (issue #647)
- IntelliJ Themes:
- Fixed default button hover background in "Solarized Light" theme. (issue
#628)
- Avoid that accent color affect some colors in some IntelliJ themes. (issue
#625)
- Updated "Hiberbee Dark" and "Material Theme UI Lite" themes.
- Styling: Fixed resolving of UI variables in styles that use other variables.
- MenuItem: Fixed horizontal alignment of icons. (issue #631)
- Table: Fixed potential performance issue with paint cell focus indicator
border. (issue #654)
- Tree: Fixed missing custom closed/opened/leaf icons of a custom
`DefaultTreeCellRenderer`. (issue #653; regression since implementing PR #609
in FlatLaf 3.0)
- Tree: Fixed truncated node text and too small painted non-wide node background
if custom cell renderer sets icon, but not disabled icon, and tree is
disabled. (issue #640)
- Fixed `HiDPIUtils.paintAtScale1x()`, which painted at wrong location if
graphics is rotated, is scaled and `x` or `y` parameters are not zero. (issue
#646)
## 3.0
#### 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
- Linux: Use X11 window manager events to move window and to show window menu
(right-click on window title bar), if custom window decorations are enabled.
This gives FlatLaf windows a more "native" feeling. (issue #482)
- MenuBar: Support different menu selection style UI defaults for `MenuBar` and
`MenuItem`. (issue #587)
- MenuBar: Top level menus now use `MenuBar.font` instead of `Menu.font`. (issue
#589)
- PasswordField: Reveal button is now hidden (and turned off) if password field
is disabled. (issue #501)
- TabbedPane: New option to disable tab run rotation in wrap layout. Set UI
value `TabbedPane.rotateTabRuns` to `false`. (issue #574)
- Window decorations:
- Added client property to mark components in embedded menu bar as "caption"
(allow moving window). (issue #569)
- Option to show window icon only in frames, but not in dialogs. Set UI value
`TitlePane.showIconInDialogs` to `false`. (issue #589)
- Added UI value `TitlePane.font` to customize window title font. (issue #589)
- Added system property `flatlaf.updateUIOnSystemFontChange` to allow disabling
automatic UI update when system font changes. (issue #580)
#### Fixed bugs
- Fixed missing UI value `MenuItem.acceleratorDelimiter` on macOS. (was `null`,
is now an empty string)
- Fixed possible exception in `FlatUIUtils.resetRenderingHints()`. (issue #575)
- Fixed AWT components on macOS, which use Swing components internally. (issue
#583)
- SwingX: Fixed missing highlighting of "today" in `JXMonthView` and
`JXDatePicker`.
## 2.4
#### New features and improvements
- Native window decorations (Windows 10/11 only):
- There is now a small area at top of the embedded menu bar to resize the
window.
- Improved window title bar layout for small window widths:
- Width of iconify/maximize/close buttons is reduced (if necessary) to give
more space to embedded menu bar and title.
- Window title now has a minimum width to always allow moving window
(click-and-drag on window title). Instead, embedded menu bar is made
smaller.
- Option to show window icon beside window title, if menu bar is embedded or
title is centered. Set UI value `TitlePane.showIconBesideTitle` to `true`.
- No longer reduce height of window title bar if it has an embedded menu bar
and is maximized.
#### Fixed bugs
- ComboBox: Fixed vertical alignment of text in popup list with text in combo
box in IntelliJ/Darcula themes.
- Menus: Fixed application freeze under very special conditions (invoking
`FlatLaf.initialize()` twice in NetBeans GUI builder) and using menu that has
submenus. See
[NetBeans issue #4231](https://github.com/apache/netbeans/issues/4231#issuecomment-1179611682)
for details.
- MenuItem: Fixed sometimes wrapped HTML text on HiDPI screens on Windows.
- TableHeader: Fixed exception when changing table structure (e.g. removing
column) from a table header popup menu action. (issue #532)
- `HiDPIUtils.paintAtScale1x()` now supports rotated graphics. (issue #557)
- Typography: No longer use `Consolas` or `Courier New` as monospaced font on
Windows because they have bad vertically placement.
- Native window decorations (Windows 10/11 only):
- Do not center window title if embedded menu bar is empty or has no menus at
left side, but some components at right side. (issue #558)
- Do not use window decorations if system property `sun.java2d.opengl` is
`true` on Windows 10. (issue #540)
- Fixed missing top window border in dark themes if window drop shadows are
disabled in system settings. (issue #554; Windows 10 only)
- Right-to-left component orientation of title bar was lost when switching
theme.
## 2.3
#### New features and improvements
- FileChooser: Added (optional) shortcuts panel. On Windows it contains "Recent
Items", "Desktop", "Documents", "This PC" and "Network". On macOS and Linux it
is empty/hidden. (issue #100)
- Button and ToggleButton: Added missing foreground colors for hover, pressed,
focused and selected states. (issue #535)
- Table: Optionally paint alternating rows below table if table is smaller than
scroll pane. Set UI value `Table.paintOutsideAlternateRows` to `true`.
Requires that `Table.alternateRowColor` is set to a color. (issue #504)
- ToggleButton: Made the underline placement of tab-style toggle buttons
configurable. (PR #530; issue #529)
- Added spanish translation. (PR #525)
#### Fixed bugs
- IntelliJ Themes: Fixed `TitledBorder` text color in "Monokai Pro" theme.
(issue #524)
## 2.2
#### New features and improvements
- SplitPane: Allow limiting one-touch expanding to a single side (set client
property `JSplitPane.expandableSide` to `"left"` or `"right"`). (issue #355)
- TabbedPane: Selected tab underline color now changes depending on whether the
focus is within the tab content. (issue #398)
- IntelliJ Themes:
- Added "Monokai Pro" and "Xcode-Dark" themes.
- TabbedPane now use different background color for selected tabs in all "Arc"
themes, in "Hiberbee Dark" and in all "Material UI Lite" themes.
#### Fixed bugs
- Native window decorations (Windows 10/11 only): Fixed wrong window title
character encoding used in Windows taskbar. (issue #502)
- Button: Fixed icon layout and preferred width of default buttons that use bold
font. (issue #506)
- FileChooser: Enabled full row selection for details view to fix alternate row
coloring. (issue #512)
- SplitPane: Fixed `StackOverflowError` caused by layout loop that may occur
under special circumstances. (issue #513)
- Table: Slightly changed grid colors to make grid better recognizable. (issue
#514)
- ToolBar: Fixed endless loop in focus navigation that may occur under special
circumstances. (issue #505)
- IntelliJ Themes: `Component.accentColor` UI property now has useful theme
specific values. (issue #507)
## 2.1
#### New features and improvements
- Menus: Improved usability of submenus. (PR #490; issue #247)
- Menus: Scroll large menus using mouse wheel or up/down arrows. (issue #225)
- Linux: Support using custom window decorations. Enable with
`JFrame.setDefaultLookAndFeelDecorated(true)` and
`JDialog.setDefaultLookAndFeelDecorated(true)` before creating a window.
(issue #482)
- ScrollBar: Added UI value `ScrollBar.minimumButtonSize` to specify minimum
scroll arrow button size (if shown). (issue #493)
#### Fixed bugs
- PasswordField: Fixed reveal button appearance in IntelliJ themes. (issue #494)
- ScrollBar: Center and scale arrows in scroll up/down buttons (if shown).
(issue #493)
- TextArea, TextPane and EditorPane: No longer select all text when component is
focused for the first time. (issue #498; regression in FlatLaf 2.0)
- TabbedPane: Disable all items in "Show Hidden Tabs" popup menu if tabbed pane
is disabled.
#### Incompatibilities
- Method `FlatUIUtils.paintArrow()` (and class `FlatArrowButton`) now paints
arrows one pixel smaller than before. To fix this, increase parameter
`arrowSize` by one.
## 2.0.2
- Native window decorations (Windows 10/11 only): Fixed rendering artifacts on
HiDPI screens when dragging window partly offscreen and back into screen
bounds. (issue #477)
- Repaint component when setting client property `JComponent.outline` (issue
#480).
- macOS: Fixed NPE when using some icons in main menu items. (issue #483)
## 2.0.1
- Fixed memory leak in Panel, Separator and ToolBarSeparator. (issue #471;
regression in FlatLaf 2.0)
- ToolTip: Fixed wrong tooltip location if component overrides
`JComponent.getToolTipLocation()` and wants place tooltip under mouse
location. (issue #468)
- Extras: Added copy constructor to `FlatSVGIcon`. (issue #465)
- Moved `module-info.class` from `META-INF\versions\9\` to root folder of JARs.
(issue #466)
## 2.0
- Added system property `flatlaf.nativeLibraryPath` to load native libraries
from a directory. (PR #453)
- Fixed "endless recursion in font" exception in
`FlatLaf$ActiveFont.createValue()` if `UIManager.getFont()` is invoked from
multiple threads. (issue #456)
- PasswordField: Preserve reveal button state when switching theme. (PR #442;
issue #173)
- PasswordField: Reveal button did not show password if
`JPasswordField.setEchoChar()` was invoked from application. (PR #442; issue
#173)
- Slider: Fixed/improved focused indicator color when changing accent color. (PR
#375)
- TextField:
- Improved hover/pressed/selected colors of leading/trailing buttons (e.g.
"reveal" button in password field). (issue #452)
- Clear button no longer paints over round border. (issue #451)
- Extras: Fixed concurrent loading of SVG icons on multiple threads. (issue
#459)
- Use FlatLaf native window decorations by default when running in
[JetBrains Runtime](https://github.com/JetBrains/JetBrainsRuntime/wiki)
(instead of using JetBrains custom decorations). System variable
`flatlaf.useJetBrainsCustomDecorations` is now `false` by default (was `true`
in FlatLaf 1.x). (issue #454)
- Native window decorations:
- Fixed blurry iconify/maximize/close button hover rectangles at 125%, 150% or
175% scaling. (issue #431)
- Updated maximize and restore icons for Windows 11 style. (requires Java
8u321, 11.0.14, 17.0.2 or 18+)
- Updated hover and pressed colors of iconify/maximize/close buttons for
Windows 11 style.
## 2.0-rc1
#### New features and improvements #### New features and improvements
@@ -489,22 +24,13 @@ FlatLaf Change Log
- Possibility to hide window title bar icon (for single window set client - Possibility to hide window title bar icon (for single window set client
property `JRootPane.titleBarShowIcon` to `false`; for all windows set UI property `JRootPane.titleBarShowIcon` to `false`; for all windows set UI
value `TitlePane.showIcon` to `false`). value `TitlePane.showIcon` to `false`).
- OptionPane: Hide window title bar icon by default. Can be made visibly by - OptionPane: Hide window title bar icon by default. Can be be made visibly by
setting UI default `OptionPane.showIcon` to `true`. (issue #416) setting UI default `OptionPane.showIcon` to `true`. (issue #416)
- No longer show the Java "duke/cup" icon if no window icon image is set. - No longer show the Java "duke/cup" icon if no window icon image is set.
(issue #416) (issue #416)
- TextField, FormattedTextField and PasswordField: - TextField, FormattedTextField and PasswordField: Support leading and trailing
- Support leading and trailing icons (set client property icons (set client property `JTextField.leadingIcon` or
`JTextField.leadingIcon` or `JTextField.trailingIcon` to a `JTextField.trailingIcon` to an `Icon`). (PR #378; issue #368)
`javax.swing.Icon`). (PR #378; issue #368)
- Support leading and trailing components (set client property
`JTextField.leadingComponent` or `JTextField.trailingComponent` to a
`java.awt.Component`). (PR #386)
- Support "clear" (or "cancel") button to empty text field. Only shown if text
field is not empty, editable and enabled. (set client property
`JTextField.showClearButton` to `true`). (PR #442)
- PasswordField: Support reveal (or "eye") button to show password. (see UI
value `PasswordField.showRevealButton`) (PR #442; issue #173)
- TextComponents: Double/triple-click-and-drag now extends selection by whole - TextComponents: Double/triple-click-and-drag now extends selection by whole
words/lines. words/lines.
- Theming improvements: Reworks core themes to make it easier to create new - Theming improvements: Reworks core themes to make it easier to create new
@@ -535,10 +61,6 @@ FlatLaf Change Log
- Slider: Support specifying width of thumb border (see UI value - Slider: Support specifying width of thumb border (see UI value
`Slider.thumbBorderWidth`). `Slider.thumbBorderWidth`).
- TabbedPane: Optionally paint selected tab as card. (PR #343) - TabbedPane: Optionally paint selected tab as card. (PR #343)
- MenuItem:
- Paint the selected icon when the item is selected. (PR #415)
- Vertically align text if icons have different widths. (issue #437)
- Panel: Support painting background with rounded corners. (issue #367)
- Added more color functions to class `ColorFunctions` for easy use in - Added more color functions to class `ColorFunctions` for easy use in
applications: `lighten()`, `darken()`, `saturate()`, `desaturate()`, `spin()`, applications: `lighten()`, `darken()`, `saturate()`, `desaturate()`, `spin()`,
`tint()`, `shade()` and `luma()`. `tint()`, `shade()` and `luma()`.
@@ -551,40 +73,6 @@ FlatLaf Change Log
- `FlatSVGIcon`: Support loading SVG from `URL` (for JPMS), `URI`, `File` or - `FlatSVGIcon`: Support loading SVG from `URL` (for JPMS), `URI`, `File` or
`InputStream`. (issues #419 and #325) `InputStream`. (issues #419 and #325)
- `FlatSVGUtils`: Support loading SVG from `URL` (for JPMS). (issue #325) - `FlatSVGUtils`: Support loading SVG from `URL` (for JPMS). (issue #325)
- SwingX:
- New "column control" icon for `JXTable` that scales and uses antialiasing.
(issue #434)
#### Fixed bugs
- Native window decorations: Fixed `UnsatisfiedLinkError` on Windows 11 for ARM
processors. (issue #443)
- MenuBar: Do not fill background if non-opaque and having custom background
color. (issue #409)
- InternalFrame: Fill background to avoid that parent may shine through internal
frame if it contains non-opaque components. (better fix for issue #274)
- SwingX: Fixed `NullPointerException` in `FlatCaret` when using
`org.jdesktop.swingx.prompt.PromptSupport.setPrompt()` on a text field and
then switching theme.
## 1.6.5
#### Fixed bugs
- Linux: Fixed font problems when running on Oracle Java (OpenJDK is not
affected):
- oversized text if system font is "Inter" (issue #427)
- missing text if system font is "Cantarell" (on Fedora)
- MenuItem: Changed accelerator delimiter from `-` to `+`. (Windows and Linux).
- ComboBox: Fixed occasional `StackOverflowError` when modifying combo box not
on AWT thread. (issue #432)
- macOS: Fixed `NullPointerException` when using AWT component
`java.awt.Choice`. (issue #439)
- Native window decorations: Do not exit application with `UnsatisfiedLinkError`
in case that FlatLaf DLL cannot be executed because of restrictions on
temporary directory. Instead, continue with default window decorations. (issue
#436)
## 1.6.4 ## 1.6.4

288
README.md
View File

@@ -6,19 +6,14 @@ Swing desktop applications.
It looks almost flat (no shadows or gradients), clean, simple and elegant. It looks almost flat (no shadows or gradients), clean, simple and elegant.
FlatLaf comes with **Light**, **Dark**, **IntelliJ** and **Darcula** themes, FlatLaf comes with **Light**, **Dark**, **IntelliJ** and **Darcula** themes,
scales on **HiDPI** displays and runs on Java 8 or newer (LTS and latest). scales on **HiDPI** displays and runs on Java 8 or newer.
The look is heavily inspired by **Darcula** and **IntelliJ** themes from The look is heavily inspired by **Darcula** and **IntelliJ** themes from
IntelliJ IDEA 2019.2+ and uses almost the same colors and icons. IntelliJ IDEA 2019.2+ and uses almost the same colors and icons.
![FlatLaf Light](images/flat_light.png) ![Flat Light](images/flat_light.png)
![FlatLaf Dark](images/flat_dark.png) ![Flat Dark](images/flat_dark.png)
macOS Themes
------------
![FlatLaf macOS themes](images/flat_macos_themes.png)
IntelliJ Platform Themes IntelliJ Platform Themes
@@ -30,17 +25,6 @@ FlatLaf can use 3rd party themes created for IntelliJ Platform (see
![IntelliJ Platform Themes](images/intellij_platform_themes.png) ![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 Demo
---- ----
@@ -66,11 +50,6 @@ Otherwise download `flatlaf-<version>.jar` here:
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.formdev/flatlaf/badge.svg?style=flat-square&color=007ec6)](https://maven-badges.herokuapp.com/maven-central/com.formdev/flatlaf) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.formdev/flatlaf/badge.svg?style=flat-square&color=007ec6)](https://maven-badges.herokuapp.com/maven-central/com.formdev/flatlaf)
See also
[Native Libraries distribution](https://www.formdev.com/flatlaf/native-libraries/)
for instructions on how to redistribute FlatLaf native libraries with your
application.
### Snapshots ### Snapshots
@@ -95,8 +74,6 @@ Addons
- [SwingX](flatlaf-swingx) - support for SwingX components - [SwingX](flatlaf-swingx) - support for SwingX components
- [JIDE Common Layer](flatlaf-jide-oss) - support for JIDE Common Layer - [JIDE Common Layer](flatlaf-jide-oss) - support for JIDE Common Layer
components components
- [Fonts](flatlaf-fonts) - some font families bundled in easy-to-use and
redistributable JARs
Getting started Getting started
@@ -122,27 +99,14 @@ For more information and documentation visit
- [Customizing](https://www.formdev.com/flatlaf/customizing/) - [Customizing](https://www.formdev.com/flatlaf/customizing/)
- [How to Customize](https://www.formdev.com/flatlaf/how-to-customize/) - [How to Customize](https://www.formdev.com/flatlaf/how-to-customize/)
- [Properties Files](https://www.formdev.com/flatlaf/properties-files/) - [Properties Files](https://www.formdev.com/flatlaf/properties-files/)
- [Components UI Properties](https://www.formdev.com/flatlaf/components/)
- [Typography](https://www.formdev.com/flatlaf/typography/)
- [Client Properties](https://www.formdev.com/flatlaf/client-properties/) - [Client Properties](https://www.formdev.com/flatlaf/client-properties/)
- [System Properties](https://www.formdev.com/flatlaf/system-properties/) - [System Properties](https://www.formdev.com/flatlaf/system-properties/)
Theme Editor
------------
The Theme Editor that supports editing FlatLaf theme properties files. See
[Theme Editor documentation](https://www.formdev.com/flatlaf/theme-editor/) for
details and downloads.
![Theme Editor](images/theme-editor@1.5x.png)
Buzz Buzz
---- ----
- [What others say about FlatLaf on Twitter](https://twitter.com/search?f=live&q=flatlaf) - [What others say about FlatLaf on Twitter](https://twitter.com/search?f=live&q=flatlaf)
- [FlatLaf 3.1 (and 3.0) announcement on Reddit](https://www.reddit.com/r/java/comments/12xgrsu/flatlaf_31_and_30_swing_look_and_feel/)
- [FlatLaf 1.0 announcement on Reddit](https://www.reddit.com/r/java/comments/lsbcwe/flatlaf_10_swing_look_and_feel/) - [FlatLaf 1.0 announcement on Reddit](https://www.reddit.com/r/java/comments/lsbcwe/flatlaf_10_swing_look_and_feel/)
- [FlatLaf announcement on Reddit](https://www.reddit.com/r/java/comments/dl0hu3/flatlaf_flat_look_and_feel/) - [FlatLaf announcement on Reddit](https://www.reddit.com/r/java/comments/dl0hu3/flatlaf_flat_look_and_feel/)
@@ -150,193 +114,89 @@ Buzz
Applications using FlatLaf Applications using FlatLaf
-------------------------- --------------------------
### Featured - [Apache NetBeans](https://netbeans.apache.org/) 11.3 - IDE for Java, PHP, HTML
and much more
- ![Sponsor](images/sponsor.svg) [JFormDesigner](https://www.formdev.com/) - [jclasslib bytecode viewer](https://github.com/ingokegel/jclasslib) 5.5
(**commercial**) - Java/Swing GUI Designer (from the FlatLaf creators) - [KeyStore Explorer](https://keystore-explorer.org/) 5.4.3
- ![Sponsor](images/sponsor.svg) - ![New](images/new.svg)
[JProfiler](https://www.ej-technologies.com/products/jprofiler/overview.html)
(**commercial**) - the award-winning all-in-one Java profiler
- ![Sponsor](images/sponsor.svg)
[install4j](https://www.ej-technologies.com/products/install4j/overview.html) [install4j](https://www.ej-technologies.com/products/install4j/overview.html)
(**commercial**) - the powerful multi-platform Java installer builder 9.0 (**commercial**) - the powerful multi-platform Java installer builder
- ![Sponsor](images/sponsor.svg) [DbVisualizer](https://www.dbvis.com/) - ![New](images/new.svg) [DbVisualizer](https://www.dbvis.com/) 12.0
(**commercial**) - the universal database tool for developers, analysts and (**commercial**) - the universal database tool for developers, analysts and
DBAs DBAs
- ![Hot](images/hot.svg) [Apache NetBeans](https://netbeans.apache.org/) - IDE - ![New](images/new.svg) [MagicPlot](https://magicplot.com/) 3.0
for Java, PHP, HTML and much more (**commercial**) - Software for nonlinear fitting, plotting and data analysis
- ![Sponsor](images/sponsor.svg) - ![New](images/new.svg)
[Thermo-Calc](https://thermocalc.com/products/thermo-calc/) (**commercial**) - [Thermo-Calc](https://thermocalc.com/products/thermo-calc/) 2021a
Thermodynamics and Properties Software (**commercial**) - Thermodynamics and Properties Software
- [OWASP ZAP](https://www.zaproxy.org/) 2.10 - the worlds most widely used web
### Data app scanner
- ![Hot](images/hot.svg) [Ultorg](https://www.ultorg.com/) (**commercial**) - a
visual query system for relational databases
- [Jailer](https://github.com/Wisser/Jailer) - database subsetting and
relational data browsing tool
- ![Hot](images/hot.svg) [MagicPlot](https://magicplot.com/) (**commercial**) -
Software for nonlinear fitting, plotting and data analysis
- ![New](images/new.svg) [Constellation](https://www.constellation-app.com/) -
Data Visualization and Analytics (based on NetBeans platform)
- ![New](images/new.svg) - ![New](images/new.svg)
[Kafka Visualizer](https://github.com/kumait/kafkavisualizer) - Kafka GUI
client
### Security
- ![Hot](images/hot.svg) [ZAP](https://www.zaproxy.org/) - the world's most
widely used web app scanner
- ![Hot](images/hot.svg)
[Burp Suite Professional and Community Edition](https://portswigger.net/burp/pro) [Burp Suite Professional and Community Edition](https://portswigger.net/burp/pro)
(**commercial**) - the leading software for web security testing 2020.11.2 (**commercial**) - the leading software for web security testing
- ![New](images/new.svg) - ![New](images/new.svg)
[Ghidra](https://github.com/NationalSecurityAgency/ghidra) - a software [BurpCustomizer](https://github.com/CoreyD97/BurpCustomizer) - adds more
reverse engineering (SRE) framework
- ![New](images/new.svg) [jadx](https://github.com/skylot/jadx) - Dex to Java
decompiler
- [BurpCustomizer](https://github.com/CoreyD97/BurpCustomizer) - adds more
FlatLaf themes to Burp Suite FlatLaf themes to Burp Suite
- [Total Validator](https://www.totalvalidator.com/) (**commercial**) - checks - [JOSM](https://josm.openstreetmap.de/) - an extensible editor for
your website [OpenStreetMap](https://www.openstreetmap.org/) (requires FlatLaf JOSM plugin)
- [JPass](https://github.com/gaborbata/jpass) - password manager with strong - [jAlbum](https://jalbum.net/) 21 (**commercial**) - creates photo album
encryption websites
- [XMLmind XML Editor](https://www.xmlmind.com/xmleditor/) 9.3 (**commercial**)
### Software Development - [Total Validator](https://www.totalvalidator.com/) 15 (**commercial**) -
checks your website
- [jclasslib bytecode viewer](https://github.com/ingokegel/jclasslib) - [j-lawyer](https://github.com/jlawyerorg/j-lawyer-org) - Kanzleisoftware
- [KeyStore Explorer](https://keystore-explorer.org/) - [MegaMek](https://github.com/MegaMek/megamek) v0.47.4 and
- ![New](images/new.svg) [MekHQ](https://github.com/MegaMek/mekhq) v0.47.5 - a turn-based sci-fi board
[muCommander](https://github.com/mucommander/mucommander) - lightweight game
cross-platform file manager - [GUIslice Builder](https://github.com/ImpulseAdventure/GUIslice-Builder)
- ![New](images/new.svg) [Guiffy](https://www.guiffy.com/) (**commercial**) - 0.13.b024 - GUI builder for
advanced cross-platform Diff/Merge [GUIslice](https://github.com/ImpulseAdventure/GUIslice), a lightweight GUI
- ![New](images/new.svg) [HashGarten](https://github.com/jonelo/HashGarten) - framework for embedded displays
cross-platform Swing GUI for Jacksum - [Rest Suite](https://github.com/supanadit/restsuite) - Rest API testing
- [Pseudo Assembler IDE](https://github.com/tomasz-herman/PseudoAssemblerIDE) - - [ControllerBuddy](https://github.com/bwRavencl/ControllerBuddy) - advanced
IDE for Pseudo-Assembler gamepad mapping software
- [Linotte](https://github.com/cpc6128/LangageLinotte) - French programming - [SpringRemote](https://github.com/HaleyWang/SpringRemote) - remote Linux SSH
language created to learn programming connections manager
- [lsfusion platform](https://github.com/lsfusion/platform) - information - [jEnTunnel](https://github.com/ggrandes/jentunnel) - manage SSH Tunnels made
systems development platform easy
### Electrical
- [Antares](https://www.antarescircuit.io/) - a free, powerful platform for
designing, simulating and explaining digital circuits
- [Logisim-evolution](https://github.com/logisim-evolution/logisim-evolution) -
Digital logic design tool and simulator
- [Makelangelo Software](https://github.com/MarginallyClever/Makelangelo-software) -
for plotters, especially the wall-hanging polargraph
- [GUIslice Builder](https://github.com/ImpulseAdventure/GUIslice-Builder) - GUI
builder for [GUIslice](https://github.com/ImpulseAdventure/GUIslice), a
lightweight GUI framework for embedded displays
- [ThunderFocus](https://github.com/marcocipriani01/ThunderFocus) -
Arduino-based telescope focuser
- [RemoteLight](https://github.com/Drumber/RemoteLight) - multifunctional LED
control software
### Media
- ![Hot](images/hot.svg) [jAlbum](https://jalbum.net/) (**commercial**) -
creates photo album websites
- ![New](images/new.svg) [MediathekView](https://mediathekview.de/) - search in
media libraries of various German broadcasters
- [Cinecred](https://loadingbyte.com/cinecred/) - create beautiful film credit
sequences
- [tinyMediaManager](https://www.tinymediamanager.org/) (**commercial**) - a
media management tool
- [Weasis](https://nroduit.github.io/) - medical DICOM viewer used in healthcare
by hospitals, health networks, etc
- [Shutter Encoder](https://www.shutterencoder.com/)
([source code](https://github.com/paulpacifico/shutter-encoder)) -
professional video converter and compression tool
- [Sound Analysis](https://github.com/tomasz-herman/SoundAnalysis) - analyze
sound files in time or frequency domain
- [Novel-Grabber](https://github.com/Flameish/Novel-Grabber) - download novels
from any webnovel and lightnovel site
- [lectureStudio](https://www.lecturestudio.org/) - digitize your lectures with
ease
### Modelling
- ![New](images/new.svg) [Astah](https://astah.net/) (**commercial**) - create
UML, ER Diagram, Flowchart, Data Flow Diagram, Requirement Diagram, SysML
diagrams and more
- [IGMAS+](https://www.gfz-potsdam.de/igmas) - Interactive Gravity and Magnetic
Application System
### Documents
- ![New](images/new.svg) [Big Faceless (BFO) PDF Viewer](https://bfo.com/)
(**commercial**) - Swing PDF Viewer
- [PDF Studio](https://www.qoppa.com/pdfstudio/) (**commercial**) - create,
review and edit PDF documents
- [XMLmind XML Editor](https://www.xmlmind.com/xmleditor/) (**commercial**)
### Geo
- ![Hot](images/hot.svg) [JOSM](https://josm.openstreetmap.de/) - an extensible
editor for [OpenStreetMap](https://www.openstreetmap.org/) (requires FlatLaf
JOSM plugin)
- [Mapton](https://mapton.org/)
([source code](https://github.com/trixon/mapton)) - some kind of map
application (based on NetBeans platform)
- [MeteoInfo](https://github.com/meteoinfo/MeteoInfo) - GIS and scientific
computation environment for meteorological community
### Business / Legal
- ![Sponsor](images/sponsor.svg)
[j-lawyer](https://github.com/jlawyerorg/j-lawyer-org) - Kanzleisoftware
- ![Sponsor](images/sponsor.svg) [Jeyla Studio](https://www.jeylastudio.com/) -
Salon Software
- [Fanurio](https://www.fanuriotimetracking.com/) (**commercial**) - time
tracking and billing for freelancers and teams
- [Jes](https://www.jes-eur.de) - Die Java-EÜR
- [mendelson AS2](https://sourceforge.net/projects/mec-as2/), - [mendelson AS2](https://sourceforge.net/projects/mec-as2/),
[AS4](https://sourceforge.net/projects/mendelson-as4/) and [AS4](https://sourceforge.net/projects/mendelson-as4/) and
[OFTP2](https://sourceforge.net/projects/mendelson-oftp2/) (open-source) and [OFTP2](https://sourceforge.net/projects/mendelson-oftp2/) (open-source) and
[mendelson AS2](https://mendelson-e-c.com/as2/), [mendelson AS2](https://mendelson-e-c.com/as2/),
[AS4](https://mendelson-e-c.com/as4/) and [AS4](https://mendelson-e-c.com/as4/) and
[OFTP2](https://mendelson-e-c.com/oftp2) (**commercial**) [OFTP2](https://mendelson-e-c.com/oftp2) (**commercial**)
- ![New](images/new.svg) [IGMAS+](https://www.gfz-potsdam.de/igmas) -
### Messaging Interactive Gravity and Magnetic Application System
- [MeteoInfo](https://github.com/meteoinfo/MeteoInfo) 2.2 - GIS and scientific
- ![New](images/new.svg) [Spark](https://github.com/igniterealtime/Spark) - computation environment for meteorological community
cross-platform IM client optimized for businesses and organizations - [lsfusion platform](https://github.com/lsfusion/platform) 4 - information
- ![New](images/new.svg) [Chatty](https://github.com/chatty/chatty) - Twitch systems development platform
Chat Client - [JPass](https://github.com/gaborbata/jpass) - password manager with strong
encryption
### Gaming - [Jes - Die Java-EÜR](https://www.jes-eur.de)
- [Mapton](https://mapton.org/) 2.0
- ![New](images/new.svg) ![Sponsor](images/sponsor.svg) ([source code](https://github.com/trixon/mapton)) - some kind of map
[BGBlitz](https://www.bgblitz.com/) (**commercial**) - professional Backgammon application (based on NetBeans platform)
- ![New](images/new.svg) [MapTool](https://github.com/RPTools/maptool) - virtual - [Pseudo Assembler IDE](https://github.com/tomasz-herman/PseudoAssemblerIDE) -
Tabletop for playing role-playing games IDE for Pseudo-Assembler
- [MegaMek](https://github.com/MegaMek/megamek), - [Linotte](https://github.com/cpc6128/LangageLinotte) 3.1 - French programming
[MegaMekLab](https://github.com/MegaMek/megameklab) and language created to learn programming
[MekHQ](https://github.com/MegaMek/mekhq) - a sci-fi tabletop BattleTech - [MEKA](https://github.com/Waikato/meka) 1.9.3 - multi-label classifiers and
simulator suite handling battles, unit building, and campaigns evaluation procedures using the Weka machine learning framework
- [ControllerBuddy](https://github.com/bwRavencl/ControllerBuddy) - advanced - [Shutter Encoder](https://www.shutterencoder.com/) 14.2
gamepad mapping software ([source code](https://github.com/paulpacifico/shutter-encoder)) -
professional video converter and compression tool (screenshots show **old**
### Utilities look)
- [Sound Analysis](https://github.com/tomasz-herman/SoundAnalysis) - analyze
- [MooInfo](https://github.com/rememberber/MooInfo) - visual implementation of sound files in time or frequency domain
OSHI, to view information about the system and hardware - [RemoteLight](https://github.com/Drumber/RemoteLight) - multifunctional LED
- ![New](images/new.svg) control software
[Linux Task Manager (LTM)](https://github.com/ajee10x/LTM-LinuxTaskManager) - - [ThunderFocus](https://github.com/marcocipriani01/ThunderFocus) -
GUI for monitoring and managing various aspects of a Linux system Arduino-based telescope focuser
- [Rest Suite](https://github.com/supanadit/restsuite) - Rest API testing - [Novel-Grabber](https://github.com/Flameish/Novel-Grabber) - download novels
- [SpringRemote](https://github.com/HaleyWang/SpringRemote) - remote Linux SSH from any webnovel and lightnovel site
connections manager - [lectureStudio](https://www.lecturestudio.org/) 4.3.1060 - digitize your
- [jEnTunnel](https://github.com/ggrandes/jentunnel) - manage SSH Tunnels made lectures with ease
easy
- [Android Tool](https://github.com/fast-geek/Android-Tool) - makes popular adb - [Android Tool](https://github.com/fast-geek/Android-Tool) - makes popular adb
and fastboot commands easier to use and fastboot commands easier to use
- and more...
### Miscellaneous
- [MEKA](https://github.com/Waikato/meka) - multi-label classifiers and
evaluation procedures using the Weka machine learning framework

View File

@@ -14,9 +14,10 @@
* limitations under the License. * limitations under the License.
*/ */
import net.ltgt.gradle.errorprone.errorprone val releaseVersion = "1.6.4"
val developmentVersion = "2.0-SNAPSHOT"
version = property( if( hasProperty( "release" ) ) "flatlaf.releaseVersion" else "flatlaf.developmentVersion" ) as String version = if( java.lang.Boolean.getBoolean( "release" ) ) releaseVersion else developmentVersion
allprojects { allprojects {
version = rootProject.version version = rootProject.version
@@ -36,16 +37,9 @@ println( "----------------------------------------------------------------------
println( "FlatLaf Version: ${version}" ) println( "FlatLaf Version: ${version}" )
println( "Gradle ${gradle.gradleVersion} at ${gradle.gradleHomeDir}" ) println( "Gradle ${gradle.gradleVersion} at ${gradle.gradleHomeDir}" )
println( "Java ${System.getProperty( "java.version" )}" ) println( "Java ${System.getProperty( "java.version" )}" )
val toolchainJavaVersion = System.getProperty( "toolchain" )
if( !toolchainJavaVersion.isNullOrEmpty() )
println( "Java toolchain ${toolchainJavaVersion}" )
println() println()
plugins {
alias( libs.plugins.errorprone ) apply false
}
allprojects { allprojects {
tasks { tasks {
withType<JavaCompile>().configureEach { withType<JavaCompile>().configureEach {
@@ -84,56 +78,4 @@ allprojects {
isFailOnError = false isFailOnError = false
} }
} }
//---- Error Prone ----
tasks.register( "errorprone" ) {
group = "verification"
tasks.withType<JavaCompile>().forEach {
dependsOn( it )
}
}
val useErrorProne = gradle.startParameter.taskNames.contains( "errorprone" )
if( useErrorProne ) {
plugins.withType<JavaPlugin> {
apply( plugin = libs.plugins.errorprone.get().pluginId )
dependencies {
"errorprone"( libs.errorprone )
}
tasks.withType<JavaCompile>().configureEach {
options.compilerArgs.add( "-Werror" )
options.errorprone {
disable(
"ReferenceEquality", // reports usage of '==' for objects
"StringSplitter", // reports String.split()
"JavaTimeDefaultTimeZone", // reports Year.now()
"MissingSummary", // reports `/** @since 2 */`
"InvalidBlockTag", // reports @uiDefault in javadoc
"AlreadyChecked", // reports false positives
"InlineMeSuggester", // suggests using Error Prone annotations for deprecated methods
"TypeParameterUnusedInFormals",
"UnsynchronizedOverridesSynchronized",
"NonApiType", // reports ArrayList/HashSet in parameter or return type
)
when( project.name ) {
"flatlaf-intellij-themes" -> disable(
"MutablePublicArray", // reports FlatAllIJThemes.INFOS
)
"flatlaf-theme-editor" -> disable(
"CatchAndPrintStackTrace",
)
"flatlaf-testing" -> disable(
"CatchAndPrintStackTrace",
"JdkObsolete", // reports Hashtable used for JSlider.setLabelTable()
"JavaUtilDate", // reports usage of class Date
)
}
}
}
}
}
} }

View File

@@ -1,46 +0,0 @@
/*
* 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 {
`cpp-library`
}
library {
// disable debuggable for release builds to make shared libraries smaller
binaries.configureEach( CppSharedLibrary::class ) {
with( compileTask.get() ) {
if( name.contains( "Release" ) )
isDebuggable = false
}
with( linkTask.get() ) {
if( name.contains( "Release" ) )
debuggable.set( false )
}
}
}
tasks {
withType<CppCompile>().configureEach {
doFirst {
println( "Used Tool Chain:" )
println( " - ${toolChain.get()}" )
println( "Available Tool Chains:" )
toolChains.forEach {
println( " - $it" )
}
}
}
}

View File

@@ -28,7 +28,7 @@ if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) {
} }
dependencies { dependencies {
add( "java9Implementation", sourceSets.main.get().output ) add( "java9Compile", sourceSets.main.get().output )
} }
tasks { tasks {

View File

@@ -1,36 +0,0 @@
/*
* 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.
*/
open class JniHeadersExtension {
var headers: List<String> = emptyList()
}
val extension = project.extensions.create<JniHeadersExtension>( "flatlafJniHeaders" )
tasks {
register<Copy>( "jni-headers" ) {
// depend on :flatlaf-core:compileJava because it generates the JNI headers
dependsOn( ":flatlaf-core:compileJava" )
from( project( ":flatlaf-core" ).layout.buildDirectory.dir( "generated/jni-headers" ) )
into( "src/main/headers" )
include( extension.headers )
filter<org.apache.tools.ant.filters.FixCrLfFilter>(
"eol" to org.apache.tools.ant.filters.FixCrLfFilter.CrLf.newInstance( "lf" )
)
}
}

View File

@@ -61,9 +61,13 @@ if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) {
} }
jar { jar {
manifest.attributes( "Multi-Release" to "true" )
into( "META-INF/versions/9" ) {
from( sourceSets["module-info"].output ) { from( sourceSets["module-info"].output ) {
include( "module-info.class" ) include( "module-info.class" )
} }
} }
} }
} }
}

View File

@@ -15,13 +15,10 @@
*/ */
open class NativeArtifact( val fileName: String, val classifier: String, val type: String ) {}
open class PublishExtension { open class PublishExtension {
var artifactId: String? = null var artifactId: String? = null
var name: String? = null var name: String? = null
var description: String? = null var description: String? = null
var nativeArtifacts: List<NativeArtifact>? = null
} }
val extension = project.extensions.create<PublishExtension>( "flatlafPublish" ) val extension = project.extensions.create<PublishExtension>( "flatlafPublish" )
@@ -74,15 +71,6 @@ publishing {
url.set( "https://github.com/JFormDesigner/FlatLaf/issues" ) url.set( "https://github.com/JFormDesigner/FlatLaf/issues" )
} }
} }
afterEvaluate {
extension.nativeArtifacts?.forEach {
artifact( artifacts.add( "archives", file( it.fileName ) ) {
classifier = it.classifier
type = it.type
} )
}
}
} }
} }
@@ -92,7 +80,7 @@ publishing {
val releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" val releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
val snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots/" val snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots/"
url = uri( if( rootProject.hasProperty( "release" ) ) releasesRepoUrl else snapshotsRepoUrl ) url = uri( if( java.lang.Boolean.getBoolean( "release" ) ) releasesRepoUrl else snapshotsRepoUrl )
credentials { credentials {
// get from gradle.properties // get from gradle.properties
@@ -120,13 +108,5 @@ signing {
// disable signing of snapshots // disable signing of snapshots
tasks.withType<Sign>().configureEach { tasks.withType<Sign>().configureEach {
onlyIf { rootProject.hasProperty( "release" ) } onlyIf { java.lang.Boolean.getBoolean( "release" ) }
}
// check whether parallel build is enabled
tasks.withType<PublishToMavenRepository>().configureEach {
doFirst {
if( System.getProperty( "org.gradle.parallel" ) == "true" )
throw RuntimeException( "Publishing does not work correctly with enabled parallel build. Disable parallel build with VM option '-Dorg.gradle.parallel=false'." )
}
} }

View File

@@ -1,26 +0,0 @@
/*
* 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 ) )
}
}

2151
compare1.txt Normal file

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -14,11 +14,8 @@
* limitations under the License. * limitations under the License.
*/ */
import Flatlaf_publish_gradle.NativeArtifact
plugins { plugins {
`java-library` `java-library`
`flatlaf-toolchain`
`flatlaf-module-info` `flatlaf-module-info`
`flatlaf-java9` `flatlaf-java9`
`flatlaf-publish` `flatlaf-publish`
@@ -27,11 +24,12 @@ plugins {
val sigtest = configurations.create( "sigtest" ) val sigtest = configurations.create( "sigtest" )
dependencies { dependencies {
testImplementation( libs.bundles.junit ) testImplementation( "org.junit.jupiter:junit-jupiter-api:5.7.2" )
testRuntimeOnly( libs.junit.engine ) testImplementation( "org.junit.jupiter:junit-jupiter-params" )
testRuntimeOnly( "org.junit.jupiter:junit-jupiter-engine" )
// https://github.com/jtulach/netbeans-apitest // https://github.com/jtulach/netbeans-apitest
sigtest( libs.sigtest ) sigtest( "org.netbeans.tools:sigtest-maven-plugin:1.4" )
} }
java { java {
@@ -42,7 +40,12 @@ java {
tasks { tasks {
compileJava { compileJava {
// generate JNI headers // generate JNI headers
options.headerOutputDirectory.set( layout.buildDirectory.dir( "generated/jni-headers" ) ) options.headerOutputDirectory.set( buildDir.resolve( "generated/jni-headers" ) )
}
processResources {
// build native libraries
dependsOn( ":flatlaf-natives-windows:assemble" )
} }
jar { jar {
@@ -68,9 +71,6 @@ tasks {
test { test {
useJUnitPlatform() useJUnitPlatform()
testLogging.exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL testLogging.exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
if( JavaVersion.current() >= JavaVersion.VERSION_1_9 )
jvmArgs( listOf( "--add-opens", "java.desktop/javax.swing.plaf.basic=ALL-UNNAMED" ) )
} }
register( "sigtestGenerate" ) { register( "sigtestGenerate" ) {
@@ -88,7 +88,7 @@ tasks {
"action" to "generate", "action" to "generate",
"fileName" to "${project.name}-sigtest.txt", "fileName" to "${project.name}-sigtest.txt",
"classpath" to jar.get().outputs.files.asPath, "classpath" to jar.get().outputs.files.asPath,
"packages" to "com.formdev.flatlaf,com.formdev.flatlaf.themes,com.formdev.flatlaf.util", "packages" to "com.formdev.flatlaf,com.formdev.flatlaf.util",
"version" to version, "version" to version,
"release" to "1.8", // Java version "release" to "1.8", // Java version
"failonerror" to "true" ) "failonerror" to "true" )
@@ -124,12 +124,4 @@ flatlafPublish {
artifactId = "flatlaf" artifactId = "flatlaf"
name = "FlatLaf" name = "FlatLaf"
description = "Flat Look and Feel" description = "Flat Look and Feel"
val natives = "src/main/resources/com/formdev/flatlaf/natives"
nativeArtifacts = listOf(
NativeArtifact( "${natives}/flatlaf-windows-x86.dll", "windows-x86", "dll" ),
NativeArtifact( "${natives}/flatlaf-windows-x86_64.dll", "windows-x86_64", "dll" ),
NativeArtifact( "${natives}/flatlaf-windows-arm64.dll", "windows-arm64", "dll" ),
NativeArtifact( "${natives}/libflatlaf-linux-x86_64.so", "linux-x86_64", "so" ),
)
} }

View File

@@ -1,5 +1,5 @@
#Signature file v4.1 #Signature file v4.1
#Version 3.2.2 #Version 1.6
CLSS public abstract interface com.formdev.flatlaf.FlatClientProperties CLSS public abstract interface com.formdev.flatlaf.FlatClientProperties
fld public final static java.lang.String BUTTON_TYPE = "JButton.buttonType" fld public final static java.lang.String BUTTON_TYPE = "JButton.buttonType"
@@ -11,8 +11,6 @@ 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 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_FOCUS_OWNER = "JComponent.focusOwner"
fld public final static java.lang.String COMPONENT_ROUND_RECT = "JComponent.roundRect" fld public final static java.lang.String COMPONENT_ROUND_RECT = "JComponent.roundRect"
fld public final static java.lang.String COMPONENT_TITLE_BAR_CAPTION = "JComponent.titleBarCaption"
fld public final static java.lang.String GLASS_PANE_FULL_HEIGHT = "JRootPane.glassPaneFullHeight"
fld public final static java.lang.String MENU_BAR_EMBEDDED = "JRootPane.menuBarEmbedded" fld public final static java.lang.String MENU_BAR_EMBEDDED = "JRootPane.menuBarEmbedded"
fld public final static java.lang.String MINIMUM_HEIGHT = "JComponent.minimumHeight" fld public final static java.lang.String MINIMUM_HEIGHT = "JComponent.minimumHeight"
fld public final static java.lang.String MINIMUM_WIDTH = "JComponent.minimumWidth" fld public final static java.lang.String MINIMUM_WIDTH = "JComponent.minimumWidth"
@@ -20,7 +18,6 @@ fld public final static java.lang.String OUTLINE = "JComponent.outline"
fld public final static java.lang.String OUTLINE_ERROR = "error" fld public final static java.lang.String OUTLINE_ERROR = "error"
fld public final static java.lang.String OUTLINE_WARNING = "warning" fld public final static java.lang.String OUTLINE_WARNING = "warning"
fld public final static java.lang.String PLACEHOLDER_TEXT = "JTextField.placeholderText" fld public final static java.lang.String PLACEHOLDER_TEXT = "JTextField.placeholderText"
fld public final static java.lang.String POPUP_BORDER_CORNER_RADIUS = "Popup.borderCornerRadius"
fld public final static java.lang.String POPUP_DROP_SHADOW_PAINTED = "Popup.dropShadowPainted" fld public final static java.lang.String POPUP_DROP_SHADOW_PAINTED = "Popup.dropShadowPainted"
fld public final static java.lang.String POPUP_FORCE_HEAVY_WEIGHT = "Popup.forceHeavyWeight" fld public final static java.lang.String POPUP_FORCE_HEAVY_WEIGHT = "Popup.forceHeavyWeight"
fld public final static java.lang.String PROGRESS_BAR_LARGE_HEIGHT = "JProgressBar.largeHeight" fld public final static java.lang.String PROGRESS_BAR_LARGE_HEIGHT = "JProgressBar.largeHeight"
@@ -33,12 +30,7 @@ fld public final static java.lang.String SELECT_ALL_ON_FOCUS_POLICY = "JTextFiel
fld public final static java.lang.String SELECT_ALL_ON_FOCUS_POLICY_ALWAYS = "always" fld public final static java.lang.String SELECT_ALL_ON_FOCUS_POLICY_ALWAYS = "always"
fld public final static java.lang.String SELECT_ALL_ON_FOCUS_POLICY_NEVER = "never" fld public final static java.lang.String SELECT_ALL_ON_FOCUS_POLICY_NEVER = "never"
fld public final static java.lang.String SELECT_ALL_ON_FOCUS_POLICY_ONCE = "once" fld public final static java.lang.String SELECT_ALL_ON_FOCUS_POLICY_ONCE = "once"
fld public final static java.lang.String SPLIT_PANE_EXPANDABLE_SIDE = "JSplitPane.expandableSide"
fld public final static java.lang.String SPLIT_PANE_EXPANDABLE_SIDE_LEFT = "left"
fld public final static java.lang.String SPLIT_PANE_EXPANDABLE_SIDE_RIGHT = "right"
fld public final static java.lang.String SQUARE_SIZE = "JButton.squareSize" fld public final static java.lang.String SQUARE_SIZE = "JButton.squareSize"
fld public final static java.lang.String STYLE = "FlatLaf.style"
fld public final static java.lang.String STYLE_CLASS = "FlatLaf.styleClass"
fld public final static java.lang.String TABBED_PANE_ALIGN_CENTER = "center" fld public final static java.lang.String TABBED_PANE_ALIGN_CENTER = "center"
fld public final static java.lang.String TABBED_PANE_ALIGN_FILL = "fill" fld public final static java.lang.String TABBED_PANE_ALIGN_FILL = "fill"
fld public final static java.lang.String TABBED_PANE_ALIGN_LEADING = "leading" fld public final static java.lang.String TABBED_PANE_ALIGN_LEADING = "leading"
@@ -67,9 +59,6 @@ fld public final static java.lang.String TABBED_PANE_TAB_CLOSE_TOOLTIPTEXT = "JT
fld public final static java.lang.String TABBED_PANE_TAB_HEIGHT = "JTabbedPane.tabHeight" fld public final static java.lang.String TABBED_PANE_TAB_HEIGHT = "JTabbedPane.tabHeight"
fld public final static java.lang.String TABBED_PANE_TAB_ICON_PLACEMENT = "JTabbedPane.tabIconPlacement" fld public final static java.lang.String TABBED_PANE_TAB_ICON_PLACEMENT = "JTabbedPane.tabIconPlacement"
fld public final static java.lang.String TABBED_PANE_TAB_INSETS = "JTabbedPane.tabInsets" fld public final static java.lang.String TABBED_PANE_TAB_INSETS = "JTabbedPane.tabInsets"
fld public final static java.lang.String TABBED_PANE_TAB_TYPE = "JTabbedPane.tabType"
fld public final static java.lang.String TABBED_PANE_TAB_TYPE_CARD = "card"
fld public final static java.lang.String TABBED_PANE_TAB_TYPE_UNDERLINED = "underlined"
fld public final static java.lang.String TABBED_PANE_TAB_WIDTH_MODE = "JTabbedPane.tabWidthMode" fld public final static java.lang.String TABBED_PANE_TAB_WIDTH_MODE = "JTabbedPane.tabWidthMode"
fld public final static java.lang.String TABBED_PANE_TAB_WIDTH_MODE_COMPACT = "compact" fld public final static java.lang.String TABBED_PANE_TAB_WIDTH_MODE_COMPACT = "compact"
fld public final static java.lang.String TABBED_PANE_TAB_WIDTH_MODE_EQUAL = "equal" fld public final static java.lang.String TABBED_PANE_TAB_WIDTH_MODE_EQUAL = "equal"
@@ -78,27 +67,12 @@ fld public final static java.lang.String TABBED_PANE_TRAILING_COMPONENT = "JTabb
fld public final static java.lang.String TAB_BUTTON_SELECTED_BACKGROUND = "JToggleButton.tab.selectedBackground" fld public final static java.lang.String TAB_BUTTON_SELECTED_BACKGROUND = "JToggleButton.tab.selectedBackground"
fld public final static java.lang.String TAB_BUTTON_UNDERLINE_COLOR = "JToggleButton.tab.underlineColor" fld public final static java.lang.String TAB_BUTTON_UNDERLINE_COLOR = "JToggleButton.tab.underlineColor"
fld public final static java.lang.String TAB_BUTTON_UNDERLINE_HEIGHT = "JToggleButton.tab.underlineHeight" fld public final static java.lang.String TAB_BUTTON_UNDERLINE_HEIGHT = "JToggleButton.tab.underlineHeight"
fld public final static java.lang.String TAB_BUTTON_UNDERLINE_PLACEMENT = "JToggleButton.tab.underlinePlacement"
fld public final static java.lang.String TEXT_FIELD_CLEAR_CALLBACK = "JTextField.clearCallback"
fld public final static java.lang.String TEXT_FIELD_LEADING_COMPONENT = "JTextField.leadingComponent"
fld public final static java.lang.String TEXT_FIELD_LEADING_ICON = "JTextField.leadingIcon"
fld public final static java.lang.String TEXT_FIELD_PADDING = "JTextField.padding" fld public final static java.lang.String TEXT_FIELD_PADDING = "JTextField.padding"
fld public final static java.lang.String TEXT_FIELD_SHOW_CLEAR_BUTTON = "JTextField.showClearButton"
fld public final static java.lang.String TEXT_FIELD_TRAILING_COMPONENT = "JTextField.trailingComponent"
fld public final static java.lang.String TEXT_FIELD_TRAILING_ICON = "JTextField.trailingIcon"
fld public final static java.lang.String TITLE_BAR_BACKGROUND = "JRootPane.titleBarBackground" fld public final static java.lang.String TITLE_BAR_BACKGROUND = "JRootPane.titleBarBackground"
fld public final static java.lang.String TITLE_BAR_FOREGROUND = "JRootPane.titleBarForeground" fld public final static java.lang.String TITLE_BAR_FOREGROUND = "JRootPane.titleBarForeground"
fld public final static java.lang.String TITLE_BAR_SHOW_CLOSE = "JRootPane.titleBarShowClose"
fld public final static java.lang.String TITLE_BAR_SHOW_ICON = "JRootPane.titleBarShowIcon"
fld public final static java.lang.String TITLE_BAR_SHOW_ICONIFFY = "JRootPane.titleBarShowIconify"
fld public final static java.lang.String TITLE_BAR_SHOW_MAXIMIZE = "JRootPane.titleBarShowMaximize"
fld public final static java.lang.String TITLE_BAR_SHOW_TITLE = "JRootPane.titleBarShowTitle"
fld public final static java.lang.String TREE_PAINT_SELECTION = "JTree.paintSelection" fld public final static java.lang.String TREE_PAINT_SELECTION = "JTree.paintSelection"
fld public final static java.lang.String TREE_WIDE_SELECTION = "JTree.wideSelection" fld public final static java.lang.String TREE_WIDE_SELECTION = "JTree.wideSelection"
fld public final static java.lang.String USE_WINDOW_DECORATIONS = "JRootPane.useWindowDecorations" fld public final static java.lang.String USE_WINDOW_DECORATIONS = "JRootPane.useWindowDecorations"
fld public final static java.lang.String WINDOW_STYLE = "Window.style"
fld public final static java.lang.String WINDOW_STYLE_SMALL = "small"
meth public static <%0 extends java.lang.Object> {%%0} clientProperty(javax.swing.JComponent,java.lang.String,{%%0},java.lang.Class<{%%0}>)
meth public static boolean clientPropertyBoolean(javax.swing.JComponent,java.lang.String,boolean) meth public static boolean clientPropertyBoolean(javax.swing.JComponent,java.lang.String,boolean)
meth public static boolean clientPropertyEquals(javax.swing.JComponent,java.lang.String,java.lang.Object) meth public static boolean clientPropertyEquals(javax.swing.JComponent,java.lang.String,java.lang.Object)
meth public static int clientPropertyInt(javax.swing.JComponent,java.lang.String,int) meth public static int clientPropertyInt(javax.swing.JComponent,java.lang.String,int)
@@ -191,10 +165,8 @@ meth public boolean isSupportedLookAndFeel()
meth public final boolean equals(java.lang.Object) meth public final boolean equals(java.lang.Object)
meth public final int hashCode() meth public final int hashCode()
meth public java.lang.String getID() 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.Icon getDisabledIcon(javax.swing.JComponent,javax.swing.Icon)
meth public javax.swing.UIDefaults getDefaults() 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) meth public static boolean install(javax.swing.LookAndFeel)
anno 0 java.lang.Deprecated() anno 0 java.lang.Deprecated()
meth public static boolean isLafDark() meth public static boolean isLafDark()
@@ -202,14 +174,6 @@ meth public static boolean isShowMnemonics()
meth public static boolean isUseNativeWindowDecorations() meth public static boolean isUseNativeWindowDecorations()
meth public static boolean setup(javax.swing.LookAndFeel) meth public static boolean setup(javax.swing.LookAndFeel)
meth public static boolean supportsNativeWindowDecorations() meth public static boolean supportsNativeWindowDecorations()
meth public static java.lang.Object parseDefaultsValue(java.lang.String,java.lang.String,java.lang.Class<?>)
meth public static java.lang.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 javax.swing.UIDefaults$ActiveValue createActiveFontValue(float)
meth public static void hideMnemonics() meth public static void hideMnemonics()
meth public static void initIconColors(javax.swing.UIDefaults,boolean) meth public static void initIconColors(javax.swing.UIDefaults,boolean)
@@ -217,31 +181,22 @@ meth public static void installLafInfo(java.lang.String,java.lang.Class<? extend
meth public static void registerCustomDefaultsSource(java.io.File) meth public static void registerCustomDefaultsSource(java.io.File)
meth public static void registerCustomDefaultsSource(java.lang.String) meth public static void registerCustomDefaultsSource(java.lang.String)
meth public static void registerCustomDefaultsSource(java.lang.String,java.lang.ClassLoader) meth public static void registerCustomDefaultsSource(java.lang.String,java.lang.ClassLoader)
meth public static void registerCustomDefaultsSource(java.net.URL)
meth public static void repaintAllFramesAndDialogs() meth public static void repaintAllFramesAndDialogs()
meth public static void revalidateAndRepaintAllFramesAndDialogs() meth public static void revalidateAndRepaintAllFramesAndDialogs()
meth public static void runWithUIDefaultsGetter(java.util.function.Function<java.lang.Object,java.lang.Object>,java.lang.Runnable) meth public static void runWithUIDefaultsGetter(java.util.function.Function<java.lang.Object,java.lang.Object>,java.lang.Runnable)
meth public static void setGlobalExtraDefaults(java.util.Map<java.lang.String,java.lang.String>)
meth public static void setPreferredFontFamily(java.lang.String)
meth public static void setPreferredLightFontFamily(java.lang.String)
meth public static void setPreferredMonospacedFontFamily(java.lang.String)
meth public static void setPreferredSemiboldFontFamily(java.lang.String)
meth public static void setSystemColorGetter(java.util.function.Function<java.lang.String,java.awt.Color>)
meth public static void setUseNativeWindowDecorations(boolean) meth public static void setUseNativeWindowDecorations(boolean)
meth public static void showMnemonics(java.awt.Component) meth public static void showMnemonics(java.awt.Component)
meth public static void unregisterCustomDefaultsSource(java.io.File) meth public static void unregisterCustomDefaultsSource(java.io.File)
meth public static void unregisterCustomDefaultsSource(java.lang.String) meth public static void unregisterCustomDefaultsSource(java.lang.String)
meth public static void unregisterCustomDefaultsSource(java.lang.String,java.lang.ClassLoader) meth public static void unregisterCustomDefaultsSource(java.lang.String,java.lang.ClassLoader)
meth public static void unregisterCustomDefaultsSource(java.net.URL)
meth public static void updateUI() meth public static void updateUI()
meth public static void updateUILater() meth public static void updateUILater()
meth public void initialize() meth public void initialize()
meth public void registerUIDefaultsGetter(java.util.function.Function<java.lang.Object,java.lang.Object>) meth public void registerUIDefaultsGetter(java.util.function.Function<java.lang.Object,java.lang.Object>)
meth public void setExtraDefaults(java.util.Map<java.lang.String,java.lang.String>)
meth public void uninitialize() meth public void uninitialize()
meth public void unregisterUIDefaultsGetter(java.util.function.Function<java.lang.Object,java.lang.Object>) meth public void unregisterUIDefaultsGetter(java.util.function.Function<java.lang.Object,java.lang.Object>)
supr javax.swing.plaf.basic.BasicLookAndFeel supr javax.swing.plaf.basic.BasicLookAndFeel
hfds DESKTOPFONTHINTS,aquaLoaded,customDefaultsSources,desktopPropertyListener,desktopPropertyName,desktopPropertyName2,extraDefaults,getUIMethod,getUIMethodInitialized,globalExtraDefaults,mnemonicHandler,oldPopupFactory,postInitialization,preferredFontFamily,preferredLightFontFamily,preferredMonospacedFontFamily,preferredSemiboldFontFamily,subMenuUsabilityHelperInstalled,systemColorGetter,uiDefaultsGetters,updateUIPending hfds DESKTOPFONTHINTS,aquaLoaded,customDefaultsSources,desktopPropertyListener,desktopPropertyName,desktopPropertyName2,mnemonicHandler,oldPopupFactory,postInitialization,uiDefaultsGetters,updateUIPending
hcls ActiveFont,FlatUIDefaults,ImageIconUIResource hcls ActiveFont,FlatUIDefaults,ImageIconUIResource
CLSS public abstract interface static com.formdev.flatlaf.FlatLaf$DisabledIconProvider CLSS public abstract interface static com.formdev.flatlaf.FlatLaf$DisabledIconProvider
@@ -276,13 +231,10 @@ hfds baseTheme,dark,name,properties
CLSS public abstract interface com.formdev.flatlaf.FlatSystemProperties CLSS public abstract interface com.formdev.flatlaf.FlatSystemProperties
fld public final static java.lang.String ANIMATION = "flatlaf.animation" fld public final static java.lang.String ANIMATION = "flatlaf.animation"
fld public final static java.lang.String MENUBAR_EMBEDDED = "flatlaf.menuBarEmbedded" fld public final static java.lang.String MENUBAR_EMBEDDED = "flatlaf.menuBarEmbedded"
fld public final static java.lang.String NATIVE_LIBRARY_PATH = "flatlaf.nativeLibraryPath"
fld public final static java.lang.String UI_SCALE = "flatlaf.uiScale" 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_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 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_JETBRAINS_CUSTOM_DECORATIONS = "flatlaf.useJetBrainsCustomDecorations"
fld public final static java.lang.String USE_NATIVE_LIBRARY = "flatlaf.useNativeLibrary"
fld public final static java.lang.String USE_TEXT_Y_CORRECTION = "flatlaf.useTextYCorrection" fld public final static java.lang.String USE_TEXT_Y_CORRECTION = "flatlaf.useTextYCorrection"
fld public final static java.lang.String USE_UBUNTU_FONT = "flatlaf.useUbuntuFont" fld public final static java.lang.String USE_UBUNTU_FONT = "flatlaf.useUbuntuFont"
fld public final static java.lang.String USE_WINDOW_DECORATIONS = "flatlaf.useWindowDecorations" fld public final static java.lang.String USE_WINDOW_DECORATIONS = "flatlaf.useWindowDecorations"
@@ -301,7 +253,7 @@ meth public static boolean setup(java.io.InputStream)
meth public static com.formdev.flatlaf.FlatLaf createLaf(com.formdev.flatlaf.IntelliJTheme) meth public static com.formdev.flatlaf.FlatLaf createLaf(com.formdev.flatlaf.IntelliJTheme)
meth public static com.formdev.flatlaf.FlatLaf createLaf(java.io.InputStream) throws java.io.IOException meth public static com.formdev.flatlaf.FlatLaf createLaf(java.io.InputStream) throws java.io.IOException
supr java.lang.Object supr java.lang.Object
hfds checkboxDuplicateColors,checkboxKeyMapping,colors,icons,isMaterialUILite,namedColors,ui,uiKeyCopying,uiKeyDoNotOverride,uiKeyExcludes,uiKeyInverseMapping,uiKeyMapping hfds checkboxDuplicateColors,checkboxKeyMapping,colors,icons,isMaterialUILite,namedColors,ui,uiKeyCopying,uiKeyInverseMapping,uiKeyMapping
CLSS public static com.formdev.flatlaf.IntelliJTheme$ThemeLaf CLSS public static com.formdev.flatlaf.IntelliJTheme$ThemeLaf
outer com.formdev.flatlaf.IntelliJTheme outer com.formdev.flatlaf.IntelliJTheme
@@ -314,26 +266,6 @@ meth public java.lang.String getName()
supr com.formdev.flatlaf.FlatLaf supr com.formdev.flatlaf.FlatLaf
hfds theme hfds theme
CLSS public com.formdev.flatlaf.themes.FlatMacDarkLaf
cons public init()
fld public final static java.lang.String NAME = "FlatLaf macOS Dark"
meth public boolean isDark()
meth public java.lang.String getDescription()
meth public java.lang.String getName()
meth public static boolean setup()
meth public static void installLafInfo()
supr com.formdev.flatlaf.FlatDarkLaf
CLSS public com.formdev.flatlaf.themes.FlatMacLightLaf
cons public init()
fld public final static java.lang.String NAME = "FlatLaf macOS Light"
meth public boolean isDark()
meth public java.lang.String getDescription()
meth public java.lang.String getName()
meth public static boolean setup()
meth public static void installLafInfo()
supr com.formdev.flatlaf.FlatLightLaf
CLSS public abstract interface com.formdev.flatlaf.util.AnimatedIcon CLSS public abstract interface com.formdev.flatlaf.util.AnimatedIcon
innr public static AnimationSupport innr public static AnimationSupport
intf javax.swing.Icon intf javax.swing.Icon
@@ -398,16 +330,7 @@ innr public static HSLIncreaseDecrease
innr public static Mix innr public static Mix
meth public !varargs static java.awt.Color applyFunctions(java.awt.Color,com.formdev.flatlaf.util.ColorFunctions$ColorFunction[]) meth public !varargs static java.awt.Color applyFunctions(java.awt.Color,com.formdev.flatlaf.util.ColorFunctions$ColorFunction[])
meth public static float clamp(float) 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 mix(java.awt.Color,java.awt.Color,float)
meth public static java.awt.Color saturate(java.awt.Color,float)
meth public static java.awt.Color shade(java.awt.Color,float)
meth public static java.awt.Color spin(java.awt.Color,float)
meth public static java.awt.Color tint(java.awt.Color,float)
supr java.lang.Object supr java.lang.Object
CLSS public abstract interface static com.formdev.flatlaf.util.ColorFunctions$ColorFunction CLSS public abstract interface static com.formdev.flatlaf.util.ColorFunctions$ColorFunction
@@ -477,17 +400,6 @@ meth public java.lang.String toString()
supr javax.swing.plaf.ColorUIResource supr javax.swing.plaf.ColorUIResource
hfds baseOfDefaultColorRGB,functions,hasBaseOfDefaultColor hfds baseOfDefaultColorRGB,functions,hasBaseOfDefaultColor
CLSS public com.formdev.flatlaf.util.FontUtils
cons public init()
meth public static boolean installFont(java.net.URL)
meth public static java.awt.Font getCompositeFont(java.lang.String,int,int)
meth public static java.awt.Font[] getAllFonts()
meth public static java.lang.String[] getAvailableFontFamilyNames()
meth public static void loadFontFamily(java.lang.String)
meth public static void registerFontFamilyLoader(java.lang.String,java.lang.Runnable)
supr java.lang.Object
hfds loadersMap
CLSS public com.formdev.flatlaf.util.Graphics2DProxy CLSS public com.formdev.flatlaf.util.Graphics2DProxy
cons public init(java.awt.Graphics2D) cons public init(java.awt.Graphics2D)
meth public boolean drawImage(java.awt.Image,int,int,int,int,int,int,int,int,java.awt.Color,java.awt.image.ImageObserver) meth public boolean drawImage(java.awt.Image,int,int,int,int,int,int,int,int,java.awt.Color,java.awt.image.ImageObserver)
@@ -624,7 +536,7 @@ meth public static void drawStringWithYCorrection(javax.swing.JComponent,java.aw
meth public static void paintAtScale1x(java.awt.Graphics2D,int,int,int,int,com.formdev.flatlaf.util.HiDPIUtils$Painter) meth public static void paintAtScale1x(java.awt.Graphics2D,int,int,int,int,com.formdev.flatlaf.util.HiDPIUtils$Painter)
meth public static void paintAtScale1x(java.awt.Graphics2D,javax.swing.JComponent,com.formdev.flatlaf.util.HiDPIUtils$Painter) meth public static void paintAtScale1x(java.awt.Graphics2D,javax.swing.JComponent,com.formdev.flatlaf.util.HiDPIUtils$Painter)
supr java.lang.Object supr java.lang.Object
hfds CORRECTION_INTER,CORRECTION_OPEN_SANS,CORRECTION_SEGOE_UI,CORRECTION_TAHOMA,SCALE_FACTORS,useDebugScaleFactor,useTextYCorrection hfds useTextYCorrection
CLSS public abstract interface static com.formdev.flatlaf.util.HiDPIUtils$Painter CLSS public abstract interface static com.formdev.flatlaf.util.HiDPIUtils$Painter
outer com.formdev.flatlaf.util.HiDPIUtils outer com.formdev.flatlaf.util.HiDPIUtils
@@ -654,8 +566,6 @@ meth public static java.util.List<java.awt.Image> getResolutionVariants(java.awt
supr java.lang.Object supr java.lang.Object
CLSS public com.formdev.flatlaf.util.NativeLibrary 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) cons public init(java.lang.String,java.lang.ClassLoader,boolean)
meth public boolean isLoaded() meth public boolean isLoaded()
supr java.lang.Object supr java.lang.Object
@@ -679,59 +589,23 @@ meth public void paintIcon(java.awt.Component,java.awt.Graphics,int,int)
supr java.lang.Object supr java.lang.Object
hfds iconHeight,iconWidth,imageIcon,lastImage,lastSystemScaleFactor,lastUserScaleFactor hfds iconHeight,iconWidth,imageIcon,lastImage,lastSystemScaleFactor,lastUserScaleFactor
CLSS public com.formdev.flatlaf.util.SoftCache<%0 extends java.lang.Object, %1 extends java.lang.Object>
cons public init()
cons public init(int)
intf java.util.Map<{com.formdev.flatlaf.util.SoftCache%0},{com.formdev.flatlaf.util.SoftCache%1}>
meth public boolean containsKey(java.lang.Object)
meth public boolean containsValue(java.lang.Object)
meth public boolean isEmpty()
meth public int size()
meth public java.util.Collection<{com.formdev.flatlaf.util.SoftCache%1}> values()
meth public java.util.Set<java.util.Map$Entry<{com.formdev.flatlaf.util.SoftCache%0},{com.formdev.flatlaf.util.SoftCache%1}>> entrySet()
meth public java.util.Set<{com.formdev.flatlaf.util.SoftCache%0}> keySet()
meth public void clear()
meth public void forEach(java.util.function.BiConsumer<? super {com.formdev.flatlaf.util.SoftCache%0},? super {com.formdev.flatlaf.util.SoftCache%1}>)
meth public void putAll(java.util.Map<? extends {com.formdev.flatlaf.util.SoftCache%0},? extends {com.formdev.flatlaf.util.SoftCache%1}>)
meth public void replaceAll(java.util.function.BiFunction<? super {com.formdev.flatlaf.util.SoftCache%0},? super {com.formdev.flatlaf.util.SoftCache%1},? extends {com.formdev.flatlaf.util.SoftCache%1}>)
meth public {com.formdev.flatlaf.util.SoftCache%1} get(java.lang.Object)
meth public {com.formdev.flatlaf.util.SoftCache%1} put({com.formdev.flatlaf.util.SoftCache%0},{com.formdev.flatlaf.util.SoftCache%1})
meth public {com.formdev.flatlaf.util.SoftCache%1} remove(java.lang.Object)
supr java.lang.Object
hfds map,queue
hcls CacheReference
CLSS public com.formdev.flatlaf.util.StringUtils CLSS public com.formdev.flatlaf.util.StringUtils
cons public init() cons public init()
meth public static boolean isEmpty(java.lang.String) meth public static boolean isEmpty(java.lang.String)
meth public static boolean isTrimmedEmpty(java.lang.String)
meth public static java.lang.String removeLeading(java.lang.String,java.lang.String) meth public static java.lang.String removeLeading(java.lang.String,java.lang.String)
meth public static java.lang.String removeTrailing(java.lang.String,java.lang.String) meth public static java.lang.String removeTrailing(java.lang.String,java.lang.String)
meth public static java.lang.String substringTrimmed(java.lang.String,int)
meth public static java.lang.String substringTrimmed(java.lang.String,int,int)
meth public static java.util.List<java.lang.String> split(java.lang.String,char) meth public static java.util.List<java.lang.String> split(java.lang.String,char)
meth public static java.util.List<java.lang.String> split(java.lang.String,char,boolean,boolean)
supr java.lang.Object
CLSS public com.formdev.flatlaf.util.SwingUtils
cons public init()
meth public static <%0 extends java.awt.Component> {%%0} getComponentByName(java.awt.Container,java.lang.String)
supr java.lang.Object supr java.lang.Object
CLSS public com.formdev.flatlaf.util.SystemInfo CLSS public com.formdev.flatlaf.util.SystemInfo
cons public init() cons public init()
fld public final static boolean isAARCH64
fld public final static boolean isJava_11_orLater fld public final static boolean isJava_11_orLater
fld public final static boolean isJava_12_orLater
fld public final static boolean isJava_15_orLater fld public final static boolean isJava_15_orLater
fld public final static boolean isJava_17_orLater
fld public final static boolean isJava_18_orLater
fld public final static boolean isJava_9_orLater fld public final static boolean isJava_9_orLater
fld public final static boolean isJetBrainsJVM fld public final static boolean isJetBrainsJVM
fld public final static boolean isJetBrainsJVM_11_orLater fld public final static boolean isJetBrainsJVM_11_orLater
fld public final static boolean isKDE fld public final static boolean isKDE
fld public final static boolean isLinux fld public final static boolean isLinux
fld public final static boolean isMacFullWindowContentSupported
fld public final static boolean isMacOS fld public final static boolean isMacOS
fld public final static boolean isMacOS_10_11_ElCapitan_orLater fld public final static boolean isMacOS_10_11_ElCapitan_orLater
fld public final static boolean isMacOS_10_14_Mojave_orLater fld public final static boolean isMacOS_10_14_Mojave_orLater
@@ -741,8 +615,6 @@ fld public final static boolean isWebswing
fld public final static boolean isWinPE fld public final static boolean isWinPE
fld public final static boolean isWindows fld public final static boolean isWindows
fld public final static boolean isWindows_10_orLater fld public final static boolean isWindows_10_orLater
fld public final static boolean isWindows_11_orLater
fld public final static boolean isX86
fld public final static boolean isX86_64 fld public final static boolean isX86_64
fld public final static long javaVersion fld public final static long javaVersion
fld public final static long osVersion fld public final static long osVersion
@@ -755,7 +627,6 @@ cons public init()
meth public static boolean isSystemScalingEnabled() meth public static boolean isSystemScalingEnabled()
meth public static double getSystemScaleFactor(java.awt.Graphics2D) meth public static double getSystemScaleFactor(java.awt.Graphics2D)
meth public static double getSystemScaleFactor(java.awt.GraphicsConfiguration) meth public static double getSystemScaleFactor(java.awt.GraphicsConfiguration)
meth public static float computeFontScaleFactor(java.awt.Font)
meth public static float getUserScaleFactor() meth public static float getUserScaleFactor()
meth public static float scale(float) meth public static float scale(float)
meth public static float unscale(float) meth public static float unscale(float)
@@ -1062,34 +933,6 @@ CLSS public abstract interface !annotation java.lang.annotation.Target
intf java.lang.annotation.Annotation intf java.lang.annotation.Annotation
meth public abstract java.lang.annotation.ElementType[] value() meth public abstract java.lang.annotation.ElementType[] value()
CLSS public abstract interface java.util.Map<%0 extends java.lang.Object, %1 extends java.lang.Object>
innr public abstract interface static Entry
meth public abstract boolean containsKey(java.lang.Object)
meth public abstract boolean containsValue(java.lang.Object)
meth public abstract boolean equals(java.lang.Object)
meth public abstract boolean isEmpty()
meth public abstract int hashCode()
meth public abstract int size()
meth public abstract java.util.Collection<{java.util.Map%1}> values()
meth public abstract java.util.Set<java.util.Map$Entry<{java.util.Map%0},{java.util.Map%1}>> entrySet()
meth public abstract java.util.Set<{java.util.Map%0}> keySet()
meth public abstract void clear()
meth public abstract void putAll(java.util.Map<? extends {java.util.Map%0},? extends {java.util.Map%1}>)
meth public abstract {java.util.Map%1} get(java.lang.Object)
meth public abstract {java.util.Map%1} put({java.util.Map%0},{java.util.Map%1})
meth public abstract {java.util.Map%1} remove(java.lang.Object)
meth public boolean remove(java.lang.Object,java.lang.Object)
meth public boolean replace({java.util.Map%0},{java.util.Map%1},{java.util.Map%1})
meth public void forEach(java.util.function.BiConsumer<? super {java.util.Map%0},? super {java.util.Map%1}>)
meth public void replaceAll(java.util.function.BiFunction<? super {java.util.Map%0},? super {java.util.Map%1},? extends {java.util.Map%1}>)
meth public {java.util.Map%1} compute({java.util.Map%0},java.util.function.BiFunction<? super {java.util.Map%0},? super {java.util.Map%1},? extends {java.util.Map%1}>)
meth public {java.util.Map%1} computeIfAbsent({java.util.Map%0},java.util.function.Function<? super {java.util.Map%0},? extends {java.util.Map%1}>)
meth public {java.util.Map%1} computeIfPresent({java.util.Map%0},java.util.function.BiFunction<? super {java.util.Map%0},? super {java.util.Map%1},? extends {java.util.Map%1}>)
meth public {java.util.Map%1} getOrDefault(java.lang.Object,{java.util.Map%1})
meth public {java.util.Map%1} merge({java.util.Map%0},{java.util.Map%1},java.util.function.BiFunction<? super {java.util.Map%1},? super {java.util.Map%1},? extends {java.util.Map%1}>)
meth public {java.util.Map%1} putIfAbsent({java.util.Map%0},{java.util.Map%1})
meth public {java.util.Map%1} replace({java.util.Map%0},{java.util.Map%1})
CLSS public abstract interface javax.swing.Icon CLSS public abstract interface javax.swing.Icon
meth public abstract int getIconHeight() meth public abstract int getIconHeight()
meth public abstract int getIconWidth() meth public abstract int getIconWidth()

View File

@@ -17,8 +17,6 @@
package com.formdev.flatlaf; package com.formdev.flatlaf;
import java.awt.Color; import java.awt.Color;
import java.awt.IllegalComponentStateException;
import java.awt.Window;
import java.util.Objects; import java.util.Objects;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.SwingConstants; import javax.swing.SwingConstants;
@@ -126,7 +124,6 @@ public interface FlatClientProperties
*/ */
String SQUARE_SIZE = "JButton.squareSize"; String SQUARE_SIZE = "JButton.squareSize";
//---- JComponent --------------------------------------------------------- //---- JComponent ---------------------------------------------------------
/** /**
@@ -256,41 +253,8 @@ public interface FlatClientProperties
*/ */
String COMPONENT_FOCUS_OWNER = "JComponent.focusOwner"; String COMPONENT_FOCUS_OWNER = "JComponent.focusOwner";
/**
* Specifies whether a component in an embedded menu bar should behave as caption
* (left-click allows moving window, right-click shows window system menu).
* The component does not receive mouse pressed/released/clicked/dragged events,
* but it gets mouse entered/exited/moved events.
* <p>
* <strong>Component</strong> {@link javax.swing.JComponent}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
*
* @since 2.5
*/
String COMPONENT_TITLE_BAR_CAPTION = "JComponent.titleBarCaption";
//---- Popup -------------------------------------------------------------- //---- Popup --------------------------------------------------------------
/**
* Specifies the popup border corner radius if the component is shown in a popup
* or if the component is the owner of another component that is shown in a popup.
* <p>
* Note that this is not available on all platforms since it requires special support.
* Supported platforms:
* <p>
* <strong>Windows 11</strong> (x86 or x86_64): Only two corner radiuses are supported
* by the OS: {@code DWMWCP_ROUND} is 8px and {@code DWMWCP_ROUNDSMALL} is 4px.
* If this value is {@code 1 - 4}, then {@code DWMWCP_ROUNDSMALL} is used.
* If it is {@code >= 5}, then {@code DWMWCP_ROUND} is used.
* <p>
* <strong>Component</strong> {@link javax.swing.JComponent}<br>
* <strong>Value type</strong> {@link java.lang.Integer}<br>
*
* @since 3.1
*/
String POPUP_BORDER_CORNER_RADIUS = "Popup.borderCornerRadius";
/** /**
* Specifies whether a drop shadow is painted if the component is shown in a popup * Specifies whether a drop shadow is painted if the component is shown in a popup
* or if the component is the owner of another component that is shown in a popup. * or if the component is the owner of another component that is shown in a popup.
@@ -309,7 +273,6 @@ public interface FlatClientProperties
*/ */
String POPUP_FORCE_HEAVY_WEIGHT = "Popup.forceHeavyWeight"; String POPUP_FORCE_HEAVY_WEIGHT = "Popup.forceHeavyWeight";
//---- JProgressBar ------------------------------------------------------- //---- JProgressBar -------------------------------------------------------
/** /**
@@ -328,7 +291,6 @@ public interface FlatClientProperties
*/ */
String PROGRESS_BAR_SQUARE = "JProgressBar.square"; String PROGRESS_BAR_SQUARE = "JProgressBar.square";
//---- JRootPane ---------------------------------------------------------- //---- JRootPane ----------------------------------------------------------
/** /**
@@ -371,7 +333,7 @@ public interface FlatClientProperties
/** /**
* Specifies whether the window icon should be shown in the window title bar * Specifies whether the window icon should be shown in the window title bar
* (requires enabled window decorations). Default is UI property {@code TitlePane.showIcon}. * (requires enabled window decorations).
* <p> * <p>
* Setting this shows/hides the windows icon * Setting this shows/hides the windows icon
* for the {@code JFrame} or {@code JDialog} that contains the root pane. * for the {@code JFrame} or {@code JDialog} that contains the root pane.
@@ -387,62 +349,6 @@ public interface FlatClientProperties
*/ */
String TITLE_BAR_SHOW_ICON = "JRootPane.titleBarShowIcon"; 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). * Background color of window title bar (requires enabled window decorations).
* <p> * <p>
@@ -467,48 +373,6 @@ public interface FlatClientProperties
*/ */
String TITLE_BAR_FOREGROUND = "JRootPane.titleBarForeground"; String TITLE_BAR_FOREGROUND = "JRootPane.titleBarForeground";
/**
* Specifies whether the glass pane should have full height and overlap the title bar,
* if FlatLaf window decorations are enabled. Default is {@code false}.
* <p>
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
*
* @since 3.1
*/
String GLASS_PANE_FULL_HEIGHT = "JRootPane.glassPaneFullHeight";
/**
* Specifies the style of the window title bar.
* Besides the default title bar style, you can use a Utility-style title bar,
* which is smaller than the default title bar.
* <p>
* On Windows 10/11, this requires FlatLaf window decorations.
* On macOS, Java supports this out of the box.
* <p>
* Note that this client property must be set before the window becomes displayable.
* Otherwise an {@link IllegalComponentStateException} is thrown.
* <p>
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
* <strong>Value type</strong> {@link java.lang.String}<br>
* <strong>Allowed Values</strong>
* {@link #WINDOW_STYLE_SMALL}
*
* @since 3.2
*/
String WINDOW_STYLE = "Window.style";
/**
* The window has Utility-style title bar, which is smaller than default title bar.
* <p>
* This is the same as using {@link Window#setType}( {@link Window.Type#UTILITY} ).
*
* @see #WINDOW_STYLE
* @since 3.2
*/
String WINDOW_STYLE_SMALL = "small";
//---- JScrollBar / JScrollPane ------------------------------------------- //---- JScrollBar / JScrollPane -------------------------------------------
/** /**
@@ -527,42 +391,6 @@ public interface FlatClientProperties
*/ */
String SCROLL_PANE_SMOOTH_SCROLLING = "JScrollPane.smoothScrolling"; String SCROLL_PANE_SMOOTH_SCROLLING = "JScrollPane.smoothScrolling";
//---- JSplitPane ---------------------------------------------------------
/**
* Specifies what side of the spilt pane is allowed to expand
* via one-touch expanding arrow buttons.
* Requires that one-touch expanding is enabled with
* {@link javax.swing.JSplitPane#setOneTouchExpandable(boolean)}.
* <p>
* <strong>Component</strong> {@link javax.swing.JSplitPane}<br>
* <strong>Value type</strong> {@link java.lang.String}<br>
* <strong>Allowed Values</strong>
* {@link #SPLIT_PANE_EXPANDABLE_SIDE_LEFT} or
* {@link #SPLIT_PANE_EXPANDABLE_SIDE_RIGHT}
*
* @since 2.2
*/
String SPLIT_PANE_EXPANDABLE_SIDE = "JSplitPane.expandableSide";
/**
* Allow expanding only left/top side of the split pane.
*
* @see #SPLIT_PANE_EXPANDABLE_SIDE
* @since 2.2
*/
String SPLIT_PANE_EXPANDABLE_SIDE_LEFT = "left";
/**
* Allow expanding only right/bottom side of the split pane.
*
* @see #SPLIT_PANE_EXPANDABLE_SIDE
* @since 2.2
*/
String SPLIT_PANE_EXPANDABLE_SIDE_RIGHT = "right";
//---- JTabbedPane -------------------------------------------------------- //---- JTabbedPane --------------------------------------------------------
/** /**
@@ -935,9 +763,9 @@ public interface FlatClientProperties
/** /**
* Specifies a component that will be placed at the leading edge of the tabs area. * Specifies a component that will be placed at the leading edge of the tabs area.
* <p> * <p>
* For top and bottom tab placement, the laid out component size will be * For top and bottom tab placement, the layed out component size will be
* the preferred component width and the tab area height.<br> * the preferred component width and the tab area height.<br>
* For left and right tab placement, the laid out component size will be * For left and right tab placement, the layed out component size will be
* the tab area width and the preferred component height. * the tab area width and the preferred component height.
* <p> * <p>
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br> * <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
@@ -948,9 +776,9 @@ public interface FlatClientProperties
/** /**
* Specifies a component that will be placed at the trailing edge of the tabs area. * Specifies a component that will be placed at the trailing edge of the tabs area.
* <p> * <p>
* For top and bottom tab placement, the laid out component size will be * For top and bottom tab placement, the layed out component size will be
* the available horizontal space (minimum is preferred component width) and the tab area height.<br> * the available horizontal space (minimum is preferred component width) and the tab area height.<br>
* For left and right tab placement, the laid out component size will be * For left and right tab placement, the layed out component size will be
* the tab area width and the available vertical space (minimum is preferred component height). * the tab area width and the available vertical space (minimum is preferred component height).
* <p> * <p>
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br> * <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
@@ -958,7 +786,6 @@ public interface FlatClientProperties
*/ */
String TABBED_PANE_TRAILING_COMPONENT = "JTabbedPane.trailingComponent"; String TABBED_PANE_TRAILING_COMPONENT = "JTabbedPane.trailingComponent";
//---- JTextField --------------------------------------------------------- //---- JTextField ---------------------------------------------------------
/** /**
@@ -1036,118 +863,10 @@ public interface FlatClientProperties
*/ */
String TEXT_FIELD_TRAILING_ICON = "JTextField.trailingIcon"; String TEXT_FIELD_TRAILING_ICON = "JTextField.trailingIcon";
/**
* Specifies a component that will be placed at the leading edge of the text field.
* <p>
* The component will be positioned inside and aligned to the visible text field border.
* There is no gap between the visible border and the component.
* The laid out component size will be the preferred component width
* and the inner text field height.
* <p>
* The component should be not opaque because the text field border is painted
* slightly inside the usually visible border in some cases.
* E.g. when focused (in some themes) or when an outline color is specified
* (see {@link #OUTLINE}).
* <p>
* The component is prepared in the following way:
* <ul>
* <li>Component client property {@link #STYLE_CLASS} is set to {@code inTextField}.
* <li>If component is a button or toggle button, client property {@link #BUTTON_TYPE}
* is set to {@link #BUTTON_TYPE_TOOLBAR_BUTTON}
* and button cursor is set to default cursor (if not set).
* <li>If component is a toolbar, client property {@link #STYLE_CLASS}
* is set to {@code inTextField} on all toolbar children
* and toolbar cursor is set to default cursor (if not set).
* </ul>
* Because text fields use the text cursor by default and the cursor is inherited by child components,
* it may be necessary to explicitly set component cursor if you e.g. need the default arrow cursor.
* E.g. {@code comp.setCursor( Cursor.getDefaultCursor() )}.
* <p>
* Styling is used to modify insets/margins and appearance of buttons and toolbars
* so that they fit nicely into the text field and do not increase text field height.
* See styles {@code [style]Button.inTextField} and {@code [style]ToolBar.inTextField}
* in {@code Flat[Light|Dark]Laf.properties}.
* <p>
* <strong>Component</strong> {@link javax.swing.JTextField} (and subclasses)<br>
* <strong>Value type</strong> {@link javax.swing.JComponent}
*
* @since 2
*/
String TEXT_FIELD_LEADING_COMPONENT = "JTextField.leadingComponent";
/**
* Specifies a component that will be placed at the trailing edge of the text field.
* <p>
* See {@link #TEXT_FIELD_LEADING_COMPONENT} for details.
* <p>
* <strong>Component</strong> {@link javax.swing.JTextField} (and subclasses)<br>
* <strong>Value type</strong> {@link javax.swing.JComponent}
*
* @since 2
*/
String TEXT_FIELD_TRAILING_COMPONENT = "JTextField.trailingComponent";
/**
* Specifies whether a "clear" (or "cancel") button is shown on the trailing side
* if the text field is not empty, editable and enabled. Default is {@code false}.
* <p>
* <strong>Component</strong> {@link javax.swing.JTextField} (and subclasses)<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
*
* @since 2
*/
String TEXT_FIELD_SHOW_CLEAR_BUTTON = "JTextField.showClearButton";
/**
* Specifies the callback that is invoked when a "clear" (or "cancel") button is clicked.
* If a callback is specified than it is responsible for clearing the text field.
* Without callback, the text field clears itself.
* <p>
* Either use a {@link java.lang.Runnable}:
* <pre>{@code
* myTextField.putClientProperty( "JTextField.clearCallback",
* (Runnable) () -> {
* // clear field here or cancel search
* } );
* }</pre>
* Or use a {@link java.util.function.Consumer}&lt;javax.swing.text.JTextComponent&gt;
* that receives the text field as parameter:
* <pre>{@code
* myTextField.putClientProperty( "JTextField.clearCallback",
* (Consumer<JTextComponent>) textField -> {
* // clear field here or cancel search
* } );
* }</pre>
* <p>
* <strong>Component</strong> {@link javax.swing.JTextField} (and subclasses)<br>
* <strong>Value type</strong> {@link java.lang.Runnable}
* or {@link java.util.function.Consumer}&lt;javax.swing.text.JTextComponent&gt;
*
* @see #TEXT_FIELD_SHOW_CLEAR_BUTTON
* @since 2
*/
String TEXT_FIELD_CLEAR_CALLBACK = "JTextField.clearCallback";
//---- JToggleButton ------------------------------------------------------ //---- JToggleButton ------------------------------------------------------
/** /**
* Placement of underline if toggle button type is {@link #BUTTON_TYPE_TAB} * Height of underline if toggle button type is {@link #BUTTON_TYPE_TAB}.
* <p>
* <strong>Component</strong> {@link javax.swing.JToggleButton}<br>
* <strong>Value type</strong> {@link java.lang.Integer}<br>
* <strong>SupportedValues:</strong>
* {@link SwingConstants#BOTTOM} (default)
* {@link SwingConstants#TOP},
* {@link SwingConstants#LEFT} or
* {@link SwingConstants#RIGHT}
*
* @since 2.3
*/
String TAB_BUTTON_UNDERLINE_PLACEMENT = "JToggleButton.tab.underlinePlacement";
/**
* Thickness of underline if toggle button type is {@link #BUTTON_TYPE_TAB}.
* <p> * <p>
* <strong>Component</strong> {@link javax.swing.JToggleButton}<br> * <strong>Component</strong> {@link javax.swing.JToggleButton}<br>
* <strong>Value type</strong> {@link java.lang.Integer} * <strong>Value type</strong> {@link java.lang.Integer}
@@ -1170,7 +889,6 @@ public interface FlatClientProperties
*/ */
String TAB_BUTTON_SELECTED_BACKGROUND = "JToggleButton.tab.selectedBackground"; String TAB_BUTTON_SELECTED_BACKGROUND = "JToggleButton.tab.selectedBackground";
//---- JTree -------------------------------------------------------------- //---- JTree --------------------------------------------------------------
/** /**
@@ -1190,7 +908,6 @@ public interface FlatClientProperties
*/ */
String TREE_PAINT_SELECTION = "JTree.paintSelection"; String TREE_PAINT_SELECTION = "JTree.paintSelection";
//---- helper methods ----------------------------------------------------- //---- helper methods -----------------------------------------------------
/** /**

View File

@@ -34,8 +34,6 @@ public class FlatDarculaLaf
/** /**
* Sets the application look and feel to this LaF * Sets the application look and feel to this LaF
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}. * using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
*
* @since 1.2
*/ */
public static boolean setup() { public static boolean setup() {
return setup( new FlatDarculaLaf() ); return setup( new FlatDarculaLaf() );

View File

@@ -33,8 +33,6 @@ public class FlatDarkLaf
/** /**
* Sets the application look and feel to this LaF * Sets the application look and feel to this LaF
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}. * using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
*
* @since 1.2
*/ */
public static boolean setup() { public static boolean setup() {
return setup( new FlatDarkLaf() ); return setup( new FlatDarkLaf() );

View File

@@ -26,7 +26,7 @@ import javax.swing.UIDefaults;
* Allows loading of additional .properties files from addon JARs. * Allows loading of additional .properties files from addon JARs.
* {@link java.util.ServiceLoader} is used to load extensions of this class from addon JARs. * {@link java.util.ServiceLoader} is used to load extensions of this class from addon JARs.
* <p> * <p>
* If you extend this class in an addon JAR, you also have to add a text file named * If you extend this class in a addon JAR, you also have to add a text file named
* {@code META-INF/services/com.formdev.flatlaf.FlatDefaultsAddon} * {@code META-INF/services/com.formdev.flatlaf.FlatDefaultsAddon}
* to the addon JAR. The file must contain a single line with the class name. * to the addon JAR. The file must contain a single line with the class name.
* <p> * <p>
@@ -61,7 +61,7 @@ public abstract class FlatDefaultsAddon
/** /**
* Returns the priority used to sort addon loading. * Returns the priority used to sort addon loading.
* The order is only important if you want to overwrite UI defaults of other addons. * The order is only important if you want overwrite UI defaults of other addons.
* Lower numbers mean higher priority. * Lower numbers mean higher priority.
* Returns 10000 by default. * Returns 10000 by default.
*/ */

View File

@@ -19,7 +19,7 @@ package com.formdev.flatlaf;
/** /**
* Default color palette for action icons and object icons. * Default color palette for action icons and object icons.
* <p> * <p>
* The idea is to use only this well-defined set of colors in SVG icons, and * The idea is to use only this well defined set of colors in SVG icons and
* then they are replaced at runtime to dark variants or to other theme colors. * then they are replaced at runtime to dark variants or to other theme colors.
* Then a single SVG icon (light variant) can be used for dark themes too. * Then a single SVG icon (light variant) can be used for dark themes too.
* IntelliJ Platform uses this mechanism to allow themes to change IntelliJ Platform icons. * IntelliJ Platform uses this mechanism to allow themes to change IntelliJ Platform icons.
@@ -35,7 +35,7 @@ package com.formdev.flatlaf;
* <p> * <p>
* You may use these colors also in your application (outside of SVG icons), but do * You may use these colors also in your application (outside of SVG icons), but do
* not use the RGB values defined in this enum.<br> * not use the RGB values defined in this enum.<br>
* Instead, use {@code UIManager.getColor( FlatIconColors.ACTIONS_GREY.key )}. * Instead use {@code UIManager.getColor( FlatIconColors.ACTIONS_GREY.key )}.
* *
* @author Karl Tauber * @author Karl Tauber
*/ */

View File

@@ -50,8 +50,7 @@ class FlatInputMaps
} }
modifyInputMap( defaults, "ComboBox.ancestorInputMap", modifyInputMap( defaults, "ComboBox.ancestorInputMap",
// Space key still shows popup, but from FlatComboBoxUI.FlatKeySelectionManager "SPACE", "spacePopup",
// "SPACE", "spacePopup",
"UP", mac( "selectPrevious2", "selectPrevious" ), "UP", mac( "selectPrevious2", "selectPrevious" ),
"DOWN", mac( "selectNext2", "selectNext" ), "DOWN", mac( "selectNext2", "selectNext" ),
@@ -597,7 +596,7 @@ class FlatInputMaps
//---- class LazyInputMapEx ----------------------------------------------- //---- class LazyInputMapEx -----------------------------------------------
/** /**
* Lazily creates an input map. * Lazily creates a input map.
* Similar to {@link UIDefaults.LazyInputMap}, but can use multiple bindings arrays. * Similar to {@link UIDefaults.LazyInputMap}, but can use multiple bindings arrays.
*/ */
private static class LazyInputMapEx private static class LazyInputMapEx

View File

@@ -34,8 +34,6 @@ public class FlatIntelliJLaf
/** /**
* Sets the application look and feel to this LaF * Sets the application look and feel to this LaF
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}. * using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
*
* @since 1.2
*/ */
public static boolean setup() { public static boolean setup() {
return setup( new FlatIntelliJLaf() ); return setup( new FlatIntelliJLaf() );

View File

@@ -30,9 +30,6 @@ import java.awt.image.ImageProducer;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.io.File; import java.io.File;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.URL; import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
@@ -55,7 +52,6 @@ import javax.swing.ImageIcon;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JDialog; import javax.swing.JDialog;
import javax.swing.JFrame; import javax.swing.JFrame;
import javax.swing.JMenuBar;
import javax.swing.LookAndFeel; import javax.swing.LookAndFeel;
import javax.swing.PopupFactory; import javax.swing.PopupFactory;
import javax.swing.RootPaneContainer; import javax.swing.RootPaneContainer;
@@ -66,20 +62,16 @@ import javax.swing.UIDefaults.LazyValue;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException; import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.plaf.ColorUIResource; import javax.swing.plaf.ColorUIResource;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.FontUIResource; import javax.swing.plaf.FontUIResource;
import javax.swing.plaf.IconUIResource; import javax.swing.plaf.IconUIResource;
import javax.swing.plaf.UIResource; import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicLookAndFeel; import javax.swing.plaf.basic.BasicLookAndFeel;
import javax.swing.plaf.metal.MetalLookAndFeel;
import javax.swing.text.StyleContext; import javax.swing.text.StyleContext;
import javax.swing.text.html.HTMLEditorKit; import javax.swing.text.html.HTMLEditorKit;
import com.formdev.flatlaf.ui.FlatNativeWindowBorder; import com.formdev.flatlaf.ui.FlatNativeWindowBorder;
import com.formdev.flatlaf.ui.FlatPopupFactory; import com.formdev.flatlaf.ui.FlatPopupFactory;
import com.formdev.flatlaf.ui.FlatRootPaneUI; import com.formdev.flatlaf.ui.FlatRootPaneUI;
import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.util.FontUtils;
import com.formdev.flatlaf.util.GrayFilter; import com.formdev.flatlaf.util.GrayFilter;
import com.formdev.flatlaf.util.LoggingFacade; import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.MultiResolutionImageSupport; import com.formdev.flatlaf.util.MultiResolutionImageSupport;
@@ -100,7 +92,6 @@ public abstract class FlatLaf
private static List<Object> customDefaultsSources; private static List<Object> customDefaultsSources;
private static Map<String, String> globalExtraDefaults; private static Map<String, String> globalExtraDefaults;
private Map<String, String> extraDefaults; private Map<String, String> extraDefaults;
private static Function<String, Color> systemColorGetter;
private String desktopPropertyName; private String desktopPropertyName;
private String desktopPropertyName2; private String desktopPropertyName2;
@@ -111,21 +102,13 @@ public abstract class FlatLaf
private PopupFactory oldPopupFactory; private PopupFactory oldPopupFactory;
private MnemonicHandler mnemonicHandler; private MnemonicHandler mnemonicHandler;
private boolean subMenuUsabilityHelperInstalled;
private Consumer<UIDefaults> postInitialization; private Consumer<UIDefaults> postInitialization;
private List<Function<Object, Object>> uiDefaultsGetters; 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 * Sets the application look and feel to the given LaF
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}. * using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
*
* @since 1.2
*/ */
public static boolean setup( LookAndFeel newLookAndFeel ) { public static boolean setup( LookAndFeel newLookAndFeel ) {
try { try {
@@ -182,19 +165,18 @@ public abstract class FlatLaf
* Returns whether FlatLaf supports custom window decorations. * Returns whether FlatLaf supports custom window decorations.
* This depends on the operating system and on the used Java runtime. * This depends on the operating system and on the used Java runtime.
* <p> * <p>
* This method returns {@code true} on Windows 10/11 (see exception below) * This method returns {@code true} on Windows 10 (see exception below), {@code false} otherwise.
* and on Linux, {@code false} otherwise.
* <p> * <p>
* Returns also {@code false} on Windows 10/11 if: * Returns also {@code false} on Windows 10 if:
* <ul> * <ul>
* <li>FlatLaf native window border support is available (requires Windows 10/11)</li> * <li>FlatLaf native window border support is available (requires Windows 10)</li>
* <li>running in * <li>running in
* <a href="https://confluence.jetbrains.com/display/JBR/JetBrains+Runtime">JetBrains Runtime 11 (or later)</a> * <a href="https://confluence.jetbrains.com/display/JBR/JetBrains+Runtime">JetBrains Runtime 11 (or later)</a>
* (<a href="https://github.com/JetBrains/JetBrainsRuntime">source code on github</a>) * (<a href="https://github.com/JetBrains/JetBrainsRuntime">source code on github</a>)
* and JBR supports custom window decorations * and JBR supports custom window decorations
* </li> * </li>
* </ul> * </ul>
* In these cases, custom decorations are enabled by the root pane. * In this cases, custom decorations are enabled by the root pane.
* Usage of {@link JFrame#setDefaultLookAndFeelDecorated(boolean)} or * Usage of {@link JFrame#setDefaultLookAndFeelDecorated(boolean)} or
* {@link JDialog#setDefaultLookAndFeelDecorated(boolean)} is not necessary. * {@link JDialog#setDefaultLookAndFeelDecorated(boolean)} is not necessary.
*/ */
@@ -207,7 +189,7 @@ public abstract class FlatLaf
FlatNativeWindowBorder.isSupported() ) FlatNativeWindowBorder.isSupported() )
return false; return false;
return SystemInfo.isWindows_10_orLater || SystemInfo.isLinux; return SystemInfo.isWindows_10_orLater;
} }
@Override @Override
@@ -247,15 +229,6 @@ public abstract class FlatLaf
@Override @Override
public void initialize() { public void initialize() {
// do not initialize if this is not the current look and feel
// This is only necessary for special Laf usage. E.g. in GUI builders,
// which may use multiple Lafs and may invoke this method directly.
// This avoids that listeners and factories are installed multiple times.
// In case of the NetBeans GUI builder, which does not invoke uninitialize(),
// this also avoids that listeners stay registered in the system.
if( UIManager.getLookAndFeel() != this )
return;
if( SystemInfo.isMacOS ) if( SystemInfo.isMacOS )
initializeAqua(); initializeAqua();
@@ -269,9 +242,6 @@ public abstract class FlatLaf
mnemonicHandler = new MnemonicHandler(); mnemonicHandler = new MnemonicHandler();
mnemonicHandler.install(); mnemonicHandler.install();
// install submenu usability helper
subMenuUsabilityHelperInstalled = SubMenuUsabilityHelper.install();
// listen to desktop property changes to update UI if system font or scaling changes // listen to desktop property changes to update UI if system font or scaling changes
if( SystemInfo.isWindows ) { if( SystemInfo.isWindows ) {
// Windows 10 allows increasing font size independent of scaling: // Windows 10 allows increasing font size independent of scaling:
@@ -289,9 +259,6 @@ public abstract class FlatLaf
} }
if( desktopPropertyName != null ) { if( desktopPropertyName != null ) {
desktopPropertyListener = e -> { desktopPropertyListener = e -> {
if( !FlatSystemProperties.getBoolean( FlatSystemProperties.UPDATE_UI_ON_SYSTEM_FONT_CHANGE, true ) )
return;
String propertyName = e.getPropertyName(); String propertyName = e.getPropertyName();
if( desktopPropertyName.equals( propertyName ) || propertyName.equals( desktopPropertyName2 ) ) if( desktopPropertyName.equals( propertyName ) || propertyName.equals( desktopPropertyName2 ) )
reSetLookAndFeel(); reSetLookAndFeel();
@@ -330,10 +297,6 @@ public abstract class FlatLaf
@Override @Override
public void uninitialize() { public void uninitialize() {
// do not uninitialize if this is not the current look and feel
if( UIManager.getLookAndFeel() != this )
return;
// remove desktop property listener // remove desktop property listener
if( desktopPropertyListener != null ) { if( desktopPropertyListener != null ) {
Toolkit toolkit = Toolkit.getDefaultToolkit(); Toolkit toolkit = Toolkit.getDefaultToolkit();
@@ -358,12 +321,6 @@ public abstract class FlatLaf
mnemonicHandler = null; mnemonicHandler = null;
} }
// uninstall submenu usability helper
if( subMenuUsabilityHelperInstalled ) {
SubMenuUsabilityHelper.uninstall();
subMenuUsabilityHelperInstalled = false;
}
// restore default link color // restore default link color
new HTMLEditorKit().getStyleSheet().addRule( "a, address { color: blue; }" ); new HTMLEditorKit().getStyleSheet().addRule( "a, address { color: blue; }" );
postInitialization = null; postInitialization = null;
@@ -392,7 +349,7 @@ public abstract class FlatLaf
Method m = UIManager.class.getMethod( "createLookAndFeel", String.class ); Method m = UIManager.class.getMethod( "createLookAndFeel", String.class );
aquaLaf = (BasicLookAndFeel) m.invoke( null, "Mac OS X" ); aquaLaf = (BasicLookAndFeel) m.invoke( null, "Mac OS X" );
} else } else
aquaLaf = Class.forName( aquaLafClassName ).asSubclass( BasicLookAndFeel.class ).getDeclaredConstructor().newInstance(); aquaLaf = (BasicLookAndFeel) Class.forName( aquaLafClassName ).getDeclaredConstructor().newInstance();
} catch( Exception ex ) { } catch( Exception ex ) {
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to initialize Aqua look and feel '" + aquaLafClassName + "'.", ex ); LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to initialize Aqua look and feel '" + aquaLafClassName + "'.", ex );
throw new IllegalStateException(); throw new IllegalStateException();
@@ -544,7 +501,7 @@ public abstract class FlatLaf
// which can happen in applications that use some plugin system // which can happen in applications that use some plugin system
// and load FlatLaf in a plugin that uses its own classloader. // and load FlatLaf in a plugin that uses its own classloader.
// (e.g. Apache NetBeans) // (e.g. Apache NetBeans)
if( defaults.get( "TabbedPane.moreTabsButtonToolTipText" ) != null ) if( defaults.get( "FileChooser.fileNameHeaderText" ) != null )
return; return;
// load FlatLaf resource bundle and add content to defaults // load FlatLaf resource bundle and add content to defaults
@@ -582,17 +539,13 @@ public abstract class FlatLaf
Object activeFont = new ActiveFont( null, null, -1, 0, 0, 0, 0 ); Object activeFont = new ActiveFont( null, null, -1, 0, 0, 0, 0 );
// override fonts // override fonts
List<String> fontKeys = new ArrayList<>( 50 );
for( Object key : defaults.keySet() ) { for( Object key : defaults.keySet() ) {
if( key instanceof String && (((String)key).endsWith( ".font" ) || ((String)key).endsWith( "Font" )) ) if( key instanceof String && (((String)key).endsWith( ".font" ) || ((String)key).endsWith( "Font" )) )
fontKeys.add( (String) key );
}
for( String key : fontKeys )
defaults.put( key, activeFont ); defaults.put( key, activeFont );
}
// add fonts that are not set in BasicLookAndFeel // add fonts that are not set in BasicLookAndFeel
defaults.put( "RootPane.font", activeFont ); defaults.put( "RootPane.font", activeFont );
defaults.put( "TitlePane.font", activeFont );
} }
private void initDefaultFont( UIDefaults defaults ) { private void initDefaultFont( UIDefaults defaults ) {
@@ -641,13 +594,6 @@ public abstract class FlatLaf
if( uiFont == null ) if( uiFont == null )
uiFont = createCompositeFont( Font.SANS_SERIF, Font.PLAIN, 12 ); 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 // get/remove "defaultFont" from defaults if set in properties files
// (use remove() to avoid that ActiveFont.createValue() gets invoked) // (use remove() to avoid that ActiveFont.createValue() gets invoked)
Object defaultFont = defaults.remove( "defaultFont" ); Object defaultFont = defaults.remove( "defaultFont" );
@@ -658,7 +604,7 @@ public abstract class FlatLaf
uiFont = ((ActiveFont)defaultFont).derive( baseFont, fontSize -> { uiFont = ((ActiveFont)defaultFont).derive( baseFont, fontSize -> {
return Math.round( fontSize * UIScale.computeFontScaleFactor( baseFont ) ); return Math.round( fontSize * UIScale.computeFontScaleFactor( baseFont ) );
} ); } );
} };
// increase font size if system property "flatlaf.uiScale" is set // increase font size if system property "flatlaf.uiScale" is set
uiFont = UIScale.applyCustomScaleFactor( uiFont ); uiFont = UIScale.applyCustomScaleFactor( uiFont );
@@ -668,9 +614,6 @@ public abstract class FlatLaf
} }
static FontUIResource createCompositeFont( String family, int style, int size ) { static FontUIResource createCompositeFont( String family, int style, int size ) {
// load lazy font family
FontUtils.loadFontFamily( family );
// using StyleContext.getFont() here because it uses // using StyleContext.getFont() here because it uses
// sun.font.FontUtilities.getCompositeFontUIResource() // sun.font.FontUtilities.getCompositeFontUIResource()
// and creates a composite font that is able to display all Unicode characters // and creates a composite font that is able to display all Unicode characters
@@ -816,7 +759,7 @@ public abstract class FlatLaf
* Invoke this method before setting the look and feel. * Invoke this method before setting the look and feel.
* <p> * <p>
* If using Java modules, the package must be opened in {@code module-info.java}. * If using Java modules, the package must be opened in {@code module-info.java}.
* Otherwise, use {@link #registerCustomDefaultsSource(URL)}. * Otherwise use {@link #registerCustomDefaultsSource(URL)}.
* *
* @param packageName a package name (e.g. "com.myapp.resources") * @param packageName a package name (e.g. "com.myapp.resources")
*/ */
@@ -918,14 +861,14 @@ public abstract class FlatLaf
* E.g. using {@link UIManager#setLookAndFeel(LookAndFeel)} or {@link #setup(LookAndFeel)}. * E.g. using {@link UIManager#setLookAndFeel(LookAndFeel)} or {@link #setup(LookAndFeel)}.
* <p> * <p>
* The global extra defaults are useful for smaller additional defaults that may change. * The global extra defaults are useful for smaller additional defaults that may change.
* Otherwise, FlatLaf properties files should be used. * E.g. accent color. Otherwise FlatLaf properties files should be used.
* See {@link #registerCustomDefaultsSource(String)}. * See {@link #registerCustomDefaultsSource(String)}.
* <p> * <p>
* The keys and values are strings in same format as in FlatLaf properties files. * The keys and values are strings in same format as in FlatLaf properties files.
* <p> * <p>
* Sample that setups "FlatLaf Light" theme with white background color: * Sample that setups "FlatLaf Light" theme with red accent color:
* <pre>{@code * <pre>{@code
* FlatLaf.setGlobalExtraDefaults( Collections.singletonMap( "@background", "#fff" ) ); * FlatLaf.setGlobalExtraDefaults( Collections.singletonMap( "@accentColor", "#f00" ) );
* FlatLightLaf.setup(); * FlatLightLaf.setup();
* }</pre> * }</pre>
* *
@@ -950,15 +893,15 @@ public abstract class FlatLaf
* E.g. using {@link UIManager#setLookAndFeel(LookAndFeel)} or {@link #setup(LookAndFeel)}. * E.g. using {@link UIManager#setLookAndFeel(LookAndFeel)} or {@link #setup(LookAndFeel)}.
* <p> * <p>
* The extra defaults are useful for smaller additional defaults that may change. * The extra defaults are useful for smaller additional defaults that may change.
* Otherwise, FlatLaf properties files should be used. * E.g. accent color. Otherwise FlatLaf properties files should be used.
* See {@link #registerCustomDefaultsSource(String)}. * See {@link #registerCustomDefaultsSource(String)}.
* <p> * <p>
* The keys and values are strings in same format as in FlatLaf properties files. * The keys and values are strings in same format as in FlatLaf properties files.
* <p> * <p>
* Sample that setups "FlatLaf Light" theme with white background color: * Sample that setups "FlatLaf Light" theme with red accent color:
* <pre>{@code * <pre>{@code
* FlatLaf laf = new FlatLightLaf(); * FlatLaf laf = new FlatLightLaf();
* laf.setExtraDefaults( Collections.singletonMap( "@background", "#fff" ) ); * laf.setExtraDefaults( Collections.singletonMap( "@accentColor", "#f00" ) );
* FlatLaf.setup( laf ); * FlatLaf.setup( laf );
* }</pre> * }</pre>
* *
@@ -1000,36 +943,6 @@ public abstract class FlatLaf
return val; 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() { private static void reSetLookAndFeel() {
EventQueue.invokeLater( () -> { EventQueue.invokeLater( () -> {
LookAndFeel lookAndFeel = UIManager.getLookAndFeel(); LookAndFeel lookAndFeel = UIManager.getLookAndFeel();
@@ -1037,7 +950,7 @@ public abstract class FlatLaf
// re-set current LaF // re-set current LaF
UIManager.setLookAndFeel( lookAndFeel ); UIManager.setLookAndFeel( lookAndFeel );
// must fire property change events ourselves because old and new LaF are the same // must fire property change events ourself because old and new LaF are the same
PropertyChangeEvent e = new PropertyChangeEvent( UIManager.class, "lookAndFeel", lookAndFeel, lookAndFeel ); PropertyChangeEvent e = new PropertyChangeEvent( UIManager.class, "lookAndFeel", lookAndFeel, lookAndFeel );
for( PropertyChangeListener l : UIManager.getPropertyChangeListeners() ) for( PropertyChangeListener l : UIManager.getPropertyChangeListeners() )
l.propertyChange( e ); l.propertyChange( e );
@@ -1081,7 +994,7 @@ public abstract class FlatLaf
/** /**
* Returns whether native window decorations are supported on current platform. * Returns whether native window decorations are supported on current platform.
* <p> * <p>
* This requires Windows 10/11, but may be disabled if running in special environments * This requires Windows 10, but may be disabled if running in special environments
* (JetBrains Projector, Webswing or WinPE) or if loading native library fails. * (JetBrains Projector, Webswing or WinPE) or if loading native library fails.
* If system property {@link FlatSystemProperties#USE_WINDOW_DECORATIONS} is set to * If system property {@link FlatSystemProperties#USE_WINDOW_DECORATIONS} is set to
* {@code false}, then this method also returns {@code false}. * {@code false}, then this method also returns {@code false}.
@@ -1123,23 +1036,12 @@ public abstract class FlatLaf
/** /**
* Revalidate and repaint all displayable frames and dialogs. * Revalidate and repaint all displayable frames and dialogs.
* <p>
* Useful to update UI after changing {@code TitlePane.menuBarEmbedded}.
* *
* @since 1.1.2 * @since 1.1.2
*/ */
public static void revalidateAndRepaintAllFramesAndDialogs() { public static void revalidateAndRepaintAllFramesAndDialogs() {
for( Window w : Window.getWindows() ) { for( Window w : Window.getWindows() ) {
if( isDisplayableFrameOrDialog( w ) ) { if( isDisplayableFrameOrDialog( w ) ) {
// revalidate menu bar
JMenuBar menuBar = (w instanceof JFrame)
? ((JFrame)w).getJMenuBar()
: (w instanceof JDialog
? ((JDialog)w).getJMenuBar()
: null);
if( menuBar != null )
menuBar.revalidate();
w.revalidate(); w.revalidate();
w.repaint(); w.repaint();
} }
@@ -1148,9 +1050,6 @@ public abstract class FlatLaf
/** /**
* Repaint all displayable frames and dialogs. * Repaint all displayable frames and dialogs.
* <p>
* Useful to update UI after changing {@code TitlePane.unifiedBackground},
* {@code MenuItem.selectionType} or {@code Component.hideMnemonics}.
* *
* @since 1.1.2 * @since 1.1.2
*/ */
@@ -1287,181 +1186,28 @@ public abstract class FlatLaf
*/ */
public static final Object NULL_VALUE = new Object(); public static final Object NULL_VALUE = new Object();
/**
* Returns information about styleable values of a component.
* <p>
* This is equivalent to: {@code ((StyleableUI)c.getUI()).getStyleableInfos(c)}
*
* @since 2.5
*/
public static Map<String, Class<?>> getStyleableInfos( JComponent c ) {
StyleableUI ui = getStyleableUI( c );
return (ui != null) ? ui.getStyleableInfos( c ) : null;
}
/**
* Returns the (styled) value for the given key from the given component.
* <p>
* This is equivalent to: {@code ((StyleableUI)c.getUI()).getStyleableValue(c, key)}
*
* @since 2.5
*/
@SuppressWarnings( "unchecked" )
public static <T> T getStyleableValue( JComponent c, String key ) {
StyleableUI ui = getStyleableUI( c );
return (ui != null) ? (T) ui.getStyleableValue( c, key ) : null;
}
private static StyleableUI getStyleableUI( JComponent c ) {
if( !getUIMethodInitialized ) {
getUIMethodInitialized = true;
if( SystemInfo.isJava_9_orLater ) {
try {
// JComponent.getUI() is available since Java 9
getUIMethod = MethodHandles.lookup().findVirtual( JComponent.class, "getUI",
MethodType.methodType( ComponentUI.class ) );
} catch( Exception ex ) {
// ignore
}
}
}
try {
Object ui;
if( getUIMethod != null )
ui = getUIMethod.invoke( c );
else
ui = c.getClass().getMethod( "getUI" ).invoke( c );
return (ui instanceof StyleableUI) ? (StyleableUI) ui : null;
} catch( Throwable ex ) {
// ignore
return null;
}
}
private static boolean getUIMethodInitialized;
private static MethodHandle getUIMethod;
/**
* Returns the preferred font family to be used for (nearly) all fonts; or {@code null}.
*
* @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 ----------------------------------------------- //---- class FlatUIDefaults -----------------------------------------------
private class FlatUIDefaults private class FlatUIDefaults
extends UIDefaults extends UIDefaults
{ {
private UIDefaults metalDefaults;
FlatUIDefaults( int initialCapacity, float loadFactor ) { FlatUIDefaults( int initialCapacity, float loadFactor ) {
super( initialCapacity, loadFactor ); super( initialCapacity, loadFactor );
} }
@Override @Override
public Object get( Object key ) { public Object get( Object key ) {
return get( key, null ); Object value = getValue( key );
return (value != null) ? (value != NULL_VALUE ? value : null) : super.get( key );
} }
@Override @Override
public Object get( Object key, Locale l ) { public Object get( Object key, Locale l ) {
Object value = getFromUIDefaultsGetters( key ); Object value = getValue( key );
if( value != null ) return (value != null) ? (value != NULL_VALUE ? value : null) : super.get( key, l );
return (value != NULL_VALUE) ? value : null;
value = super.get( key, l );
if( value != null )
return value;
// get file chooser texts from Metal
return (key instanceof String && ((String)key).startsWith( "FileChooser." ))
? getFromMetal( (String) key, l )
: null;
} }
private Object getFromUIDefaultsGetters( Object key ) { private Object getValue( Object key ) {
// use local variable for getters to avoid potential multi-threading issues
List<Function<Object, Object>> uiDefaultsGetters = FlatLaf.this.uiDefaultsGetters;
if( uiDefaultsGetters == null ) if( uiDefaultsGetters == null )
return null; return null;
@@ -1473,22 +1219,6 @@ public abstract class FlatLaf
return null; return null;
} }
private synchronized Object getFromMetal( String key, Locale l ) {
if( metalDefaults == null ) {
metalDefaults = new MetalLookAndFeel() {
// avoid unnecessary initialization
@Override protected void initClassDefaults( UIDefaults table ) {}
@Override protected void initSystemColorDefaults( UIDefaults table ) {}
}.getDefaults();
// empty not needed defaults (to save memory) because we're only interested
// in resource bundle strings, which are stored in another internal map
metalDefaults.clear();
}
return metalDefaults.get( key, l );
}
} }
//---- class ActiveFont --------------------------------------------------- //---- class ActiveFont ---------------------------------------------------
@@ -1531,9 +1261,8 @@ public abstract class FlatLaf
this.scaleSize = scaleSize; this.scaleSize = scaleSize;
} }
// using synchronized to avoid exception if invoked at the same time on multiple threads
@Override @Override
public synchronized Object createValue( UIDefaults table ) { public Object createValue( UIDefaults table ) {
if( inCreateValue ) if( inCreateValue )
throw new IllegalStateException( "FlatLaf: endless recursion in font" ); throw new IllegalStateException( "FlatLaf: endless recursion in font" );
@@ -1571,7 +1300,7 @@ public abstract class FlatLaf
int newStyle = (style != -1) int newStyle = (style != -1)
? style ? style
: (styleChange != 0) : (styleChange != 0)
? (baseStyle & ~((styleChange >> 16) & 0xffff)) | (styleChange & 0xffff) ? baseStyle & ~((styleChange >> 16) & 0xffff) | (styleChange & 0xffff)
: baseStyle; : baseStyle;
// new size // new size
@@ -1587,34 +1316,17 @@ public abstract class FlatLaf
// create font for family // create font for family
if( families != null && !families.isEmpty() ) { 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 ) { for( String family : families ) {
Font font = createCompositeFont( family, newStyle, newSize ); Font font = createCompositeFont( family, newStyle, newSize );
if( !isFallbackFont( font ) || isDialogFamily( family ) ) if( !isFallbackFont( font ) || family.equalsIgnoreCase( Font.DIALOG ) )
return toUIResource( font ); return toUIResource( font );
} }
} }
// derive font // derive font
if( newStyle != baseStyle || newSize != baseSize ) { if( newStyle != baseStyle || newSize != baseSize )
// hack for font "Ubuntu Medium" on Linux, which curiously belongs
// to family "Ubuntu Light" and using deriveFont() would create a light font
if( "Ubuntu Medium".equalsIgnoreCase( baseFont.getName() ) &&
"Ubuntu Light".equalsIgnoreCase( baseFont.getFamily() ) )
{
Font font = createCompositeFont( "Ubuntu Medium", newStyle, newSize );
if( !isFallbackFont( font ) )
return toUIResource( font );
}
return toUIResource( baseFont.deriveFont( newStyle, newSize ) ); return toUIResource( baseFont.deriveFont( newStyle, newSize ) );
} else else
return toUIResource( baseFont ); return toUIResource( baseFont );
} }
@@ -1625,26 +1337,9 @@ public abstract class FlatLaf
: new FontUIResource( font ); : new FontUIResource( font );
} }
private static boolean isFallbackFont( Font font ) { private boolean isFallbackFont( Font font ) {
return Font.DIALOG.equalsIgnoreCase( font.getFamily() ); 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 ------------------------------------------ //---- class ImageIconUIResource ------------------------------------------

View File

@@ -33,8 +33,6 @@ public class FlatLightLaf
/** /**
* Sets the application look and feel to this LaF * Sets the application look and feel to this LaF
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}. * using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
*
* @since 1.2
*/ */
public static boolean setup() { public static boolean setup() {
return setup( new FlatLightLaf() ); return setup( new FlatLightLaf() );

View File

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

View File

@@ -16,7 +16,6 @@
package com.formdev.flatlaf; package com.formdev.flatlaf;
import javax.swing.SwingUtilities;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
/** /**
@@ -35,7 +34,7 @@ public interface FlatSystemProperties
* To replace the Java 9+ system scale factor, use system property "sun.java2d.uiScale", * To replace the Java 9+ system scale factor, use system property "sun.java2d.uiScale",
* which has the same syntax as this one. * which has the same syntax as this one.
* <p> * <p>
* Since FlatLaf 1.1.2: Scale factors less than 100% are allowed. * Since FlatLaf 1.1.2: Scale factors less then 100% are allowed.
* <p> * <p>
* <strong>Allowed Values</strong> e.g. {@code 1.5}, {@code 1.5x}, {@code 150%} or {@code 144dpi} (96dpi is 100%)<br> * <strong>Allowed Values</strong> e.g. {@code 1.5}, {@code 1.5x}, {@code 150%} or {@code 144dpi} (96dpi is 100%)<br>
*/ */
@@ -82,7 +81,7 @@ public interface FlatSystemProperties
* {@link FlatClientProperties#USE_WINDOW_DECORATIONS} and * {@link FlatClientProperties#USE_WINDOW_DECORATIONS} and
* UI default {@code TitlePane.useWindowDecorations}. * UI default {@code TitlePane.useWindowDecorations}.
* <p> * <p>
* (requires Window 10/11) * (requires Window 10)
* <p> * <p>
* <strong>Allowed Values</strong> {@code false} and {@code true}<br> * <strong>Allowed Values</strong> {@code false} and {@code true}<br>
* <strong>Default</strong> none * <strong>Default</strong> none
@@ -93,16 +92,16 @@ public interface FlatSystemProperties
* Specifies whether JetBrains Runtime custom window decorations should be used * Specifies whether JetBrains Runtime custom window decorations should be used
* when creating {@code JFrame} or {@code JDialog}. * when creating {@code JFrame} or {@code JDialog}.
* Requires that the application runs in a * Requires that the application runs in a
* <a href="https://github.com/JetBrains/JetBrainsRuntime/wiki">JetBrains Runtime</a> * <a href="https://confluence.jetbrains.com/display/JBR/JetBrains+Runtime">JetBrains Runtime</a>
* (based on OpenJDK). * (based on OpenJDK).
* <p> * <p>
* Setting this to {@code false} disables using JetBrains Runtime custom window decorations. * Setting this to {@code false} disables using JetBrains Runtime custom window decorations.
* Then FlatLaf native window decorations are used. * Then FlatLaf native window decorations are used.
* <p> * <p>
* (requires Window 10/11) * (requires Window 10)
* <p> * <p>
* <strong>Allowed Values</strong> {@code false} and {@code true}<br> * <strong>Allowed Values</strong> {@code false} and {@code true}<br>
* <strong>Default</strong> {@code false} (since v2; was {@code true} in v1) * <strong>Default</strong> {@code true}
*/ */
String USE_JETBRAINS_CUSTOM_DECORATIONS = "flatlaf.useJetBrainsCustomDecorations"; String USE_JETBRAINS_CUSTOM_DECORATIONS = "flatlaf.useJetBrainsCustomDecorations";
@@ -117,7 +116,7 @@ public interface FlatSystemProperties
* {@link FlatClientProperties#MENU_BAR_EMBEDDED} and * {@link FlatClientProperties#MENU_BAR_EMBEDDED} and
* UI default {@code TitlePane.menuBarEmbedded}. * UI default {@code TitlePane.menuBarEmbedded}.
* <p> * <p>
* (requires Window 10/11) * (requires Window 10)
* <p> * <p>
* <strong>Allowed Values</strong> {@code false} and {@code true}<br> * <strong>Allowed Values</strong> {@code false} and {@code true}<br>
* <strong>Default</strong> none * <strong>Default</strong> none
@@ -140,53 +139,6 @@ public interface FlatSystemProperties
*/ */
String USE_TEXT_Y_CORRECTION = "flatlaf.useTextYCorrection"; String USE_TEXT_Y_CORRECTION = "flatlaf.useTextYCorrection";
/**
* Specifies whether FlatLaf updates the UI when the system font changes.
* If {@code true}, {@link SwingUtilities#updateComponentTreeUI(java.awt.Component)}
* gets invoked for all windows if the system font has changed.
* This is the similar to when switching to another look and feel (theme).
* Applications that do not work correctly when switching look and feel,
* should disable this option to avoid corrupted UI.
* <p>
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
* <strong>Default</strong> {@code true}
*
* @since 2.5
*/
String UPDATE_UI_ON_SYSTEM_FONT_CHANGE = "flatlaf.updateUIOnSystemFontChange";
/**
* Specifies whether FlatLaf native library should be used.
* <p>
* Setting this to {@code false} disables loading native library,
* which also disables some features that depend on the native library.
* <p>
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
* <strong>Default</strong> {@code true}
*
* @since 3.2
*/
String USE_NATIVE_LIBRARY = "flatlaf.useNativeLibrary";
/**
* Specifies a directory in which the native FlatLaf libraries have been extracted.
* The path can be absolute or relative to current application working directory.
* 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
*/
String NATIVE_LIBRARY_PATH = "flatlaf.nativeLibraryPath";
/** /**
* Checks whether a system property is set and returns {@code true} if its value * Checks whether a system property is set and returns {@code true} if its value
* is {@code "true"} (case-insensitive), otherwise it returns {@code false}. * is {@code "true"} (case-insensitive), otherwise it returns {@code false}.

View File

@@ -23,17 +23,13 @@ import java.io.InputStreamReader;
import java.io.Reader; import java.io.Reader;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.Map.Entry;
import javax.swing.UIDefaults; import javax.swing.UIDefaults;
import javax.swing.plaf.ColorUIResource; import javax.swing.plaf.ColorUIResource;
import com.formdev.flatlaf.json.Json; import com.formdev.flatlaf.json.Json;
@@ -41,7 +37,6 @@ import com.formdev.flatlaf.json.ParseException;
import com.formdev.flatlaf.util.ColorFunctions; import com.formdev.flatlaf.util.ColorFunctions;
import com.formdev.flatlaf.util.LoggingFacade; import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.StringUtils; import com.formdev.flatlaf.util.StringUtils;
import com.formdev.flatlaf.util.SystemInfo;
/** /**
* This class supports loading IntelliJ .theme.json files and using them as a Laf. * This class supports loading IntelliJ .theme.json files and using them as a Laf.
@@ -65,9 +60,9 @@ public class IntelliJTheme
private final boolean isMaterialUILite; private final boolean isMaterialUILite;
private Map<String, String> colors; private final Map<String, String> colors;
private Map<String, Object> ui; private final Map<String, Object> ui;
private Map<String, Object> icons; private final Map<String, Object> icons;
private Map<String, ColorUIResource> namedColors = Collections.emptyMap(); private Map<String, ColorUIResource> namedColors = Collections.emptyMap();
@@ -77,8 +72,6 @@ public class IntelliJTheme
* *
* The input stream is automatically closed. * The input stream is automatically closed.
* Using a buffered input stream is not necessary. * Using a buffered input stream is not necessary.
*
* @since 1.2
*/ */
public static boolean setup( InputStream in ) { public static boolean setup( InputStream in ) {
try { try {
@@ -169,11 +162,8 @@ public class IntelliJTheme
applyCheckBoxColors( defaults ); applyCheckBoxColors( defaults );
// copy values // copy values
for( Map.Entry<String, String> e : uiKeyCopying.entrySet() ) { for( Map.Entry<String, String> e : uiKeyCopying.entrySet() )
Object value = defaults.get( e.getValue() ); defaults.put( e.getKey(), defaults.get( e.getValue() ) );
if( value != null )
defaults.put( e.getKey(), value );
}
// IDEA does not paint button background if disabled, but FlatLaf does // IDEA does not paint button background if disabled, but FlatLaf does
Object panelBackground = defaults.get( "Panel.background" ); Object panelBackground = defaults.get( "Panel.background" );
@@ -185,7 +175,7 @@ public class IntelliJTheme
defaults.put( "Button.hoverBorderColor", defaults.get( "Button.focusedBorderColor" ) ); defaults.put( "Button.hoverBorderColor", defaults.get( "Button.focusedBorderColor" ) );
defaults.put( "HelpButton.hoverBorderColor", defaults.get( "Button.focusedBorderColor" ) ); defaults.put( "HelpButton.hoverBorderColor", defaults.get( "Button.focusedBorderColor" ) );
// IDEA uses an SVG icon for the help button, but paints the background with Button.startBackground and Button.endBackground // IDEA uses a SVG icon for the help button, but paints the background with Button.startBackground and Button.endBackground
Object helpButtonBackground = defaults.get( "Button.startBackground" ); Object helpButtonBackground = defaults.get( "Button.startBackground" );
Object helpButtonBorderColor = defaults.get( "Button.startBorderColor" ); Object helpButtonBorderColor = defaults.get( "Button.startBorderColor" );
if( helpButtonBackground == null ) if( helpButtonBackground == null )
@@ -200,9 +190,8 @@ public class IntelliJTheme
defaults.put( "HelpButton.focusedBackground", defaults.get( "Button.focusedBackground" ) ); defaults.put( "HelpButton.focusedBackground", defaults.get( "Button.focusedBackground" ) );
// IDEA uses TextField.background for editable ComboBox and Spinner // IDEA uses TextField.background for editable ComboBox and Spinner
Object textFieldBackground = get( defaults, themeSpecificDefaults, "TextField.background" ); defaults.put( "ComboBox.editableBackground", defaults.get( "TextField.background" ) );
defaults.put( "ComboBox.editableBackground", textFieldBackground ); defaults.put( "Spinner.background", defaults.get( "TextField.background" ) );
defaults.put( "Spinner.background", textFieldBackground );
// Spinner arrow button always has same colors as ComboBox arrow button // Spinner arrow button always has same colors as ComboBox arrow button
defaults.put( "Spinner.buttonBackground", defaults.get( "ComboBox.buttonEditableBackground" ) ); defaults.put( "Spinner.buttonBackground", defaults.get( "ComboBox.buttonEditableBackground" ) );
@@ -210,41 +199,22 @@ public class IntelliJTheme
defaults.put( "Spinner.buttonDisabledArrowColor", defaults.get( "ComboBox.buttonDisabledArrowColor" ) ); defaults.put( "Spinner.buttonDisabledArrowColor", defaults.get( "ComboBox.buttonDisabledArrowColor" ) );
// some themes specify colors for TextField.background, but forget to specify it for other components // some themes specify colors for TextField.background, but forget to specify it for other components
// (probably because those components are not used in IntelliJ IDEA) // (probably because those components are not used in IntelliJ)
putAll( defaults, textFieldBackground, if( uiKeys.contains( "TextField.background" ) ) {
"EditorPane.background", Object textFieldBackground = defaults.get( "TextField.background" );
"FormattedTextField.background", if( !uiKeys.contains( "FormattedTextField.background" ) )
"PasswordField.background", defaults.put( "FormattedTextField.background", textFieldBackground );
"TextArea.background", if( !uiKeys.contains( "PasswordField.background" ) )
"TextPane.background" defaults.put( "PasswordField.background", textFieldBackground );
); if( !uiKeys.contains( "EditorPane.background" ) )
putAll( defaults, get( defaults, themeSpecificDefaults, "TextField.selectionBackground" ), defaults.put( "EditorPane.background", textFieldBackground );
"EditorPane.selectionBackground", if( !uiKeys.contains( "TextArea.background" ) )
"FormattedTextField.selectionBackground", defaults.put( "TextArea.background", textFieldBackground );
"PasswordField.selectionBackground", if( !uiKeys.contains( "TextPane.background" ) )
"TextArea.selectionBackground", defaults.put( "TextPane.background", textFieldBackground );
"TextPane.selectionBackground" if( !uiKeys.contains( "Spinner.background" ) )
); defaults.put( "Spinner.background", textFieldBackground );
putAll( defaults, get( defaults, themeSpecificDefaults, "TextField.selectionForeground" ), }
"EditorPane.selectionForeground",
"FormattedTextField.selectionForeground",
"PasswordField.selectionForeground",
"TextArea.selectionForeground",
"TextPane.selectionForeground"
);
// fix disabled and not-editable backgrounds for text components, combobox and spinner
// (IntelliJ IDEA does not use those colors; instead it used background color of parent)
putAll( defaults, panelBackground,
"ComboBox.disabledBackground",
"EditorPane.disabledBackground", "EditorPane.inactiveBackground",
"FormattedTextField.disabledBackground", "FormattedTextField.inactiveBackground",
"PasswordField.disabledBackground", "PasswordField.inactiveBackground",
"Spinner.disabledBackground",
"TextArea.disabledBackground", "TextArea.inactiveBackground",
"TextField.disabledBackground", "TextField.inactiveBackground",
"TextPane.disabledBackground", "TextPane.inactiveBackground"
);
// fix ToggleButton // fix ToggleButton
if( !uiKeys.contains( "ToggleButton.startBackground" ) && !uiKeys.contains( "*.startBackground" ) ) if( !uiKeys.contains( "ToggleButton.startBackground" ) && !uiKeys.contains( "*.startBackground" ) )
@@ -271,61 +241,8 @@ public class IntelliJTheme
if( rowHeight > 22 ) if( rowHeight > 22 )
defaults.put( "Tree.rowHeight", 22 ); defaults.put( "Tree.rowHeight", 22 );
// get (and remove) theme specific wildcard replacements, which override all other defaults that end with same suffix
HashMap<String, Object> wildcards = new HashMap<>();
Iterator<Entry<Object, Object>> it = themeSpecificDefaults.entrySet().iterator();
while( it.hasNext() ) {
Entry<Object, Object> e = it.next();
String key = (String) e.getKey();
if( key.startsWith( "*." ) ) {
wildcards.put( key.substring( "*.".length() ), e.getValue() );
it.remove();
}
}
// override UI defaults with theme specific wildcard replacements
if( !wildcards.isEmpty() ) {
for( Object key : defaults.keySet().toArray() ) {
int dot;
if( !(key instanceof String) ||
(dot = ((String)key).lastIndexOf( '.' )) < 0 )
continue;
String wildcardKey = ((String)key).substring( dot + 1 );
Object wildcardValue = wildcards.get( wildcardKey );
if( wildcardValue != null )
defaults.put( key, wildcardValue );
}
}
// apply theme specific UI defaults at the end to allow overwriting // apply theme specific UI defaults at the end to allow overwriting
for( Map.Entry<Object, Object> e : themeSpecificDefaults.entrySet() ) { defaults.putAll( themeSpecificDefaults );
Object key = e.getKey();
Object value = e.getValue();
// append styles to existing styles
if( key instanceof String && ((String)key).startsWith( "[style]" ) ) {
Object oldValue = defaults.get( key );
if( oldValue != null )
value = oldValue + "; " + value;
}
defaults.put( key, value );
}
// let Java release memory
colors = null;
ui = null;
icons = null;
}
private Object get( UIDefaults defaults, Map<Object, Object> themeSpecificDefaults, String key ) {
return themeSpecificDefaults.getOrDefault( key, defaults.get( key ) );
}
private void putAll( UIDefaults defaults, Object value, String... keys ) {
for( String key : keys )
defaults.put( key, value );
} }
private Map<Object, Object> removeThemeSpecificDefaults( UIDefaults defaults ) { private Map<Object, Object> removeThemeSpecificDefaults( UIDefaults defaults ) {
@@ -367,7 +284,7 @@ public class IntelliJTheme
for( Map.Entry<String, String> e : colors.entrySet() ) { for( Map.Entry<String, String> e : colors.entrySet() ) {
String value = e.getValue(); String value = e.getValue();
ColorUIResource color = parseColor( value ); ColorUIResource color = UIDefaultsLoader.parseColor( value );
if( color != null ) { if( color != null ) {
String key = e.getKey(); String key = e.getKey();
namedColors.put( key, color ); namedColors.put( key, color );
@@ -382,30 +299,16 @@ public class IntelliJTheme
@SuppressWarnings( "unchecked" ) @SuppressWarnings( "unchecked" )
private void apply( String key, Object value, UIDefaults defaults, ArrayList<Object> defaultsKeysCache, Set<String> uiKeys ) { private void apply( String key, Object value, UIDefaults defaults, ArrayList<Object> defaultsKeysCache, Set<String> uiKeys ) {
if( value instanceof Map ) { if( value instanceof Map ) {
Map<String, Object> map = (Map<String, Object>)value; for( Map.Entry<String, Object> e : ((Map<String, Object>)value).entrySet() )
if( map.containsKey( "os.default" ) || map.containsKey( "os.windows" ) || map.containsKey( "os.mac" ) || map.containsKey( "os.linux" ) ) {
String osKey = SystemInfo.isWindows ? "os.windows"
: SystemInfo.isMacOS ? "os.mac"
: SystemInfo.isLinux ? "os.linux" : null;
if( osKey != null && map.containsKey( osKey ) )
apply( key, map.get( osKey ), defaults, defaultsKeysCache, uiKeys );
else if( map.containsKey( "os.default" ) )
apply( key, map.get( "os.default" ), defaults, defaultsKeysCache, uiKeys );
} else {
for( Map.Entry<String, Object> e : map.entrySet() )
apply( key + '.' + e.getKey(), e.getValue(), defaults, defaultsKeysCache, uiKeys ); apply( key + '.' + e.getKey(), e.getValue(), defaults, defaultsKeysCache, uiKeys );
}
} else { } else {
if( "".equals( value ) ) if( "".equals( value ) )
return; // ignore empty value return; // ignore empty value
// ignore some properties that affect sizes uiKeys.add( key );
if( key.endsWith( ".border" ) ||
key.endsWith( ".rowHeight" ) || // fix ComboBox size and Spinner border in all Material UI Lite themes
key.equals( "ComboBox.padding" ) || if( isMaterialUILite && (key.equals( "ComboBox.padding" ) || key.equals( "Spinner.border" )) )
key.equals( "Spinner.padding" ) ||
key.equals( "Tree.leftChildIndent" ) ||
key.equals( "Tree.rightChildIndent" ) )
return; // ignore return; // ignore
// map keys // map keys
@@ -413,16 +316,6 @@ public class IntelliJTheme
if( key.isEmpty() ) if( key.isEmpty() )
return; // ignore key return; // ignore key
// exclude properties
int dot = key.indexOf( '.' );
if( dot > 0 && uiKeyExcludes.contains( key.substring( 0, dot + 1 ) ) )
return;
if( uiKeyDoNotOverride.contains( key ) && uiKeys.contains( key ) )
return;
uiKeys.add( key );
String valueStr = value.toString(); String valueStr = value.toString();
// map named colors // map named colors
@@ -468,8 +361,7 @@ public class IntelliJTheme
// replace all values in UI defaults that match the wildcard key // replace all values in UI defaults that match the wildcard key
for( Object k : defaultsKeysCache ) { for( Object k : defaultsKeysCache ) {
if( k.equals( "Desktop.background" ) || if( k.equals( "Desktop.background" ) ||
k.equals( "DesktopIcon.background" ) || k.equals( "DesktopIcon.background" ) )
k.equals( "TabbedPane.focusColor" ) )
continue; continue;
if( k instanceof String ) { if( k instanceof String ) {
@@ -527,20 +419,12 @@ public class IntelliJTheme
ColorUIResource color = namedColors.get( value ); ColorUIResource color = namedColors.get( value );
// parse color // parse color
return (color != null) ? color : parseColor( value ); return (color != null) ? color : UIDefaultsLoader.parseColor( value );
}
private ColorUIResource parseColor( String value ) {
try {
return UIDefaultsLoader.parseColor( value );
} catch( IllegalArgumentException ex ) {
return null;
}
} }
/** /**
* Because IDEA uses SVGs for check boxes and radio buttons, the colors for * Because IDEA uses SVGs for check boxes and radio buttons, the colors for
* these two components are specified in "icons > ColorPalette". * this two components are specified in "icons > ColorPalette".
* FlatLaf uses vector icons and expects colors for the two components in UI defaults. * FlatLaf uses vector icons and expects colors for the two components in UI defaults.
*/ */
private void applyCheckBoxColors( UIDefaults defaults ) { private void applyCheckBoxColors( UIDefaults defaults ) {
@@ -560,6 +444,18 @@ public class IntelliJTheme
if( !key.startsWith( "Checkbox." ) || !(value instanceof String) ) if( !key.startsWith( "Checkbox." ) || !(value instanceof String) )
continue; continue;
if( key.equals( "Checkbox.Background.Default" ) ||
key.equals( "Checkbox.Foreground.Selected" ) )
{
// This two keys do not work correctly in IDEA because they
// map SVG color "#ffffff" to another color, but checkBox.svg and
// radio.svg (in package com.intellij.ide.ui.laf.icons.intellij)
// use "#fff". So use white to get same appearance as in IDEA.
value = "#ffffff";
}
String key2 = checkboxDuplicateColors.get( key );
if( dark ) if( dark )
key = StringUtils.removeTrailing( key, ".Dark" ); key = StringUtils.removeTrailing( key, ".Dark" );
@@ -573,7 +469,6 @@ public class IntelliJTheme
if( color != null ) { if( color != null ) {
defaults.put( newKey, color ); defaults.put( newKey, color );
String key2 = checkboxDuplicateColors.get( key + ".Dark");
if( key2 != null ) { if( key2 != null ) {
// When IDEA replaces colors in SVGs it uses color values and not the keys // When IDEA replaces colors in SVGs it uses color values and not the keys
// from com.intellij.ide.ui.UITheme.colorPalette, but there are some keys that // from com.intellij.ide.ui.UITheme.colorPalette, but there are some keys that
@@ -616,7 +511,7 @@ public class IntelliJTheme
// radioFocused.svg and radioSelectedFocused.svg // radioFocused.svg and radioSelectedFocused.svg
// use opacity=".65" for the border // use opacity=".65" for the border
// --> add alpha to focused border colors // --> add alpha to focused border colors
String[] focusedBorderColorKeys = { String[] focusedBorderColorKeys = new String[] {
"CheckBox.icon.focusedBorderColor", "CheckBox.icon.focusedBorderColor",
"CheckBox.icon.focusedSelectedBorderColor", "CheckBox.icon.focusedSelectedBorderColor",
"CheckBox.icon[filled].focusedBorderColor", "CheckBox.icon[filled].focusedBorderColor",
@@ -638,59 +533,17 @@ public class IntelliJTheme
defaults.put( destKey, defaults.get( srcKey ) ); defaults.put( destKey, defaults.get( srcKey ) );
} }
private static final Set<String> uiKeyExcludes;
private static final Set<String> uiKeyDoNotOverride;
/** Rename UI default keys (key --> value). */ /** Rename UI default keys (key --> value). */
private static final Map<String, String> uiKeyMapping = new HashMap<>(); private static Map<String, String> uiKeyMapping = new HashMap<>();
/** Copy UI default keys (value --> key). */ /** Copy UI default keys (value --> key). */
private static final Map<String, String> uiKeyCopying = new LinkedHashMap<>(); private static Map<String, String> uiKeyCopying = new HashMap<>();
private static final Map<String, String> uiKeyInverseMapping = new HashMap<>(); private static Map<String, String> uiKeyInverseMapping = new HashMap<>();
private static final Map<String, String> checkboxKeyMapping = new HashMap<>(); private static Map<String, String> checkboxKeyMapping = new HashMap<>();
private static final Map<String, String> checkboxDuplicateColors = new HashMap<>(); private static Map<String, String> checkboxDuplicateColors = new HashMap<>();
static { static {
// IntelliJ UI properties that are not used in FlatLaf
uiKeyExcludes = new HashSet<>( Arrays.asList(
"ActionButton.", "ActionToolbar.", "ActionsList.", "AppInspector.", "AssignedMnemonic.", "Autocomplete.",
"AvailableMnemonic.",
"BigSpinner.", "Bookmark.", "BookmarkIcon.", "BookmarkMnemonicAssigned.", "BookmarkMnemonicAvailable.",
"BookmarkMnemonicCurrent.", "BookmarkMnemonicIcon.", "Borders.", "Breakpoint.",
"Canvas.", "CodeWithMe.", "ComboBoxButton.", "CompletionPopup.", "ComplexPopup.", "Content.",
"CurrentMnemonic.", "Counter.",
"Debugger.", "DebuggerPopup.", "DebuggerTabs.", "DefaultTabs.", "Dialog.", "DialogWrapper.", "DragAndDrop.",
"Editor.", "EditorGroupsTabs.", "EditorTabs.",
"FileColor.", "FlameGraph.", "Focus.",
"Git.", "Github.", "GotItTooltip.", "Group.", "Gutter.", "GutterTooltip.",
"HeaderColor.", "HelpTooltip.", "Hg.",
"IconBadge.", "InformationHint.", "InplaceRefactoringPopup.",
"Lesson.", "Link.", "LiveIndicator.",
"MainMenu.", "MainToolbar.", "MemoryIndicator.", "MlModelBinding.", "MnemonicIcon.",
"NavBar.", "NewClass.", "NewPSD.", "Notification.", "Notifications.", "NotificationsToolwindow.",
"OnePixelDivider.", "OptionButton.", "Outline.",
"ParameterInfo.", "Plugins.", "ProgressIcon.", "PsiViewer.",
"ReviewList.", "RunWidget.",
"ScreenView.", "SearchEverywhere.", "SearchFieldWithExtension.", "SearchMatch.", "SearchOption.",
"SearchResults.", "SegmentedButton.", "Settings.", "SidePanel.", "Space.", "SpeedSearch.", "StateWidget.",
"StatusBar.",
"Tag.", "TipOfTheDay.", "ToolbarComboWidget.", "ToolWindow.",
"UIDesigner.", "UnattendedHostStatus.",
"ValidationTooltip.", "VersionControl.",
"WelcomeScreen.",
// lower case
"darcula.", "dropArea.", "icons.", "intellijlaf.", "macOSWindow.", "material.", "tooltips.",
// possible typos in .theme.json files
"Checkbox.", "Toolbar.", "Tooltip.", "UiDesigner.", "link."
) );
uiKeyDoNotOverride = new HashSet<>( Arrays.asList(
"TabbedPane.selectedForeground"
) );
// ComboBox // ComboBox
uiKeyMapping.put( "ComboBox.background", "" ); // ignore uiKeyMapping.put( "ComboBox.background", "" ); // ignore
uiKeyMapping.put( "ComboBox.buttonBackground", "" ); // ignore
uiKeyMapping.put( "ComboBox.nonEditableBackground", "ComboBox.background" ); uiKeyMapping.put( "ComboBox.nonEditableBackground", "ComboBox.background" );
uiKeyMapping.put( "ComboBox.ArrowButton.background", "ComboBox.buttonEditableBackground" ); uiKeyMapping.put( "ComboBox.ArrowButton.background", "ComboBox.buttonEditableBackground" );
uiKeyMapping.put( "ComboBox.ArrowButton.disabledIconColor", "ComboBox.buttonDisabledArrowColor" ); uiKeyMapping.put( "ComboBox.ArrowButton.disabledIconColor", "ComboBox.buttonDisabledArrowColor" );
@@ -747,11 +600,6 @@ public class IntelliJTheme
uiKeyCopying.put( "Spinner.buttonSeparatorColor", "Component.borderColor" ); uiKeyCopying.put( "Spinner.buttonSeparatorColor", "Component.borderColor" );
uiKeyCopying.put( "Spinner.buttonDisabledSeparatorColor", "Component.disabledBorderColor" ); uiKeyCopying.put( "Spinner.buttonDisabledSeparatorColor", "Component.disabledBorderColor" );
// TabbedPane
uiKeyMapping.put( "DefaultTabs.underlinedTabBackground", "TabbedPane.selectedBackground" );
uiKeyMapping.put( "DefaultTabs.underlinedTabForeground", "TabbedPane.selectedForeground" );
uiKeyMapping.put( "DefaultTabs.inactiveUnderlineColor", "TabbedPane.inactiveUnderlineColor" );
// TitlePane // TitlePane
uiKeyCopying.put( "TitlePane.inactiveBackground", "TitlePane.background" ); uiKeyCopying.put( "TitlePane.inactiveBackground", "TitlePane.background" );
uiKeyMapping.put( "TitlePane.infoForeground", "TitlePane.foreground" ); uiKeyMapping.put( "TitlePane.infoForeground", "TitlePane.foreground" );

View File

@@ -17,22 +17,18 @@
package com.formdev.flatlaf; package com.formdev.flatlaf;
import java.awt.Font; import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.GraphicsConfiguration; import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment; import java.awt.GraphicsEnvironment;
import java.awt.Toolkit; import java.awt.Toolkit;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import javax.swing.text.StyleContext;
import com.formdev.flatlaf.util.LoggingFacade; import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.StringUtils; import com.formdev.flatlaf.util.StringUtils;
import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.SystemInfo;
@@ -71,7 +67,7 @@ class LinuxFontPolicy
if( word.endsWith( "," ) ) if( word.endsWith( "," ) )
word = word.substring( 0, word.length() - 1 ).trim(); word = word.substring( 0, word.length() - 1 ).trim();
String lword = word.toLowerCase( Locale.ENGLISH ); String lword = word.toLowerCase();
if( lword.equals( "italic" ) || lword.equals( "oblique" ) ) if( lword.equals( "italic" ) || lword.equals( "oblique" ) )
style |= Font.ITALIC; style |= Font.ITALIC;
else if( lword.equals( "bold" ) ) else if( lword.equals( "bold" ) )
@@ -107,7 +103,7 @@ class LinuxFontPolicy
size = 1; size = 1;
// handle logical font names // handle logical font names
String logicalFamily = mapFcName( family.toLowerCase( Locale.ENGLISH ) ); String logicalFamily = mapFcName( family.toLowerCase() );
if( logicalFamily != null ) if( logicalFamily != null )
family = logicalFamily; family = logicalFamily;
@@ -125,28 +121,17 @@ class LinuxFontPolicy
for(;;) { for(;;) {
Font font = createFont( family, style, size, dsize ); Font font = createFont( family, style, size, dsize );
if( Font.DIALOG.equals( family ) )
return font;
// if the font family does not match any font on the system, "Dialog" family is returned // if the font family does not match any font on the system, "Dialog" family is returned
if( !Font.DIALOG.equals( font.getFamily() ) ) { if( !"Dialog".equals( font.getFamily() ) || "Dialog".equals( family ) )
// check for font problems
// - font height much larger than expected (e.g. font Inter; Oracle Java 8)
// - character width is zero (e.g. font Cantarell; Fedora; Oracle Java 8)
FontMetrics fm = StyleContext.getDefaultStyleContext().getFontMetrics( font );
if( fm.getHeight() > size * 2 || fm.stringWidth( "a" ) == 0 )
return createFont( Font.DIALOG, style, size, dsize );
return font; return font;
}
// find last word in family // find last word in family
int index = family.lastIndexOf( ' ' ); int index = family.lastIndexOf( ' ' );
if( index < 0 ) if( index < 0 )
return createFont( Font.DIALOG, style, size, dsize ); return createFont( "Dialog", style, size, dsize );
// check whether last work contains some font weight (e.g. Ultra-Bold or Heavy) // check whether last work contains some font weight (e.g. Ultra-Bold or Heavy)
String lastWord = family.substring( index + 1 ).toLowerCase( Locale.ENGLISH ); String lastWord = family.substring( index + 1 ).toLowerCase();
if( lastWord.contains( "bold" ) || lastWord.contains( "heavy" ) || lastWord.contains( "black" ) ) if( lastWord.contains( "bold" ) || lastWord.contains( "heavy" ) || lastWord.contains( "black" ) )
style |= Font.BOLD; style |= Font.BOLD;
@@ -173,7 +158,7 @@ class LinuxFontPolicy
Object value = Toolkit.getDefaultToolkit().getDesktopProperty( "gnome.Xft/DPI" ); Object value = Toolkit.getDefaultToolkit().getDesktopProperty( "gnome.Xft/DPI" );
if( value instanceof Integer ) { if( value instanceof Integer ) {
int dpi = (Integer) value / 1024; int dpi = ((Integer)value).intValue() / 1024;
if( dpi == -1 ) if( dpi == -1 )
dpi = 96; dpi = 96;
if( dpi < 50 ) if( dpi < 50 )
@@ -200,7 +185,7 @@ class LinuxFontPolicy
} }
/** /**
* Gets the default font for KDE from KDE configuration files. * Gets the default font for KDE for KDE configuration files.
* *
* The Swing fonts are not updated when the user changes system font size * The Swing fonts are not updated when the user changes system font size
* (System Settings > Fonts > Force Font DPI). A application restart is necessary. * (System Settings > Fonts > Force Font DPI). A application restart is necessary.
@@ -260,7 +245,6 @@ class LinuxFontPolicy
return createFont( family, style, size, dsize ); return createFont( family, style, size, dsize );
} }
@SuppressWarnings( "MixedMutabilityReturnType" ) // Error Prone
private static List<String> readConfig( String filename ) { private static List<String> readConfig( String filename ) {
File userHome = new File( System.getProperty( "user.home" ) ); File userHome = new File( System.getProperty( "user.home" ) );
@@ -281,10 +265,8 @@ class LinuxFontPolicy
// read config file // read config file
ArrayList<String> lines = new ArrayList<>( 200 ); ArrayList<String> lines = new ArrayList<>( 200 );
try( BufferedReader reader = new BufferedReader( new InputStreamReader( try( BufferedReader reader = new BufferedReader( new FileReader( file ) ) ) {
new FileInputStream( file ), StandardCharsets.US_ASCII ) ) ) String line = null;
{
String line;
while( (line = reader.readLine()) != null ) while( (line = reader.readLine()) != null )
lines.add( line ); lines.add( line );
} catch( IOException ex ) { } catch( IOException ex ) {

View File

@@ -1,336 +0,0 @@
/*
* 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;
import java.awt.AWTEvent;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.PointerInfo;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.MouseEvent;
import javax.swing.JComponent;
import javax.swing.JLayeredPane;
import javax.swing.JMenu;
import javax.swing.JPopupMenu;
import javax.swing.MenuElement;
import javax.swing.MenuSelectionManager;
import javax.swing.RootPaneContainer;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import com.formdev.flatlaf.ui.FlatUIUtils;
/**
* Improves usability of submenus by using a
* <a href="https://height.app/blog/guide-to-build-context-menus#safe-triangle">safe triangle</a>
* to avoid that the submenu closes while the user moves the mouse to it.
*
* @author Karl Tauber
*/
class SubMenuUsabilityHelper
implements ChangeListener
{
private static final String KEY_USE_SAFE_TRIANGLE = "Menu.useSafeTriangle";
private static final String KEY_SHOW_SAFE_TRIANGLE = "FlatLaf.debug.menu.showSafeTriangle";
// Using a static field to ensure that there is only one instance in the system.
// Multiple instances would freeze the application.
// https://github.com/apache/netbeans/issues/4231#issuecomment-1179616607
private static SubMenuUsabilityHelper instance;
private SubMenuEventQueue subMenuEventQueue;
private SafeTrianglePainter safeTrianglePainter;
private boolean changePending;
// mouse location in screen coordinates
private int mouseX;
private int mouseY;
// target popup bounds in screen coordinates
private int targetX;
private int targetTopY;
private int targetBottomY;
private Rectangle invokerBounds;
static synchronized boolean install() {
if( instance != null )
return false;
instance = new SubMenuUsabilityHelper();
MenuSelectionManager.defaultManager().addChangeListener( instance );
return true;
}
static synchronized void uninstall() {
if( instance == null )
return;
MenuSelectionManager.defaultManager().removeChangeListener( instance );
instance.uninstallEventQueue();
instance = null;
}
@Override
public void stateChanged( ChangeEvent e ) {
if( !FlatUIUtils.getUIBoolean( KEY_USE_SAFE_TRIANGLE, true ))
return;
// handle menu selection change later, but only once in case of temporary changes
// e.g. moving mouse from one menu item to another one, fires two events:
// 1. old menu item is removed from menu selection
// 2. new menu item is added to menu selection
synchronized( this ) {
if( changePending )
return;
changePending = true;
}
EventQueue.invokeLater( () -> {
synchronized( this ) {
changePending = false;
}
menuSelectionChanged();
} );
}
private void menuSelectionChanged() {
MenuElement[] path = MenuSelectionManager.defaultManager().getSelectedPath();
/*debug
System.out.println( "--- " + path.length );
for( int i = 0; i < path.length; i++ )
System.out.println( " " + i + ": " + path[i].getClass().getName() );
debug*/
// find submenu in menu selection
int subMenuIndex = findSubMenu( path );
// uninstall if there is no submenu in selection
if( subMenuIndex < 0 || subMenuIndex != path.length - 1 ) {
uninstallEventQueue();
return;
}
// get current mouse location
PointerInfo pointerInfo = MouseInfo.getPointerInfo();
Point mouseLocation = (pointerInfo != null) ? pointerInfo.getLocation() : new Point();
mouseX = mouseLocation.x;
mouseY = mouseLocation.y;
// check whether popup is showing, which is e.g. not the case if it is empty
JPopupMenu popup = (JPopupMenu) path[subMenuIndex];
if( !popup.isShowing() ) {
uninstallEventQueue();
return;
}
// get invoker screen bounds
Component invoker = popup.getInvoker();
invokerBounds = (invoker != null && invoker.isShowing())
? new Rectangle( invoker.getLocationOnScreen(), invoker.getSize() )
: null;
// check whether mouse location is within invoker
if( invokerBounds != null && !invokerBounds.contains( mouseX, mouseY ) ) {
uninstallEventQueue();
return;
}
// compute top/bottom target locations
Point popupLocation = popup.getLocationOnScreen();
Dimension popupSize = popup.getSize();
targetX = (mouseX < popupLocation.x + (popupSize.width / 2))
? popupLocation.x
: popupLocation.x + popupSize.width;
targetTopY = popupLocation.y;
targetBottomY = popupLocation.y + popupSize.height;
// install own event queue to supress mouse events when mouse is moved within safe triangle
if( subMenuEventQueue == null )
subMenuEventQueue = new SubMenuEventQueue();
// create safe triangle painter
if( safeTrianglePainter == null && UIManager.getBoolean( KEY_SHOW_SAFE_TRIANGLE ) )
safeTrianglePainter = new SafeTrianglePainter( popup );
}
private void uninstallEventQueue() {
if( subMenuEventQueue != null ) {
subMenuEventQueue.uninstall();
subMenuEventQueue = null;
}
if( safeTrianglePainter != null ) {
safeTrianglePainter.uninstall();
safeTrianglePainter = null;
}
}
private int findSubMenu( MenuElement[] path ) {
for( int i = path.length - 1; i >= 1; i-- ) {
if( path[i] instanceof JPopupMenu &&
path[i - 1] instanceof JMenu &&
!((JMenu)path[i - 1]).isTopLevelMenu() )
return i;
}
return -1;
}
private Polygon createSafeTriangle() {
return new Polygon(
new int[] { mouseX, targetX, targetX },
new int[] { mouseY, targetTopY, targetBottomY },
3 );
}
//---- class SubMenuEventQueue --------------------------------------------
private class SubMenuEventQueue
extends EventQueue
{
private Timer mouseUpdateTimer;
private Timer timeoutTimer;
private int newMouseX;
private int newMouseY;
private AWTEvent lastMouseEvent;
SubMenuEventQueue() {
// timer used to slightly delay update of mouse location used for safe triangle
mouseUpdateTimer = new Timer( 50, e -> {
mouseX = newMouseX;
mouseY = newMouseY;
if( safeTrianglePainter != null )
safeTrianglePainter.repaint();
} );
mouseUpdateTimer.setRepeats( false );
// timer used to timeout safe triangle when mouse stops moving
timeoutTimer = new Timer( 200, e -> {
if( invokerBounds != null && !invokerBounds.contains( newMouseX, newMouseY ) ) {
// post last mouse event, which selects menu item at mouse location
if( lastMouseEvent != null ) {
postEvent( lastMouseEvent );
lastMouseEvent = null;
}
uninstallEventQueue();
return;
}
} );
timeoutTimer.setRepeats( false );
Toolkit.getDefaultToolkit().getSystemEventQueue().push( this );
}
void uninstall() {
mouseUpdateTimer.stop();
mouseUpdateTimer = null;
timeoutTimer.stop();
timeoutTimer = null;
lastMouseEvent = null;
super.pop();
}
@Override
protected void dispatchEvent( AWTEvent e ) {
int id = e.getID();
if( e instanceof MouseEvent &&
(id == MouseEvent.MOUSE_MOVED || id == MouseEvent.MOUSE_DRAGGED) )
{
newMouseX = ((MouseEvent)e).getXOnScreen();
newMouseY = ((MouseEvent)e).getYOnScreen();
if( safeTrianglePainter != null )
safeTrianglePainter.repaint();
mouseUpdateTimer.stop();
timeoutTimer.stop();
// check whether mouse moved within safe triangle
if( createSafeTriangle().contains( newMouseX, newMouseY ) ) {
// update mouse location delayed (this changes the safe triangle)
mouseUpdateTimer.start();
timeoutTimer.start();
// remember last mouse event, which will be posted if the mouse stops moving
lastMouseEvent = e;
// ignore mouse event
return;
}
// update mouse location immediately (this changes the safe triangle)
mouseX = newMouseX;
mouseY = newMouseY;
}
super.dispatchEvent( e );
}
}
//---- class SafeTrianglePainter ------------------------------------------
private class SafeTrianglePainter
extends JComponent
{
SafeTrianglePainter( JPopupMenu popup ) {
Window window = SwingUtilities.windowForComponent( popup.getInvoker() );
if( window instanceof RootPaneContainer ) {
JLayeredPane layeredPane = ((RootPaneContainer)window).getLayeredPane();
setSize( layeredPane.getSize() );
layeredPane.add( this, Integer.valueOf( JLayeredPane.POPUP_LAYER + 1 ) );
}
}
void uninstall() {
Container parent = getParent();
if( parent != null ) {
parent.remove( this );
parent.repaint();
}
}
@Override
protected void paintComponent( Graphics g ) {
Point locationOnScreen = getLocationOnScreen();
g.translate( -locationOnScreen.x, -locationOnScreen.y );
g.setColor( Color.red );
((Graphics2D)g).draw( createSafeTriangle() );
}
}
}

View File

@@ -27,12 +27,8 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.StreamTokenizer; import java.io.StreamTokenizer;
import java.io.StringReader; import java.io.StringReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.Method;
import java.net.URL; import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
@@ -84,11 +80,10 @@ class UIDefaultsLoader
private static final String OPTIONAL_PREFIX = "?"; private static final String OPTIONAL_PREFIX = "?";
private static final String WILDCARD_PREFIX = "*."; private static final String WILDCARD_PREFIX = "*.";
static final String KEY_VARIABLES = "FlatLaf.internal.variables"; private static final String KEY_VARIABLES = "FlatLaf.internal.variables";
private static int parseColorDepth; private static int parseColorDepth;
private static Map<String, ColorUIResource> systemColorCache;
private static final SoftCache<String, Object> fontCache = new SoftCache<>(); private static final SoftCache<String, Object> fontCache = new SoftCache<>();
static void loadDefaultsFromProperties( Class<?> lookAndFeelClass, List<FlatDefaultsAddon> addons, static void loadDefaultsFromProperties( Class<?> lookAndFeelClass, List<FlatDefaultsAddon> addons,
@@ -110,10 +105,6 @@ class UIDefaultsLoader
Properties additionalDefaults, boolean dark, UIDefaults defaults ) Properties additionalDefaults, boolean dark, UIDefaults defaults )
{ {
try { 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 // load core properties files
Properties properties = new Properties(); Properties properties = new Properties();
for( Class<?> lafClass : lafClasses ) { for( Class<?> lafClass : lafClasses ) {
@@ -275,9 +266,8 @@ class UIDefaultsLoader
continue; continue;
} }
String value = (String) e.getValue(); String value = resolveValue( (String) e.getValue(), propertiesGetter );
try { try {
value = resolveValue( value, propertiesGetter );
defaults.put( key, parseValue( key, value, null, null, resolver, addonClassLoaders ) ); defaults.put( key, parseValue( key, value, null, null, resolver, addonClassLoaders ) );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
logParseError( key, value, ex, true ); logParseError( key, value, ex, true );
@@ -286,9 +276,6 @@ class UIDefaultsLoader
// remember variables in defaults to allow using them in styles // remember variables in defaults to allow using them in styles
defaults.put( KEY_VARIABLES, variables ); defaults.put( KEY_VARIABLES, variables );
// clear/disable system color cache
systemColorCache = null;
} catch( IOException ex ) { } catch( IOException ex ) {
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to load properties files.", ex ); LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to load properties files.", ex );
} }
@@ -302,9 +289,7 @@ class UIDefaultsLoader
LoggingFacade.INSTANCE.logConfig( message, ex ); LoggingFacade.INSTANCE.logConfig( message, ex );
} }
static String resolveValue( String value, Function<String, String> propertiesGetter ) static String resolveValue( String value, Function<String, String> propertiesGetter ) {
throws IllegalArgumentException
{
value = value.trim(); value = value.trim();
String value0 = value; String value0 = value;
@@ -333,9 +318,7 @@ class UIDefaultsLoader
return resolveValue( newValue, propertiesGetter ); return resolveValue( newValue, propertiesGetter );
} }
static String resolveValueFromUIManager( String value ) static String resolveValueFromUIManager( String value ) {
throws IllegalArgumentException
{
if( value.startsWith( VARIABLE_PREFIX ) ) { if( value.startsWith( VARIABLE_PREFIX ) ) {
@SuppressWarnings( "unchecked" ) @SuppressWarnings( "unchecked" )
Map<String, String> variables = (Map<String, String>) UIManager.get( KEY_VARIABLES ); Map<String, String> variables = (Map<String, String>) UIManager.get( KEY_VARIABLES );
@@ -343,7 +326,7 @@ class UIDefaultsLoader
if( newValue == null ) if( newValue == null )
throw new IllegalArgumentException( "variable '" + value + "' not found" ); throw new IllegalArgumentException( "variable '" + value + "' not found" );
return resolveValueFromUIManager( newValue ); return newValue;
} }
if( !value.startsWith( PROPERTY_PREFIX ) ) if( !value.startsWith( PROPERTY_PREFIX ) )
@@ -357,11 +340,8 @@ class UIDefaultsLoader
// convert binary color to string // convert binary color to string
if( newValue instanceof Color ) { if( newValue instanceof Color ) {
Color color = (Color) newValue; Color color = (Color) newValue;
int rgb = color.getRGB() & 0xffffff;
int alpha = color.getAlpha(); int alpha = color.getAlpha();
return (alpha != 255) return String.format( (alpha != 255) ? "#%06x%02x" : "#%06x", color.getRGB() & 0xffffff, alpha );
? String.format( "#%06x%02x", rgb, alpha )
: String.format( "#%06x", rgb );
} }
throw new IllegalArgumentException( "property value type '" + newValue.getClass().getName() + "' not supported in references" ); throw new IllegalArgumentException( "property value type '" + newValue.getClass().getName() + "' not supported in references" );
@@ -370,29 +350,20 @@ class UIDefaultsLoader
enum ValueType { UNKNOWN, STRING, BOOLEAN, CHARACTER, INTEGER, INTEGERORFLOAT, FLOAT, BORDER, ICON, INSETS, DIMENSION, COLOR, FONT, enum ValueType { UNKNOWN, STRING, BOOLEAN, CHARACTER, INTEGER, INTEGERORFLOAT, FLOAT, BORDER, ICON, INSETS, DIMENSION, COLOR, FONT,
SCALEDINTEGER, SCALEDFLOAT, SCALEDINSETS, SCALEDDIMENSION, INSTANCE, CLASS, GRAYFILTER, NULL, LAZY } SCALEDINTEGER, SCALEDFLOAT, SCALEDINSETS, SCALEDDIMENSION, INSTANCE, CLASS, GRAYFILTER, NULL, LAZY }
private static final ValueType[] tempResultValueType = new ValueType[1]; private static ValueType[] tempResultValueType = new ValueType[1];
private static Map<Class<?>, ValueType> javaValueTypes; private static Map<Class<?>, ValueType> javaValueTypes;
private static Map<String, ValueType> knownValueTypes; private static Map<String, ValueType> knownValueTypes;
static Object parseValue( String key, String value, Class<?> valueType ) static Object parseValue( String key, String value, Class<?> valueType ) {
throws IllegalArgumentException
{
return parseValue( key, value, valueType, null, v -> v, Collections.emptyList() ); return parseValue( key, value, valueType, null, v -> v, Collections.emptyList() );
} }
static Object parseValue( String key, String value, Class<?> javaValueType, ValueType[] resultValueType, static Object parseValue( String key, String value, Class<?> javaValueType, ValueType[] resultValueType,
Function<String, String> resolver, List<ClassLoader> addonClassLoaders ) Function<String, String> resolver, List<ClassLoader> addonClassLoaders )
throws IllegalArgumentException
{ {
if( resultValueType == null ) if( resultValueType == null )
resultValueType = tempResultValueType; resultValueType = tempResultValueType;
// do not parse styles here
if( key.startsWith( "[style]" ) ) {
resultValueType[0] = ValueType.STRING;
return value;
}
value = value.trim(); value = value.trim();
// null // null
@@ -412,7 +383,7 @@ class UIDefaultsLoader
if( value.startsWith( "if(" ) && value.endsWith( ")" ) ) { if( value.startsWith( "if(" ) && value.endsWith( ")" ) ) {
List<String> params = splitFunctionParams( value.substring( 3, value.length() - 1 ), ',' ); List<String> params = splitFunctionParams( value.substring( 3, value.length() - 1 ), ',' );
if( params.size() != 3 ) if( params.size() != 3 )
throw newMissingParametersException( value ); throwMissingParametersException( value );
boolean ifCondition = parseCondition( params.get( 0 ), resolver, addonClassLoaders ); boolean ifCondition = parseCondition( params.get( 0 ), resolver, addonClassLoaders );
String ifValue = params.get( ifCondition ? 1 : 2 ); String ifValue = params.get( ifCondition ? 1 : 2 );
@@ -489,10 +460,6 @@ class UIDefaultsLoader
if( knownValueTypes == null ) { if( knownValueTypes == null ) {
// create lazy // create lazy
knownValueTypes = new HashMap<>(); knownValueTypes = new HashMap<>();
// system colors
knownValueTypes.put( "activeCaptionBorder", ValueType.COLOR );
knownValueTypes.put( "inactiveCaptionBorder", ValueType.COLOR );
knownValueTypes.put( "windowBorder", ValueType.COLOR );
// SplitPane // SplitPane
knownValueTypes.put( "SplitPane.dividerSize", ValueType.INTEGER ); knownValueTypes.put( "SplitPane.dividerSize", ValueType.INTEGER );
knownValueTypes.put( "SplitPaneDivider.gripDotSize", ValueType.INTEGER ); knownValueTypes.put( "SplitPaneDivider.gripDotSize", ValueType.INTEGER );
@@ -548,20 +515,20 @@ class UIDefaultsLoader
case STRING: return value; case STRING: return value;
case BOOLEAN: return parseBoolean( value ); case BOOLEAN: return parseBoolean( value );
case CHARACTER: return parseCharacter( value ); case CHARACTER: return parseCharacter( value );
case INTEGER: return parseInteger( value ); case INTEGER: return parseInteger( value, true );
case INTEGERORFLOAT:return parseIntegerOrFloat( value ); case INTEGERORFLOAT:return parseIntegerOrFloat( value, true );
case FLOAT: return parseFloat( value ); case FLOAT: return parseFloat( value, true );
case BORDER: return parseBorder( value, resolver, addonClassLoaders ); case BORDER: return parseBorder( value, resolver, addonClassLoaders );
case ICON: return parseInstance( value, resolver, addonClassLoaders ); case ICON: return parseInstance( value, addonClassLoaders );
case INSETS: return parseInsets( value ); case INSETS: return parseInsets( value );
case DIMENSION: return parseDimension( value ); case DIMENSION: return parseDimension( value );
case COLOR: return parseColorOrFunction( value, resolver ); case COLOR: return parseColorOrFunction( value, resolver, true );
case FONT: return parseFont( value ); case FONT: return parseFont( value );
case SCALEDINTEGER: return parseScaledInteger( value ); case SCALEDINTEGER: return parseScaledInteger( value );
case SCALEDFLOAT: return parseScaledFloat( value ); case SCALEDFLOAT: return parseScaledFloat( value );
case SCALEDINSETS: return parseScaledInsets( value ); case SCALEDINSETS: return parseScaledInsets( value );
case SCALEDDIMENSION:return parseScaledDimension( value ); case SCALEDDIMENSION:return parseScaledDimension( value );
case INSTANCE: return parseInstance( value, resolver, addonClassLoaders ); case INSTANCE: return parseInstance( value, addonClassLoaders );
case CLASS: return parseClass( value, addonClassLoaders ); case CLASS: return parseClass( value, addonClassLoaders );
case GRAYFILTER: return parseGrayFilter( value ); case GRAYFILTER: return parseGrayFilter( value );
case UNKNOWN: case UNKNOWN:
@@ -573,34 +540,24 @@ class UIDefaultsLoader
} }
// colors // colors
if( value.startsWith( "#" ) || value.endsWith( ")" ) ) { Object color = parseColorOrFunction( value, resolver, false );
Object color = parseColorOrFunction( value, resolver ); if( color != null ) {
resultValueType[0] = (color != null) ? ValueType.COLOR : ValueType.NULL; resultValueType[0] = ValueType.COLOR;
return color; return color;
} }
// integer or float
char firstChar = value.charAt( 0 );
if( (firstChar >= '0' && firstChar <= '9') ||
firstChar == '-' || firstChar == '+' || firstChar == '.' )
{
// integer // integer
try { Integer integer = parseInteger( value, false );
Integer integer = parseInteger( value ); if( integer != null ) {
resultValueType[0] = ValueType.INTEGER; resultValueType[0] = ValueType.INTEGER;
return integer; return integer;
} catch( NumberFormatException ex ) {
// ignore
} }
// float // float
try { Float f = parseFloat( value, false );
Float f = parseFloat( value ); if( f != null ) {
resultValueType[0] = ValueType.FLOAT; resultValueType[0] = ValueType.FLOAT;
return f; return f;
} catch( NumberFormatException ex ) {
// ignore
}
} }
// string // string
@@ -623,47 +580,28 @@ class UIDefaultsLoader
} }
} }
private static Object parseBorder( String value, Function<String, String> resolver, List<ClassLoader> addonClassLoaders ) private static Object parseBorder( String value, Function<String, String> resolver, List<ClassLoader> addonClassLoaders ) {
throws IllegalArgumentException
{
if( value.indexOf( ',' ) >= 0 ) { if( value.indexOf( ',' ) >= 0 ) {
// Syntax: top,left,bottom,right[,lineColor[,lineThickness[,arc]]] // top,left,bottom,right[,lineColor[,lineThickness]]
List<String> parts = splitFunctionParams( value, ',' ); List<String> parts = splitFunctionParams( value, ',' );
Insets insets = parseInsets( value ); Insets insets = parseInsets( value );
ColorUIResource lineColor = (parts.size() >= 5) ColorUIResource lineColor = (parts.size() >= 5)
? (ColorUIResource) parseColorOrFunction( resolver.apply( parts.get( 4 ) ), resolver ) ? (ColorUIResource) parseColorOrFunction( resolver.apply( parts.get( 4 ) ), resolver, true )
: null; : null;
float lineThickness = (parts.size() >= 6 && !parts.get( 5 ).isEmpty()) ? parseFloat( parts.get( 5 ) ) : 1f; float lineThickness = (parts.size() >= 6) ? parseFloat( parts.get( 5 ), true ) : 1f;
int arc = (parts.size() >= 7) ? parseInteger( parts.get( 6 ) ) : 0;
return (LazyValue) t -> { return (LazyValue) t -> {
return (lineColor != null) return (lineColor != null)
? new FlatLineBorder( insets, lineColor, lineThickness, arc ) ? new FlatLineBorder( insets, lineColor, lineThickness )
: new FlatEmptyBorder( insets ); : new FlatEmptyBorder( insets );
}; };
} else } else
return parseInstance( value, resolver, addonClassLoaders ); return parseInstance( value, addonClassLoaders );
} }
private static Object parseInstance( String value, Function<String, String> resolver, List<ClassLoader> addonClassLoaders ) { private static Object parseInstance( String value, List<ClassLoader> addonClassLoaders ) {
return (LazyValue) t -> { return (LazyValue) t -> {
try { try {
if( value.indexOf( ',' ) >= 0 ) {
// Syntax: className,param1,param2,...
List<String> parts = splitFunctionParams( value, ',' );
String className = parts.get( 0 );
Class<?> cls = findClass( className, addonClassLoaders );
Constructor<?>[] constructors = cls.getDeclaredConstructors();
Object result = invokeConstructorOrStaticMethod( constructors, parts, resolver );
if( result != null )
return result;
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to instantiate '" + className
+ "': no constructor found for parameters '"
+ value.substring( value.indexOf( ',' + 1 ) ) + "'.", null );
return null;
} else
return findClass( value, addonClassLoaders ).getDeclaredConstructor().newInstance(); return findClass( value, addonClassLoaders ).getDeclaredConstructor().newInstance();
} catch( Exception ex ) { } catch( Exception ex ) {
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to instantiate '" + value + "'.", ex ); LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to instantiate '" + value + "'.", ex );
@@ -701,9 +639,7 @@ class UIDefaultsLoader
} }
} }
private static Insets parseInsets( String value ) private static Insets parseInsets( String value ) {
throws IllegalArgumentException
{
List<String> numbers = StringUtils.split( value, ',', true, false ); List<String> numbers = StringUtils.split( value, ',', true, false );
try { try {
return new InsetsUIResource( return new InsetsUIResource(
@@ -716,9 +652,7 @@ class UIDefaultsLoader
} }
} }
private static Dimension parseDimension( String value ) private static Dimension parseDimension( String value ) {
throws IllegalArgumentException
{
List<String> numbers = StringUtils.split( value, ',', true, false ); List<String> numbers = StringUtils.split( value, ',', true, false );
try { try {
return new DimensionUIResource( return new DimensionUIResource(
@@ -729,39 +663,43 @@ class UIDefaultsLoader
} }
} }
private static Object parseColorOrFunction( String value, Function<String, String> resolver ) private static Object parseColorOrFunction( String value, Function<String, String> resolver, boolean reportError ) {
throws IllegalArgumentException
{
if( value.endsWith( ")" ) ) if( value.endsWith( ")" ) )
return parseColorFunctions( value, resolver ); return parseColorFunctions( value, resolver, reportError );
return parseColor( value ); return parseColor( value, reportError );
} }
/** static ColorUIResource parseColor( String value ) {
* Parses a hex color in {@code #RGB}, {@code #RGBA}, {@code #RRGGBB} or {@code #RRGGBBAA} return parseColor( value, false );
* format and returns it as color object. }
*/
static ColorUIResource parseColor( String value ) private static ColorUIResource parseColor( String value, boolean reportError ) {
throws IllegalArgumentException try {
{
int rgba = parseColorRGBA( value ); int rgba = parseColorRGBA( value );
return ((rgba & 0xff000000) == 0xff000000) return ((rgba & 0xff000000) == 0xff000000)
? new ColorUIResource( rgba ) ? new ColorUIResource( rgba )
: new ColorUIResource( new Color( rgba, true ) ); : new ColorUIResource( new Color( rgba, true ) );
} catch( IllegalArgumentException ex ) {
if( reportError )
throw new IllegalArgumentException( "invalid color '" + value + "'" );
// not a color --> ignore
}
return null;
} }
/** /**
* Parses a hex color in {@code #RGB}, {@code #RGBA}, {@code #RRGGBB} or {@code #RRGGBBAA} * Parses a hex color in {@code #RGB}, {@code #RGBA}, {@code #RRGGBB} or {@code #RRGGBBAA}
* format and returns it as {@code rgba} integer suitable for {@link java.awt.Color}, * format and returns it as {@code rgba} integer suitable for {@link java.awt.Color},
* which includes alpha component in bits 24-31. * which includes alpha component in bits 24-31.
*
* @throws IllegalArgumentException
*/ */
static int parseColorRGBA( String value ) static int parseColorRGBA( String value ) {
throws IllegalArgumentException
{
int len = value.length(); int len = value.length();
if( (len != 4 && len != 5 && len != 7 && len != 9) || value.charAt( 0 ) != '#' ) if( (len != 4 && len != 5 && len != 7 && len != 9) || value.charAt( 0 ) != '#' )
throw newInvalidColorException( value ); throw new IllegalArgumentException();
// parse hex // parse hex
int n = 0; int n = 0;
@@ -776,7 +714,7 @@ class UIDefaultsLoader
else if( ch >= 'A' && ch <= 'F' ) else if( ch >= 'A' && ch <= 'F' )
digit = ch - 'A' + 10; digit = ch - 'A' + 10;
else else
throw newInvalidColorException( value ); throw new IllegalArgumentException();
n = (n << 4) | digit; n = (n << 4) | digit;
} }
@@ -795,21 +733,18 @@ class UIDefaultsLoader
: (((n >> 8) & 0xffffff) | ((n & 0xff) << 24)); // move alpha from lowest to highest byte : (((n >> 8) & 0xffffff) | ((n & 0xff) << 24)); // move alpha from lowest to highest byte
} }
private static IllegalArgumentException newInvalidColorException( String value ) { private static Object parseColorFunctions( String value, Function<String, String> resolver, boolean reportError ) {
return new IllegalArgumentException( "invalid color '" + value + "'" );
}
private static Object parseColorFunctions( String value, Function<String, String> resolver )
throws IllegalArgumentException
{
int paramsStart = value.indexOf( '(' ); int paramsStart = value.indexOf( '(' );
if( paramsStart < 0 ) if( paramsStart < 0 ) {
if( reportError )
throw new IllegalArgumentException( "missing opening parenthesis in function '" + value + "'" ); throw new IllegalArgumentException( "missing opening parenthesis in function '" + value + "'" );
return null;
}
String function = StringUtils.substringTrimmed( value, 0, paramsStart ); String function = StringUtils.substringTrimmed( value, 0, paramsStart );
List<String> params = splitFunctionParams( value.substring( paramsStart + 1, value.length() - 1 ), ',' ); List<String> params = splitFunctionParams( value.substring( paramsStart + 1, value.length() - 1 ), ',' );
if( params.isEmpty() ) if( params.isEmpty() )
throw newMissingParametersException( value ); throwMissingParametersException( value );
if( parseColorDepth > 100 ) if( parseColorDepth > 100 )
throw new IllegalArgumentException( "endless recursion in color function '" + value + "'" ); throw new IllegalArgumentException( "endless recursion in color function '" + value + "'" );
@@ -817,29 +752,27 @@ class UIDefaultsLoader
parseColorDepth++; parseColorDepth++;
try { try {
switch( function ) { switch( function ) {
case "if": return parseColorIf( value, params, resolver ); case "if": return parseColorIf( value, params, resolver, reportError );
case "systemColor": return parseColorSystemColor( value, params, resolver ); case "rgb": return parseColorRgbOrRgba( false, params, resolver, reportError );
case "rgb": return parseColorRgbOrRgba( false, params, resolver ); case "rgba": return parseColorRgbOrRgba( true, params, resolver, reportError );
case "rgba": return parseColorRgbOrRgba( true, params, resolver );
case "hsl": return parseColorHslOrHsla( false, params ); case "hsl": return parseColorHslOrHsla( false, params );
case "hsla": return parseColorHslOrHsla( true, params ); case "hsla": return parseColorHslOrHsla( true, params );
case "lighten": return parseColorHSLIncreaseDecrease( 2, true, params, resolver ); case "lighten": return parseColorHSLIncreaseDecrease( 2, true, params, resolver, reportError );
case "darken": return parseColorHSLIncreaseDecrease( 2, false, params, resolver ); case "darken": return parseColorHSLIncreaseDecrease( 2, false, params, resolver, reportError );
case "saturate": return parseColorHSLIncreaseDecrease( 1, true, params, resolver ); case "saturate": return parseColorHSLIncreaseDecrease( 1, true, params, resolver, reportError );
case "desaturate": return parseColorHSLIncreaseDecrease( 1, false, params, resolver ); case "desaturate": return parseColorHSLIncreaseDecrease( 1, false, params, resolver, reportError );
case "fadein": return parseColorHSLIncreaseDecrease( 3, true, params, resolver ); case "fadein": return parseColorHSLIncreaseDecrease( 3, true, params, resolver, reportError );
case "fadeout": return parseColorHSLIncreaseDecrease( 3, false, params, resolver ); case "fadeout": return parseColorHSLIncreaseDecrease( 3, false, params, resolver, reportError );
case "fade": return parseColorFade( params, resolver ); case "fade": return parseColorFade( params, resolver, reportError );
case "spin": return parseColorSpin( params, resolver ); case "spin": return parseColorSpin( params, resolver, reportError );
case "changeHue": return parseColorChange( 0, params, resolver ); case "changeHue": return parseColorChange( 0, params, resolver, reportError );
case "changeSaturation":return parseColorChange( 1, params, resolver ); case "changeSaturation":return parseColorChange( 1, params, resolver, reportError );
case "changeLightness": return parseColorChange( 2, params, resolver ); case "changeLightness": return parseColorChange( 2, params, resolver, reportError );
case "changeAlpha": return parseColorChange( 3, params, resolver ); case "changeAlpha": return parseColorChange( 3, params, resolver, reportError );
case "mix": return parseColorMix( null, params, resolver ); case "mix": return parseColorMix( null, params, resolver, reportError );
case "tint": return parseColorMix( "#fff", params, resolver ); case "tint": return parseColorMix( "#fff", params, resolver, reportError );
case "shade": return parseColorMix( "#000", params, resolver ); case "shade": return parseColorMix( "#000", params, resolver, reportError );
case "contrast": return parseColorContrast( params, resolver ); case "contrast": return parseColorContrast( params, resolver, reportError );
case "over": return parseColorOver( params, resolver );
} }
} finally { } finally {
parseColorDepth--; parseColorDepth--;
@@ -852,57 +785,15 @@ class UIDefaultsLoader
* Syntax: if(condition,trueValue,falseValue) * Syntax: if(condition,trueValue,falseValue)
* <p> * <p>
* This "if" function is only used if the "if" is passed as parameter to another * This "if" function is only used if the "if" is passed as parameter to another
* color function. Otherwise, the general "if" function is used. * color function. Otherwise the general "if" function is used.
*/ */
private static Object parseColorIf( String value, List<String> params, Function<String, String> resolver ) private static Object parseColorIf( String value, List<String> params, Function<String, String> resolver, boolean reportError ) {
throws IllegalArgumentException
{
if( params.size() != 3 ) if( params.size() != 3 )
throw newMissingParametersException( value ); throwMissingParametersException( value );
boolean ifCondition = parseCondition( params.get( 0 ), resolver, Collections.emptyList() ); boolean ifCondition = parseCondition( params.get( 0 ), resolver, Collections.emptyList() );
String ifValue = params.get( ifCondition ? 1 : 2 ); String ifValue = params.get( ifCondition ? 1 : 2 );
return parseColorOrFunction( resolver.apply( ifValue ), resolver ); return parseColorOrFunction( resolver.apply( ifValue ), resolver, reportError );
}
/**
* 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 )
throws IllegalArgumentException
{
if( params.size() < 1 )
throw newMissingParametersException( 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;
} }
/** /**
@@ -913,8 +804,7 @@ class UIDefaultsLoader
* - alpha: an integer 0-255 or a percentage 0-100% * - alpha: an integer 0-255 or a percentage 0-100%
*/ */
private static ColorUIResource parseColorRgbOrRgba( boolean hasAlpha, List<String> params, private static ColorUIResource parseColorRgbOrRgba( boolean hasAlpha, List<String> params,
Function<String, String> resolver ) Function<String, String> resolver, boolean reportError )
throws IllegalArgumentException
{ {
if( hasAlpha && params.size() == 2 ) { if( hasAlpha && params.size() == 2 ) {
// syntax rgba(color,alpha), which allows adding alpha to any color // syntax rgba(color,alpha), which allows adding alpha to any color
@@ -923,7 +813,7 @@ class UIDefaultsLoader
String colorStr = params.get( 0 ); String colorStr = params.get( 0 );
int alpha = parseInteger( params.get( 1 ), 0, 255, true ); int alpha = parseInteger( params.get( 1 ), 0, 255, true );
ColorUIResource color = (ColorUIResource) parseColorOrFunction( resolver.apply( colorStr ), resolver ); ColorUIResource color = (ColorUIResource) parseColorOrFunction( resolver.apply( colorStr ), resolver, reportError );
return new ColorUIResource( new Color( ((alpha & 0xff) << 24) | (color.getRGB() & 0xffffff), true ) ); return new ColorUIResource( new Color( ((alpha & 0xff) << 24) | (color.getRGB() & 0xffffff), true ) );
} }
@@ -944,15 +834,13 @@ class UIDefaultsLoader
* - lightness: a percentage 0-100% * - lightness: a percentage 0-100%
* - alpha: a percentage 0-100% * - alpha: a percentage 0-100%
*/ */
private static ColorUIResource parseColorHslOrHsla( boolean hasAlpha, List<String> params ) private static ColorUIResource parseColorHslOrHsla( boolean hasAlpha, List<String> params ) {
throws IllegalArgumentException
{
int hue = parseInteger( params.get( 0 ), 0, 360, false ); int hue = parseInteger( params.get( 0 ), 0, 360, false );
int saturation = parsePercentage( params.get( 1 ) ); int saturation = parsePercentage( params.get( 1 ) );
int lightness = parsePercentage( params.get( 2 ) ); int lightness = parsePercentage( params.get( 2 ) );
int alpha = hasAlpha ? parsePercentage( params.get( 3 ) ) : 100; int alpha = hasAlpha ? parsePercentage( params.get( 3 ) ) : 100;
float[] hsl = { hue, saturation, lightness }; float[] hsl = new float[] { hue, saturation, lightness };
return new ColorUIResource( HSLColor.toRGB( hsl, alpha / 100f ) ); return new ColorUIResource( HSLColor.toRGB( hsl, alpha / 100f ) );
} }
@@ -965,8 +853,7 @@ class UIDefaultsLoader
* - options: [relative] [autoInverse] [noAutoInverse] [lazy] [derived] * - options: [relative] [autoInverse] [noAutoInverse] [lazy] [derived]
*/ */
private static Object parseColorHSLIncreaseDecrease( int hslIndex, boolean increase, private static Object parseColorHSLIncreaseDecrease( int hslIndex, boolean increase,
List<String> params, Function<String, String> resolver ) List<String> params, Function<String, String> resolver, boolean reportError )
throws IllegalArgumentException
{ {
String colorStr = params.get( 0 ); String colorStr = params.get( 0 );
int amount = parsePercentage( params.get( 1 ) ); int amount = parsePercentage( params.get( 1 ) );
@@ -1001,43 +888,30 @@ class UIDefaultsLoader
} }
// parse base color, apply function and create derived color // parse base color, apply function and create derived color
return parseFunctionBaseColor( colorStr, function, derived, resolver ); return parseFunctionBaseColor( colorStr, function, derived, resolver, reportError );
} }
/** /**
* Syntax: fade(color,amount[,options]) * Syntax: fade(color,amount[,options])
* - color: a color (e.g. #f00) or a color function * - color: a color (e.g. #f00) or a color function
* - amount: percentage 0-100% * - amount: percentage 0-100%
* - options: [derived] [lazy] * - options: [derived]
*/ */
private static Object parseColorFade( List<String> params, Function<String, String> resolver ) private static Object parseColorFade( List<String> params, Function<String, String> resolver, boolean reportError ) {
throws IllegalArgumentException
{
String colorStr = params.get( 0 ); String colorStr = params.get( 0 );
int amount = parsePercentage( params.get( 1 ) ); int amount = parsePercentage( params.get( 1 ) );
boolean derived = false; boolean derived = false;
boolean lazy = false;
if( params.size() > 2 ) { if( params.size() > 2 ) {
String options = params.get( 2 ); String options = params.get( 2 );
derived = options.contains( "derived" ); derived = options.contains( "derived" );
lazy = options.contains( "lazy" );
} }
// create function // create function
ColorFunction function = new ColorFunctions.Fade( amount ); ColorFunction function = new ColorFunctions.Fade( amount );
if( lazy ) {
return (LazyValue) t -> {
Object color = lazyUIManagerGet( colorStr );
return (color instanceof Color)
? new ColorUIResource( ColorFunctions.applyFunctions( (Color) color, function ) )
: null;
};
}
// parse base color, apply function and create derived color // parse base color, apply function and create derived color
return parseFunctionBaseColor( colorStr, function, derived, resolver ); return parseFunctionBaseColor( colorStr, function, derived, resolver, reportError );
} }
/** /**
@@ -1046,11 +920,9 @@ class UIDefaultsLoader
* - angle: number of degrees to rotate * - angle: number of degrees to rotate
* - options: [derived] * - options: [derived]
*/ */
private static Object parseColorSpin( List<String> params, Function<String, String> resolver ) private static Object parseColorSpin( List<String> params, Function<String, String> resolver, boolean reportError ) {
throws IllegalArgumentException
{
String colorStr = params.get( 0 ); String colorStr = params.get( 0 );
int amount = parseInteger( params.get( 1 ) ); int amount = parseInteger( params.get( 1 ), true );
boolean derived = false; boolean derived = false;
if( params.size() > 2 ) { if( params.size() > 2 ) {
@@ -1062,7 +934,7 @@ class UIDefaultsLoader
ColorFunction function = new ColorFunctions.HSLIncreaseDecrease( 0, true, amount, false, false ); ColorFunction function = new ColorFunctions.HSLIncreaseDecrease( 0, true, amount, false, false );
// parse base color, apply function and create derived color // parse base color, apply function and create derived color
return parseFunctionBaseColor( colorStr, function, derived, resolver ); return parseFunctionBaseColor( colorStr, function, derived, resolver, reportError );
} }
/** /**
@@ -1075,12 +947,11 @@ class UIDefaultsLoader
* - options: [derived] * - options: [derived]
*/ */
private static Object parseColorChange( int hslIndex, private static Object parseColorChange( int hslIndex,
List<String> params, Function<String, String> resolver ) List<String> params, Function<String, String> resolver, boolean reportError )
throws IllegalArgumentException
{ {
String colorStr = params.get( 0 ); String colorStr = params.get( 0 );
int value = (hslIndex == 0) int value = (hslIndex == 0)
? parseInteger( params.get( 1 ) ) ? parseInteger( params.get( 1 ), true )
: parsePercentage( params.get( 1 ) ); : parsePercentage( params.get( 1 ) );
boolean derived = false; boolean derived = false;
@@ -1093,7 +964,7 @@ class UIDefaultsLoader
ColorFunction function = new ColorFunctions.HSLChange( hslIndex, value ); ColorFunction function = new ColorFunctions.HSLChange( hslIndex, value );
// parse base color, apply function and create derived color // parse base color, apply function and create derived color
return parseFunctionBaseColor( colorStr, function, derived, resolver ); return parseFunctionBaseColor( colorStr, function, derived, resolver, reportError );
} }
/** /**
@@ -1105,9 +976,7 @@ class UIDefaultsLoader
* - weight: the weight (in range 0-100%) to mix the two colors * - weight: the weight (in range 0-100%) to mix the two colors
* larger weight uses more of first color, smaller weight more of second color * larger weight uses more of first color, smaller weight more of second color
*/ */
private static Object parseColorMix( String color1Str, List<String> params, Function<String, String> resolver ) private static Object parseColorMix( String color1Str, List<String> params, Function<String, String> resolver, boolean reportError ) {
throws IllegalArgumentException
{
int i = 0; int i = 0;
if( color1Str == null ) if( color1Str == null )
color1Str = params.get( i++ ); color1Str = params.get( i++ );
@@ -1115,7 +984,7 @@ class UIDefaultsLoader
int weight = (params.size() > i) ? parsePercentage( params.get( i ) ) : 50; int weight = (params.size() > i) ? parsePercentage( params.get( i ) ) : 50;
// parse second color // parse second color
ColorUIResource color2 = (ColorUIResource) parseColorOrFunction( resolver.apply( color2Str ), resolver ); ColorUIResource color2 = (ColorUIResource) parseColorOrFunction( resolver.apply( color2Str ), resolver, reportError );
if( color2 == null ) if( color2 == null )
return null; return null;
@@ -1123,7 +992,7 @@ class UIDefaultsLoader
ColorFunction function = new ColorFunctions.Mix( color2, weight ); ColorFunction function = new ColorFunctions.Mix( color2, weight );
// parse first color, apply function and create mixed color // parse first color, apply function and create mixed color
return parseFunctionBaseColor( color1Str, function, false, resolver ); return parseFunctionBaseColor( color1Str, function, false, resolver, reportError );
} }
/** /**
@@ -1134,16 +1003,14 @@ class UIDefaultsLoader
* - threshold: the threshold (in range 0-100%) to specify where the transition * - threshold: the threshold (in range 0-100%) to specify where the transition
* from "dark" to "light" is (default is 43%) * from "dark" to "light" is (default is 43%)
*/ */
private static Object parseColorContrast( List<String> params, Function<String, String> resolver ) private static Object parseColorContrast( List<String> params, Function<String, String> resolver, boolean reportError ) {
throws IllegalArgumentException
{
String colorStr = params.get( 0 ); String colorStr = params.get( 0 );
String darkStr = params.get( 1 ); String darkStr = params.get( 1 );
String lightStr = params.get( 2 ); String lightStr = params.get( 2 );
int threshold = (params.size() > 3) ? parsePercentage( params.get( 3 ) ) : 43; int threshold = (params.size() > 3) ? parsePercentage( params.get( 3 ) ) : 43;
// parse color to compare against // parse color to compare against
ColorUIResource color = (ColorUIResource) parseColorOrFunction( resolver.apply( colorStr ), resolver ); ColorUIResource color = (ColorUIResource) parseColorOrFunction( resolver.apply( colorStr ), resolver, reportError );
if( color == null ) if( color == null )
return null; return null;
@@ -1153,46 +1020,15 @@ class UIDefaultsLoader
: darkStr; : darkStr;
// parse dark or light color // parse dark or light color
return parseColorOrFunction( resolver.apply( darkOrLightColor ), resolver ); return parseColorOrFunction( resolver.apply( darkOrLightColor ), resolver, reportError );
}
/**
* Syntax: over(foreground,background)
* - foreground: a foreground color (e.g. #f00) or a color function;
* 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 )
throws IllegalArgumentException
{
String foregroundStr = params.get( 0 );
String backgroundStr = params.get( 1 );
// parse foreground color
ColorUIResource foreground = (ColorUIResource) parseColorOrFunction( resolver.apply( foregroundStr ), resolver );
if( foreground == null || foreground.getAlpha() == 255 )
return foreground;
// foreground color without alpha
ColorUIResource foreground2 = new ColorUIResource( foreground.getRGB() );
// parse background color
ColorUIResource background = (ColorUIResource) parseColorOrFunction( resolver.apply( backgroundStr ), resolver );
if( background == null )
return foreground2;
// create new color
float weight = foreground.getAlpha() / 255f;
return new ColorUIResource( ColorFunctions.mix( foreground2, background, weight ) );
} }
private static Object parseFunctionBaseColor( String colorStr, ColorFunction function, private static Object parseFunctionBaseColor( String colorStr, ColorFunction function,
boolean derived, Function<String, String> resolver ) boolean derived, Function<String, String> resolver, boolean reportError )
throws IllegalArgumentException
{ {
// parse base color // parse base color
String resolvedColorStr = resolver.apply( colorStr ); String resolvedColorStr = resolver.apply( colorStr );
ColorUIResource baseColor = (ColorUIResource) parseColorOrFunction( resolvedColorStr, resolver ); ColorUIResource baseColor = (ColorUIResource) parseColorOrFunction( resolvedColorStr, resolver, reportError );
if( baseColor == null ) if( baseColor == null )
return null; return null;
@@ -1220,9 +1056,7 @@ class UIDefaultsLoader
/** /**
* Syntax: [normal] [bold|+bold|-bold] [italic|+italic|-italic] [<size>|+<incr>|-<decr>|<percent>%] [family[, family]] [$baseFontKey] * Syntax: [normal] [bold|+bold|-bold] [italic|+italic|-italic] [<size>|+<incr>|-<decr>|<percent>%] [family[, family]] [$baseFontKey]
*/ */
private static Object parseFont( String value ) private static Object parseFont( String value ) {
throws IllegalArgumentException
{
Object font = fontCache.get( value ); Object font = fontCache.get( value );
if( font != null ) if( font != null )
return font; return font;
@@ -1278,11 +1112,11 @@ class UIDefaultsLoader
throw new IllegalArgumentException( "size specified more than once in '" + value + "'" ); throw new IllegalArgumentException( "size specified more than once in '" + value + "'" );
if( firstChar == '+' || firstChar == '-' ) if( firstChar == '+' || firstChar == '-' )
relativeSize = parseInteger( param ); relativeSize = parseInteger( param, true );
else if( param.endsWith( "%" ) ) else if( param.endsWith( "%" ) )
scaleSize = parseInteger( param.substring( 0, param.length() - 1 ) ) / 100f; scaleSize = parseInteger( param.substring( 0, param.length() - 1 ), true ) / 100f;
else else
absoluteSize = parseInteger( param ); absoluteSize = parseInteger( param, true );
} else if( firstChar == '$' ) { } else if( firstChar == '$' ) {
// reference to base font // reference to base font
if( baseFontKey != null ) if( baseFontKey != null )
@@ -1320,9 +1154,7 @@ class UIDefaultsLoader
return font; return font;
} }
private static int parsePercentage( String value ) private static int parsePercentage( String value ) {
throws IllegalArgumentException, NumberFormatException
{
if( !value.endsWith( "%" ) ) if( !value.endsWith( "%" ) )
throw new NumberFormatException( "invalid percentage '" + value + "'" ); throw new NumberFormatException( "invalid percentage '" + value + "'" );
@@ -1338,9 +1170,7 @@ class UIDefaultsLoader
return val; return val;
} }
private static Boolean parseBoolean( String value ) private static Boolean parseBoolean( String value ) {
throws IllegalArgumentException
{
switch( value ) { switch( value ) {
case "false": return false; case "false": return false;
case "true": return true; case "true": return true;
@@ -1348,101 +1178,87 @@ class UIDefaultsLoader
throw new IllegalArgumentException( "invalid boolean '" + value + "'" ); throw new IllegalArgumentException( "invalid boolean '" + value + "'" );
} }
private static Character parseCharacter( String value ) private static Character parseCharacter( String value ) {
throws IllegalArgumentException
{
if( value.length() != 1 ) if( value.length() != 1 )
throw new IllegalArgumentException( "invalid character '" + value + "'" ); throw new IllegalArgumentException( "invalid character '" + value + "'" );
return value.charAt( 0 ); return value.charAt( 0 );
} }
private static Integer parseInteger( String value, int min, int max, boolean allowPercentage ) private static Integer parseInteger( String value, int min, int max, boolean allowPercentage ) {
throws IllegalArgumentException, NumberFormatException
{
if( allowPercentage && value.endsWith( "%" ) ) { if( allowPercentage && value.endsWith( "%" ) ) {
int percent = parsePercentage( value ); int percent = parsePercentage( value );
return (max * percent) / 100; return (max * percent) / 100;
} }
Integer integer = parseInteger( value ); Integer integer = parseInteger( value, true );
if( integer < min || integer > max ) if( integer.intValue() < min || integer.intValue() > max )
throw new NumberFormatException( "integer '" + value + "' out of range (" + min + '-' + max + ')' ); throw new NumberFormatException( "integer '" + value + "' out of range (" + min + '-' + max + ')' );
return integer; return integer;
} }
private static Integer parseInteger( String value ) private static Integer parseInteger( String value, boolean reportError ) {
throws NumberFormatException
{
try { try {
return Integer.parseInt( value ); return Integer.parseInt( value );
} catch( NumberFormatException ex ) { } 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 ) private static Number parseIntegerOrFloat( String value, boolean reportError ) {
throws NumberFormatException
{
try { try {
return Integer.parseInt( value ); return Integer.parseInt( value );
} catch( NumberFormatException ex ) { } catch( NumberFormatException ex ) {
try { try {
return Float.parseFloat( value ); return Float.parseFloat( value );
} catch( NumberFormatException ex2 ) { } 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 ) private static Float parseFloat( String value, boolean reportError ) {
throws NumberFormatException
{
try { try {
return Float.parseFloat( value ); return Float.parseFloat( value );
} catch( NumberFormatException ex ) { } 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 ) private static ActiveValue parseScaledInteger( String value ) {
throws NumberFormatException int val = parseInteger( value, true );
{ return (ActiveValue) t -> {
int val = parseInteger( value );
return t -> {
return UIScale.scale( val ); return UIScale.scale( val );
}; };
} }
private static ActiveValue parseScaledFloat( String value ) private static ActiveValue parseScaledFloat( String value ) {
throws NumberFormatException float val = parseFloat( value, true );
{ return (ActiveValue) t -> {
float val = parseFloat( value );
return t -> {
return UIScale.scale( val ); return UIScale.scale( val );
}; };
} }
private static ActiveValue parseScaledInsets( String value ) private static ActiveValue parseScaledInsets( String value ) {
throws IllegalArgumentException
{
Insets insets = parseInsets( value ); Insets insets = parseInsets( value );
return t -> { return (ActiveValue) t -> {
return UIScale.scale( insets ); return UIScale.scale( insets );
}; };
} }
private static ActiveValue parseScaledDimension( String value ) private static ActiveValue parseScaledDimension( String value ) {
throws IllegalArgumentException
{
Dimension dimension = parseDimension( value ); Dimension dimension = parseDimension( value );
return t -> { return (ActiveValue) t -> {
return UIScale.scale( dimension ); return UIScale.scale( dimension );
}; };
} }
private static Object parseGrayFilter( String value ) private static Object parseGrayFilter( String value ) {
throws IllegalArgumentException
{
List<String> numbers = StringUtils.split( value, ',', true, false ); List<String> numbers = StringUtils.split( value, ',', true, false );
try { try {
int brightness = Integer.parseInt( numbers.get( 0 ) ); int brightness = Integer.parseInt( numbers.get( 0 ) );
@@ -1477,95 +1293,11 @@ class UIDefaultsLoader
start = i + 1; 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; return strs;
} }
private static Object invokeConstructorOrStaticMethod( Executable[] constructorsOrMethods,
List<String> parts, Function<String, String> resolver )
throws Exception
{
// order constructors/methods by parameter types:
// - String parameters to the end
// - int before float parameters
constructorsOrMethods = constructorsOrMethods.clone();
Arrays.sort( constructorsOrMethods, (c1, c2) -> {
Class<?>[] ptypes1 = c1.getParameterTypes();
Class<?>[] ptypes2 = c2.getParameterTypes();
if( ptypes1.length != ptypes2.length )
return ptypes1.length - ptypes2.length;
for( int i = 0; i < ptypes1.length; i++ ) {
Class<?> pt1 = ptypes1[i];
Class<?> pt2 = ptypes2[i];
if( pt1 == pt2 )
continue;
// order methods with String parameters to the end
if( pt1 == String.class )
return 2;
if( pt2 == String.class )
return -2;
// order int before float
if( pt1 == int.class )
return -1;
if( pt2 == int.class )
return 1;
}
return 0;
} );
// search for best constructor/method for given parameter values
for( Executable cm : constructorsOrMethods ) {
if( cm.getParameterCount() != parts.size() - 1 )
continue;
Object[] params = parseMethodParams( cm.getParameterTypes(), parts, resolver );
if( params == null )
continue;
// invoke constructor or static method
if( cm instanceof Constructor )
return ((Constructor<?>)cm).newInstance( params );
else
return ((Method)cm).invoke( null, params );
}
return null;
}
private static Object[] parseMethodParams( Class<?>[] paramTypes, List<String> parts, Function<String, String> resolver ) {
Object[] params = new Object[paramTypes.length];
try {
for( int i = 0; i < params.length; i++ ) {
Class<?> paramType = paramTypes[i];
String paramValue = parts.get( i + 1 );
if( paramType == String.class )
params[i] = paramValue;
else if( paramType == boolean.class )
params[i] = parseBoolean( paramValue );
else if( paramType == int.class )
params[i] = parseInteger( paramValue );
else if( paramType == float.class )
params[i] = parseFloat( paramValue );
else if( paramType == Color.class )
params[i] = parseColorOrFunction( resolver.apply( paramValue ), resolver );
else
return null; // unsupported parameter type
}
} catch( IllegalArgumentException ex ) {
return null; // failed to parse parameter for expected parameter type
}
return params;
}
/** /**
* For use in LazyValue to get value for given key from UIManager and report error * For use in LazyValue to get value for given key from UIManager and report error
* if not found. If key is prefixed by '?', then no error is reported. * if not found. If key is prefixed by '?', then no error is reported.
@@ -1583,7 +1315,7 @@ class UIDefaultsLoader
return value; return value;
} }
private static IllegalArgumentException newMissingParametersException( String value ) { private static void throwMissingParametersException( String value ) {
return new IllegalArgumentException( "missing parameters in function '" + value + "'" ); throw new IllegalArgumentException( "missing parameters in function '" + value + "'" );
} }
} }

View File

@@ -69,7 +69,13 @@ public abstract class FlatAbstractIcon
} }
} }
protected abstract void paintIcon( Component c, Graphics2D g2 ); /**
* Paint the icon at {@code [0,0]} location.
* <p>
* The given graphics context is scaled.
* Use unscaled coordinates, width and height for painting.
*/
protected abstract void paintIcon( Component c, Graphics2D g );
@Override @Override
public int getIconWidth() { public int getIconWidth() {

View File

@@ -21,16 +21,17 @@ import java.awt.Component;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import com.formdev.flatlaf.util.AnimatedIcon; import com.formdev.flatlaf.util.AnimatedIcon;
import com.formdev.flatlaf.util.AnimatedPainter;
/** /**
* Base class for animated icons that scale width and height, creates and initializes * Base class for animated icons that scales width and height, creates and initializes
* a scaled graphics context for icon painting. * a scaled graphics context for icon painting.
* <p> * <p>
* Subclasses do not need to scale icon painting. * Subclasses do not need to scale icon painting.
* <p> * <p>
* This class does not store any state information (needed for animation) in its instance. * This class does not store any state information (needed for animation) in its instance.
* Instead, a client property is set on the painted component. * Instead a client property is set on the painted component.
* This makes it possible to use a share icon instance for multiple components. * This makes it possible to use a shared icon instance for multiple components.
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@@ -45,11 +46,34 @@ public abstract class FlatAnimatedIcon
@Override @Override
public void paintIcon( Component c, Graphics g, int x, int y ) { public void paintIcon( Component c, Graphics g, int x, int y ) {
super.paintIcon( c, g, x, y ); super.paintIcon( c, g, x, y );
AnimatedIcon.AnimationSupport.saveIconLocation( this, c, x, y ); AnimatedPainter.saveRepaintLocation( this, c, x, y );
} }
@Override @Override
protected void paintIcon( Component c, Graphics2D g ) { protected void paintIcon( Component c, Graphics2D g ) {
AnimatedIcon.AnimationSupport.paintIcon( this, c, g, 0, 0 ); paintWithAnimation( c, g, 0, 0, getIconWidth(), getIconHeight() );
} }
/**
* Delegates painting to {@link #paintIconAnimated(Component, Graphics2D, float[])}.
* Ignores the given bounds because {@code [x,y]} are always {@code [0,0]} and
* {@code [width,height]} are scaled, but painting code should use unscaled width
* and height because given graphics context is scaled.
*
* @since 2
*/
@Override
public void paintAnimated( Component c, Graphics2D g, int x, int y, int width, int height, float[] animatedValues ) {
paintIconAnimated( c, g, animatedValues );
}
/**
* Paint the icon at {@code 0,0} location.
* <p>
* The given graphics context is scaled.
* Use unscaled coordinates, width and height for painting.
*
* @since 2
*/
protected abstract void paintIconAnimated( Component c, Graphics2D g, float[] animatedValues );
} }

View File

@@ -51,7 +51,7 @@ public class FlatAscendingSortIcon
boolean chevron = this.chevron; boolean chevron = this.chevron;
Color sortIconColor = this.sortIconColor; Color sortIconColor = this.sortIconColor;
// Because this icon is always shared for all table headers, // Because this icons are always shared for all table headers,
// get icon specific style from FlatTableHeaderUI. // get icon specific style from FlatTableHeaderUI.
JTableHeader tableHeader = (JTableHeader) SwingUtilities.getAncestorOfClass( JTableHeader.class, c ); JTableHeader tableHeader = (JTableHeader) SwingUtilities.getAncestorOfClass( JTableHeader.class, c );
if( tableHeader != null ) { if( tableHeader != null ) {

View File

@@ -16,12 +16,9 @@
package com.formdev.flatlaf.icons; package com.formdev.flatlaf.icons;
import java.awt.BasicStroke;
import java.awt.Color; import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Area;
import java.awt.geom.Path2D; import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D; import java.awt.geom.RoundRectangle2D;
@@ -39,8 +36,6 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
public class FlatCapsLockIcon public class FlatCapsLockIcon
extends FlatAbstractIcon extends FlatAbstractIcon
{ {
private Path2D path;
public FlatCapsLockIcon() { public FlatCapsLockIcon() {
super( 16, 16, UIManager.getColor( "PasswordField.capsLockIconColor" ) ); super( 16, 16, UIManager.getColor( "PasswordField.capsLockIconColor" ) );
} }
@@ -54,36 +49,22 @@ public class FlatCapsLockIcon
} }
} }
/** @since 2.5 */
public Object getStyleableValue( String key ) {
switch( key ) {
case "capsLockIconColor": return color;
default: return null;
}
}
@Override @Override
protected void paintIcon( Component c, Graphics2D g ) { protected void paintIcon( Component c, Graphics2D g ) {
/* /*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd"> <g fill="none" fill-rule="evenodd">
<rect width="16" height="16" fill="#6E6E6E" rx="3"/> <rect width="16" height="16" fill="#6E6E6E" rx="3"/>
<rect width="5" height="2" x="5.5" y="11.5" stroke="#FFF" stroke-linejoin="round"/> <rect width="6" height="2" x="5" y="11.5" fill="#FFF"/>
<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"/> <path fill="#FFF" d="M2,8 L8,2 L14,8 L11,8 L11,10 L5,10 L5,8 L2,8 Z"/>
</g> </g>
</svg> </svg>
*/ */
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE ); Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
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 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 Rectangle2D.Float( 5, 11.5f, 6, 2 ), false );
path.append( new Area( stroke.createStrokedShape( FlatUIUtils.createPath( path.append( FlatUIUtils.createPath( 2,8, 8,2, 14,8, 11,8, 11,10, 5,10, 5,8 ), false );
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 ); g.fill( path );
} }
} }

View File

@@ -172,11 +172,6 @@ public class FlatCheckBoxIcon
return FlatStylingSupport.getAnnotatedStyleableInfos( this ); return FlatStylingSupport.getAnnotatedStyleableInfos( this );
} }
/** @since 2.5 */
public Object getStyleableValue( String key ) {
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
}
@Override @Override
protected void paintIcon( Component c, Graphics2D g ) { protected void paintIcon( Component c, Graphics2D g ) {
boolean indeterminate = isIndeterminate( c ); boolean indeterminate = isIndeterminate( c );
@@ -242,7 +237,7 @@ public class FlatCheckBoxIcon
} }
protected void paintCheckmark( Component c, Graphics2D g ) { protected void paintCheckmark( Component c, Graphics2D g ) {
Path2D.Float path = new Path2D.Float( Path2D.WIND_NON_ZERO, 3 ); Path2D.Float path = new Path2D.Float();
path.moveTo( 4.5f, 7.5f ); path.moveTo( 4.5f, 7.5f );
path.lineTo( 6.6f, 10f ); path.lineTo( 6.6f, 10f );
path.lineTo( 11.25f, 3.5f ); path.lineTo( 11.25f, 3.5f );

View File

@@ -59,11 +59,6 @@ public class FlatCheckBoxMenuItemIcon
return FlatStylingSupport.getAnnotatedStyleableInfos( this ); return FlatStylingSupport.getAnnotatedStyleableInfos( this );
} }
/** @since 2.5 */
public Object getStyleableValue( String key ) {
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
}
@Override @Override
protected void paintIcon( Component c, Graphics2D g2 ) { protected void paintIcon( Component c, Graphics2D g2 ) {
boolean selected = (c instanceof AbstractButton) && ((AbstractButton)c).isSelected(); boolean selected = (c instanceof AbstractButton) && ((AbstractButton)c).isSelected();
@@ -76,7 +71,7 @@ public class FlatCheckBoxMenuItemIcon
} }
protected void paintCheckmark( Graphics2D g2 ) { protected void paintCheckmark( Graphics2D g2 ) {
Path2D.Float path = new Path2D.Float( Path2D.WIND_NON_ZERO, 3 ); Path2D.Float path = new Path2D.Float();
path.moveTo( 4.5f, 7.5f ); path.moveTo( 4.5f, 7.5f );
path.lineTo( 6.6f, 10f ); path.lineTo( 6.6f, 10f );
path.lineTo( 11.25f, 3.5f ); path.lineTo( 11.25f, 3.5f );

View File

@@ -20,6 +20,7 @@ import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D; import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D; import java.awt.geom.Path2D;
import java.util.Map; import java.util.Map;
import javax.swing.AbstractButton; import javax.swing.AbstractButton;
@@ -46,16 +47,8 @@ public class FlatClearIcon
@Styleable protected Color clearIconHoverColor = UIManager.getColor( "SearchField.clearIconHoverColor" ); @Styleable protected Color clearIconHoverColor = UIManager.getColor( "SearchField.clearIconHoverColor" );
@Styleable protected Color clearIconPressedColor = UIManager.getColor( "SearchField.clearIconPressedColor" ); @Styleable protected Color clearIconPressedColor = UIManager.getColor( "SearchField.clearIconPressedColor" );
private final boolean ignoreButtonState;
public FlatClearIcon() { public FlatClearIcon() {
this( false );
}
/** @since 2 */
public FlatClearIcon( boolean ignoreButtonState ) {
super( 16, 16, null ); super( 16, 16, null );
this.ignoreButtonState = ignoreButtonState;
} }
/** @since 2 */ /** @since 2 */
@@ -68,14 +61,9 @@ public class FlatClearIcon
return FlatStylingSupport.getAnnotatedStyleableInfos( this ); return FlatStylingSupport.getAnnotatedStyleableInfos( this );
} }
/** @since 2.5 */
public Object getStyleableValue( String key ) {
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
}
@Override @Override
protected void paintIcon( Component c, Graphics2D g ) { protected void paintIcon( Component c, Graphics2D g ) {
if( !ignoreButtonState && c instanceof AbstractButton ) { if( c instanceof AbstractButton ) {
ButtonModel model = ((AbstractButton)c).getModel(); ButtonModel model = ((AbstractButton)c).getModel();
if( model.isPressed() || model.isRollover() ) { if( model.isPressed() || model.isRollover() ) {
/* /*
@@ -102,11 +90,9 @@ public class FlatClearIcon
// paint cross // paint cross
g.setColor( clearIconColor ); g.setColor( clearIconColor );
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD, 4 ); Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
path.moveTo( 5, 5 ); path.append( new Line2D.Float( 5,5, 11,11 ), false );
path.lineTo( 11, 11 ); path.append( new Line2D.Float( 5,11, 11,5 ), false );
path.moveTo( 5, 11 );
path.lineTo( 11, 5 );
g.draw( path ); g.draw( path );
} }
} }

View File

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

View File

@@ -16,10 +16,8 @@
package com.formdev.flatlaf.icons; package com.formdev.flatlaf.icons;
import java.awt.BasicStroke;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.UIManager; import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.ui.FlatUIUtils;
@@ -41,22 +39,10 @@ public class FlatFileChooserHomeFolderIcon
protected void paintIcon( Component c, Graphics2D g ) { protected void paintIcon( Component c, Graphics2D g ) {
/* /*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <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" 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"/>
<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> </svg>
*/ */
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE ); 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.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,11 +16,8 @@
package com.formdev.flatlaf.icons; package com.formdev.flatlaf.icons;
import java.awt.BasicStroke;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.RoundRectangle2D;
import javax.swing.UIManager; import javax.swing.UIManager;
/** /**
@@ -42,20 +39,17 @@ public class FlatFileChooserListViewIcon
/* /*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd"> <g fill="none" fill-rule="evenodd">
<rect width="4" height="4" x="2.5" y="2.5" stroke="#6E6E6E" rx="1.5"/> <rect width="4" height="4" x="3" y="3" fill="#6E6E6E"/>
<rect width="4" height="4" x="2.5" y="9.5" stroke="#6E6E6E" rx="1.5"/> <rect width="4" height="4" x="3" y="9" fill="#6E6E6E"/>
<rect width="4" height="4" x="9.5" y="9.5" stroke="#6E6E6E" rx="1.5"/> <rect width="4" height="4" x="9" y="9" fill="#6E6E6E"/>
<rect width="4" height="4" x="9.5" y="2.5" stroke="#6E6E6E" rx="1.5"/> <rect width="4" height="4" x="9" y="3" fill="#6E6E6E"/>
</g> </g>
</svg> </svg>
*/ */
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE ); g.fillRect( 3, 3, 4, 4 );
g.setStroke( new BasicStroke( 1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) ); g.fillRect( 3, 9, 4, 4 );
g.fillRect( 9, 9, 4, 4 );
g.draw( new RoundRectangle2D.Float( 2.5f, 2.5f, 4, 4, 2, 2 ) ); g.fillRect( 9, 3, 4, 4 );
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,13 +16,10 @@
package com.formdev.flatlaf.icons; package com.formdev.flatlaf.icons;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Line2D;
import javax.swing.UIManager; import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatUIUtils;
/** /**
* "new folder" icon for {@link javax.swing.JFileChooser}. * "new folder" icon for {@link javax.swing.JFileChooser}.
@@ -34,8 +31,6 @@ import javax.swing.UIManager;
public class FlatFileChooserNewFolderIcon public class FlatFileChooserNewFolderIcon
extends FlatAbstractIcon extends FlatAbstractIcon
{ {
private final Color greenColor = UIManager.getColor( "Actions.Green" );
public FlatFileChooserNewFolderIcon() { public FlatFileChooserNewFolderIcon() {
super( 16, 16, UIManager.getColor( "Actions.Grey" ) ); super( 16, 16, UIManager.getColor( "Actions.Grey" ) );
} }
@@ -45,20 +40,13 @@ public class FlatFileChooserNewFolderIcon
/* /*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd"> <g fill="none" fill-rule="evenodd">
<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"/> <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"/>
<line x1="5.5" x2="10.5" y1="9" y2="9" stroke="#59A869" stroke-linecap="round"/> <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"/>
<line x1="8" x2="8" y1="6.5" y2="11.5" stroke="#59A869" stroke-linecap="round"/>
</g> </g>
</svg> </svg>
*/ */
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE ); 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.setStroke( new BasicStroke( 1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) ); 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.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,12 +16,9 @@
package com.formdev.flatlaf.icons; package com.formdev.flatlaf.icons;
import java.awt.BasicStroke;
import java.awt.Color; import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Line2D;
import javax.swing.UIManager; import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.ui.FlatUIUtils;
@@ -47,20 +44,15 @@ public class FlatFileChooserUpFolderIcon
/* /*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd"> <g fill="none" fill-rule="evenodd">
<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"/> <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"/>
<line x1="8" x2="8" y1="6.5" y2="11.5" stroke="#389FD6" stroke-linecap="round"/> <path fill="#389FD6" d="M12,4 L12,8 L10,8 L10,4 L8,4 L11,1 L14,4 L12,4 Z"/>
<polyline stroke="#389FD6" stroke-linecap="round" stroke-linejoin="round" points="5.5 9 8 6.5 10.5 9"/>
</g> </g>
</svg> </svg>
*/ */
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE ); 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.setStroke( new BasicStroke( 1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) );
g.draw( FlatFileViewDirectoryIcon.createFolderPath() );
g.setColor( blueColor ); g.setColor( blueColor );
g.draw( new Line2D.Float( 8, 6.5f, 8, 11.5f ) ); g.fill( FlatUIUtils.createPath( 12,4, 12,8, 10,8, 10,4, 8,4, 11,1, 14,4, 12,4 ) );
g.draw( FlatUIUtils.createPath( false, 5.5,9, 8,6.5, 10.5,9 ) );
} }
} }

View File

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

View File

@@ -18,8 +18,6 @@ package com.formdev.flatlaf.icons;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Path2D;
import javax.swing.UIManager; import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.ui.FlatUIUtils;
@@ -33,8 +31,6 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
public class FlatFileViewDirectoryIcon public class FlatFileViewDirectoryIcon
extends FlatAbstractIcon extends FlatAbstractIcon
{ {
private Path2D path;
public FlatFileViewDirectoryIcon() { public FlatFileViewDirectoryIcon() {
super( 16, 16, UIManager.getColor( "Objects.Grey" ) ); super( 16, 16, UIManager.getColor( "Objects.Grey" ) );
} }
@@ -43,32 +39,10 @@ public class FlatFileViewDirectoryIcon
protected void paintIcon( Component c, Graphics2D g ) { protected void paintIcon( Component c, Graphics2D g ) {
/* /*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<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"/> <polygon fill="#6E6E6E" fill-rule="evenodd" points="1 2 6 2 8 4 15 4 15 13 1 13"/>
</svg> </svg>
*/ */
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE ); g.fill( FlatUIUtils.createPath( 1,2, 6,2, 8,4, 15,4, 15,13, 1,13 ) );
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,11 +16,8 @@
package com.formdev.flatlaf.icons; package com.formdev.flatlaf.icons;
import java.awt.BasicStroke;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Path2D;
import javax.swing.UIManager; import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.ui.FlatUIUtils;
@@ -34,8 +31,6 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
public class FlatFileViewFileIcon public class FlatFileViewFileIcon
extends FlatAbstractIcon extends FlatAbstractIcon
{ {
private Path2D path;
public FlatFileViewFileIcon() { public FlatFileViewFileIcon() {
super( 16, 16, UIManager.getColor( "Objects.Grey" ) ); super( 16, 16, UIManager.getColor( "Objects.Grey" ) );
} }
@@ -44,33 +39,14 @@ public class FlatFileViewFileIcon
protected void paintIcon( Component c, Graphics2D g ) { protected void paintIcon( Component c, Graphics2D g ) {
/* /*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd" stroke-linejoin="round"> <g fill="none" fill-rule="evenodd">
<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"/> <polygon fill="#6E6E6E" points="8 6 8 1 13 1 13 15 3 15 3 6"/>
<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"/> <polygon fill="#6E6E6E" points="3 5 7 5 7 1"/>
</g> </g>
</svg> </svg>
*/ */
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE ); g.fill( FlatUIUtils.createPath( 8,6, 8,1, 13,1, 13,15, 3,15, 3,6 ) );
g.setStroke( new BasicStroke( 1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) ); g.fill( FlatUIUtils.createPath( 3,5, 7,5, 7,1 ) );
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,10 +16,9 @@
package com.formdev.flatlaf.icons; package com.formdev.flatlaf.icons;
import java.awt.BasicStroke;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.RenderingHints; import java.awt.geom.Path2D;
import javax.swing.UIManager; import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.ui.FlatUIUtils;
@@ -41,22 +40,18 @@ public class FlatFileViewFloppyDriveIcon
protected void paintIcon( Component c, Graphics2D g ) { protected void paintIcon( Component c, Graphics2D g ) {
/* /*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd" stroke-linejoin="round"> <g fill="none" fill-rule="evenodd">
<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"/> <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"/>
<polyline stroke="#6E6E6E" points="4.5 13 4.5 9.5 11.5 9.5 11.5 13"/> <rect width="4" height="2" x="6" y="12" fill="#6E6E6E"/>
<polyline stroke="#6E6E6E" points="5.5 3 5.5 5.5 10.5 5.5 10.5 3"/>
</g> </g>
</svg> </svg>
*/ */
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE ); Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
g.setStroke( new BasicStroke( 1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) ); 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.draw( FlatUIUtils.createPath( 3.5,2.5, 11.5,2.5, 11.5,2.5, 13.5,4.5, g.fillRect( 6, 12, 4, 2 );
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,12 +16,10 @@
package com.formdev.flatlaf.icons; package com.formdev.flatlaf.icons;
import java.awt.BasicStroke;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.RenderingHints; import java.awt.geom.Path2D;
import java.awt.geom.Ellipse2D; import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import javax.swing.UIManager; import javax.swing.UIManager;
/** /**
@@ -42,19 +40,14 @@ public class FlatFileViewHardDriveIcon
protected void paintIcon( Component c, Graphics2D g ) { protected void paintIcon( Component c, Graphics2D g ) {
/* /*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <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" 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"/>
<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> </svg>
*/ */
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE ); Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
g.setStroke( new BasicStroke( 1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) ); path.append( new Rectangle2D.Float( 2, 6, 12, 4 ), false );
path.append( new Rectangle2D.Float( 12, 8, 1, 1 ), false );
g.draw( new RoundRectangle2D.Float( 2.5f, 5.5f, 11, 5, 2, 2 ) ); path.append( new Rectangle2D.Float( 10, 8, 1, 1 ), false );
g.fill( new Ellipse2D.Float( 10.8f, 7.8f, 1.4f, 1.4f ) ); g.fill( path );
g.fill( new Ellipse2D.Float( 8.8f, 7.8f, 1.4f, 1.4f ) );
} }
} }

View File

@@ -17,11 +17,9 @@
package com.formdev.flatlaf.icons; package com.formdev.flatlaf.icons;
import static com.formdev.flatlaf.util.UIScale.*; import static com.formdev.flatlaf.util.UIScale.*;
import java.awt.BasicStroke;
import java.awt.Color; import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Ellipse2D; import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D; import java.awt.geom.Path2D;
import java.util.Map; import java.util.Map;
@@ -86,11 +84,6 @@ public class FlatHelpButtonIcon
return FlatStylingSupport.getAnnotatedStyleableInfos( this ); return FlatStylingSupport.getAnnotatedStyleableInfos( this );
} }
/** @since 2.5 */
public Object getStyleableValue( String key ) {
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
}
@Override @Override
protected void paintIcon( Component c, Graphics2D g2 ) { protected void paintIcon( Component c, Graphics2D g2 ) {
/* /*
@@ -98,14 +91,13 @@ public class FlatHelpButtonIcon
<g fill="none" fill-rule="evenodd"> <g fill="none" fill-rule="evenodd">
<circle cx="11" cy="11" r="10.5" fill="#6E6E6E"/> <circle cx="11" cy="11" r="10.5" fill="#6E6E6E"/>
<circle cx="11" cy="11" r="9.5" fill="#FFF"/> <circle cx="11" cy="11" r="9.5" fill="#FFF"/>
<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"/> <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"/>
<circle cx="11" cy="16" r="1.2" fill="#6E6E6E"/>
</g> </g>
</svg> </svg>
*/ */
boolean enabled = c == null || c.isEnabled(); boolean enabled = c.isEnabled();
boolean focused = c != null && FlatUIUtils.isPermanentFocusOwner( c ); boolean focused = FlatUIUtils.isPermanentFocusOwner( c );
float xy = 0.5f; float xy = 0.5f;
float wh = iconSize() - 1; float wh = iconSize() - 1;
@@ -150,19 +142,22 @@ public class FlatHelpButtonIcon
g2.fill( new Ellipse2D.Float( xy, xy, wh, wh ) ); g2.fill( new Ellipse2D.Float( xy, xy, wh, wh ) );
// paint question mark // paint question mark
Path2D q = new Path2D.Float( Path2D.WIND_NON_ZERO, 10 ); Path2D q = new Path2D.Float();
q.moveTo( 8,8.5 ); q.moveTo( 11, 5 );
q.curveTo( 8.25,7, 9.66585007,6, 11,6 ); q.curveTo( 8.8,5, 7,6.8, 7,9 );
q.curveTo( 12.5,6, 14,7, 14,8.5 ); q.lineTo( 9, 9 );
q.curveTo( 14,10.5, 11,11, 11,13 ); q.curveTo( 9,7.9, 9.9,7, 11,7 );
q.curveTo( 12.1,7, 13,7.9, 13,9 );
g2.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE ); q.curveTo( 13,11, 10,10.75, 10,14 );
g2.setStroke( new BasicStroke( 2, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) ); 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();
g2.translate( focusWidth, focusWidth ); g2.translate( focusWidth, focusWidth );
g2.setColor( enabled ? questionMarkColor : disabledQuestionMarkColor ); g2.setColor( enabled ? questionMarkColor : disabledQuestionMarkColor );
g2.draw( q ); g2.fill( q );
g2.fill( new Ellipse2D.Float( 9.8f, 14.8f, 2.4f, 2.4f ) ); g2.fillRect( 10, 15, 2, 2 );
} }
@Override @Override

View File

@@ -20,6 +20,7 @@ import java.awt.BasicStroke;
import java.awt.Color; import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D; import java.awt.geom.Path2D;
import javax.swing.UIManager; import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatButtonUI; import com.formdev.flatlaf.ui.FlatButtonUI;
@@ -53,15 +54,13 @@ public class FlatInternalFrameCloseIcon
g.setColor( FlatButtonUI.buttonStateColor( c, c.getForeground(), null, null, hoverForeground, pressedForeground ) ); g.setColor( FlatButtonUI.buttonStateColor( c, c.getForeground(), null, null, hoverForeground, pressedForeground ) );
float mx = width / 2f; float mx = width / 2;
float my = height / 2f; float my = height / 2;
float r = 3.25f; float r = 3.25f;
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD, 4 ); Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
path.moveTo( mx - r, my - r ); path.append( new Line2D.Float( mx - r, my - r, mx + r, my + r ), false );
path.lineTo( mx + r, my + r ); path.append( new Line2D.Float( mx - r, my + r, mx + r, my - r ), false );
path.moveTo( mx - r, my + r );
path.lineTo( mx + r, my - r );
g.setStroke( new BasicStroke( 1f ) ); g.setStroke( new BasicStroke( 1f ) );
g.draw( path ); g.draw( path );
} }

View File

@@ -61,14 +61,9 @@ public class FlatMenuArrowIcon
return FlatStylingSupport.getAnnotatedStyleableInfos( this ); return FlatStylingSupport.getAnnotatedStyleableInfos( this );
} }
/** @since 2.5 */
public Object getStyleableValue( String key ) {
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
}
@Override @Override
protected void paintIcon( Component c, Graphics2D g ) { protected void paintIcon( Component c, Graphics2D g ) {
if( c != null && !c.getComponentOrientation().isLeftToRight() ) if( !c.getComponentOrientation().isLeftToRight() )
g.rotate( Math.toRadians( 180 ), width / 2., height / 2. ); g.rotate( Math.toRadians( 180 ), width / 2., height / 2. );
g.setColor( getArrowColor( c ) ); g.setColor( getArrowColor( c ) );
@@ -87,7 +82,7 @@ public class FlatMenuArrowIcon
if( c instanceof JMenu && ((JMenu)c).isSelected() && !isUnderlineSelection() ) if( c instanceof JMenu && ((JMenu)c).isSelected() && !isUnderlineSelection() )
return selectionForeground; return selectionForeground;
return c == null || c.isEnabled() ? arrowColor : disabledArrowColor; return c.isEnabled() ? arrowColor : disabledArrowColor;
} }
protected boolean isUnderlineSelection() { protected boolean isUnderlineSelection() {

View File

@@ -21,16 +21,14 @@ import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
/** /**
* "arrow" icon for {@link javax.swing.JMenuItem}, {@link javax.swing.JCheckBoxMenuItem} * "arrow" icon for {@link javax.swing.JMenuItem}.
* and {@link javax.swing.JRadioButtonMenuItem}.
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatMenuItemArrowIcon public class FlatMenuItemArrowIcon
extends FlatAbstractIcon extends FlatMenuArrowIcon
{ {
public FlatMenuItemArrowIcon() { public FlatMenuItemArrowIcon() {
super( 6, 10, null );
} }
@Override @Override

View File

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

View File

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

View File

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

View File

@@ -17,9 +17,8 @@
package com.formdev.flatlaf.icons; package com.formdev.flatlaf.icons;
import java.awt.Shape; import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D; import java.awt.geom.Path2D;
import java.awt.geom.RoundRectangle2D; import java.awt.geom.Rectangle2D;
import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.ui.FlatUIUtils;
/** /**
@@ -40,24 +39,23 @@ public class FlatOptionPaneWarningIcon
/* /*
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"> <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
<g fill="none" fill-rule="evenodd"> <g fill="none" fill-rule="evenodd">
<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"/> <polygon fill="#EDA200" points="16 2 31 28 1 28"/>
<rect width="4" height="11" x="14" y="8" fill="#FFF" rx="2"/> <rect width="4" height="8" x="14" y="10" fill="#FFF"/>
<circle cx="16" cy="23" r="2" fill="#FFF"/> <rect width="4" height="4" x="14" y="21" fill="#FFF"/>
</g> </g>
</svg> </svg>
*/ */
@Override @Override
protected Shape createOutside() { protected Shape createOutside() {
return FlatUIUtils.createRoundTrianglePath( 16,0, 32,28, 0,28, 4 ); return FlatUIUtils.createPath( 16,2, 31,28, 1,28 );
} }
@Override @Override
protected Shape createInside() { protected Shape createInside() {
Path2D inside = new Path2D.Float( Path2D.WIND_EVEN_ODD ); Path2D inside = new Path2D.Float( Path2D.WIND_EVEN_ODD );
inside.append( new RoundRectangle2D.Float( 14, 8, 4, 11, 4, 4 ), false ); inside.append( new Rectangle2D.Float( 14, 10, 4, 8 ), false );
inside.append( new Ellipse2D.Float( 14, 21, 4, 4 ), false ); inside.append( new Rectangle2D.Float( 14, 21, 4, 4 ), false );
return inside; return inside;
} }
} }

View File

@@ -1,56 +0,0 @@
/*
* Copyright 2021 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.icons;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import javax.swing.UIManager;
/**
* "eye" icon for {@link javax.swing.JPasswordField}.
*
* @uiDefault PasswordField.revealIconColor Color
*
* @author Karl Tauber
* @since 2
*/
public class FlatRevealIcon
extends FlatAbstractIcon
{
public FlatRevealIcon() {
super( 16, 16, UIManager.getColor( "PasswordField.revealIconColor" ) );
}
@Override
protected void paintIcon( Component c, Graphics2D g ) {
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
path.append( new Ellipse2D.Float( 5.15f, 6.15f, 5.7f, 5.7f ), false );
path.append( new Ellipse2D.Float( 6, 7, 4, 4 ), false );
g.fill( path );
Path2D path2 = new Path2D.Float( Path2D.WIND_EVEN_ODD );
path2.append( new Ellipse2D.Float( 2.15f, 4.15f, 11.7f, 11.7f ), false );
path2.append( new Ellipse2D.Float( 3, 5, 10, 10 ), false );
Area area = new Area( path2 );
area.subtract( new Area( new Rectangle2D.Float( 0, 9.5f, 16, 16 ) ) );
g.fill( area );
}
}

View File

@@ -45,17 +45,8 @@ public class FlatSearchIcon
@Styleable protected Color searchIconHoverColor = UIManager.getColor( "SearchField.searchIconHoverColor" ); @Styleable protected Color searchIconHoverColor = UIManager.getColor( "SearchField.searchIconHoverColor" );
@Styleable protected Color searchIconPressedColor = UIManager.getColor( "SearchField.searchIconPressedColor" ); @Styleable protected Color searchIconPressedColor = UIManager.getColor( "SearchField.searchIconPressedColor" );
private final boolean ignoreButtonState;
private Area area;
public FlatSearchIcon() { public FlatSearchIcon() {
this( false );
}
/** @since 2 */
public FlatSearchIcon( boolean ignoreButtonState ) {
super( 16, 16, null ); super( 16, 16, null );
this.ignoreButtonState = ignoreButtonState;
} }
/** @since 2 */ /** @since 2 */
@@ -68,11 +59,6 @@ public class FlatSearchIcon
return FlatStylingSupport.getAnnotatedStyleableInfos( this ); return FlatStylingSupport.getAnnotatedStyleableInfos( this );
} }
/** @since 2.5 */
public Object getStyleableValue( String key ) {
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
}
@Override @Override
protected void paintIcon( Component c, Graphics2D g ) { protected void paintIcon( Component c, Graphics2D g ) {
/* /*
@@ -84,17 +70,13 @@ public class FlatSearchIcon
</svg> </svg>
*/ */
g.setColor( ignoreButtonState g.setColor( FlatButtonUI.buttonStateColor( c, searchIconColor, searchIconColor,
? searchIconColor
: FlatButtonUI.buttonStateColor( c, searchIconColor, searchIconColor,
null, searchIconHoverColor, searchIconPressedColor ) ); null, searchIconHoverColor, searchIconPressedColor ) );
// paint magnifier // paint magnifier
if( area == null ) { Area area = new Area( new Ellipse2D.Float( 2, 2, 10, 10 ) );
area = new Area( new Ellipse2D.Float( 2, 2, 10, 10 ) );
area.subtract( new Area( new Ellipse2D.Float( 3, 3, 8, 8 ) ) ); 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 ) ) ); area.add( new Area( FlatUIUtils.createPath( 10.813,9.75, 14,12.938, 12.938,14, 9.75,10.813 ) ) );
}
g.fill( area ); g.fill( area );
} }
} }

View File

@@ -30,12 +30,6 @@ public class FlatSearchWithHistoryIcon
extends FlatSearchIcon extends FlatSearchIcon
{ {
public FlatSearchWithHistoryIcon() { public FlatSearchWithHistoryIcon() {
this( false );
}
/** @since 2 */
public FlatSearchWithHistoryIcon( boolean ignoreButtonState ) {
super( ignoreButtonState );
} }
@Override @Override

View File

@@ -21,6 +21,7 @@ import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D; import java.awt.geom.Path2D;
import java.util.Map; import java.util.Map;
import javax.swing.UIManager; import javax.swing.UIManager;
@@ -75,11 +76,6 @@ public class FlatTabbedPaneCloseIcon
return FlatStylingSupport.getAnnotatedStyleableInfos( this ); return FlatStylingSupport.getAnnotatedStyleableInfos( this );
} }
/** @since 2.5 */
public Object getStyleableValue( String key ) {
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
}
@Override @Override
protected void paintIcon( Component c, Graphics2D g ) { protected void paintIcon( Component c, Graphics2D g ) {
// paint background // paint background
@@ -94,16 +90,14 @@ public class FlatTabbedPaneCloseIcon
Color fg = FlatButtonUI.buttonStateColor( c, closeForeground, null, null, closeHoverForeground, closePressedForeground ); Color fg = FlatButtonUI.buttonStateColor( c, closeForeground, null, null, closeHoverForeground, closePressedForeground );
g.setColor( FlatUIUtils.deriveColor( fg, c.getForeground() ) ); g.setColor( FlatUIUtils.deriveColor( fg, c.getForeground() ) );
float mx = width / 2f; float mx = width / 2;
float my = height / 2f; float my = height / 2;
float r = ((bg != null) ? closeCrossFilledSize : closeCrossPlainSize) / 2; float r = ((bg != null) ? closeCrossFilledSize : closeCrossPlainSize) / 2;
// paint cross // paint cross
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD, 4 ); Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
path.moveTo( mx - r, my - r ); path.append( new Line2D.Float( mx - r, my - r, mx + r, my + r ), false );
path.lineTo( mx + r, my + r ); path.append( new Line2D.Float( mx - r, my + r, mx + r, my - r ), false );
path.moveTo( mx - r, my + r );
path.lineTo( mx + r, my - r );
g.setStroke( new BasicStroke( closeCrossLineWidth ) ); g.setStroke( new BasicStroke( closeCrossLineWidth ) );
g.draw( path ); g.draw( path );
} }

View File

@@ -18,9 +18,8 @@ package com.formdev.flatlaf.icons;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Path2D;
import javax.swing.UIManager; import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatUIUtils;
/** /**
* "closed" icon for {@link javax.swing.JTree} used by {@link javax.swing.tree.DefaultTreeCellRenderer}. * "closed" icon for {@link javax.swing.JTree} used by {@link javax.swing.tree.DefaultTreeCellRenderer}.
@@ -32,8 +31,6 @@ import javax.swing.UIManager;
public class FlatTreeClosedIcon public class FlatTreeClosedIcon
extends FlatAbstractIcon extends FlatAbstractIcon
{ {
private Path2D path;
public FlatTreeClosedIcon() { public FlatTreeClosedIcon() {
super( 16, 16, UIManager.getColor( "Tree.icon.closedColor" ) ); super( 16, 16, UIManager.getColor( "Tree.icon.closedColor" ) );
} }
@@ -44,14 +41,10 @@ public class FlatTreeClosedIcon
/* /*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<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"/> <polygon fill="#6E6E6E" fill-rule="evenodd" points="1 2 6 2 8 4 15 4 15 13 1 13"/>
</svg> </svg>
*/ */
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE ); g.fill( FlatUIUtils.createPath( 1,2, 6,2, 8,4, 15,4, 15,13, 1,13 ) );
if( path == null )
path = FlatFileViewDirectoryIcon.createFolderPath();
g.draw( path );
} }
} }

View File

@@ -16,11 +16,9 @@
package com.formdev.flatlaf.icons; package com.formdev.flatlaf.icons;
import java.awt.BasicStroke;
import java.awt.Color; import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.geom.Path2D;
import java.util.function.Function; import java.util.function.Function;
import javax.swing.JTree; import javax.swing.JTree;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
@@ -41,7 +39,6 @@ public class FlatTreeCollapsedIcon
extends FlatAbstractIcon extends FlatAbstractIcon
{ {
private final boolean chevron; private final boolean chevron;
private Path2D path;
public FlatTreeCollapsedIcon() { public FlatTreeCollapsedIcon() {
this( UIManager.getColor( "Tree.icon.collapsedColor" ) ); this( UIManager.getColor( "Tree.icon.collapsedColor" ) );
@@ -62,15 +59,10 @@ public class FlatTreeCollapsedIcon
if( chevron ) { if( chevron ) {
// chevron arrow // chevron arrow
g.setStroke( new BasicStroke( 1f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER ) ); 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 ) );
if( path == null )
path = FlatUIUtils.createPath( false, 3.5,1.5, 7.5,5.5, 3.5,9.5 );
g.draw( path );
} else { } else {
// triangle arrow // triangle arrow
if( path == null ) g.fill( FlatUIUtils.createPath( 2,1, 2,10, 10,5.5 ) );
path = FlatUIUtils.createPath( 2,1, 2,10, 10,5.5 );
g.fill( path );
} }
} }
@@ -84,7 +76,7 @@ public class FlatTreeCollapsedIcon
} }
/** /**
* Because this icon is always shared for all trees, * Because this icons are always shared for all trees,
* get icon specific style from FlatTreeUI. * get icon specific style from FlatTreeUI.
*/ */
static <T> T getStyleFromTreeUI( Component c, Function<FlatTreeUI, T> f ) { static <T> T getStyleFromTreeUI( Component c, Function<FlatTreeUI, T> f ) {

View File

@@ -16,14 +16,10 @@
package com.formdev.flatlaf.icons; package com.formdev.flatlaf.icons;
import java.awt.BasicStroke;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Line2D;
import java.awt.geom.RoundRectangle2D;
import javax.swing.UIManager; import javax.swing.UIManager;
import com.formdev.flatlaf.util.ColorFunctions; import com.formdev.flatlaf.ui.FlatUIUtils;
/** /**
* "leaf" icon for {@link javax.swing.JTree} used by {@link javax.swing.tree.DefaultTreeCellRenderer}. * "leaf" icon for {@link javax.swing.JTree} used by {@link javax.swing.tree.DefaultTreeCellRenderer}.
@@ -46,22 +42,13 @@ public class FlatTreeLeafIcon
/* /*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd"> <g fill="none" fill-rule="evenodd">
<rect width="11" height="13" x="2.5" y="1.5" stroke="#6E6E6E" rx="1.5"/> <polygon fill="#6E6E6E" points="8 6 8 1 13 1 13 15 3 15 3 6"/>
<line x1="5.5" x2="10.5" y1="5.5" y2="5.5" stroke="#6E6E6E" stroke-linecap="round" stroke-opacity=".6"/> <polygon fill="#6E6E6E" points="3 5 7 5 7 1"/>
<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> </g>
</svg> </svg>
*/ */
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE ); g.fill( FlatUIUtils.createPath( 8,6, 8,1, 13,1, 13,15, 3,15, 3,6 ) );
g.setStroke( new BasicStroke( 1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) ); g.fill( FlatUIUtils.createPath( 3,5, 7,5, 7,1 ) );
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,11 +16,8 @@
package com.formdev.flatlaf.icons; package com.formdev.flatlaf.icons;
import java.awt.BasicStroke;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Path2D;
import javax.swing.UIManager; import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.ui.FlatUIUtils;
@@ -34,8 +31,6 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
public class FlatTreeOpenIcon public class FlatTreeOpenIcon
extends FlatAbstractIcon extends FlatAbstractIcon
{ {
private Path2D path;
public FlatTreeOpenIcon() { public FlatTreeOpenIcon() {
super( 16, 16, UIManager.getColor( "Tree.icon.openColor" ) ); super( 16, 16, UIManager.getColor( "Tree.icon.openColor" ) );
} }
@@ -46,38 +41,14 @@ public class FlatTreeOpenIcon
/* /*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<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"/> <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>
</svg> </svg>
*/ */
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE ); g.fill( FlatUIUtils.createPath( 1,2, 6,2, 8,4, 14,4, 14,6, 3.5,6, 1,11 ) );
g.setStroke( new BasicStroke( 1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER ) ); g.fill( FlatUIUtils.createPath( 4,7, 16,7, 13,13, 1,13 ) );
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,7 @@ import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.RenderingHints; import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatButtonUI; import com.formdev.flatlaf.ui.FlatButtonUI;
import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.util.HiDPIUtils; import com.formdev.flatlaf.util.HiDPIUtils;
@@ -29,7 +29,6 @@ import com.formdev.flatlaf.util.HiDPIUtils;
* Base class for window icons. * Base class for window icons.
* *
* @uiDefault TitlePane.buttonSize Dimension * @uiDefault TitlePane.buttonSize Dimension
* @uiDefault TitlePane.buttonSymbolHeight int
* @uiDefault TitlePane.buttonHoverBackground Color * @uiDefault TitlePane.buttonHoverBackground Color
* @uiDefault TitlePane.buttonPressedBackground Color * @uiDefault TitlePane.buttonPressedBackground Color
* *
@@ -38,22 +37,17 @@ import com.formdev.flatlaf.util.HiDPIUtils;
public abstract class FlatWindowAbstractIcon public abstract class FlatWindowAbstractIcon
extends FlatAbstractIcon extends FlatAbstractIcon
{ {
private final int symbolHeight;
private final Color hoverBackground; private final Color hoverBackground;
private final Color pressedBackground; private final Color pressedBackground;
/** @since 3.2 */ public FlatWindowAbstractIcon() {
protected FlatWindowAbstractIcon( String windowStyle ) { this( UIManager.getDimension( "TitlePane.buttonSize" ),
this( FlatUIUtils.getSubUIDimension( "TitlePane.buttonSize", windowStyle ), UIManager.getColor( "TitlePane.buttonHoverBackground" ),
FlatUIUtils.getSubUIInt( "TitlePane.buttonSymbolHeight", windowStyle, 10 ), UIManager.getColor( "TitlePane.buttonPressedBackground" ) );
FlatUIUtils.getSubUIColor( "TitlePane.buttonHoverBackground", windowStyle ),
FlatUIUtils.getSubUIColor( "TitlePane.buttonPressedBackground", windowStyle ) );
} }
/** @since 3.2 */ public FlatWindowAbstractIcon( Dimension size, Color hoverBackground, Color pressedBackground ) {
protected FlatWindowAbstractIcon( Dimension size, int symbolHeight, Color hoverBackground, Color pressedBackground ) {
super( size.width, size.height, null ); super( size.width, size.height, null );
this.symbolHeight = symbolHeight;
this.hoverBackground = hoverBackground; this.hoverBackground = hoverBackground;
this.pressedBackground = pressedBackground; this.pressedBackground = pressedBackground;
} }
@@ -71,23 +65,12 @@ public abstract class FlatWindowAbstractIcon
protected void paintBackground( Component c, Graphics2D g ) { protected void paintBackground( Component c, Graphics2D g ) {
Color background = FlatButtonUI.buttonStateColor( c, null, null, null, hoverBackground, pressedBackground ); Color background = FlatButtonUI.buttonStateColor( c, null, null, null, hoverBackground, pressedBackground );
if( background != null ) { if( background != null ) {
// disable antialiasing for background rectangle painting to avoid blury edges when scaled (e.g. at 125% or 175%)
Object oldHint = g.getRenderingHint( RenderingHints.KEY_ANTIALIASING );
g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF );
g.setColor( FlatUIUtils.deriveColor( background, c.getBackground() ) ); g.setColor( FlatUIUtils.deriveColor( background, c.getBackground() ) );
g.fillRect( 0, 0, width, height ); g.fillRect( 0, 0, width, height );
g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, oldHint );
} }
} }
protected Color getForeground( Component c ) { protected Color getForeground( Component c ) {
return c.getForeground(); return c.getForeground();
} }
/** @since 3.2 */
protected int getSymbolHeight() {
return symbolHeight;
}
} }

View File

@@ -20,10 +20,10 @@ import java.awt.BasicStroke;
import java.awt.Color; import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D; import java.awt.geom.Path2D;
import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatButtonUI; import com.formdev.flatlaf.ui.FlatButtonUI;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.util.SystemInfo;
/** /**
* "close" icon for windows (frames and dialogs). * "close" icon for windows (frames and dialogs).
@@ -38,38 +38,27 @@ import com.formdev.flatlaf.util.SystemInfo;
public class FlatWindowCloseIcon public class FlatWindowCloseIcon
extends FlatWindowAbstractIcon extends FlatWindowAbstractIcon
{ {
private final Color hoverForeground; private final Color hoverForeground = UIManager.getColor( "TitlePane.closeHoverForeground" );
private final Color pressedForeground; private final Color pressedForeground = UIManager.getColor( "TitlePane.closePressedForeground" );
public FlatWindowCloseIcon() { public FlatWindowCloseIcon() {
this( null ); super( UIManager.getDimension( "TitlePane.buttonSize" ),
} UIManager.getColor( "TitlePane.closeHoverBackground" ),
UIManager.getColor( "TitlePane.closePressedBackground" ) );
/** @since 3.2 */
public FlatWindowCloseIcon( String windowStyle ) {
super( FlatUIUtils.getSubUIDimension( "TitlePane.buttonSize", windowStyle ),
FlatUIUtils.getSubUIInt( "TitlePane.buttonSymbolHeight", windowStyle, 10 ),
FlatUIUtils.getSubUIColor( "TitlePane.closeHoverBackground", windowStyle ),
FlatUIUtils.getSubUIColor( "TitlePane.closePressedBackground", windowStyle ) );
hoverForeground = FlatUIUtils.getSubUIColor( "TitlePane.closeHoverForeground", windowStyle );
pressedForeground = FlatUIUtils.getSubUIColor( "TitlePane.closePressedForeground", windowStyle );
} }
@Override @Override
protected void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) { protected void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
int iwh = (int) (getSymbolHeight() * scaleFactor); int iwh = (int) (10 * scaleFactor);
int ix = x + ((width - iwh) / 2); int ix = x + ((width - iwh) / 2);
int iy = y + ((height - iwh) / 2); int iy = y + ((height - iwh) / 2);
int ix2 = ix + iwh - 1; int ix2 = ix + iwh - 1;
int iy2 = iy + iwh - 1; int iy2 = iy + iwh - 1;
float thickness = SystemInfo.isWindows_11_orLater ? (float) scaleFactor : (int) scaleFactor; int thickness = (int) scaleFactor;
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD, 4 ); Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
path.moveTo( ix, iy ); path.append( new Line2D.Float( ix, iy, ix2, iy2 ), false );
path.lineTo( ix2, iy2 ); path.append( new Line2D.Float( ix, iy2, ix2, iy ), false );
path.moveTo( ix, iy2 );
path.lineTo( ix2, iy );
g.setStroke( new BasicStroke( thickness ) ); g.setStroke( new BasicStroke( thickness ) );
g.draw( path ); g.draw( path );
} }

View File

@@ -27,17 +27,11 @@ public class FlatWindowIconifyIcon
extends FlatWindowAbstractIcon extends FlatWindowAbstractIcon
{ {
public FlatWindowIconifyIcon() { public FlatWindowIconifyIcon() {
this( null );
}
/** @since 3.2 */
public FlatWindowIconifyIcon( String windowStyle ) {
super( windowStyle );
} }
@Override @Override
protected void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) { protected void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
int iw = (int) (getSymbolHeight() * scaleFactor); int iw = (int) (10 * scaleFactor);
int ih = (int) scaleFactor; int ih = (int) scaleFactor;
int ix = x + ((width - iw) / 2); int ix = x + ((width - iw) / 2);
int iy = y + ((height - ih) / 2); int iy = y + ((height - ih) / 2);

View File

@@ -18,7 +18,6 @@ package com.formdev.flatlaf.icons;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.util.SystemInfo;
/** /**
* "maximize" icon for windows (frames and dialogs). * "maximize" icon for windows (frames and dialogs).
@@ -29,24 +28,15 @@ public class FlatWindowMaximizeIcon
extends FlatWindowAbstractIcon extends FlatWindowAbstractIcon
{ {
public FlatWindowMaximizeIcon() { public FlatWindowMaximizeIcon() {
this( null );
}
/** @since 3.2 */
public FlatWindowMaximizeIcon( String windowStyle ) {
super( windowStyle );
} }
@Override @Override
protected void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) { protected void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
int iwh = (int) (getSymbolHeight() * scaleFactor); int iwh = (int) (10 * scaleFactor);
int ix = x + ((width - iwh) / 2); int ix = x + ((width - iwh) / 2);
int iy = y + ((height - iwh) / 2); int iy = y + ((height - iwh) / 2);
float thickness = SystemInfo.isWindows_11_orLater ? (float) scaleFactor : (int) scaleFactor; int thickness = (int) scaleFactor;
int arc = Math.max( (int) (1.5 * scaleFactor), 2 );
g.fill( SystemInfo.isWindows_11_orLater g.fill( FlatUIUtils.createRectangle( ix, iy, iwh, iwh, thickness ) );
? FlatUIUtils.createRoundRectangle( ix, iy, iwh, iwh, thickness, arc, arc, arc, arc )
: FlatUIUtils.createRectangle( ix, iy, iwh, iwh, thickness ) );
} }
} }

View File

@@ -21,7 +21,6 @@ import java.awt.geom.Area;
import java.awt.geom.Path2D; import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.util.SystemInfo;
/** /**
* "restore" icon for windows (frames and dialogs). * "restore" icon for windows (frames and dialogs).
@@ -32,46 +31,25 @@ public class FlatWindowRestoreIcon
extends FlatWindowAbstractIcon extends FlatWindowAbstractIcon
{ {
public FlatWindowRestoreIcon() { public FlatWindowRestoreIcon() {
this( null );
}
/** @since 3.2 */
public FlatWindowRestoreIcon( String windowStyle ) {
super( windowStyle );
} }
@Override @Override
protected void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) { protected void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
int iwh = (int) (getSymbolHeight() * scaleFactor); int iwh = (int) (10 * scaleFactor);
int ix = x + ((width - iwh) / 2); int ix = x + ((width - iwh) / 2);
int iy = y + ((height - iwh) / 2); int iy = y + ((height - iwh) / 2);
float thickness = SystemInfo.isWindows_11_orLater ? (float) scaleFactor : (int) scaleFactor; int thickness = (int) scaleFactor;
int arc = Math.max( (int) (1.5 * scaleFactor), 2 );
int arcOuter = (int) (arc + (1.5 * scaleFactor));
int rwh = (int) ((getSymbolHeight() - 2) * scaleFactor); int rwh = (int) (8 * scaleFactor);
int ro2 = iwh - rwh; int ro2 = iwh - rwh;
// upper-right rectangle Path2D r1 = FlatUIUtils.createRectangle( ix + ro2, iy, rwh, rwh, thickness );
Path2D r1 = SystemInfo.isWindows_11_orLater Path2D r2 = FlatUIUtils.createRectangle( ix, iy + ro2, rwh, rwh, thickness );
? FlatUIUtils.createRoundRectangle( ix + ro2, iy, rwh, rwh, thickness, arc, arcOuter, arc, arc )
: FlatUIUtils.createRectangle( ix + ro2, iy, rwh, rwh, thickness );
// lower-left rectangle
Path2D r2 = SystemInfo.isWindows_11_orLater
? FlatUIUtils.createRoundRectangle( ix, iy + ro2, rwh, rwh, thickness, arc, arc, arc, arc )
: FlatUIUtils.createRectangle( ix, iy + ro2, rwh, rwh, thickness );
// paint upper-right rectangle
Area area = new Area( r1 ); Area area = new Area( r1 );
if( SystemInfo.isWindows_11_orLater ) {
area.subtract( new Area( new Rectangle2D.Float( ix, (float) (iy + scaleFactor), rwh, rwh ) ) );
area.subtract( new Area( new Rectangle2D.Float( (float) (ix + scaleFactor), iy + ro2, rwh, rwh ) ) );
} else
area.subtract( new Area( new Rectangle2D.Float( ix, iy + ro2, rwh, rwh ) ) ); area.subtract( new Area( new Rectangle2D.Float( ix, iy + ro2, rwh, rwh ) ) );
g.fill( area ); g.fill( area );
// paint lower-left rectangle
g.fill( r2 ); g.fill( r2 );
} }
} }

View File

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

View File

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

View File

@@ -18,8 +18,8 @@ package com.formdev.flatlaf.resources;
/** /**
* The only purpose of this file is to add a .class file to this package to make it non-empty. * The only purpose of this file is to add a .class file to this package to make it non-empty.
* Otherwise, the compiler outputs a warning because this package is opened in module-info.java. * Otherwise the compiler outputs a warning because this package is opend in module-info.java.
* Also, when using --patch-module (e.g. from an IDE), an error would occur for empty packages. * Also when using --patch-module (e.g. from an IDE), an error would occur for empty packages.
* *
* @author Karl Tauber * @author Karl Tauber
*/ */

View File

@@ -1,68 +0,0 @@
/*
* 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

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

View File

@@ -101,12 +101,6 @@ public class FlatBorder
return FlatStylingSupport.getAnnotatedStyleableInfos( this ); return FlatStylingSupport.getAnnotatedStyleableInfos( this );
} }
/** @since 2.5 */
@Override
public Object getStyleableValue( String key ) {
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
}
@Override @Override
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) { public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
Graphics2D g2 = (Graphics2D) g.create(); Graphics2D g2 = (Graphics2D) g.create();

View File

@@ -159,7 +159,7 @@ public class FlatButtonBorder
public Insets getBorderInsets( Component c, Insets insets ) { public Insets getBorderInsets( Component c, Insets insets ) {
if( FlatButtonUI.isToolBarButton( c ) ) { if( FlatButtonUI.isToolBarButton( c ) ) {
// In toolbars, use button margin only if explicitly set. // In toolbars, use button margin only if explicitly set.
// Otherwise, use toolbar margin specified in UI defaults. // Otherwise use toolbar margin specified in UI defaults.
Insets margin = (c instanceof AbstractButton) Insets margin = (c instanceof AbstractButton)
? ((AbstractButton)c).getMargin() ? ((AbstractButton)c).getMargin()
: null; : null;

View File

@@ -20,7 +20,6 @@ import static com.formdev.flatlaf.FlatClientProperties.*;
import static com.formdev.flatlaf.util.UIScale.scale; import static com.formdev.flatlaf.util.UIScale.scale;
import java.awt.Color; import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Font; import java.awt.Font;
import java.awt.FontMetrics; import java.awt.FontMetrics;
@@ -39,23 +38,15 @@ import javax.swing.ButtonModel;
import javax.swing.Icon; import javax.swing.Icon;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JTextField;
import javax.swing.JToggleButton; import javax.swing.JToggleButton;
import javax.swing.JToolBar; import javax.swing.JToolBar;
import javax.swing.LookAndFeel; import javax.swing.LookAndFeel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.plaf.ButtonUI; import javax.swing.plaf.ButtonUI;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.ToolBarUI;
import javax.swing.plaf.UIResource; import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicButtonListener; import javax.swing.plaf.basic.BasicButtonListener;
import javax.swing.plaf.basic.BasicButtonUI; import javax.swing.plaf.basic.BasicButtonUI;
import javax.swing.plaf.basic.BasicHTML;
import javax.swing.text.View;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.icons.FlatHelpButtonIcon; import com.formdev.flatlaf.icons.FlatHelpButtonIcon;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable; import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
@@ -83,27 +74,20 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault Button.startBackground Color optional; if set, a gradient paint is used and Button.background is ignored * @uiDefault Button.startBackground Color optional; if set, a gradient paint is used and Button.background is ignored
* @uiDefault Button.endBackground Color optional; if set, a gradient paint is used * @uiDefault Button.endBackground Color optional; if set, a gradient paint is used
* @uiDefault Button.focusedBackground Color optional * @uiDefault Button.focusedBackground Color optional
* @uiDefault Button.focusedForeground Color optional
* @uiDefault Button.hoverBackground Color optional * @uiDefault Button.hoverBackground Color optional
* @uiDefault Button.hoverForeground Color optional
* @uiDefault Button.pressedBackground Color optional * @uiDefault Button.pressedBackground Color optional
* @uiDefault Button.pressedForeground Color optional
* @uiDefault Button.selectedBackground Color * @uiDefault Button.selectedBackground Color
* @uiDefault Button.selectedForeground Color * @uiDefault Button.selectedForeground Color
* @uiDefault Button.disabledBackground Color optional * @uiDefault Button.disabledBackground Color optional
* @uiDefault Button.disabledText Color * @uiDefault Button.disabledText Color
* @uiDefault Button.disabledSelectedBackground Color * @uiDefault Button.disabledSelectedBackground Color
* @uiDefault Button.disabledSelectedForeground Color optional
* @uiDefault Button.default.background Color * @uiDefault Button.default.background Color
* @uiDefault Button.default.startBackground Color optional; if set, a gradient paint is used and Button.default.background is ignored * @uiDefault Button.default.startBackground Color optional; if set, a gradient paint is used and Button.default.background is ignored
* @uiDefault Button.default.endBackground Color optional; if set, a gradient paint is used * @uiDefault Button.default.endBackground Color optional; if set, a gradient paint is used
* @uiDefault Button.default.foreground Color * @uiDefault Button.default.foreground Color
* @uiDefault Button.default.focusedBackground Color optional * @uiDefault Button.default.focusedBackground Color optional
* @uiDefault Button.default.focusedForeground Color optional
* @uiDefault Button.default.hoverBackground Color optional * @uiDefault Button.default.hoverBackground Color optional
* @uiDefault Button.default.hoverForeground Color optional
* @uiDefault Button.default.pressedBackground Color optional * @uiDefault Button.default.pressedBackground Color optional
* @uiDefault Button.default.pressedForeground Color optional
* @uiDefault Button.default.boldText boolean * @uiDefault Button.default.boldText boolean
* @uiDefault Button.paintShadow boolean default is false * @uiDefault Button.paintShadow boolean default is false
* @uiDefault Button.shadowWidth int default is 2 * @uiDefault Button.shadowWidth int default is 2
@@ -111,13 +95,8 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault Button.default.shadowColor Color optional * @uiDefault Button.default.shadowColor Color optional
* @uiDefault Button.toolbar.spacingInsets Insets * @uiDefault Button.toolbar.spacingInsets Insets
* @uiDefault Button.toolbar.hoverBackground Color * @uiDefault Button.toolbar.hoverBackground Color
* @uiDefault Button.toolbar.hoverForeground Color optional
* @uiDefault Button.toolbar.pressedBackground Color * @uiDefault Button.toolbar.pressedBackground Color
* @uiDefault Button.toolbar.pressedForeground Color optional
* @uiDefault Button.toolbar.selectedBackground Color * @uiDefault Button.toolbar.selectedBackground Color
* @uiDefault Button.toolbar.selectedForeground Color optional
* @uiDefault Button.toolbar.disabledSelectedBackground Color optional
* @uiDefault Button.toolbar.disabledSelectedForeground Color optional
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@@ -134,27 +113,20 @@ public class FlatButtonUI
protected Color startBackground; protected Color startBackground;
protected Color endBackground; protected Color endBackground;
@Styleable protected Color focusedBackground; @Styleable protected Color focusedBackground;
/** @since 2.3 */ @Styleable protected Color focusedForeground;
@Styleable protected Color hoverBackground; @Styleable protected Color hoverBackground;
/** @since 2.3 */ @Styleable protected Color hoverForeground;
@Styleable protected Color pressedBackground; @Styleable protected Color pressedBackground;
/** @since 2.3 */ @Styleable protected Color pressedForeground;
@Styleable protected Color selectedBackground; @Styleable protected Color selectedBackground;
@Styleable protected Color selectedForeground; @Styleable protected Color selectedForeground;
@Styleable protected Color disabledBackground; @Styleable protected Color disabledBackground;
@Styleable protected Color disabledText; @Styleable protected Color disabledText;
@Styleable protected Color disabledSelectedBackground; @Styleable protected Color disabledSelectedBackground;
/** @since 2.3 */ @Styleable protected Color disabledSelectedForeground;
@Styleable(dot=true) protected Color defaultBackground; @Styleable(dot=true) protected Color defaultBackground;
protected Color defaultEndBackground; protected Color defaultEndBackground;
@Styleable(dot=true) protected Color defaultForeground; @Styleable(dot=true) protected Color defaultForeground;
@Styleable(dot=true) protected Color defaultFocusedBackground; @Styleable(dot=true) protected Color defaultFocusedBackground;
/** @since 2.3 */ @Styleable(dot=true) protected Color defaultFocusedForeground;
@Styleable(dot=true) protected Color defaultHoverBackground; @Styleable(dot=true) protected Color defaultHoverBackground;
/** @since 2.3 */ @Styleable(dot=true) protected Color defaultHoverForeground;
@Styleable(dot=true) protected Color defaultPressedBackground; @Styleable(dot=true) protected Color defaultPressedBackground;
/** @since 2.3 */ @Styleable(dot=true) protected Color defaultPressedForeground;
@Styleable(dot=true) protected boolean defaultBoldText; @Styleable(dot=true) protected boolean defaultBoldText;
@Styleable protected boolean paintShadow; @Styleable protected boolean paintShadow;
@@ -163,13 +135,8 @@ public class FlatButtonUI
@Styleable(dot=true) protected Color defaultShadowColor; @Styleable(dot=true) protected Color defaultShadowColor;
@Styleable(dot=true) protected Color toolbarHoverBackground; @Styleable(dot=true) protected Color toolbarHoverBackground;
/** @since 2.3 */ @Styleable(dot=true) protected Color toolbarHoverForeground;
@Styleable(dot=true) protected Color toolbarPressedBackground; @Styleable(dot=true) protected Color toolbarPressedBackground;
/** @since 2.3 */ @Styleable(dot=true) protected Color toolbarPressedForeground;
@Styleable(dot=true) protected Color toolbarSelectedBackground; @Styleable(dot=true) protected Color toolbarSelectedBackground;
/** @since 2.3 */ @Styleable(dot=true) protected Color toolbarSelectedForeground;
/** @since 2.3 */ @Styleable(dot=true) protected Color toolbarDisabledSelectedBackground;
/** @since 2.3 */ @Styleable(dot=true) protected Color toolbarDisabledSelectedForeground;
// only used via styling (not in UI defaults, but has likewise client properties) // only used via styling (not in UI defaults, but has likewise client properties)
/** @since 2 */ @Styleable protected String buttonType; /** @since 2 */ @Styleable protected String buttonType;
@@ -186,7 +153,7 @@ public class FlatButtonUI
private AtomicBoolean borderShared; private AtomicBoolean borderShared;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return FlatUIUtils.canUseSharedUI( c ) && !FlatUIUtils.needsLightAWTPeer( c ) return FlatUIUtils.canUseSharedUI( c )
? FlatUIUtils.createSharedUI( FlatButtonUI.class, () -> new FlatButtonUI( true ) ) ? FlatUIUtils.createSharedUI( FlatButtonUI.class, () -> new FlatButtonUI( true ) )
: new FlatButtonUI( false ); : new FlatButtonUI( false );
} }
@@ -198,13 +165,6 @@ public class FlatButtonUI
@Override @Override
public void installUI( JComponent c ) { public void installUI( JComponent c ) {
if( FlatUIUtils.needsLightAWTPeer( c ) )
FlatUIUtils.runWithLightAWTPeerUIDefaults( () -> installUIImpl( c ) );
else
installUIImpl( c );
}
private void installUIImpl( JComponent c ) {
super.installUI( c ); super.installUI( c );
installStyle( (AbstractButton) c ); installStyle( (AbstractButton) c );
@@ -226,27 +186,20 @@ public class FlatButtonUI
startBackground = UIManager.getColor( prefix + "startBackground" ); startBackground = UIManager.getColor( prefix + "startBackground" );
endBackground = UIManager.getColor( prefix + "endBackground" ); endBackground = UIManager.getColor( prefix + "endBackground" );
focusedBackground = UIManager.getColor( prefix + "focusedBackground" ); focusedBackground = UIManager.getColor( prefix + "focusedBackground" );
focusedForeground = UIManager.getColor( prefix + "focusedForeground" );
hoverBackground = UIManager.getColor( prefix + "hoverBackground" ); hoverBackground = UIManager.getColor( prefix + "hoverBackground" );
hoverForeground = UIManager.getColor( prefix + "hoverForeground" );
pressedBackground = UIManager.getColor( prefix + "pressedBackground" ); pressedBackground = UIManager.getColor( prefix + "pressedBackground" );
pressedForeground = UIManager.getColor( prefix + "pressedForeground" );
selectedBackground = UIManager.getColor( prefix + "selectedBackground" ); selectedBackground = UIManager.getColor( prefix + "selectedBackground" );
selectedForeground = UIManager.getColor( prefix + "selectedForeground" ); selectedForeground = UIManager.getColor( prefix + "selectedForeground" );
disabledBackground = UIManager.getColor( prefix + "disabledBackground" ); disabledBackground = UIManager.getColor( prefix + "disabledBackground" );
disabledText = UIManager.getColor( prefix + "disabledText" ); disabledText = UIManager.getColor( prefix + "disabledText" );
disabledSelectedBackground = UIManager.getColor( prefix + "disabledSelectedBackground" ); disabledSelectedBackground = UIManager.getColor( prefix + "disabledSelectedBackground" );
disabledSelectedForeground = UIManager.getColor( prefix + "disabledSelectedForeground" );
defaultBackground = FlatUIUtils.getUIColor( "Button.default.startBackground", "Button.default.background" ); defaultBackground = FlatUIUtils.getUIColor( "Button.default.startBackground", "Button.default.background" );
defaultEndBackground = UIManager.getColor( "Button.default.endBackground" ); defaultEndBackground = UIManager.getColor( "Button.default.endBackground" );
defaultForeground = UIManager.getColor( "Button.default.foreground" ); defaultForeground = UIManager.getColor( "Button.default.foreground" );
defaultFocusedBackground = UIManager.getColor( "Button.default.focusedBackground" ); defaultFocusedBackground = UIManager.getColor( "Button.default.focusedBackground" );
defaultFocusedForeground = UIManager.getColor( "Button.default.focusedForeground" );
defaultHoverBackground = UIManager.getColor( "Button.default.hoverBackground" ); defaultHoverBackground = UIManager.getColor( "Button.default.hoverBackground" );
defaultHoverForeground = UIManager.getColor( "Button.default.hoverForeground" );
defaultPressedBackground = UIManager.getColor( "Button.default.pressedBackground" ); defaultPressedBackground = UIManager.getColor( "Button.default.pressedBackground" );
defaultPressedForeground = UIManager.getColor( "Button.default.pressedForeground" );
defaultBoldText = UIManager.getBoolean( "Button.default.boldText" ); defaultBoldText = UIManager.getBoolean( "Button.default.boldText" );
paintShadow = UIManager.getBoolean( "Button.paintShadow" ); paintShadow = UIManager.getBoolean( "Button.paintShadow" );
@@ -255,13 +208,8 @@ public class FlatButtonUI
defaultShadowColor = UIManager.getColor( "Button.default.shadowColor" ); defaultShadowColor = UIManager.getColor( "Button.default.shadowColor" );
toolbarHoverBackground = UIManager.getColor( prefix + "toolbar.hoverBackground" ); toolbarHoverBackground = UIManager.getColor( prefix + "toolbar.hoverBackground" );
toolbarHoverForeground = UIManager.getColor( prefix + "toolbar.hoverForeground" );
toolbarPressedBackground = UIManager.getColor( prefix + "toolbar.pressedBackground" ); toolbarPressedBackground = UIManager.getColor( prefix + "toolbar.pressedBackground" );
toolbarPressedForeground = UIManager.getColor( prefix + "toolbar.pressedForeground" );
toolbarSelectedBackground = UIManager.getColor( prefix + "toolbar.selectedBackground" ); toolbarSelectedBackground = UIManager.getColor( prefix + "toolbar.selectedBackground" );
toolbarSelectedForeground = UIManager.getColor( prefix + "toolbar.selectedForeground" );
toolbarDisabledSelectedBackground = UIManager.getColor( prefix + "toolbar.disabledSelectedBackground" );
toolbarDisabledSelectedForeground = UIManager.getColor( prefix + "toolbar.disabledSelectedForeground" );
helpButtonIcon = UIManager.getIcon( "HelpButton.icon" ); helpButtonIcon = UIManager.getIcon( "HelpButton.icon" );
defaultMargin = UIManager.getInsets( prefix + "margin" ); defaultMargin = UIManager.getInsets( prefix + "margin" );
@@ -311,15 +259,11 @@ public class FlatButtonUI
b.repaint(); b.repaint();
break; break;
case OUTLINE:
b.repaint();
break;
case STYLE: case STYLE:
case STYLE_CLASS: case STYLE_CLASS:
if( shared && FlatStylingSupport.hasStyleProperty( b ) ) { if( shared && FlatStylingSupport.hasStyleProperty( b ) ) {
// unshare component UI if necessary // unshare component UI if necessary
// updateUI() invokes installStyle() from installUI() // updateUI() invokes applyStyle() from installUI()
b.updateUI(); b.updateUI();
} else } else
installStyle( b ); installStyle( b );
@@ -364,9 +308,6 @@ public class FlatButtonUI
return ((FlatHelpButtonIcon)helpButtonIcon).applyStyleProperty( key, value ); return ((FlatHelpButtonIcon)helpButtonIcon).applyStyleProperty( key, value );
} }
if( "iconTextGap".equals( key ) && value instanceof Integer )
value = UIScale.scale( (Integer) value );
if( borderShared == null ) if( borderShared == null )
borderShared = new AtomicBoolean( true ); borderShared = new AtomicBoolean( true );
return FlatStylingSupport.applyToAnnotatedObjectOrBorder( this, key, value, b, borderShared ); return FlatStylingSupport.applyToAnnotatedObjectOrBorder( this, key, value, b, borderShared );
@@ -381,18 +322,6 @@ public class FlatButtonUI
return infos; return infos;
} }
/** @since 2.5 */
@Override
public Object getStyleableValue( JComponent c, String key ) {
if( key.startsWith( "help." ) ) {
return (helpButtonIcon instanceof FlatHelpButtonIcon)
? ((FlatHelpButtonIcon)helpButtonIcon).getStyleableValue( key.substring( "help.".length() ) )
: null;
}
return FlatStylingSupport.getAnnotatedStyleableValue( this, c.getBorder(), key );
}
static boolean isContentAreaFilled( Component c ) { static boolean isContentAreaFilled( Component c ) {
return !(c instanceof AbstractButton) || ((AbstractButton)c).isContentAreaFilled(); return !(c instanceof AbstractButton) || ((AbstractButton)c).isContentAreaFilled();
} }
@@ -407,7 +336,7 @@ public class FlatButtonUI
/** /**
* Returns true if the button has an icon but no text, * Returns true if the button has an icon but no text,
* or it does not have an icon and the text is either "..." or one character. * or it it does not have an icon and the text is either "..." or one character.
*/ */
static boolean isIconOnlyOrSingleCharacterButton( Component c ) { static boolean isIconOnlyOrSingleCharacterButton( Component c ) {
if( !(c instanceof JButton) && !(c instanceof JToggleButton) ) if( !(c instanceof JButton) && !(c instanceof JToggleButton) )
@@ -491,21 +420,11 @@ public class FlatButtonUI
try { try {
FlatUIUtils.setRenderingHints( g2 ); FlatUIUtils.setRenderingHints( g2 );
boolean def = isDefaultButton( c );
boolean isToolBarButton = isToolBarButton( c ); boolean isToolBarButton = isToolBarButton( c );
float focusWidth = isToolBarButton ? 0 : FlatUIUtils.getBorderFocusWidth( c ); float focusWidth = isToolBarButton ? 0 : FlatUIUtils.getBorderFocusWidth( c );
float arc = FlatUIUtils.getBorderArc( c ); float arc = FlatUIUtils.getBorderArc( c );
float textFieldArc = 0;
// if toolbar button is in leading/trailing component of a text field, boolean def = isDefaultButton( c );
// increase toolbar button arc to match text field arc (if necessary)
if( isToolBarButton &&
FlatClientProperties.clientProperty( c, STYLE_CLASS, "", String.class ).contains( "inTextField" ) )
{
JTextField textField = (JTextField) SwingUtilities.getAncestorOfClass( JTextField.class, c );
if( textField != null )
textFieldArc = FlatUIUtils.getBorderArc( textField );
}
int x = 0; int x = 0;
int y = 0; int y = 0;
@@ -518,15 +437,8 @@ public class FlatButtonUI
y += spacing.top; y += spacing.top;
width -= spacing.left + spacing.right; width -= spacing.left + spacing.right;
height -= spacing.top + spacing.bottom; height -= spacing.top + spacing.bottom;
// reduce text field arc
textFieldArc -= spacing.top + spacing.bottom;
} }
// increase toolbar button arc to match text field arc (if necessary)
if( arc < textFieldArc )
arc = textFieldArc;
// paint shadow // paint shadow
Color shadowColor = def ? defaultShadowColor : this.shadowColor; Color shadowColor = def ? defaultShadowColor : this.shadowColor;
if( paintShadow && if( paintShadow &&
@@ -553,62 +465,9 @@ public class FlatButtonUI
} }
} }
/**
* Similar to BasicButtonUI.paint(), but does not use zero insets for HTML text,
* which is done in BasicButtonUI.layout() since Java 19.
* See https://github.com/openjdk/jdk/pull/8407
* and https://github.com/openjdk/jdk/pull/8407#issuecomment-1761583430
*/
@Override @Override
public void paint( Graphics g, JComponent c ) { public void paint( Graphics g, JComponent c ) {
g = FlatLabelUI.createGraphicsHTMLTextYCorrection( g, c ); super.paint( FlatLabelUI.createGraphicsHTMLTextYCorrection( g, c ), c );
AbstractButton b = (AbstractButton) c;
// layout
String clippedText = layout( b, b.getFontMetrics( b.getFont() ), b.getWidth(), b.getHeight() );
// not used in FlatLaf, but invoked for compatibility with BasicButtonUI.paint()
clearTextShiftOffset();
// not used in FlatLaf, but invoked for compatibility with BasicButtonUI.paint()
ButtonModel model = b.getModel();
if( model.isArmed() && model.isPressed() )
paintButtonPressed( g, b );
// paint icon
if( b.getIcon() != null )
paintIcon( g, b, iconR );
// paint text
if( clippedText != null && !clippedText.isEmpty() ) {
View view = (View) b.getClientProperty( BasicHTML.propertyKey );
if( view != null )
view.paint( g, textR ); // HTML text
else
paintText( g, b, textR, clippedText );
}
// not used in FlatLaf, but invoked for compatibility with BasicButtonUI.paint()
if( b.isFocusPainted() && b.hasFocus() )
paintFocus( g, b, viewR, textR, iconR );
}
@Override
protected void paintIcon( Graphics g, JComponent c, Rectangle iconRect ) {
// correct icon location when using bold font for default button
int xOffset = defaultBoldPlainWidthDiff( c ) / 2;
if( xOffset > 0 ) {
boolean ltr = c.getComponentOrientation().isLeftToRight();
switch( ((AbstractButton)c).getHorizontalTextPosition() ) {
case SwingConstants.RIGHT: iconRect.x -= xOffset; break;
case SwingConstants.LEFT: iconRect.x += xOffset; break;
case SwingConstants.TRAILING: iconRect.x -= ltr ? xOffset : -xOffset; break;
case SwingConstants.LEADING: iconRect.x += ltr ? xOffset : -xOffset; break;
}
}
super.paintIcon( g, c, iconRect );
} }
@Override @Override
@@ -631,8 +490,6 @@ public class FlatButtonUI
} }
public static void paintText( Graphics g, AbstractButton b, Rectangle textRect, String text, Color foreground ) { public static void paintText( Graphics g, AbstractButton b, Rectangle textRect, String text, Color foreground ) {
if(foreground == null)
foreground=Color.red;
FontMetrics fm = b.getFontMetrics( b.getFont() ); FontMetrics fm = b.getFontMetrics( b.getFont() );
int mnemonicIndex = FlatLaf.isShowMnemonics() ? b.getDisplayedMnemonicIndex() : -1; int mnemonicIndex = FlatLaf.isShowMnemonics() ? b.getDisplayedMnemonicIndex() : -1;
@@ -646,14 +503,11 @@ public class FlatButtonUI
// selected state // selected state
if( ((AbstractButton)c).isSelected() ) { if( ((AbstractButton)c).isSelected() ) {
// in toolbar, if toolbarDisabledSelectedBackground is null, // in toolbar use same background colors for disabled and enabled because
// use same background colors for disabled and enabled because
// we assume that toolbar icon is shown disabled // we assume that toolbar icon is shown disabled
return buttonStateColor( c, return buttonStateColor( c,
toolBarButton ? toolbarSelectedBackground : selectedBackground, toolBarButton ? toolbarSelectedBackground : selectedBackground,
toolBarButton toolBarButton ? toolbarSelectedBackground : disabledSelectedBackground,
? (toolbarDisabledSelectedBackground != null ? toolbarDisabledSelectedBackground : toolbarSelectedBackground)
: disabledSelectedBackground,
null, null,
null, null,
toolBarButton ? toolbarPressedBackground : pressedBackground ); toolBarButton ? toolbarPressedBackground : pressedBackground );
@@ -680,9 +534,6 @@ public class FlatButtonUI
} }
protected Color getBackgroundBase( JComponent c, boolean def ) { protected Color getBackgroundBase( JComponent c, boolean def ) {
if( FlatUIUtils.isAWTPeer( c ) )
return background;
// use component background if explicitly set // use component background if explicitly set
Color bg = c.getBackground(); Color bg = c.getBackground();
if( isCustomBackground( bg ) ) if( isCustomBackground( bg ) )
@@ -698,9 +549,6 @@ public class FlatButtonUI
public static Color buttonStateColor( Component c, Color enabledColor, Color disabledColor, public static Color buttonStateColor( Component c, Color enabledColor, Color disabledColor,
Color focusedColor, Color hoverColor, Color pressedColor ) Color focusedColor, Color hoverColor, Color pressedColor )
{ {
if( c == null )
return enabledColor;
if( !c.isEnabled() ) if( !c.isEnabled() )
return disabledColor; return disabledColor;
@@ -721,48 +569,18 @@ public class FlatButtonUI
} }
protected Color getForeground( JComponent c ) { protected Color getForeground( JComponent c ) {
boolean toolBarButton = isToolBarButton( c ) || isBorderlessButton( c ); if( !c.isEnabled() )
return disabledText;
// selected state if( ((AbstractButton)c).isSelected() && !(isToolBarButton( c ) || isBorderlessButton( c )) )
if( ((AbstractButton)c).isSelected() ) { return selectedForeground;
return buttonStateColor( c,
toolBarButton
? (toolbarSelectedForeground != null ? toolbarSelectedForeground : c.getForeground())
: selectedForeground,
toolBarButton
? (toolbarDisabledSelectedForeground != null ? toolbarDisabledSelectedForeground : disabledText)
: (disabledSelectedForeground != null ? disabledSelectedForeground : disabledText),
null,
null,
toolBarButton ? toolbarPressedForeground : pressedForeground );
}
// toolbar button
if( toolBarButton ) {
return buttonStateColor( c,
c.getForeground(),
disabledText,
null,
toolbarHoverForeground,
toolbarPressedForeground );
}
boolean def = isDefaultButton( c );
return buttonStateColor( c,
getForegroundBase( c, def ),
disabledText,
isCustomForeground( c.getForeground() ) ? null : (def ? defaultFocusedForeground : focusedForeground),
def ? defaultHoverForeground : hoverForeground,
def ? defaultPressedForeground : pressedForeground );
}
/** @since 2.3 */
protected Color getForegroundBase( JComponent c, boolean def ) {
// use component foreground if explicitly set // use component foreground if explicitly set
Color fg = c.getForeground(); Color fg = c.getForeground();
if( isCustomForeground( fg ) ) if( isCustomForeground( fg ) )
return fg; return fg;
boolean def = isDefaultButton( c );
return def ? defaultForeground : fg; return def ? defaultForeground : fg;
} }
@@ -779,9 +597,6 @@ public class FlatButtonUI
if( prefSize == null ) if( prefSize == null )
return null; return null;
// increase width when using bold font for default button
prefSize.width += defaultBoldPlainWidthDiff( c );
// make square or apply minimum width/height // make square or apply minimum width/height
boolean isIconOnlyOrSingleCharacter = isIconOnlyOrSingleCharacterButton( c ); boolean isIconOnlyOrSingleCharacter = isIconOnlyOrSingleCharacterButton( c );
if( clientPropertyBoolean( c, SQUARE_SIZE, squareSize ) ) { if( clientPropertyBoolean( c, SQUARE_SIZE, squareSize ) ) {
@@ -802,89 +617,11 @@ public class FlatButtonUI
return prefSize; return prefSize;
} }
private int defaultBoldPlainWidthDiff( JComponent c ) {
if( defaultBoldText && isDefaultButton( c ) && c.getFont() instanceof UIResource ) {
String text = ((AbstractButton)c).getText();
if( text == null || text.isEmpty() )
return 0;
Font font = c.getFont();
Font boldFont = font.deriveFont( Font.BOLD );
int boldWidth = c.getFontMetrics( boldFont ).stringWidth( text );
int plainWidth = c.getFontMetrics( font ).stringWidth( text );
if( boldWidth > plainWidth )
return boldWidth - plainWidth;
}
return 0;
}
private boolean hasDefaultMargins( JComponent c ) { private boolean hasDefaultMargins( JComponent c ) {
Insets margin = ((AbstractButton)c).getMargin(); Insets margin = ((AbstractButton)c).getMargin();
return margin instanceof UIResource && Objects.equals( margin, defaultMargin ); return margin instanceof UIResource && Objects.equals( margin, defaultMargin );
} }
@Override
public int getBaseline( JComponent c, int width, int height ) {
return getBaselineImpl( c, width, height );
}
/**
* Similar to BasicButtonUI.getBaseline(), but does not use zero insets for HTML text,
* which is done in BasicButtonUI.layout() since Java 19.
* See https://github.com/openjdk/jdk/pull/8407
* and https://github.com/openjdk/jdk/pull/8407#issuecomment-1761583430
*/
static int getBaselineImpl( JComponent c, int width, int height ) {
if( width < 0 || height < 0 )
throw new IllegalArgumentException();
AbstractButton b = (AbstractButton) c;
String text = b.getText();
if( text == null || text.isEmpty() )
return -1;
FontMetrics fm = b.getFontMetrics( b.getFont() );
layout( b, fm, width, height );
View view = (View) b.getClientProperty( BasicHTML.propertyKey );
if( view != null ) {
// HTML text
int baseline = BasicHTML.getHTMLBaseline( view, textR.width, textR.height );
return (baseline >= 0) ? textR.y + baseline : baseline;
} else
return textR.y + fm.getAscent();
}
/**
* Similar to BasicButtonUI.layout(), but does not use zero insets for HTML text,
* which is done in BasicButtonUI.layout() since Java 19.
* See https://github.com/openjdk/jdk/pull/8407
* and https://github.com/openjdk/jdk/pull/8407#issuecomment-1761583430
*/
private static String layout( AbstractButton b, FontMetrics fm, int width, int height ) {
// compute view rectangle
Insets insets = b.getInsets();
viewR.setBounds( insets.left, insets.top,
width - insets.left - insets.right,
height - insets.top - insets.bottom );
// reset rectangles
textR.setBounds( 0, 0, 0, 0 );
iconR.setBounds( 0, 0, 0, 0 );
String text = b.getText();
return SwingUtilities.layoutCompoundLabel( b, fm, text, b.getIcon(),
b.getVerticalAlignment(), b.getHorizontalAlignment(),
b.getVerticalTextPosition(), b.getHorizontalTextPosition(),
viewR, iconR, textR,
(text != null) ? b.getIconTextGap() : 0 );
}
private static Rectangle viewR = new Rectangle();
private static Rectangle textR = new Rectangle();
private static Rectangle iconR = new Rectangle();
//---- class FlatButtonListener ------------------------------------------- //---- class FlatButtonListener -------------------------------------------
protected class FlatButtonListener protected class FlatButtonListener
@@ -902,20 +639,5 @@ public class FlatButtonUI
super.propertyChange( e ); super.propertyChange( e );
FlatButtonUI.this.propertyChange( b, 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

@@ -96,14 +96,11 @@ public class FlatCaret
// if text component is focused, then caret and selection are visible, // if text component is focused, then caret and selection are visible,
// but when switching theme, the component does not yet have // but when switching theme, the component does not yet have
// a highlighter and the selection is not painted // an highlighter and the selection is not painted
// --> make selection temporary invisible later, then the caret // --> make selection temporary invisible later, then the caret
// adds selection highlights to the text component highlighter // adds selection highlights to the text component highlighter
if( isSelectionVisible() ) { if( isSelectionVisible() ) {
EventQueue.invokeLater( () -> { EventQueue.invokeLater( () -> {
if( getComponent() == null )
return; // was deinstalled
if( isSelectionVisible() ) { if( isSelectionVisible() ) {
setSelectionVisible( false ); setSelectionVisible( false );
setSelectionVisible( true ); setSelectionVisible( true );
@@ -236,7 +233,7 @@ public class FlatCaret
if( selectAllOnFocusPolicy == null ) if( selectAllOnFocusPolicy == null )
selectAllOnFocusPolicy = this.selectAllOnFocusPolicy; selectAllOnFocusPolicy = this.selectAllOnFocusPolicy;
if( selectAllOnFocusPolicy == null || SELECT_ALL_ON_FOCUS_POLICY_NEVER.equals( selectAllOnFocusPolicy ) ) if( SELECT_ALL_ON_FOCUS_POLICY_NEVER.equals( selectAllOnFocusPolicy ) )
return; return;
if( !SELECT_ALL_ON_FOCUS_POLICY_ALWAYS.equals( selectAllOnFocusPolicy ) ) { if( !SELECT_ALL_ON_FOCUS_POLICY_ALWAYS.equals( selectAllOnFocusPolicy ) ) {
@@ -256,14 +253,7 @@ public class FlatCaret
// select all // select all
if( c instanceof JFormattedTextField ) { if( c instanceof JFormattedTextField ) {
EventQueue.invokeLater( () -> { EventQueue.invokeLater( () -> {
// Warning: do not use variables from outside of this runnable select( 0, doc.getLength() );
// because they may be out-of-date when this runnable is executed
JTextComponent c2 = getComponent();
if( c2 == null )
return; // was deinstalled
select( 0, c2.getDocument().getLength() );
} ); } );
} else { } else {
select( 0, doc.getLength() ); select( 0, doc.getLength() );

View File

@@ -16,20 +16,18 @@
package com.formdev.flatlaf.ui; package com.formdev.flatlaf.ui;
import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.lang.invoke.MethodHandles;
import java.util.Map; import java.util.Map;
import javax.swing.Icon; import javax.swing.Icon;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.LookAndFeel; import javax.swing.LookAndFeel;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicCheckBoxMenuItemUI; import javax.swing.plaf.basic.BasicCheckBoxMenuItemUI;
import javax.swing.plaf.basic.BasicMenuItemUI;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableField;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableLookupProvider;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI; import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
import com.formdev.flatlaf.util.LoggingFacade; import com.formdev.flatlaf.util.LoggingFacade;
/** /**
@@ -60,15 +58,9 @@ import com.formdev.flatlaf.util.LoggingFacade;
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@StyleableField( cls=BasicMenuItemUI.class, key="selectionBackground" )
@StyleableField( cls=BasicMenuItemUI.class, key="selectionForeground" )
@StyleableField( cls=BasicMenuItemUI.class, key="disabledForeground" )
@StyleableField( cls=BasicMenuItemUI.class, key="acceleratorForeground" )
@StyleableField( cls=BasicMenuItemUI.class, key="acceleratorSelectionForeground" )
public class FlatCheckBoxMenuItemUI public class FlatCheckBoxMenuItemUI
extends BasicCheckBoxMenuItemUI extends BasicCheckBoxMenuItemUI
implements StyleableUI, StyleableLookupProvider implements StyleableUI
{ {
private FlatMenuItemRenderer renderer; private FlatMenuItemRenderer renderer;
private Map<String, Object> oldStyleValues; private Map<String, Object> oldStyleValues;
@@ -97,7 +89,6 @@ public class FlatCheckBoxMenuItemUI
protected void uninstallDefaults() { protected void uninstallDefaults() {
super.uninstallDefaults(); super.uninstallDefaults();
FlatMenuItemRenderer.clearClientProperties( menuItem.getParent() );
renderer = null; renderer = null;
oldStyleValues = null; oldStyleValues = null;
} }
@@ -127,27 +118,29 @@ public class FlatCheckBoxMenuItemUI
/** @since 2 */ /** @since 2 */
protected Object applyStyleProperty( String key, Object value ) { protected Object applyStyleProperty( String key, Object value ) {
return FlatMenuItemUI.applyStyleProperty( menuItem, this, renderer, key, value ); try {
return renderer.applyStyleProperty( key, value );
} catch ( UnknownStyleException ex ) {
// ignore
}
Object oldValue;
switch( key ) {
// BasicMenuItemUI
case "selectionBackground": oldValue = selectionBackground; selectionBackground = (Color) value; return oldValue;
case "selectionForeground": oldValue = selectionForeground; selectionForeground = (Color) value; return oldValue;
case "disabledForeground": oldValue = disabledForeground; disabledForeground = (Color) value; return oldValue;
case "acceleratorForeground": oldValue = acceleratorForeground; acceleratorForeground = (Color) value; return oldValue;
case "acceleratorSelectionForeground": oldValue = acceleratorSelectionForeground; acceleratorSelectionForeground = (Color) value; return oldValue;
}
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, menuItem, key, value );
} }
/** @since 2 */ /** @since 2 */
@Override @Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) { public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return FlatMenuItemUI.getStyleableInfos( this, renderer ); return FlatMenuItemUI.getStyleableInfos( renderer );
}
/** @since 2.5 */
@Override
public Object getStyleableValue( JComponent c, String key ) {
return FlatMenuItemUI.getStyleableValue( this, renderer, key );
}
/** @since 2.5 */
@Override
public MethodHandles.Lookup getLookupForStyling() {
// MethodHandles.lookup() is caller sensitive and must be invoked in this class,
// otherwise it is not possible to access protected fields in JRE superclass
return MethodHandles.lookup();
} }
@Override @Override

View File

@@ -43,7 +43,7 @@ public class FlatCheckBoxUI
extends FlatRadioButtonUI extends FlatRadioButtonUI
{ {
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return FlatUIUtils.canUseSharedUI( c ) && !FlatUIUtils.needsLightAWTPeer( c ) return FlatUIUtils.canUseSharedUI( c )
? FlatUIUtils.createSharedUI( FlatCheckBoxUI.class, () -> new FlatCheckBoxUI( true ) ) ? FlatUIUtils.createSharedUI( FlatCheckBoxUI.class, () -> new FlatCheckBoxUI( true ) )
: new FlatCheckBoxUI( false ); : new FlatCheckBoxUI( false );
} }

View File

@@ -24,7 +24,6 @@ import java.awt.Component;
import java.awt.ComponentOrientation; import java.awt.ComponentOrientation;
import java.awt.Container; import java.awt.Container;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics; import java.awt.FontMetrics;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
@@ -43,18 +42,15 @@ import java.awt.event.MouseEvent;
import java.awt.event.MouseListener; import java.awt.event.MouseListener;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.lang.invoke.MethodHandles;
import java.util.Map; import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.AbstractAction; import javax.swing.AbstractAction;
import javax.swing.BorderFactory; import javax.swing.BorderFactory;
import javax.swing.CellRendererPane; import javax.swing.CellRendererPane;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultListCellRenderer; import javax.swing.DefaultListCellRenderer;
import javax.swing.InputMap; import javax.swing.InputMap;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.JComboBox; import javax.swing.JComboBox;
import javax.swing.JComboBox.KeySelectionManager;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JList; import javax.swing.JList;
import javax.swing.JPanel; import javax.swing.JPanel;
@@ -73,10 +69,7 @@ import javax.swing.plaf.basic.BasicComboBoxUI;
import javax.swing.plaf.basic.BasicComboPopup; import javax.swing.plaf.basic.BasicComboPopup;
import javax.swing.plaf.basic.ComboPopup; import javax.swing.plaf.basic.ComboPopup;
import javax.swing.text.JTextComponent; import javax.swing.text.JTextComponent;
import com.formdev.flatlaf.icons.FlatCheckBoxMenuItemIcon;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable; import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableField;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableLookupProvider;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI; import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.util.LoggingFacade; import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.SystemInfo;
@@ -93,24 +86,20 @@ import com.formdev.flatlaf.util.SystemInfo;
* @uiDefault ComboBox.padding Insets * @uiDefault ComboBox.padding Insets
* @uiDefault ComboBox.squareButton boolean default is true * @uiDefault ComboBox.squareButton boolean default is true
* *
* <!-- BasicComboPopup -->
*
* @uiDefault ComboBox.selectionBackground Color
* @uiDefault ComboBox.selectionForeground Color
*
* <!-- FlatComboBoxUI --> * <!-- FlatComboBoxUI -->
* *
* @uiDefault ComboBox.minimumWidth int * @uiDefault ComboBox.minimumWidth int
* @uiDefault ComboBox.editorColumns int * @uiDefault ComboBox.editorColumns int
* @uiDefault ComboBox.maximumRowCount int * @uiDefault ComboBox.maximumRowCount int
* @uiDefault ComboBox.buttonStyle String auto (default), button, mac or none * @uiDefault ComboBox.buttonStyle String auto (default), button or none
* @uiDefault Component.arrowType String chevron (default) or triangle * @uiDefault Component.arrowType String chevron (default) or triangle
* @uiDefault Component.isIntelliJTheme boolean
* @uiDefault ComboBox.editableBackground Color optional; defaults to ComboBox.background * @uiDefault ComboBox.editableBackground Color optional; defaults to ComboBox.background
* @uiDefault ComboBox.focusedBackground Color optional * @uiDefault ComboBox.focusedBackground Color optional
* @uiDefault ComboBox.disabledBackground Color * @uiDefault ComboBox.disabledBackground Color
* @uiDefault ComboBox.disabledForeground Color * @uiDefault ComboBox.disabledForeground Color
* @uiDefault ComboBox.buttonBackground Color optional * @uiDefault ComboBox.buttonBackground Color
* @uiDefault ComboBox.buttonEditableBackground Color optional * @uiDefault ComboBox.buttonEditableBackground Color
* @uiDefault ComboBox.buttonFocusedBackground Color optional; defaults to ComboBox.focusedBackground * @uiDefault ComboBox.buttonFocusedBackground Color optional; defaults to ComboBox.focusedBackground
* @uiDefault ComboBox.buttonSeparatorWidth int or float optional; defaults to Component.borderWidth * @uiDefault ComboBox.buttonSeparatorWidth int or float optional; defaults to Component.borderWidth
* @uiDefault ComboBox.buttonSeparatorColor Color optional * @uiDefault ComboBox.buttonSeparatorColor Color optional
@@ -120,24 +109,19 @@ import com.formdev.flatlaf.util.SystemInfo;
* @uiDefault ComboBox.buttonHoverArrowColor Color * @uiDefault ComboBox.buttonHoverArrowColor Color
* @uiDefault ComboBox.buttonPressedArrowColor Color * @uiDefault ComboBox.buttonPressedArrowColor Color
* @uiDefault ComboBox.popupBackground Color optional * @uiDefault ComboBox.popupBackground Color optional
* @uiDefault ComboBox.popupInsets Insets
* @uiDefault ComboBox.selectionInsets Insets
* @uiDefault ComboBox.selectionArc int
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@StyleableField( cls=BasicComboBoxUI.class, key="padding" )
public class FlatComboBoxUI public class FlatComboBoxUI
extends BasicComboBoxUI extends BasicComboBoxUI
implements StyleableUI, StyleableLookupProvider implements StyleableUI
{ {
@Styleable protected int minimumWidth; @Styleable protected int minimumWidth;
@Styleable protected int editorColumns; @Styleable protected int editorColumns;
@Styleable protected String buttonStyle; @Styleable protected String buttonStyle;
@Styleable protected String arrowType; @Styleable protected String arrowType;
protected boolean isIntelliJTheme;
private Color background;
@Styleable protected Color editableBackground; @Styleable protected Color editableBackground;
@Styleable protected Color focusedBackground; @Styleable protected Color focusedBackground;
@Styleable protected Color disabledBackground; @Styleable protected Color disabledBackground;
@@ -155,9 +139,6 @@ public class FlatComboBoxUI
@Styleable protected Color buttonPressedArrowColor; @Styleable protected Color buttonPressedArrowColor;
@Styleable protected Color popupBackground; @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; private MouseListener hoverListener;
protected boolean hover; protected boolean hover;
@@ -174,18 +155,8 @@ public class FlatComboBoxUI
@Override @Override
public void installUI( JComponent c ) { public void installUI( JComponent c ) {
if( FlatUIUtils.needsLightAWTPeer( c ) )
FlatUIUtils.runWithLightAWTPeerUIDefaults( () -> installUIImpl( c ) );
else
installUIImpl( c );
}
private void installUIImpl( JComponent c ) {
super.installUI( c ); super.installUI( c );
// install key selection manager that shows popup when Space key is pressed
comboBox.setKeySelectionManager( new FlatKeySelectionManager( comboBox.getKeySelectionManager() ) );
installStyle(); installStyle();
} }
@@ -244,8 +215,8 @@ public class FlatComboBoxUI
editorColumns = UIManager.getInt( "ComboBox.editorColumns" ); editorColumns = UIManager.getInt( "ComboBox.editorColumns" );
buttonStyle = UIManager.getString( "ComboBox.buttonStyle" ); buttonStyle = UIManager.getString( "ComboBox.buttonStyle" );
arrowType = UIManager.getString( "Component.arrowType" ); arrowType = UIManager.getString( "Component.arrowType" );
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
background = UIManager.getColor( "ComboBox.background" );
editableBackground = UIManager.getColor( "ComboBox.editableBackground" ); editableBackground = UIManager.getColor( "ComboBox.editableBackground" );
focusedBackground = UIManager.getColor( "ComboBox.focusedBackground" ); focusedBackground = UIManager.getColor( "ComboBox.focusedBackground" );
disabledBackground = UIManager.getColor( "ComboBox.disabledBackground" ); disabledBackground = UIManager.getColor( "ComboBox.disabledBackground" );
@@ -263,9 +234,6 @@ public class FlatComboBoxUI
buttonPressedArrowColor = UIManager.getColor( "ComboBox.buttonPressedArrowColor" ); buttonPressedArrowColor = UIManager.getColor( "ComboBox.buttonPressedArrowColor" );
popupBackground = UIManager.getColor( "ComboBox.popupBackground" ); popupBackground = UIManager.getColor( "ComboBox.popupBackground" );
popupInsets = UIManager.getInsets( "ComboBox.popupInsets" );
selectionInsets = UIManager.getInsets( "ComboBox.selectionInsets" );
selectionArc = UIManager.getInt( "ComboBox.selectionArc" );
// set maximumRowCount // set maximumRowCount
int maximumRowCount = UIManager.getInt( "ComboBox.maximumRowCount" ); int maximumRowCount = UIManager.getInt( "ComboBox.maximumRowCount" );
@@ -281,7 +249,6 @@ public class FlatComboBoxUI
protected void uninstallDefaults() { protected void uninstallDefaults() {
super.uninstallDefaults(); super.uninstallDefaults();
background = null;
editableBackground = null; editableBackground = null;
focusedBackground = null; focusedBackground = null;
disabledBackground = null; disabledBackground = null;
@@ -314,21 +281,15 @@ public class FlatComboBoxUI
public void layoutContainer( Container parent ) { public void layoutContainer( Container parent ) {
super.layoutContainer( parent ); super.layoutContainer( parent );
// on macOS, a Swing combo box is used for AWT component java.awt.Choice if( arrowButton != null ) {
// and the font may be (temporary) null
if( arrowButton != null && comboBox.getFont() != null ) {
// limit button width to height of a raw combobox (without insets) // limit button width to height of a raw combobox (without insets)
FontMetrics fm = comboBox.getFontMetrics( comboBox.getFont() ); FontMetrics fm = comboBox.getFontMetrics( comboBox.getFont() );
int maxButtonWidth = fm.getHeight() + scale( padding.top ) + scale( padding.bottom ); 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(); Insets insets = getInsets();
int buttonWidth = Math.min( Math.max( parent.getHeight() - insets.top - insets.bottom, minButtonWidth ), maxButtonWidth ); int buttonWidth = Math.min( parent.getPreferredSize().height - insets.top - insets.bottom, maxButtonWidth );
if( buttonWidth != arrowButton.getWidth() ) { if( buttonWidth != arrowButton.getWidth() ) {
// set width of arrow button // set width of arrow button to preferred height of combobox
int xOffset = comboBox.getComponentOrientation().isLeftToRight() int xOffset = comboBox.getComponentOrientation().isLeftToRight()
? arrowButton.getWidth() - buttonWidth ? arrowButton.getWidth() - buttonWidth
: 0; : 0;
@@ -390,7 +351,6 @@ public class FlatComboBoxUI
break; break;
case COMPONENT_ROUND_RECT: case COMPONENT_ROUND_RECT:
case OUTLINE:
comboBox.repaint(); comboBox.repaint();
break; break;
@@ -522,6 +482,13 @@ public class FlatComboBoxUI
/** @since 2 */ /** @since 2 */
protected Object applyStyleProperty( String key, Object value ) { protected Object applyStyleProperty( String key, Object value ) {
// BasicComboBoxUI
if( key.equals( "padding" ) ) {
Object oldValue = padding;
padding = (Insets) value;
return oldValue;
}
if( borderShared == null ) if( borderShared == null )
borderShared = new AtomicBoolean( true ); borderShared = new AtomicBoolean( true );
return FlatStylingSupport.applyToAnnotatedObjectOrBorder( this, key, value, comboBox, borderShared ); return FlatStylingSupport.applyToAnnotatedObjectOrBorder( this, key, value, comboBox, borderShared );
@@ -530,21 +497,11 @@ public class FlatComboBoxUI
/** @since 2 */ /** @since 2 */
@Override @Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) { public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return FlatStylingSupport.getAnnotatedStyleableInfos( this, comboBox.getBorder() ); Map<String, Class<?>> infos = new FlatStylingSupport.StyleableInfosMap<>();
} infos.put( "padding", Insets.class );
FlatStylingSupport.collectAnnotatedStyleableInfos( this, infos );
/** @since 2.5 */ FlatStylingSupport.collectStyleableInfos( comboBox.getBorder(), infos );
@Override return infos;
public Object getStyleableValue( JComponent c, String key ) {
return FlatStylingSupport.getAnnotatedStyleableValue( this, comboBox.getBorder(), key );
}
/** @since 2.5 */
@Override
public MethodHandles.Lookup getLookupForStyling() {
// MethodHandles.lookup() is caller sensitive and must be invoked in this class,
// otherwise it is not possible to access protected fields in JRE superclass
return MethodHandles.lookup();
} }
@Override @Override
@@ -572,9 +529,7 @@ public class FlatComboBoxUI
int height = c.getHeight(); int height = c.getHeight();
int arrowX = arrowButton.getX(); int arrowX = arrowButton.getX();
int arrowWidth = arrowButton.getWidth(); int arrowWidth = arrowButton.getWidth();
boolean paintButton = (comboBox.isEditable() || "button".equals( buttonStyle )) && boolean paintButton = (comboBox.isEditable() || "button".equals( buttonStyle )) && !"none".equals( buttonStyle );
!"none".equals( buttonStyle ) &&
!isMacStyle();
boolean enabled = comboBox.isEnabled(); boolean enabled = comboBox.isEnabled();
boolean isLeftToRight = comboBox.getComponentOrientation().isLeftToRight(); boolean isLeftToRight = comboBox.getComponentOrientation().isLeftToRight();
@@ -585,20 +540,11 @@ public class FlatComboBoxUI
// paint arrow button background // paint arrow button background
if( enabled && !isCellRenderer ) { if( enabled && !isCellRenderer ) {
Color buttonColor = paintButton g2.setColor( paintButton
? buttonEditableBackground ? buttonEditableBackground
: (buttonFocusedBackground != null || focusedBackground != null) && isPermanentFocusOwner( comboBox ) : (buttonFocusedBackground != null || focusedBackground != null) && isPermanentFocusOwner( comboBox )
? (buttonFocusedBackground != null ? buttonFocusedBackground : focusedBackground) ? (buttonFocusedBackground != null ? buttonFocusedBackground : focusedBackground)
: buttonBackground; : buttonBackground );
if( buttonColor != null ) {
g2.setColor( buttonColor );
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(); Shape oldClip = g2.getClip();
if( isLeftToRight ) if( isLeftToRight )
g2.clipRect( arrowX, 0, width - arrowX, height ); g2.clipRect( arrowX, 0, width - arrowX, height );
@@ -607,13 +553,11 @@ public class FlatComboBoxUI
FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc ); FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc );
g2.setClip( oldClip ); g2.setClip( oldClip );
} }
}
}
// paint vertical line between value and arrow button // paint vertical line between value and arrow button
if( paintButton ) { if( paintButton ) {
Color separatorColor = enabled ? buttonSeparatorColor : buttonDisabledSeparatorColor; Color separatorColor = enabled ? buttonSeparatorColor : buttonDisabledSeparatorColor;
if( separatorColor != null && buttonSeparatorWidth > 0 ) { if( separatorColor != null ) {
g2.setColor( separatorColor ); g2.setColor( separatorColor );
float lw = scale( buttonSeparatorWidth ); float lw = scale( buttonSeparatorWidth );
float lx = isLeftToRight ? arrowX : arrowX + arrowWidth - lw; float lx = isLeftToRight ? arrowX : arrowX + arrowWidth - lw;
@@ -652,7 +596,7 @@ public class FlatComboBoxUI
boolean shouldValidate = (c instanceof JPanel); boolean shouldValidate = (c instanceof JPanel);
paddingBorder.install( c, 0 ); paddingBorder.install( c );
currentValuePane.paintComponent( g, c, comboBox, bounds.x, bounds.y, bounds.width, bounds.height, shouldValidate ); currentValuePane.paintComponent( g, c, comboBox, bounds.x, bounds.y, bounds.width, bounds.height, shouldValidate );
paddingBorder.uninstall(); paddingBorder.uninstall();
@@ -667,9 +611,6 @@ public class FlatComboBoxUI
protected Color getBackground( boolean enabled ) { protected Color getBackground( boolean enabled ) {
if( enabled ) { if( enabled ) {
if( FlatUIUtils.isAWTPeer( comboBox ) )
return background;
Color background = comboBox.getBackground(); Color background = comboBox.getBackground();
// always use explicitly set color // always use explicitly set color
@@ -682,7 +623,7 @@ public class FlatComboBoxUI
return (editableBackground != null && comboBox.isEditable()) ? editableBackground : background; return (editableBackground != null && comboBox.isEditable()) ? editableBackground : background;
} else } else
return disabledBackground; return isIntelliJTheme ? FlatUIUtils.getParentBackground( comboBox ) : disabledBackground;
} }
protected Color getForeground( boolean enabled ) { protected Color getForeground( boolean enabled ) {
@@ -729,7 +670,7 @@ public class FlatComboBoxUI
@Override @Override
protected Dimension getSizeForComponent( Component comp ) { protected Dimension getSizeForComponent( Component comp ) {
paddingBorder.install( comp, 0 ); paddingBorder.install( comp );
Dimension size = super.getSizeForComponent( comp ); Dimension size = super.getSizeForComponent( comp );
paddingBorder.uninstall(); paddingBorder.uninstall();
return size; return size;
@@ -745,10 +686,6 @@ public class FlatComboBoxUI
return parentParent != null && !comboBox.getBackground().equals( parentParent.getBackground() ); return parentParent != null && !comboBox.getBackground().equals( parentParent.getBackground() );
} }
private boolean isMacStyle() {
return "mac".equals( buttonStyle );
}
/** @since 1.3 */ /** @since 1.3 */
public static boolean isPermanentFocusOwner( JComboBox<?> comboBox ) { public static boolean isPermanentFocusOwner( JComboBox<?> comboBox ) {
if( comboBox.isEditable() ) { if( comboBox.isEditable() ) {
@@ -756,7 +693,7 @@ public class FlatComboBoxUI
return true; return true;
Component editorComponent = comboBox.getEditor().getEditorComponent(); Component editorComponent = comboBox.getEditor().getEditorComponent();
return editorComponent != null && FlatUIUtils.isPermanentFocusOwner( editorComponent ); return (editorComponent != null) ? FlatUIUtils.isPermanentFocusOwner( editorComponent ) : false;
} else } else
return FlatUIUtils.isPermanentFocusOwner( comboBox ); return FlatUIUtils.isPermanentFocusOwner( comboBox );
} }
@@ -783,21 +720,6 @@ public class FlatComboBoxUI
buttonHoverArrowColor, null, buttonPressedArrowColor, null ); 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 @Override
protected boolean isHover() { protected boolean isHover() {
return super.isHover() || (!comboBox.isEditable() ? hover : false); return super.isHover() || (!comboBox.isEditable() ? hover : false);
@@ -815,20 +737,6 @@ public class FlatComboBoxUI
return super.getArrowColor(); 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 ----------------------------------------------- //---- class FlatComboPopup -----------------------------------------------
@@ -863,19 +771,12 @@ 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 // add width of vertical scroll bar
JScrollBar verticalScrollBar = scroller.getVerticalScrollBar(); JScrollBar verticalScrollBar = scroller.getVerticalScrollBar();
if( verticalScrollBar != null ) if( verticalScrollBar != null )
displayWidth += verticalScrollBar.getPreferredSize().width; displayWidth += verticalScrollBar.getPreferredSize().width;
// make popup wider if necessary // make popup wider if necessary
int pw0 = pw;
if( displayWidth > pw ) { if( displayWidth > pw ) {
// limit popup width to screen width // limit popup width to screen width
GraphicsConfiguration gc = comboBox.getGraphicsConfiguration(); GraphicsConfiguration gc = comboBox.getGraphicsConfiguration();
@@ -895,30 +796,6 @@ public class FlatComboBoxUI
px -= diff; 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 ); return super.computePopupBounds( px, py, pw, ph );
} }
@@ -929,12 +806,14 @@ public class FlatComboBoxUI
// make opaque to avoid that background shines thru border (e.g. at 150% scaling) // make opaque to avoid that background shines thru border (e.g. at 150% scaling)
setOpaque( true ); 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
Border border = UIManager.getBorder( "PopupMenu.border" ); Border border = UIManager.getBorder( "PopupMenu.border" );
if( border != null ) if( border != null )
setBorder( FlatUIUtils.nonUIResource( border ) ); setBorder( border );
}
@Override
protected void configureList() {
super.configureList();
list.setCellRenderer( new PopupListCellRenderer() ); list.setCellRenderer( new PopupListCellRenderer() );
updateStyle(); updateStyle();
@@ -943,20 +822,6 @@ public class FlatComboBoxUI
void updateStyle() { void updateStyle() {
if( popupBackground != null ) if( popupBackground != null )
list.setBackground( popupBackground ); list.setBackground( popupBackground );
// set popup background because it may shine thru when scaled (e.g. at 150%)
// 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 @Override
@@ -989,29 +854,6 @@ public class FlatComboBoxUI
} }
} }
// improve location of selected item in popup if list is large and scrollable
if( list.getHeight() == 0 ) {
// If popup is shown for the first time (or after a laf switch) and is scrollable,
// then BasicComboPopup scrolls the selected item to the top of the visible area.
// But for usability it would be better to have selected item somewhere
// in the middle of the visible area so that the user can see items above
// the selected item, which are usually more "important".
int selectedIndex = list.getSelectedIndex();
if( selectedIndex >= 1 ) {
int maximumRowCount = comboBox.getMaximumRowCount();
if( selectedIndex < maximumRowCount ) {
// selected item is in the first visible items --> scroll to top
list.scrollRectToVisible( new Rectangle() );
} else {
// scroll the selected item to the middle of the visible area
int firstVisibleIndex = Math.max( selectedIndex - (maximumRowCount / 2), 0 );
if( firstVisibleIndex > 0 )
list.ensureIndexIsVisible( firstVisibleIndex );
}
}
}
super.show( invoker, x, y ); super.show( invoker, x, y );
} }
@@ -1021,15 +863,6 @@ public class FlatComboBoxUI
paddingBorder.uninstall(); 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 ----- //---- class PopupListCellRenderer -----
private class PopupListCellRenderer private class PopupListCellRenderer
@@ -1047,14 +880,7 @@ public class FlatComboBoxUI
Component c = renderer.getListCellRendererComponent( list, value, index, isSelected, cellHasFocus ); Component c = renderer.getListCellRendererComponent( list, value, index, isSelected, cellHasFocus );
c.applyComponentOrientation( comboBox.getComponentOrientation() ); c.applyComponentOrientation( comboBox.getComponentOrientation() );
// style "mac" paddingBorder.install( c );
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; return c;
} }
@@ -1070,33 +896,22 @@ public class FlatComboBoxUI
* which vertically aligns text in popup list with text in combobox. * which vertically aligns text in popup list with text in combobox.
* <p> * <p>
* The renderer border is painted on the outer side of this border. * 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 private static class CellPaddingBorder
extends AbstractBorder extends AbstractBorder
{ {
static final String KEY_MAC_STYLE_HINT = "FlatLaf.internal.FlatComboBoxUI.macStyleHint";
static final int MAC_STYLE_GAP = 4;
private Insets padding; private Insets padding;
private JComponent rendererComponent; private JComponent rendererComponent;
private Border rendererBorder; private Border rendererBorder;
private int focusWidth;
CellPaddingBorder( Insets padding ) { CellPaddingBorder( Insets padding ) {
this.padding = padding; this.padding = padding;
} }
// using synchronized to avoid problems with code that modifies combo box void install( Component c ) {
// (model, selection, etc) not on AWT thread (which should be not done)
synchronized void install( Component c, int focusWidth ) {
if( !(c instanceof JComponent) ) if( !(c instanceof JComponent) )
return; return;
this.focusWidth = focusWidth;
JComponent jc = (JComponent) c; JComponent jc = (JComponent) c;
Border oldBorder = jc.getBorder(); Border oldBorder = jc.getBorder();
if( oldBorder == this ) if( oldBorder == this )
@@ -1125,12 +940,10 @@ public class FlatComboBoxUI
* there is no single place to uninstall it. * there is no single place to uninstall it.
* This is the reason why this method is called from various places. * This is the reason why this method is called from various places.
*/ */
synchronized void uninstall() { void uninstall() {
if( rendererComponent == null ) if( rendererComponent == null )
return; return;
rendererComponent.putClientProperty( KEY_MAC_STYLE_HINT, null );
if( rendererComponent.getBorder() == this ) if( rendererComponent.getBorder() == this )
rendererComponent.setBorder( rendererBorder ); rendererComponent.setBorder( rendererBorder );
rendererComponent = null; rendererComponent = null;
@@ -1138,9 +951,9 @@ public class FlatComboBoxUI
} }
@Override @Override
synchronized public Insets getBorderInsets( Component c, Insets insets ) { public Insets getBorderInsets( Component c, Insets insets ) {
Insets padding = scale( this.padding ); Insets padding = scale( this.padding );
if( rendererBorder != null && !(rendererBorder instanceof CellPaddingBorder) ) { if( rendererBorder != null ) {
Insets insideInsets = rendererBorder.getBorderInsets( c ); Insets insideInsets = rendererBorder.getBorderInsets( c );
insets.top = Math.max( padding.top, insideInsets.top ); insets.top = Math.max( padding.top, insideInsets.top );
insets.left = Math.max( padding.left, insideInsets.left ); insets.left = Math.max( padding.left, insideInsets.left );
@@ -1152,24 +965,6 @@ public class FlatComboBoxUI
insets.bottom = padding.bottom; insets.bottom = padding.bottom;
insets.right = padding.right; insets.right = padding.right;
} }
// if used in popup list, add focus width for exact vertical alignment
// of text in popup list with text in combobox
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; return insets;
} }
@@ -1177,35 +972,6 @@ public class FlatComboBoxUI
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) { public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
if( rendererBorder != null ) if( rendererBorder != null )
rendererBorder.paintBorder( c, g, x, y, width, height ); 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 );
} }
} }
@@ -1235,46 +1001,4 @@ public class FlatComboBoxUI
} }
} }
} }
//---- class FlatKeySelectionManager --------------------------------------
/**
* Key selection manager that delegates to the default manager.
* Shows the popup if Space key is pressed and "typed characters" buffer is empty.
* If items contain spaces (e.g. "a b") it is still possible to select them
* by pressing keys a, Space and b.
*/
private class FlatKeySelectionManager
implements JComboBox.KeySelectionManager, UIResource
{
private final KeySelectionManager delegate;
private final long timeFactor;
private long lastTime;
FlatKeySelectionManager( JComboBox.KeySelectionManager delegate ) {
this.delegate = delegate;
Long value = (Long) UIManager.get( "ComboBox.timeFactor" );
timeFactor = (value != null) ? value : 1000;
}
@SuppressWarnings( "rawtypes" )
@Override
public int selectionForKey( char aKey, ComboBoxModel aModel ) {
long time = EventQueue.getMostRecentEventTime();
long oldLastTime = lastTime;
lastTime = time;
// SPACE key shows popup if not yet visible
if( aKey == ' ' &&
time - oldLastTime >= timeFactor &&
!comboBox.isPopupVisible() )
{
comboBox.setPopupVisible( true );
return -1;
}
return delegate.selectionForKey( aKey, aModel );
}
}
} }

View File

@@ -107,12 +107,6 @@ public class FlatDropShadowBorder
return FlatStylingSupport.getAnnotatedStyleableInfos( this ); return FlatStylingSupport.getAnnotatedStyleableInfos( this );
} }
/** @since 2.5 */
@Override
public Object getStyleableValue( String key ) {
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
}
@Override @Override
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) { public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
if( shadowSize <= 0 ) if( shadowSize <= 0 )

View File

@@ -44,8 +44,8 @@ import com.formdev.flatlaf.util.LoggingFacade;
* <!-- BasicEditorPaneUI --> * <!-- BasicEditorPaneUI -->
* *
* @uiDefault EditorPane.font Font * @uiDefault EditorPane.font Font
* @uiDefault EditorPane.background Color * @uiDefault EditorPane.background Color also used if not editable
* @uiDefault EditorPane.foreground Color also used if not editable * @uiDefault EditorPane.foreground Color
* @uiDefault EditorPane.caretForeground Color * @uiDefault EditorPane.caretForeground Color
* @uiDefault EditorPane.selectionBackground Color * @uiDefault EditorPane.selectionBackground Color
* @uiDefault EditorPane.selectionForeground Color * @uiDefault EditorPane.selectionForeground Color
@@ -59,6 +59,7 @@ import com.formdev.flatlaf.util.LoggingFacade;
* <!-- FlatEditorPaneUI --> * <!-- FlatEditorPaneUI -->
* *
* @uiDefault Component.minimumWidth int * @uiDefault Component.minimumWidth int
* @uiDefault Component.isIntelliJTheme boolean
* @uiDefault EditorPane.focusedBackground Color optional * @uiDefault EditorPane.focusedBackground Color optional
* *
* @author Karl Tauber * @author Karl Tauber
@@ -68,6 +69,7 @@ public class FlatEditorPaneUI
implements StyleableUI implements StyleableUI
{ {
@Styleable protected int minimumWidth; @Styleable protected int minimumWidth;
protected boolean isIntelliJTheme;
private Color background; private Color background;
@Styleable protected Color disabledBackground; @Styleable protected Color disabledBackground;
@Styleable protected Color inactiveBackground; @Styleable protected Color inactiveBackground;
@@ -99,6 +101,7 @@ public class FlatEditorPaneUI
String prefix = getPropertyPrefix(); String prefix = getPropertyPrefix();
minimumWidth = UIManager.getInt( "Component.minimumWidth" ); minimumWidth = UIManager.getInt( "Component.minimumWidth" );
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
background = UIManager.getColor( prefix + ".background" ); background = UIManager.getColor( prefix + ".background" );
disabledBackground = UIManager.getColor( prefix + ".disabledBackground" ); disabledBackground = UIManager.getColor( prefix + ".disabledBackground" );
inactiveBackground = UIManager.getColor( prefix + ".inactiveBackground" ); inactiveBackground = UIManager.getColor( prefix + ".inactiveBackground" );
@@ -206,12 +209,6 @@ public class FlatEditorPaneUI
return FlatStylingSupport.getAnnotatedStyleableInfos( this ); return FlatStylingSupport.getAnnotatedStyleableInfos( this );
} }
/** @since 2.5 */
@Override
public Object getStyleableValue( JComponent c, String key ) {
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
}
private void updateBackground() { private void updateBackground() {
FlatTextFieldUI.updateBackground( getComponent(), background, FlatTextFieldUI.updateBackground( getComponent(), background,
disabledBackground, inactiveBackground, disabledBackground, inactiveBackground,
@@ -249,11 +246,11 @@ public class FlatEditorPaneUI
@Override @Override
protected void paintBackground( Graphics g ) { protected void paintBackground( Graphics g ) {
paintBackground( g, getComponent(), focusedBackground ); paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground );
} }
static void paintBackground( Graphics g, JTextComponent c, Color focusedBackground ) { static void paintBackground( Graphics g, JTextComponent c, boolean isIntelliJTheme, Color focusedBackground ) {
g.setColor( FlatTextFieldUI.getBackground( c, focusedBackground ) ); g.setColor( FlatTextFieldUI.getBackground( c, isIntelliJTheme, focusedBackground ) );
g.fillRect( 0, 0, c.getWidth(), c.getHeight() ); g.fillRect( 0, 0, c.getWidth(), c.getHeight() );
} }
} }

View File

@@ -56,7 +56,7 @@ public class FlatEmptyBorder
protected static Insets scaleInsets( Component c, Insets insets, protected static Insets scaleInsets( Component c, Insets insets,
int top, int left, int bottom, int right ) int top, int left, int bottom, int right )
{ {
boolean leftToRight = left == right || c == null || c.getComponentOrientation().isLeftToRight(); boolean leftToRight = left == right || c.getComponentOrientation().isLeftToRight();
insets.left = scale( leftToRight ? left : right ); insets.left = scale( leftToRight ? left : right );
insets.top = scale( top ); insets.top = scale( top );
insets.right = scale( leftToRight ? right : left ); insets.right = scale( leftToRight ? right : left );
@@ -76,9 +76,4 @@ public class FlatEmptyBorder
right = insets.right; right = insets.right;
return oldInsets; return oldInsets;
} }
/** @since 2.5 */
public Insets getStyleableValue() {
return new Insets( top, left, bottom, right );
}
} }

View File

@@ -19,22 +19,11 @@ package com.formdev.flatlaf.ui;
import java.awt.BorderLayout; import java.awt.BorderLayout;
import java.awt.Component; import java.awt.Component;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Insets; import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.RenderingHints;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File; import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.function.Function;
import javax.swing.AbstractButton; import javax.swing.AbstractButton;
import javax.swing.Box; import javax.swing.Box;
import javax.swing.BoxLayout; import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.Icon; import javax.swing.Icon;
import javax.swing.ImageIcon; import javax.swing.ImageIcon;
import javax.swing.JButton; import javax.swing.JButton;
@@ -45,17 +34,12 @@ import javax.swing.JPanel;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
import javax.swing.JTable; import javax.swing.JTable;
import javax.swing.JToggleButton; import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import javax.swing.SwingConstants;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.filechooser.FileSystemView;
import javax.swing.filechooser.FileView; import javax.swing.filechooser.FileView;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.metal.MetalFileChooserUI; import javax.swing.plaf.metal.MetalFileChooserUI;
import javax.swing.table.TableCellRenderer; import javax.swing.table.TableCellRenderer;
import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.icons.FlatFileViewDirectoryIcon;
import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.ScaledImageIcon; import com.formdev.flatlaf.util.ScaledImageIcon;
import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.SystemInfo;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
@@ -149,21 +133,12 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault FileChooser.listViewActionLabelText String * @uiDefault FileChooser.listViewActionLabelText String
* @uiDefault FileChooser.detailsViewActionLabelText String * @uiDefault FileChooser.detailsViewActionLabelText String
* *
* <!-- FlatFileChooserUI -->
*
* @uiDefault FileChooser.shortcuts.buttonSize Dimension optional; default is 84,64
* @uiDefault FileChooser.shortcuts.iconSize Dimension optional; default is 32,32
* @uiDefault FileChooser.shortcuts.filesFunction Function&lt;File[], File[]&gt;
* @uiDefault FileChooser.shortcuts.displayNameFunction Function&lt;File, String&gt;
* @uiDefault FileChooser.shortcuts.iconFunction Function&lt;File, Icon&gt;
*
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatFileChooserUI public class FlatFileChooserUI
extends MetalFileChooserUI extends MetalFileChooserUI
{ {
private final FlatFileView fileView = new FlatFileView(); private final FlatFileView fileView = new FlatFileView();
private FlatShortcutsPanel shortcutsPanel;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatFileChooserUI( (JFileChooser) c ); return new FlatFileChooserUI( (JFileChooser) c );
@@ -178,25 +153,6 @@ public class FlatFileChooserUI
super.installComponents( fc ); super.installComponents( fc );
patchUI( fc ); patchUI( fc );
if( !UIManager.getBoolean( "FileChooser.noPlacesBar" ) ) { // same as in Windows L&F
FlatShortcutsPanel panel = createShortcutsPanel( fc );
if( panel.getComponentCount() > 0 ) {
shortcutsPanel = panel;
fc.add( shortcutsPanel, BorderLayout.LINE_START );
fc.addPropertyChangeListener( shortcutsPanel );
}
}
}
@Override
public void uninstallComponents( JFileChooser fc ) {
super.uninstallComponents( fc );
if( shortcutsPanel != null ) {
fc.removePropertyChangeListener( shortcutsPanel );
shortcutsPanel = null;
}
} }
private void patchUI( JFileChooser fc ) { private void patchUI( JFileChooser fc ) {
@@ -236,27 +192,6 @@ public class FlatFileChooserUI
} catch( ArrayIndexOutOfBoundsException ex ) { } catch( ArrayIndexOutOfBoundsException ex ) {
// ignore // ignore
} }
// put north, center and south components into a new panel so that
// the shortcuts panel (at west) gets full height
LayoutManager layout = fc.getLayout();
if( layout instanceof BorderLayout ) {
BorderLayout borderLayout = (BorderLayout) layout;
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 && 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 );
}
}
} }
@Override @Override
@@ -315,19 +250,9 @@ public class FlatFileChooserUI
return p; return p;
} }
/** @since 2.3 */
protected FlatShortcutsPanel createShortcutsPanel( JFileChooser fc ) {
return new FlatShortcutsPanel( fc );
}
@Override @Override
public Dimension getPreferredSize( JComponent c ) { public Dimension getPreferredSize( JComponent c ) {
Dimension prefSize = super.getPreferredSize( c ); return UIScale.scale( super.getPreferredSize( c ) );
Dimension minSize = getMinimumSize( c );
int shortcutsPanelWidth = (shortcutsPanel != null) ? shortcutsPanel.getPreferredSize().width : 0;
return new Dimension(
Math.max( prefSize.width, minSize.width + shortcutsPanelWidth ),
Math.max( prefSize.height, minSize.height ) );
} }
@Override @Override
@@ -348,12 +273,9 @@ public class FlatFileChooserUI
fileView.clearIconCache(); fileView.clearIconCache();
} }
private static boolean doNotUseSystemIcons() { private boolean doNotUseSystemIcons() {
// Java 17 32bit craches on Windows when using system icons // Java 17 32bit craches on Windows when using system icons
// fixed in Java 18+, fix backported in Java 17.0.3+ (see https://bugs.openjdk.java.net/browse/JDK-8277299) return SystemInfo.isWindows && SystemInfo.isJava_17_orLater && !SystemInfo.isX86_64;
return SystemInfo.isWindows &&
SystemInfo.isX86 &&
(SystemInfo.isJava_17_orLater && SystemInfo.javaVersion < SystemInfo.toVersion( 17, 0, 3, 0 ));
} }
//---- class FlatFileView ------------------------------------------------- //---- class FlatFileView -------------------------------------------------
@@ -391,248 +313,4 @@ public class FlatFileChooserUI
return icon; return icon;
} }
} }
//---- class FlatShortcutsPanel -------------------------------------------
/** @since 2.3 */
public static class FlatShortcutsPanel
extends JToolBar
implements PropertyChangeListener
{
private final JFileChooser fc;
private final Dimension buttonSize;
private final Dimension iconSize;
private final Function<File[], File[]> filesFunction;
private final Function<File, String> displayNameFunction;
private final Function<File, Icon> iconFunction;
protected final File[] files;
protected final JToggleButton[] buttons;
protected final ButtonGroup buttonGroup = new ButtonGroup();
@SuppressWarnings( "unchecked" )
public FlatShortcutsPanel( JFileChooser fc ) {
super( JToolBar.VERTICAL );
this.fc = fc;
setFloatable( false );
buttonSize = UIScale.scale( getUIDimension( "FileChooser.shortcuts.buttonSize", 84, 64 ) );
iconSize = getUIDimension( "FileChooser.shortcuts.iconSize", 32, 32 );
filesFunction = (Function<File[], File[]>) UIManager.get( "FileChooser.shortcuts.filesFunction" );
displayNameFunction = (Function<File, String>) UIManager.get( "FileChooser.shortcuts.displayNameFunction" );
iconFunction = (Function<File, Icon>) UIManager.get( "FileChooser.shortcuts.iconFunction" );
FileSystemView fsv = fc.getFileSystemView();
File[] files = getChooserShortcutPanelFiles( fsv );
if( filesFunction != null )
files = filesFunction.apply( files );
// create toolbar buttons
ArrayList<File> filesList = new ArrayList<>();
ArrayList<JToggleButton> buttonsList = new ArrayList<>();
for( File file : files ) {
if( file == null )
continue;
// wrap drive path
if( fsv.isFileSystemRoot( file ) )
file = fsv.createFileObject( file.getAbsolutePath() );
String name = getDisplayName( fsv, file );
Icon icon = getIcon( fsv, file );
if( name == null )
continue;
// remove path from name
int lastSepIndex = name.lastIndexOf( File.separatorChar );
if( lastSepIndex >= 0 && lastSepIndex < name.length() - 1 )
name = name.substring( lastSepIndex + 1 );
// scale icon (if necessary)
if( icon instanceof ImageIcon )
icon = new ScaledImageIcon( (ImageIcon) icon, iconSize.width, iconSize.height );
else if( icon != null )
icon = new ShortcutIcon( icon, iconSize.width, iconSize.height );
// create button
JToggleButton button = createButton( name, icon );
File f = file;
button.addActionListener( e -> {
fc.setCurrentDirectory( f );
} );
add( button );
buttonGroup.add( button );
filesList.add( file );
buttonsList.add( button );
}
this.files = filesList.toArray( new File[filesList.size()] );
this.buttons = buttonsList.toArray( new JToggleButton[buttonsList.size()] );
directoryChanged( fc.getCurrentDirectory() );
}
private Dimension getUIDimension( String key, int defaultWidth, int defaultHeight ) {
Dimension size = UIManager.getDimension( key );
if( size == null )
size = new Dimension( defaultWidth, defaultHeight );
return size;
}
protected JToggleButton createButton( String name, Icon icon ) {
JToggleButton button = new JToggleButton( name, icon );
button.setVerticalTextPosition( SwingConstants.BOTTOM );
button.setHorizontalTextPosition( SwingConstants.CENTER );
button.setAlignmentX( Component.CENTER_ALIGNMENT );
button.setIconTextGap( 0 );
button.setPreferredSize( buttonSize );
button.setMaximumSize( buttonSize );
return button;
}
protected File[] getChooserShortcutPanelFiles( FileSystemView fsv ) {
try {
if( SystemInfo.isJava_12_orLater ) {
Method m = fsv.getClass().getMethod( "getChooserShortcutPanelFiles" );
File[] files = (File[]) m.invoke( fsv );
// on macOS and Linux, files consists only of the user home directory
if( files.length == 1 && files[0].equals( new File( System.getProperty( "user.home" ) ) ) )
files = new File[0];
return files;
} else if( SystemInfo.isWindows ) {
Class<?> cls = Class.forName( "sun.awt.shell.ShellFolder" );
Method m = cls.getMethod( "get", String.class );
return (File[]) m.invoke( null, "fileChooserShortcutPanelFolders" );
}
} catch( IllegalAccessException ex ) {
// do not log because access may be denied via VM option '--illegal-access=deny'
} catch( Exception ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex );
}
// fallback
return new File[0];
}
protected String getDisplayName( FileSystemView fsv, File file ) {
if( displayNameFunction != null ) {
String name = displayNameFunction.apply( file );
if( name != null )
return name;
}
return fsv.getSystemDisplayName( file );
}
protected Icon getIcon( FileSystemView fsv, File file ) {
if( iconFunction != null ) {
Icon icon = iconFunction.apply( file );
if( icon != null )
return icon;
}
if( doNotUseSystemIcons() )
return new FlatFileViewDirectoryIcon();
// Java 17+ supports getting larger system icons
try {
if( SystemInfo.isJava_17_orLater ) {
Method m = fsv.getClass().getMethod( "getSystemIcon", File.class, int.class, int.class );
return (Icon) m.invoke( fsv, file, iconSize.width, iconSize.height );
} else if( iconSize.width > 16 || iconSize.height > 16 ) {
Class<?> cls = Class.forName( "sun.awt.shell.ShellFolder" );
if( cls.isInstance( file ) ) {
Method m = file.getClass().getMethod( "getIcon", boolean.class );
m.setAccessible( true );
Image image = (Image) m.invoke( file, true );
if( image != null )
return new ImageIcon( image );
}
}
} catch( Exception ex ) {
// do not log InaccessibleObjectException because access
// may be denied via VM option '--illegal-access=deny' (default in Java 16)
// (not catching InaccessibleObjectException here because it is new in Java 9, but FlatLaf also runs on Java 8)
if( !"java.lang.reflect.InaccessibleObjectException".equals( ex.getClass().getName() ) )
LoggingFacade.INSTANCE.logSevere( null, ex );
}
// get system icon in default size 16x16
return fsv.getSystemIcon( file );
}
protected void directoryChanged( File file ) {
if( file != null ) {
String absolutePath = file.getAbsolutePath();
for( int i = 0; i < files.length; i++ ) {
// also compare path because otherwise selecting "Documents"
// in "Look in" combobox would not select "Documents" shortcut item
if( files[i].equals( file ) || files[i].getAbsolutePath().equals( absolutePath ) ) {
buttons[i].setSelected( true );
return;
}
}
}
buttonGroup.clearSelection();
}
@Override
public void propertyChange( PropertyChangeEvent e ) {
switch( e.getPropertyName() ) {
case JFileChooser.DIRECTORY_CHANGED_PROPERTY:
directoryChanged( fc.getCurrentDirectory() );
break;
}
}
}
//---- class ShortcutIcon -------------------------------------------------
private static class ShortcutIcon
implements Icon
{
private final Icon icon;
private final int iconWidth;
private final int iconHeight;
ShortcutIcon( Icon icon, int iconWidth, int iconHeight ) {
this.icon = icon;
this.iconWidth = iconWidth;
this.iconHeight = iconHeight;
}
@Override
public void paintIcon( Component c, Graphics g, int x, int y ) {
Graphics2D g2 = (Graphics2D) g.create();
try {
// set rendering hint for the case that the icon is a bitmap (not used for vector icons)
g2.setRenderingHint( RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC );
double scale = (double) getIconWidth() / (double) icon.getIconWidth();
g2.translate( x, y );
g2.scale( scale, scale );
icon.paintIcon( c, g2, 0, 0 );
} finally {
g2.dispose();
}
}
@Override
public int getIconWidth() {
return UIScale.scale( iconWidth );
}
@Override
public int getIconHeight() {
return UIScale.scale( iconHeight );
}
}
} }

View File

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

View File

@@ -213,13 +213,6 @@ public class FlatInternalFrameTitlePane
case "componentOrientation": case "componentOrientation":
applyComponentOrientation( frame.getComponentOrientation() ); applyComponentOrientation( frame.getComponentOrientation() );
break; break;
case "opaque":
// Do not invoke super.propertyChange() here because it always
// invokes repaint(), which would cause endless repainting.
// The opaque flag is temporary changed in FlatUIUtils.hasOpaqueBeenExplicitlySet(),
// invoked from FlatInternalFrameUI.update().
return;
} }
super.propertyChange( e ); super.propertyChange( e );

View File

@@ -179,32 +179,6 @@ public class FlatInternalFrameUI
return FlatStylingSupport.getAnnotatedStyleableInfos( this, frame.getBorder() ); return FlatStylingSupport.getAnnotatedStyleableInfos( this, frame.getBorder() );
} }
/** @since 2.5 */
@Override
public Object getStyleableValue( JComponent c, String key ) {
return FlatStylingSupport.getAnnotatedStyleableValue( this, frame.getBorder(), key );
}
@Override
public void update( Graphics g, JComponent c ) {
// The internal frame actually should be opaque and fill its background,
// but it must be non-opaque to allow translucent resize handles (outside of visual bounds).
// To avoid that parent may shine through internal frame (e.g. if menu bar is non-opaque),
// fill background excluding insets (translucent resize handles),
// but only if opaque was not set explicitly by application to false.
// If applications has set internal frame opacity to false, do not fill background (for compatibility).
if( !c.isOpaque() && !FlatUIUtils.hasOpaqueBeenExplicitlySet( c ) ) {
Insets insets = c.getInsets();
g.setColor( c.getBackground() );
g.fillRect( insets.left, insets.top,
c.getWidth() - insets.left - insets.right,
c.getHeight() - insets.top - insets.bottom );
}
super.update( g, c );
}
//---- class FlatInternalFrameBorder -------------------------------------- //---- class FlatInternalFrameBorder --------------------------------------
public static class FlatInternalFrameBorder public static class FlatInternalFrameBorder
@@ -259,23 +233,6 @@ public class FlatInternalFrameUI
return infos; return infos;
} }
/** @since 2.5 */
@Override
public Object getStyleableValue( String key ) {
switch( key ) {
case "borderMargins": return getStyleableValue();
case "activeDropShadowColor": return activeDropShadowBorder.getStyleableValue( "shadowColor" );
case "activeDropShadowInsets": return activeDropShadowBorder.getStyleableValue( "shadowInsets" );
case "activeDropShadowOpacity": return activeDropShadowBorder.getStyleableValue( "shadowOpacity" );
case "inactiveDropShadowColor": return inactiveDropShadowBorder.getStyleableValue( "shadowColor" );
case "inactiveDropShadowInsets": return inactiveDropShadowBorder.getStyleableValue( "shadowInsets" );
case "inactiveDropShadowOpacity": return inactiveDropShadowBorder.getStyleableValue( "shadowOpacity" );
}
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
}
@Override @Override
public Insets getBorderInsets( Component c, Insets insets ) { public Insets getBorderInsets( Component c, Insets insets ) {
if( c instanceof JInternalFrame && ((JInternalFrame)c).isMaximum() ) { if( c instanceof JInternalFrame && ((JInternalFrame)c).isMaximum() ) {

View File

@@ -24,7 +24,6 @@ import java.awt.Rectangle;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.swing.Icon; import javax.swing.Icon;
@@ -123,7 +122,7 @@ public class FlatLabelUI
JLabel label = (JLabel) e.getSource(); JLabel label = (JLabel) e.getSource();
if( shared && FlatStylingSupport.hasStyleProperty( label ) ) { if( shared && FlatStylingSupport.hasStyleProperty( label ) ) {
// unshare component UI if necessary // unshare component UI if necessary
// updateUI() invokes installStyle() from installUI() // updateUI() invokes applyStyle() from installUI()
label.updateUI(); label.updateUI();
} else } else
installStyle( label ); installStyle( label );
@@ -159,12 +158,6 @@ public class FlatLabelUI
return FlatStylingSupport.getAnnotatedStyleableInfos( this ); return FlatStylingSupport.getAnnotatedStyleableInfos( this );
} }
/** @since 2.5 */
@Override
public Object getStyleableValue( JComponent c, String key ) {
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
}
/** /**
* Checks whether text contains HTML tags that use "absolute-size" keywords * Checks whether text contains HTML tags that use "absolute-size" keywords
* (e.g. "x-large") for font-size in default style sheet * (e.g. "x-large") for font-size in default style sheet
@@ -180,7 +173,7 @@ public class FlatLabelUI
// BASE_SIZE rule is parsed in javax.swing.text.html.StyleSheet.addRule() // BASE_SIZE rule is parsed in javax.swing.text.html.StyleSheet.addRule()
String style = "<style>BASE_SIZE " + c.getFont().getSize() + "</style>"; String style = "<style>BASE_SIZE " + c.getFont().getSize() + "</style>";
String lowerText = text.toLowerCase( Locale.ENGLISH ); String lowerText = text.toLowerCase();
int headIndex; int headIndex;
int styleIndex; int styleIndex;
@@ -229,7 +222,7 @@ public class FlatLabelUI
int tagBegin = i + 1; int tagBegin = i + 1;
for( i += 2; i < textLength; i++ ) { for( i += 2; i < textLength; i++ ) {
if( !Character.isLetterOrDigit( text.charAt( i ) ) ) { if( !Character.isLetterOrDigit( text.charAt( i ) ) ) {
String tag = text.substring( tagBegin, i ).toLowerCase( Locale.ENGLISH ); String tag = text.substring( tagBegin, i ).toLowerCase();
if( tagsUseFontSizeSet.contains( tag ) ) if( tagsUseFontSizeSet.contains( tag ) )
return true; return true;

View File

@@ -37,18 +37,15 @@ public class FlatLineBorder
{ {
private final Color lineColor; private final Color lineColor;
private final float lineThickness; private final float lineThickness;
/** @since 2 */ private final int arc;
public FlatLineBorder( Insets insets, Color lineColor ) { public FlatLineBorder( Insets insets, Color lineColor ) {
this( insets, lineColor, 1f, 0 ); this( insets, lineColor, 1f );
} }
/** @since 2 */ public FlatLineBorder( Insets insets, Color lineColor, float lineThickness ) {
public FlatLineBorder( Insets insets, Color lineColor, float lineThickness, int arc ) {
super( insets ); super( insets );
this.lineColor = lineColor; this.lineColor = lineColor;
this.lineThickness = lineThickness; this.lineThickness = lineThickness;
this.arc = arc;
} }
public Color getLineColor() { public Color getLineColor() {
@@ -59,18 +56,13 @@ public class FlatLineBorder
return lineThickness; return lineThickness;
} }
/** @since 2 */
public int getArc() {
return arc;
}
@Override @Override
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) { public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
Graphics2D g2 = (Graphics2D) g.create(); Graphics2D g2 = (Graphics2D) g.create();
try { try {
FlatUIUtils.setRenderingHints( g2 ); FlatUIUtils.setRenderingHints( g2 );
FlatUIUtils.paintOutlinedComponent( g2, x, y, width, height, FlatUIUtils.paintOutlinedComponent( g2, x, y, width, height,
0, 0, 0, scale( getLineThickness() ), scale( getArc() ), null, getLineColor(), null ); 0, 0, 0, scale( getLineThickness() ), 0, null, getLineColor(), null );
} finally { } finally {
g2.dispose(); g2.dispose();
} }

View File

@@ -37,7 +37,7 @@ import javax.swing.plaf.ListUI;
public class FlatListCellBorder public class FlatListCellBorder
extends FlatLineBorder extends FlatLineBorder
{ {
/** @since 2 */ protected boolean showCellFocusIndicator = UIManager.getBoolean( "List.showCellFocusIndicator" ); protected boolean showCellFocusIndicator = UIManager.getBoolean( "List.showCellFocusIndicator" );
private Component c; private Component c;
@@ -72,7 +72,7 @@ public class FlatListCellBorder
} }
/** /**
* Because this border is always shared for all lists, * Because this borders are always shared for all lists,
* get border specific style from FlatListUI. * get border specific style from FlatListUI.
*/ */
static <T> T getStyleFromListUI( Component c, Function<FlatListUI, T> f ) { static <T> T getStyleFromListUI( Component c, Function<FlatListUI, T> f ) {
@@ -113,7 +113,7 @@ public class FlatListCellBorder
/** /**
* Border for selected cell that uses margins and paints focus indicator border * Border for selected cell that uses margins and paints focus indicator border
* if enabled (List.showCellFocusIndicator=true) and multiple items are selected. * if enabled (List.showCellFocusIndicator=true) and exactly one item is selected.
*/ */
public static class Selected public static class Selected
extends FlatListCellBorder extends FlatListCellBorder
@@ -125,7 +125,7 @@ public class FlatListCellBorder
if( !showCellFocusIndicator ) if( !showCellFocusIndicator )
return; return;
// paint focus indicator border only if multiple items are selected // paint focus indicator border only if exactly one item is selected
JList<?> list = (JList<?>) SwingUtilities.getAncestorOfClass( JList.class, c ); JList<?> list = (JList<?>) SwingUtilities.getAncestorOfClass( JList.class, c );
if( list != null && list.getMinSelectionIndex() == list.getMaxSelectionIndex() ) if( list != null && list.getMinSelectionIndex() == list.getMaxSelectionIndex() )
return; return;

View File

@@ -17,34 +17,20 @@
package com.formdev.flatlaf.ui; package com.formdev.flatlaf.ui;
import java.awt.Color; import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue; import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets; import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.FocusEvent; import java.awt.event.FocusEvent;
import java.awt.event.FocusListener; import java.awt.event.FocusListener;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.util.Map; import java.util.Map;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JComponent; 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.UIManager;
import javax.swing.event.ListSelectionListener;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicComboBoxRenderer;
import javax.swing.plaf.basic.BasicListUI; import javax.swing.plaf.basic.BasicListUI;
import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable; import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI; import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.util.Graphics2DProxy;
import com.formdev.flatlaf.util.LoggingFacade; import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.UIScale;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JList}. * Provides the Flat LaF UI delegate for {@link javax.swing.JList}.
@@ -73,8 +59,6 @@ import com.formdev.flatlaf.util.UIScale;
* *
* @uiDefault List.selectionInactiveBackground Color * @uiDefault List.selectionInactiveBackground Color
* @uiDefault List.selectionInactiveForeground Color * @uiDefault List.selectionInactiveForeground Color
* @uiDefault List.selectionInsets Insets
* @uiDefault List.selectionArc int
* *
* <!-- FlatListCellBorder --> * <!-- FlatListCellBorder -->
* *
@@ -92,13 +76,11 @@ public class FlatListUI
@Styleable protected Color selectionForeground; @Styleable protected Color selectionForeground;
@Styleable protected Color selectionInactiveBackground; @Styleable protected Color selectionInactiveBackground;
@Styleable protected Color selectionInactiveForeground; @Styleable protected Color selectionInactiveForeground;
/** @since 3 */ @Styleable protected Insets selectionInsets;
/** @since 3 */ @Styleable protected int selectionArc;
// for FlatListCellBorder // for FlatListCellBorder
/** @since 2 */ @Styleable protected Insets cellMargins; @Styleable protected Insets cellMargins;
/** @since 2 */ @Styleable protected Color cellFocusColor; @Styleable protected Color cellFocusColor;
/** @since 2 */ @Styleable protected Boolean showCellFocusIndicator; @Styleable protected boolean showCellFocusIndicator;
private Map<String, Object> oldStyleValues; private Map<String, Object> oldStyleValues;
@@ -108,13 +90,6 @@ public class FlatListUI
@Override @Override
public void installUI( JComponent c ) { public void installUI( JComponent c ) {
if( FlatUIUtils.needsLightAWTPeer( c ) )
FlatUIUtils.runWithLightAWTPeerUIDefaults( () -> installUIImpl( c ) );
else
installUIImpl( c );
}
private void installUIImpl( JComponent c ) {
super.installUI( c ); super.installUI( c );
installStyle(); installStyle();
@@ -128,8 +103,6 @@ public class FlatListUI
selectionForeground = UIManager.getColor( "List.selectionForeground" ); selectionForeground = UIManager.getColor( "List.selectionForeground" );
selectionInactiveBackground = UIManager.getColor( "List.selectionInactiveBackground" ); selectionInactiveBackground = UIManager.getColor( "List.selectionInactiveBackground" );
selectionInactiveForeground = UIManager.getColor( "List.selectionInactiveForeground" ); selectionInactiveForeground = UIManager.getColor( "List.selectionInactiveForeground" );
selectionInsets = UIManager.getInsets( "List.selectionInsets" );
selectionArc = UIManager.getInt( "List.selectionArc" );
toggleSelectionColors(); toggleSelectionColors();
} }
@@ -188,29 +161,6 @@ 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 */ /** @since 2 */
protected void installStyle() { protected void installStyle() {
try { try {
@@ -259,16 +209,10 @@ public class FlatListUI
return FlatStylingSupport.getAnnotatedStyleableInfos( this ); return FlatStylingSupport.getAnnotatedStyleableInfos( this );
} }
/** @since 2.5 */
@Override
public Object getStyleableValue( JComponent c, String key ) {
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
}
/** /**
* Toggle selection colors from focused to inactive and vice versa. * Toggle selection colors from focused to inactive and vice versa.
* *
* This is not an optimal solution but much easier than rewriting the whole paint methods. * This is not a optimal solution but much easier than rewriting the whole paint methods.
* *
* Using a LaF specific renderer was avoided because often a custom renderer is * Using a LaF specific renderer was avoided because often a custom renderer is
* already used in applications. Then either the inactive colors are not used, * already used in applications. Then either the inactive colors are not used,
@@ -290,165 +234,4 @@ public class FlatListUI
list.setSelectionForeground( selectionInactiveForeground ); 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,
FlatUIUtils.isPermanentFocusOwner( list ) && (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

@@ -51,12 +51,6 @@ public class FlatMenuBarBorder
return FlatStylingSupport.getAnnotatedStyleableInfos( this ); return FlatStylingSupport.getAnnotatedStyleableInfos( this );
} }
/** @since 2.5 */
@Override
public Object getStyleableValue( String key ) {
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
}
@Override @Override
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) { public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
if( !showBottomSeparator( c ) ) if( !showBottomSeparator( c ) )

View File

@@ -18,10 +18,8 @@ package com.formdev.flatlaf.ui;
import java.awt.Color; import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Container;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Insets; import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.Window; import java.awt.Window;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
@@ -29,7 +27,6 @@ import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.AbstractAction; import javax.swing.AbstractAction;
import javax.swing.ActionMap; import javax.swing.ActionMap;
import javax.swing.BoxLayout;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JMenu; import javax.swing.JMenu;
import javax.swing.JMenuBar; import javax.swing.JMenuBar;
@@ -43,13 +40,11 @@ import javax.swing.plaf.ActionMapUIResource;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource; import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicMenuBarUI; import javax.swing.plaf.basic.BasicMenuBarUI;
import javax.swing.plaf.basic.DefaultMenuLayout;
import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable; import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI; import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.util.LoggingFacade; import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.SystemInfo;
import com.formdev.flatlaf.util.UIScale;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JMenuBar}. * Provides the Flat LaF UI delegate for {@link javax.swing.JMenuBar}.
@@ -75,12 +70,7 @@ public class FlatMenuBarUI
/** @since 2 */ @Styleable protected Insets itemMargins; /** @since 2 */ @Styleable protected Insets itemMargins;
// used in FlatMenuUI // 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 */ @Styleable protected Color hoverBackground;
/** @since 2.5 */ @Styleable protected Color selectionBackground;
/** @since 2.5 */ @Styleable protected Color selectionForeground;
/** @since 2 */ @Styleable protected Color underlineSelectionBackground; /** @since 2 */ @Styleable protected Color underlineSelectionBackground;
/** @since 2 */ @Styleable protected Color underlineSelectionColor; /** @since 2 */ @Styleable protected Color underlineSelectionColor;
/** @since 2 */ @Styleable protected int underlineSelectionHeight = -1; /** @since 2 */ @Styleable protected int underlineSelectionHeight = -1;
@@ -110,10 +100,6 @@ public class FlatMenuBarUI
super.installDefaults(); super.installDefaults();
LookAndFeel.installProperty( menuBar, "opaque", false ); LookAndFeel.installProperty( menuBar, "opaque", false );
LayoutManager layout = menuBar.getLayout();
if( layout == null || layout instanceof UIResource )
menuBar.setLayout( new FlatMenuBarLayout( menuBar ) );
} }
@Override @Override
@@ -179,12 +165,6 @@ public class FlatMenuBarUI
return FlatStylingSupport.getAnnotatedStyleableInfos( this, menuBar.getBorder() ); return FlatStylingSupport.getAnnotatedStyleableInfos( this, menuBar.getBorder() );
} }
/** @since 2.5 */
@Override
public Object getStyleableValue( JComponent c, String key ) {
return FlatStylingSupport.getAnnotatedStyleableValue( this, menuBar.getBorder(), key );
}
@Override @Override
public void update( Graphics g, JComponent c ) { public void update( Graphics g, JComponent c ) {
// paint background // paint background
@@ -200,15 +180,11 @@ public class FlatMenuBarUI
protected Color getBackground( JComponent c ) { protected Color getBackground( JComponent c ) {
Color background = c.getBackground(); Color background = c.getBackground();
// paint background if opaque // paint background if opaque or if having custom background color
if( c.isOpaque() ) if( c.isOpaque() || !(background instanceof UIResource) )
return background; return background;
// do not paint background if non-opaque and having custom background color // paint background if menu bar is not the "main" menu bar
if( !(background instanceof UIResource) )
return null;
// paint background if menu bar is not the "main" menu bar (e.g. in internal frame)
JRootPane rootPane = SwingUtilities.getRootPane( c ); JRootPane rootPane = SwingUtilities.getRootPane( c );
if( rootPane == null || !(rootPane.getParent() instanceof Window) || rootPane.getJMenuBar() != c ) if( rootPane == null || !(rootPane.getParent() instanceof Window) || rootPane.getJMenuBar() != c )
return background; return background;
@@ -230,7 +206,7 @@ public class FlatMenuBarUI
// check whether: // check whether:
// - TitlePane.unifiedBackground is true and // - TitlePane.unifiedBackground is true and
// - menu bar is the "main" menu bar and // - menu bar is the "main" menu bar and
// - window root pane has custom decoration style // - window has custom decorations enabled
JRootPane rootPane; JRootPane rootPane;
// (not storing value of "TitlePane.unifiedBackground" in class to allow changing at runtime) // (not storing value of "TitlePane.unifiedBackground" in class to allow changing at runtime)
@@ -238,131 +214,7 @@ public class FlatMenuBarUI
(rootPane = SwingUtilities.getRootPane( c )) != null && (rootPane = SwingUtilities.getRootPane( c )) != null &&
rootPane.getParent() instanceof Window && rootPane.getParent() instanceof Window &&
rootPane.getJMenuBar() == c && rootPane.getJMenuBar() == c &&
rootPane.getWindowDecorationStyle() != JRootPane.NONE; FlatNativeWindowBorder.hasCustomDecoration( (Window) rootPane.getParent() );
}
//---- class FlatMenuBarLayout --------------------------------------------
/**
* @since 2.4
*/
protected static class FlatMenuBarLayout
extends DefaultMenuLayout
{
public FlatMenuBarLayout( Container target ) {
super( target, BoxLayout.LINE_AXIS );
}
@Override
public void layoutContainer( Container target ) {
super.layoutContainer( target );
// The only purpose of the code below is to make sure that a horizontal glue,
// which can be used to move window and displays the window title in embedded menu bar,
// is always visible within the menu bar bounds and has a minimum width.
// If this is not the case, the horizontal glue is made larger and
// components that are on the left side of the glue are made smaller.
// get root pane and check whether this menu bar is the root pane menu bar
JRootPane rootPane = SwingUtilities.getRootPane( target );
if( rootPane == null || rootPane.getJMenuBar() != target )
return;
// get title pane and check whether menu bar is embedded
FlatTitlePane titlePane = FlatRootPaneUI.getTitlePane( rootPane );
if( titlePane == null || !titlePane.isMenuBarEmbedded() )
return;
// check whether there is a horizontal glue (used for window title in embedded menu bar)
// and check minimum width of horizontal glue
Component horizontalGlue = titlePane.findHorizontalGlue( (JMenuBar) target );
int minTitleWidth = UIScale.scale( titlePane.titleMinimumWidth );
if( horizontalGlue != null && horizontalGlue.getWidth() < minTitleWidth ) {
// get index of glue component
int glueIndex = -1;
Component[] components = target.getComponents();
for( int i = components.length - 1; i >= 0; i-- ) {
if( components[i] == horizontalGlue ) {
glueIndex = i;
break;
}
}
if( glueIndex < 0 )
return; // should never happen
if( target.getComponentOrientation().isLeftToRight() ) {
// left-to-right
// make horizontal glue wider (minimum title width)
int offset = minTitleWidth - horizontalGlue.getWidth();
horizontalGlue.setSize( minTitleWidth, horizontalGlue.getHeight() );
// check whether glue is fully visible
int minGlueX = target.getWidth() - target.getInsets().right - minTitleWidth;
if( minGlueX < horizontalGlue.getX() ) {
// move glue to the left to make it fully visible
offset -= (horizontalGlue.getX() - minGlueX);
horizontalGlue.setLocation( minGlueX, horizontalGlue.getY() );
// shrink and move components that are on the left side of the glue
for( int i = glueIndex - 1; i >= 0; i-- ) {
Component c = components[i];
if( c.getX() > minGlueX ) {
// move component and set width to zero
c.setBounds( minGlueX, c.getY(), 0, c.getHeight() );
} else {
// reduce size of component
c.setSize( minGlueX - c.getX(), c.getHeight() );
break;
}
}
}
// move components that are on the right side of the glue
for( int i = glueIndex + 1; i < components.length; i++ ) {
Component c = components[i];
c.setLocation( c.getX() + offset, c.getY() );
}
} else {
// right-to-left
// make horizontal glue wider (minimum title width)
int offset = minTitleWidth - horizontalGlue.getWidth();
horizontalGlue.setBounds( horizontalGlue.getX() - offset, horizontalGlue.getY(),
minTitleWidth, horizontalGlue.getHeight() );
// check whether glue is fully visible
int minGlueX = target.getInsets().left;
if( minGlueX > horizontalGlue.getX() ) {
// move glue to the right to make it fully visible
offset -= (horizontalGlue.getX() - minGlueX);
horizontalGlue.setLocation( minGlueX, horizontalGlue.getY() );
// shrink and move components that are on the right side of the glue
int x = horizontalGlue.getX() + horizontalGlue.getWidth();
for( int i = glueIndex - 1; i >= 0; i-- ) {
Component c = components[i];
if( c.getX() + c.getWidth() < x ) {
// move component and set width to zero
c.setBounds( x, c.getY(), 0, c.getHeight() );
} else {
// move component and reduce size
c.setBounds( x, c.getY(), c.getWidth() - (x - c.getX()), c.getHeight() );
break;
}
}
}
// move components that are on the left side of the glue
for( int i = glueIndex + 1; i < components.length; i++ ) {
Component c = components[i];
c.setLocation( c.getX() - offset, c.getY() );
}
}
}
}
} }
//---- class TakeFocus ---------------------------------------------------- //---- class TakeFocus ----------------------------------------------------

View File

@@ -35,7 +35,7 @@ import javax.swing.plaf.MenuBarUI;
public class FlatMenuItemBorder public class FlatMenuItemBorder
extends FlatMarginBorder extends FlatMarginBorder
{ {
// only used if parent menubar is not an instance of FlatMenuBarUI // only used if parent menubar is not a instance of FlatMenuBarUI
private final Insets menuBarItemMargins = UIManager.getInsets( "MenuBar.itemMargins" ); private final Insets menuBarItemMargins = UIManager.getInsets( "MenuBar.itemMargins" );
@Override @Override

View File

@@ -19,7 +19,6 @@ package com.formdev.flatlaf.ui;
import static com.formdev.flatlaf.util.UIScale.scale; import static com.formdev.flatlaf.util.UIScale.scale;
import java.awt.Color; import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Font; import java.awt.Font;
import java.awt.FontMetrics; import java.awt.FontMetrics;
@@ -33,7 +32,6 @@ import java.awt.event.KeyEvent;
import java.text.AttributedCharacterIterator; import java.text.AttributedCharacterIterator;
import java.util.Map; import java.util.Map;
import javax.swing.Icon; import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JMenu; import javax.swing.JMenu;
import javax.swing.JMenuItem; import javax.swing.JMenuItem;
import javax.swing.KeyStroke; import javax.swing.KeyStroke;
@@ -41,7 +39,6 @@ import javax.swing.SwingUtilities;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.basic.BasicHTML; import javax.swing.plaf.basic.BasicHTML;
import javax.swing.text.View; import javax.swing.text.View;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.icons.FlatCheckBoxMenuItemIcon; import com.formdev.flatlaf.icons.FlatCheckBoxMenuItemIcon;
import com.formdev.flatlaf.icons.FlatMenuArrowIcon; import com.formdev.flatlaf.icons.FlatMenuArrowIcon;
@@ -55,17 +52,12 @@ import com.formdev.flatlaf.util.SystemInfo;
/** /**
* Renderer for menu items. * Renderer for menu items.
* *
* @uiDefault MenuItem.verticallyAlignText boolean
* @uiDefault MenuItem.minimumWidth int * @uiDefault MenuItem.minimumWidth int
* @uiDefault MenuItem.minimumIconSize Dimension * @uiDefault MenuItem.minimumIconSize Dimension
* @uiDefault MenuItem.textAcceleratorGap int * @uiDefault MenuItem.textAcceleratorGap int
* @uiDefault MenuItem.textNoAcceleratorGap int * @uiDefault MenuItem.textNoAcceleratorGap int
* @uiDefault MenuItem.acceleratorArrowGap int * @uiDefault MenuItem.acceleratorArrowGap int
* @uiDefault MenuItem.checkBackground Color * @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.underlineSelectionBackground Color
* @uiDefault MenuItem.underlineSelectionCheckBackground Color * @uiDefault MenuItem.underlineSelectionCheckBackground Color
* @uiDefault MenuItem.underlineSelectionColor Color * @uiDefault MenuItem.underlineSelectionColor Color
@@ -75,15 +67,12 @@ import com.formdev.flatlaf.util.SystemInfo;
*/ */
public class FlatMenuItemRenderer public class FlatMenuItemRenderer
{ {
private static final String KEY_MAX_ICONS_WIDTH = "FlatLaf.internal.FlatMenuItemRenderer.maxIconWidth";
protected final JMenuItem menuItem; protected final JMenuItem menuItem;
protected Icon checkIcon; protected Icon checkIcon;
protected Icon arrowIcon; protected Icon arrowIcon;
@Styleable protected Font acceleratorFont; protected final Font acceleratorFont;
protected final String acceleratorDelimiter; protected final String acceleratorDelimiter;
/** @since 2 */ @Styleable protected boolean verticallyAlignText = FlatUIUtils.getUIBoolean( "MenuItem.verticallyAlignText", true );
@Styleable protected int minimumWidth = UIManager.getInt( "MenuItem.minimumWidth" ); @Styleable protected int minimumWidth = UIManager.getInt( "MenuItem.minimumWidth" );
@Styleable protected Dimension minimumIconSize; @Styleable protected Dimension minimumIconSize;
@Styleable protected int textAcceleratorGap = FlatUIUtils.getUIInt( "MenuItem.textAcceleratorGap", 28 ); @Styleable protected int textAcceleratorGap = FlatUIUtils.getUIInt( "MenuItem.textAcceleratorGap", 28 );
@@ -93,16 +82,12 @@ public class FlatMenuItemRenderer
@Styleable protected Color checkBackground = UIManager.getColor( "MenuItem.checkBackground" ); @Styleable protected Color checkBackground = UIManager.getColor( "MenuItem.checkBackground" );
@Styleable protected Insets checkMargins = UIManager.getInsets( "MenuItem.checkMargins" ); @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 underlineSelectionBackground = UIManager.getColor( "MenuItem.underlineSelectionBackground" );
@Styleable protected Color underlineSelectionCheckBackground = UIManager.getColor( "MenuItem.underlineSelectionCheckBackground" ); @Styleable protected Color underlineSelectionCheckBackground = UIManager.getColor( "MenuItem.underlineSelectionCheckBackground" );
@Styleable protected Color underlineSelectionColor = UIManager.getColor( "MenuItem.underlineSelectionColor" ); @Styleable protected Color underlineSelectionColor = UIManager.getColor( "MenuItem.underlineSelectionColor" );
@Styleable protected int underlineSelectionHeight = UIManager.getInt( "MenuItem.underlineSelectionHeight" ); @Styleable protected int underlineSelectionHeight = UIManager.getInt( "MenuItem.underlineSelectionHeight" );
private boolean iconsShared = true; private boolean iconsShared = true;
private final Font menuFont = UIManager.getFont( "Menu.font" );
protected FlatMenuItemRenderer( JMenuItem menuItem, Icon checkIcon, Icon arrowIcon, protected FlatMenuItemRenderer( JMenuItem menuItem, Icon checkIcon, Icon arrowIcon,
Font acceleratorFont, String acceleratorDelimiter ) Font acceleratorFont, String acceleratorDelimiter )
@@ -175,19 +160,6 @@ public class FlatMenuItemRenderer
return infos; return infos;
} }
/** @since 2.5 */
public Object getStyleableValue( String key ) {
if( key.startsWith( "icon." ) ) {
String key2 = key.substring( "icon.".length() );
if( checkIcon instanceof FlatCheckBoxMenuItemIcon )
return ((FlatCheckBoxMenuItemIcon)checkIcon).getStyleableValue( key2 );
if( arrowIcon instanceof FlatMenuArrowIcon )
return ((FlatMenuArrowIcon)arrowIcon).getStyleableValue( key2 );
}
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
}
protected Dimension getPreferredMenuItemSize() { protected Dimension getPreferredMenuItemSize() {
int width = 0; int width = 0;
int height = 0; int height = 0;
@@ -199,8 +171,7 @@ public class FlatMenuItemRenderer
// layout icon and text // layout icon and text
SwingUtilities.layoutCompoundLabel( menuItem, SwingUtilities.layoutCompoundLabel( menuItem,
menuItem.getFontMetrics( isTopLevelMenu ? getTopLevelFont() : menuItem.getFont() ), menuItem.getFontMetrics( menuItem.getFont() ), menuItem.getText(), getIconForLayout(),
menuItem.getText(), getIconForLayout(),
menuItem.getVerticalAlignment(), menuItem.getHorizontalAlignment(), menuItem.getVerticalAlignment(), menuItem.getHorizontalAlignment(),
menuItem.getVerticalTextPosition(), menuItem.getHorizontalTextPosition(), menuItem.getVerticalTextPosition(), menuItem.getHorizontalTextPosition(),
viewRect, iconRect, textRect, scale( menuItem.getIconTextGap() ) ); viewRect, iconRect, textRect, scale( menuItem.getIconTextGap() ) );
@@ -302,8 +273,7 @@ public class FlatMenuItemRenderer
// layout icon and text // layout icon and text
SwingUtilities.layoutCompoundLabel( menuItem, SwingUtilities.layoutCompoundLabel( menuItem,
menuItem.getFontMetrics( isTopLevelMenu ? getTopLevelFont() : menuItem.getFont() ), menuItem.getFontMetrics( menuItem.getFont() ), menuItem.getText(), getIconForLayout(),
menuItem.getText(), getIconForLayout(),
menuItem.getVerticalAlignment(), menuItem.getHorizontalAlignment(), menuItem.getVerticalAlignment(), menuItem.getHorizontalAlignment(),
menuItem.getVerticalTextPosition(), menuItem.getHorizontalTextPosition(), menuItem.getVerticalTextPosition(), menuItem.getHorizontalTextPosition(),
labelRect, iconRect, textRect, scale( menuItem.getIconTextGap() ) ); labelRect, iconRect, textRect, scale( menuItem.getIconTextGap() ) );
@@ -342,16 +312,10 @@ public class FlatMenuItemRenderer
g.setColor( Color.orange ); g.drawRect( arrowRect.x, arrowRect.y, arrowRect.width - 1, arrowRect.height - 1 ); g.setColor( Color.orange ); g.drawRect( arrowRect.x, arrowRect.y, arrowRect.width - 1, arrowRect.height - 1 );
debug*/ debug*/
boolean armedOrSelected = isArmedOrSelected( menuItem );
boolean underlineSelection = isUnderlineSelection(); boolean underlineSelection = isUnderlineSelection();
paintBackground( g, underlineSelection ? underlineSelectionBackground : selectionBackground );
paintBackground( g ); if( underlineSelection && isArmedOrSelected( menuItem ) )
if( armedOrSelected ) { paintUnderlineSelection( g, underlineSelectionColor, underlineSelectionHeight );
if( underlineSelection )
paintUnderlineSelection( g, underlineSelectionBackground, underlineSelectionColor, underlineSelectionHeight );
else
paintSelection( g, selectionBackground, selectionInsets, selectionArc );
}
paintIcon( g, iconRect, getIconForPainting(), underlineSelection ? underlineSelectionCheckBackground : checkBackground, selectionBackground ); paintIcon( g, iconRect, getIconForPainting(), underlineSelection ? underlineSelectionCheckBackground : checkBackground, selectionBackground );
paintText( g, textRect, menuItem.getText(), selectionForeground, disabledForeground ); paintText( g, textRect, menuItem.getText(), selectionForeground, disabledForeground );
paintAccelerator( g, accelRect, getAcceleratorText(), acceleratorForeground, acceleratorSelectionForeground, disabledForeground ); paintAccelerator( g, accelRect, getAcceleratorText(), acceleratorForeground, acceleratorSelectionForeground, disabledForeground );
@@ -359,35 +323,21 @@ debug*/
paintArrowIcon( g, arrowRect, arrowIcon ); paintArrowIcon( g, arrowRect, arrowIcon );
} }
/** @since 3 */ protected void paintBackground( Graphics g, Color selectionBackground ) {
protected void paintBackground( Graphics g ) { boolean armedOrSelected = isArmedOrSelected( menuItem );
if( menuItem.isOpaque() ) { if( menuItem.isOpaque() || armedOrSelected ) {
g.setColor( menuItem.getBackground() ); // paint background
g.setColor( armedOrSelected
? deriveBackground( selectionBackground )
: menuItem.getBackground() );
g.fillRect( 0, 0, menuItem.getWidth(), menuItem.getHeight() ); g.fillRect( 0, 0, menuItem.getWidth(), menuItem.getHeight() );
} }
} }
/** @since 3 */ protected void paintUnderlineSelection( Graphics g, Color underlineSelectionColor, int underlineSelectionHeight ) {
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 width = menuItem.getWidth();
int height = menuItem.getHeight(); int height = menuItem.getHeight();
// paint background
g.setColor( deriveBackground( underlineSelectionBackground ) );
g.fillRect( 0, 0, width, height );
// paint underline
int underlineHeight = scale( underlineSelectionHeight ); int underlineHeight = scale( underlineSelectionHeight );
g.setColor( underlineSelectionColor ); g.setColor( underlineSelectionColor );
if( isTopLevelMenu( menuItem ) ) { if( isTopLevelMenu( menuItem ) ) {
@@ -433,10 +383,9 @@ debug*/
} }
int mnemonicIndex = FlatLaf.isShowMnemonics() ? menuItem.getDisplayedMnemonicIndex() : -1; int mnemonicIndex = FlatLaf.isShowMnemonics() ? menuItem.getDisplayedMnemonicIndex() : -1;
boolean isTopLevelMenu = isTopLevelMenu( menuItem ); Color foreground = (isTopLevelMenu( menuItem ) ? menuItem.getParent() : menuItem).getForeground();
Color foreground = (isTopLevelMenu ? menuItem.getParent() : menuItem).getForeground();
paintText( g, menuItem, textRect, text, mnemonicIndex, isTopLevelMenu ? getTopLevelFont() : menuItem.getFont(), paintText( g, menuItem, textRect, text, mnemonicIndex, menuItem.getFont(),
foreground, isUnderlineSelection() ? foreground : selectionForeground, disabledForeground ); foreground, isUnderlineSelection() ? foreground : selectionForeground, disabledForeground );
} }
@@ -489,29 +438,12 @@ debug*/
protected static void paintHTMLText( Graphics g, JMenuItem menuItem, protected static void paintHTMLText( Graphics g, JMenuItem menuItem,
Rectangle textRect, View htmlView, Color selectionForeground ) Rectangle textRect, View htmlView, Color selectionForeground )
{ {
// On Windows, using Segoe UI font, Java 15 or older and scaling greater than 1,
// the width of the HTML view may be initially too small (because component
// is not connected to a GraphicsConfiguration when getPreferredSize() is invoked).
// Since Java 16, this seems to be fixed somehow by doing popup menu layout twice.
//
// If using a too small width for htmlView.paint(), the view would rearrange
// its children and wrap them to two lines. To avoid this, use view preferred X span
// for painting. Core Lafs actually do the same in class MenuItemLayoutHelper.
//
// Example HTML text that causes the problem: "<html>some <b>HTML</b> <i>text</i></html>"
textRect = new Rectangle( textRect );
textRect.width = (int) htmlView.getPreferredSpan( View.X_AXIS );
if( isArmedOrSelected( menuItem ) && selectionForeground != null ) if( isArmedOrSelected( menuItem ) && selectionForeground != null )
g = new GraphicsProxyWithTextColor( (Graphics2D) g, selectionForeground ); g = new GraphicsProxyWithTextColor( (Graphics2D) g, selectionForeground );
htmlView.paint( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ), textRect ); htmlView.paint( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ), textRect );
} }
/**
* Returns {@code true} if either the menu item is armed (mouse over item)
* or it is a {@code JMenu} and selected (shows submenu).
*/
protected static boolean isArmedOrSelected( JMenuItem menuItem ) { protected static boolean isArmedOrSelected( JMenuItem menuItem ) {
return menuItem.isArmed() || (menuItem instanceof JMenu && menuItem.isSelected()); return menuItem.isArmed() || (menuItem instanceof JMenu && menuItem.isSelected());
} }
@@ -524,15 +456,6 @@ debug*/
return "underline".equals( UIManager.getString( "MenuItem.selectionType" ) ); return "underline".equals( UIManager.getString( "MenuItem.selectionType" ) );
} }
private Font getTopLevelFont() {
Font font = menuItem.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() { private Icon getIconForPainting() {
Icon icon = menuItem.getIcon(); Icon icon = menuItem.getIcon();
@@ -551,12 +474,6 @@ debug*/
return pressedIcon; return pressedIcon;
} }
if( isArmedOrSelected( menuItem ) ) {
Icon selectedIcon = menuItem.getSelectedIcon();
if( selectedIcon != null )
return selectedIcon;
}
return icon; return icon;
} }
@@ -643,44 +560,6 @@ debug*/
shiftGlyph = 0x21E7, shiftGlyph = 0x21E7,
commandGlyph = 0x2318; commandGlyph = 0x2318;
/**
* Calculates the maximum width of all menu item icons in the popup.
*/
private int getMaxIconsWidth() {
if( !verticallyAlignText )
return 0;
Container parent = menuItem.getParent();
if( !(parent instanceof JComponent) )
return 0;
int maxWidth = FlatClientProperties.clientPropertyInt( (JComponent) parent, KEY_MAX_ICONS_WIDTH, -1 );
if( maxWidth >= 0 )
return maxWidth;
maxWidth = 0;
for( Component c : parent.getComponents() ) {
if( !(c instanceof JMenuItem) )
continue;
Icon icon = ((JMenuItem)c).getIcon();
if( icon != null )
maxWidth = Math.max( maxWidth, icon.getIconWidth() );
}
((JComponent)parent).putClientProperty( KEY_MAX_ICONS_WIDTH, maxWidth );
return maxWidth;
}
static void clearClientProperties( Component c ) {
if( !(c instanceof JComponent) )
return;
JComponent jc = (JComponent) c;
jc.putClientProperty( FlatMenuItemRenderer.KEY_MAX_ICONS_WIDTH, null );
}
//---- class MinSizeIcon -------------------------------------------------- //---- class MinSizeIcon --------------------------------------------------
private class MinSizeIcon private class MinSizeIcon
@@ -695,7 +574,6 @@ debug*/
@Override @Override
public int getIconWidth() { public int getIconWidth() {
int iconWidth = (delegate != null) ? delegate.getIconWidth() : 0; int iconWidth = (delegate != null) ? delegate.getIconWidth() : 0;
iconWidth = Math.max( iconWidth, getMaxIconsWidth() );
return Math.max( iconWidth, scale( minimumIconSize.width ) ); return Math.max( iconWidth, scale( minimumIconSize.width ) );
} }

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