Compare commits

..

57 Commits
2.4 ... 2.6

Author SHA1 Message Date
Karl Tauber
069a7c809c release 2.6 2022-10-18 11:11:24 +02:00
Karl Tauber
883b4d735a changed "since 3" to "since 2.6" 2022-10-18 11:08:14 +02:00
Karl Tauber
9f39b269bb CHANGELOG.md: moved PR #595 from "Fixed bugs" to "New features and improvements" 2022-10-17 18:15:19 +02:00
Karl Tauber
36c405c708 fixed NPE in FlatUIUtils.isCellEditor() (issue #601) 2022-10-17 18:09:12 +02:00
Karl Tauber
bc7c68ebe4 MenuBar: fixed NPE in FlatMenuItemRenderer.getTopLevelFont() if menu item does not have a parent (issue #600; regression since implementing #589 in FlatLaf 2.5; commit f6c5db07f2) 2022-10-17 17:08:12 +02:00
Karl Tauber
6c502ad4c5 2.6-SNAPSHOT 2022-10-17 16:31:54 +02:00
Karl Tauber
100aa0b621 Native libraries: load jawt.dll also on Windows when running in Java 9 and later (to be on the safe side) 2022-10-06 10:58:32 +02:00
Karl Tauber
8e42b19934 Native libraries: support loading via System.loadLibrary()
(for pre-extracted native libs in NetBeans)
2022-10-06 10:49:55 +02:00
Karl Tauber
1a456d5d68 ScaledImageIcon: do not throw exceptions if image has invalid size (e.g. not found); instead paint a red rectangle (similar to FlatSVGIcon) 2022-10-01 20:12:32 +02:00
Karl Tauber
e83c26a76a - ScrollBar: show "pressed" feedback on track/thumb only for left mouse button; if absolute positioning is enabled (the default), then also for middle mouse button
- Arrow buttons in ComboBox, Spinner, ScrollBar and TabbedPane: show "pressed" feedback only for left mouse button
2022-09-30 19:55:42 +02:00
Karl Tauber
6e7c2a616b updated CHANGELOG.md for PR #595 and added tab context menu test 2022-09-30 15:33:37 +02:00
Karl Tauber
0699454df8 Merge PR #595: Switch and close tabs on left mouse click only 2022-09-30 15:10:45 +02:00
Karl Tauber
92c110548a ComboBox and Spinner: no longer use preferred height for arrow button width, because preferred height may be zero, which would hide arrow button (see https://github.com/scijava/scijava-ui-swing/issues/77#issuecomment-1261452712)
- arrow button width depends on combobox/spinner height
- default/max button width is height of a raw combobox/spinner (without insets)
- min button width is 3/4 of default button width
2022-09-30 12:30:46 +02:00
Karl Tauber
ca88023560 GitHub Actions: build using Java 19 (use toolchain because Gradle 7.5.1 does not support running on Java 19) 2022-09-28 19:15:59 +02:00
Karl Tauber
12fc2299ec update to Gradle 7.5.1
./gradlew wrapper --gradle-version=7.5.1
2022-09-28 15:44:16 +02:00
Karl Tauber
2089c77b84 updated sigtest for FlatLaf 2.5
(generated in clean workspace with gradle task `sigtestGenerate`)
2022-09-27 16:50:34 +02:00
Karl Tauber
4f5a3e8d8b release 2.5 2022-09-27 16:11:48 +02:00
ShadelessFox
95522846ac Switch and close tabs on left mouse click only 2022-09-25 21:52:44 +03:00
Karl Tauber
614ac956de updated sigtest to 1.7 2022-09-23 12:31:42 +02:00
Karl Tauber
c228362c01 Window decorations: added UI value TitlePane.font to customize window title font (issue #589) 2022-09-23 11:57:38 +02:00
Karl Tauber
f6c5db07f2 MenuBar: top level menus now use MenuBar.font instead of Menu.font (issue #589) 2022-09-23 00:31:14 +02:00
Karl Tauber
78e7839213 Window decorations: added option to show window icon only in frames, but not in dialogs (issue #589) 2022-09-23 00:13:01 +02:00
Karl Tauber
86a4f306c6 Styling: added convenience methods to invoke StyleableUI interface methods
~~~java
JButton button = new JButton();
int arc = FlatLaf.getStyleableValue( button, "arc" );
Color borderColor = FlatLaf.getStyleableValue( button, "borderColor" );
~~~
2022-09-14 10:51:11 +02:00
Karl Tauber
0e523f1193 SwingX: fixed missing highlighting of "today" in JXMonthView and JXDatePicker 2022-09-12 13:29:53 +02:00
Karl Tauber
9041a16b22 IntelliJ Themes: updated themes to newest versions (used IJThemesUpdater) 2022-09-11 18:03:11 +02:00
Karl Tauber
596ff3382d PasswordField: reveal button is now hidden (and turned off) if password field is disabled (issue #501) 2022-09-11 17:05:48 +02:00
Karl Tauber
cbd80252ed Testing: introduced client property to exclude components in FlatTestFrame.updateComponentsRecur() 2022-09-11 14:17:55 +02:00
Karl Tauber
bcd7a7e3dd FlatClientProperties: fixed typo in javadoc 2022-09-11 13:59:54 +02:00
Karl Tauber
9c98f1a553 fixed compiler warnings 2022-09-11 12:40:27 +02:00
Karl Tauber
c3d214aa23 Merge PR #579: Linux window decorations: native move window and system menu 2022-09-11 12:11:06 +02:00
Karl Tauber
d301f6e104 MenuBar: support different menu selection style UI defaults for MenuBar and MenuItem (issue #587) 2022-09-11 12:00:38 +02:00
Karl Tauber
eb9fa585f7 more fixes for AWT components on macOS (issue #583)
- ScrollBar: disable hover because scroll bar does not receive mouse exited event
2022-09-10 18:56:33 +02:00
Karl Tauber
16c6ffb032 more fixes for AWT components on macOS (issue #583)
- use light theme for AWT components if dark FlatLaf theme is active (AWT is always light)
- made AWT peer background compatible with Aqua Laf
2022-09-10 16:53:29 +02:00
Karl Tauber
7858e42e37 fixed AWT components on macOS (issue #583)
- fixed missing focus indicator
- fixed round corners
- fixed java.awt.Button background
- fixed java.awt.Choice background
- fixed java.awt.Checkbox hover
2022-09-05 14:47:17 +02:00
Karl Tauber
30132aa6b0 added system property flatlaf.updateUIOnSystemFontChange to allow disabling automatic UI update when system font changes (issue #580) 2022-08-24 19:32:38 +02:00
Karl Tauber
bf4d4cc2c5 Linux: fixed double-click on title bar to maximize/restore on Ubuntu 22.04 (issue #482) 2022-08-21 19:49:41 +02:00
Karl Tauber
9f0554c883 Linux: added libflatlaf-linux-x86_64.so (issue #482)
built by GitHub Actions:
https://github.com/JFormDesigner/FlatLaf/actions/runs/2898994332
2022-08-21 17:35:44 +02:00
Karl Tauber
218ea6ce47 Linux: fixed double-click on title bar to maximize/restore (issue #482) 2022-08-21 17:24:50 +02:00
Karl Tauber
0baae7da8b Linux: load jawt.so explicitly before loading FlatLaf native library to fix UnsatisfiedLinkError: ... libjawt.so: cannot open shared object file ... (issue #482) 2022-08-20 23:49:14 +02:00
Karl Tauber
fb4576fc1b 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 (issue #482) 2022-08-20 21:09:49 +02:00
Karl Tauber
16f3f9e6ff Window decorations: added client property to mark components in embedded menu bar as "caption" (issue #569) 2022-08-20 19:42:38 +02:00
Karl Tauber
fee7cf6265 FlatPopupFactory: use method handles instead of reflection 2022-08-13 11:18:47 +02:00
Karl Tauber
2dd75c4a64 fixed possible exception in FlatUIUtils.resetRenderingHints() (issue #575) 2022-08-12 15:41:55 +02:00
Karl Tauber
d2f46cd0b5 TabbedPane: option to disable tab run rotation in wrap layout (issue #574) 2022-08-12 15:32:39 +02:00
Karl Tauber
10914083e6 JavaCompatibility: use method handles instead of reflection 2022-08-12 11:20:42 +02:00
Karl Tauber
5d167da55e Styling: fixed styling protected JRE fields using @StyleableField annotation (regression in commit ff00a6c0f0) 2022-08-12 11:15:49 +02:00
Karl Tauber
b381e20e57 UIDefaultsLoader: over() color function should always return a ColorUIResource 2022-08-11 23:52:35 +02:00
Karl Tauber
475cc9a9a5 Testing: extended FlatPaintingIconsTest to paint icons as pixels 2022-08-11 13:51:19 +02:00
Karl Tauber
264d6fbd6d Testing: added FlatPaintingIconsTest 2022-08-11 00:28:44 +02:00
Karl Tauber
2826cf379b added arrow icons to FlatLaf Icons.sketch and exported as SVGs 2022-08-11 00:24:22 +02:00
Karl Tauber
d28745df29 added missing @since 1.2 tags to setup() methods 2022-08-05 11:19:52 +02:00
Karl Tauber
94f9e4a1be fixed missing UI value MenuItem.acceleratorDelimiter on macOS (was null, is now an empty string) 2022-08-03 13:16:43 +02:00
Karl Tauber
ec547e1d65 fixed compiler warnings 2022-08-03 11:55:59 +02:00
Karl Tauber
61d4eb649b Styling: fixed failing unit test TestFlatStyleableValue
- caused by non-english locale
- when running on Java 17
2022-08-03 11:21:06 +02:00
Karl Tauber
52ad15e375 Styling: added StyleableUI.getStyleableValue() for tooling (e.g. GUI builder) 2022-07-31 10:57:28 +02:00
Karl Tauber
ff00a6c0f0 Styling: use annotation on UI classes for fields in Basic* classes to apply style properties (to avoid boilerplate code) 2022-07-30 11:03:17 +02:00
Karl Tauber
9b1ebd658d updated sigtest for FlatLaf 2.4
(generated in clean workspace with gradle task `sigtestGenerate`)
2022-07-13 23:45:28 +02:00
174 changed files with 10631 additions and 1662 deletions

View File

@@ -26,6 +26,10 @@ jobs:
- 8 - 8
- 11 # LTS - 11 # LTS
- 17 # LTS - 17 # LTS
toolchain: [""]
include:
- java: 17
toolchain: 19 # latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
@@ -41,7 +45,7 @@ jobs:
cache: gradle cache: gradle
- name: Build with Gradle - name: Build with Gradle
run: ./gradlew build run: ./gradlew build -Dtoolchain=${{ matrix.toolchain }}
- name: Upload artifacts - name: Upload artifacts
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3

View File

@@ -9,20 +9,26 @@ on:
tags: tags:
- '[0-9]*' - '[0-9]*'
paths: paths:
- 'flatlaf-natives/flatlaf-natives-windows/**' - 'flatlaf-natives/**'
- '.github/workflows/natives.yml' - '.github/workflows/natives.yml'
- 'gradle/wrapper/gradle-wrapper.properties' - 'gradle/wrapper/gradle-wrapper.properties'
pull_request: pull_request:
branches: branches:
- '*' - '*'
paths: paths:
- 'flatlaf-natives/flatlaf-natives-windows/**' - 'flatlaf-natives/**'
- '.github/workflows/natives.yml' - '.github/workflows/natives.yml'
- 'gradle/wrapper/gradle-wrapper.properties' - 'gradle/wrapper/gradle-wrapper.properties'
jobs: jobs:
Windows: Natives:
runs-on: windows-latest strategy:
matrix:
os:
- windows
- ubuntu
runs-on: ${{ matrix.os }}-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
@@ -39,12 +45,12 @@ jobs:
- name: Build with Gradle - name: Build with Gradle
# --no-daemon is necessary on Windows otherwise caching Gradle would fail with: # --no-daemon is necessary on Windows otherwise caching Gradle would fail with:
# tar.exe: Couldn't open ~/.gradle/caches/modules-2/modules-2.lock: Permission denied # tar.exe: Couldn't open ~/.gradle/caches/modules-2/modules-2.lock: Permission denied
run: ./gradlew :flatlaf-natives-windows:build-natives --no-daemon run: ./gradlew build-natives --no-daemon
- name: Upload artifacts - name: Upload artifacts
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: FlatLaf-natives-windows-build-artifacts name: FlatLaf-natives-build-artifacts-${{ matrix.os }}
path: | path: |
flatlaf-core/src/main/resources/com/formdev/flatlaf/natives flatlaf-core/src/main/resources/com/formdev/flatlaf/natives
flatlaf-natives/flatlaf-natives-windows/build flatlaf-natives/flatlaf-natives-*/build

View File

@@ -1,6 +1,66 @@
FlatLaf Change Log FlatLaf Change Log
================== ==================
## 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 ## 2.4
#### New features and improvements #### New features and improvements

View File

@@ -14,8 +14,8 @@
* limitations under the License. * limitations under the License.
*/ */
val releaseVersion = "2.4" val releaseVersion = "2.6"
val developmentVersion = "2.5-SNAPSHOT" val developmentVersion = "3.0-SNAPSHOT"
version = if( java.lang.Boolean.getBoolean( "release" ) ) releaseVersion else developmentVersion version = if( java.lang.Boolean.getBoolean( "release" ) ) releaseVersion else developmentVersion
@@ -37,6 +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()

View File

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

@@ -0,0 +1,36 @@
/*
* 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" ).buildDir.resolve( "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

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

View File

@@ -16,6 +16,7 @@
plugins { plugins {
`java-library` `java-library`
`flatlaf-toolchain`
`flatlaf-module-info` `flatlaf-module-info`
`flatlaf-java9` `flatlaf-java9`
`flatlaf-publish` `flatlaf-publish`
@@ -29,7 +30,7 @@ dependencies {
testRuntimeOnly( "org.junit.jupiter:junit-jupiter-engine" ) testRuntimeOnly( "org.junit.jupiter:junit-jupiter-engine" )
// https://github.com/jtulach/netbeans-apitest // https://github.com/jtulach/netbeans-apitest
sigtest( "org.netbeans.tools:sigtest-maven-plugin:1.4" ) sigtest( "org.netbeans.tools:sigtest-maven-plugin:1.7" )
} }
java { java {
@@ -66,6 +67,9 @@ 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" ) {

View File

@@ -1,5 +1,5 @@
#Signature file v4.1 #Signature file v4.1
#Version 2.3 #Version 2.5
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,6 +11,7 @@ fld public final static java.lang.String BUTTON_TYPE_TAB = "tab"
fld public final static java.lang.String BUTTON_TYPE_TOOLBAR_BUTTON = "toolBarButton" fld public final static java.lang.String 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 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"
@@ -185,6 +186,7 @@ meth public java.lang.String getID()
meth public java.util.Map<java.lang.String,java.lang.String> getExtraDefaults() 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()
@@ -193,6 +195,7 @@ meth public static boolean isUseNativeWindowDecorations()
meth public static boolean setup(javax.swing.LookAndFeel) meth public static boolean setup(javax.swing.LookAndFeel)
meth public static boolean supportsNativeWindowDecorations() meth public static boolean supportsNativeWindowDecorations()
meth public static java.lang.Object parseDefaultsValue(java.lang.String,java.lang.String,java.lang.Class<?>) meth public static java.lang.Object parseDefaultsValue(java.lang.String,java.lang.String,java.lang.Class<?>)
meth public static java.util.Map<java.lang.String,java.lang.Class<?>> getStyleableInfos(javax.swing.JComponent)
meth public static java.util.Map<java.lang.String,java.lang.String> getGlobalExtraDefaults() meth public static java.util.Map<java.lang.String,java.lang.String> getGlobalExtraDefaults()
meth public static 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()
@@ -220,7 +223,7 @@ meth public void setExtraDefaults(java.util.Map<java.lang.String,java.lang.Strin
meth public void uninitialize() meth public void uninitialize()
meth public void unregisterUIDefaultsGetter(java.util.function.Function<java.lang.Object,java.lang.Object>) meth public void unregisterUIDefaultsGetter(java.util.function.Function<java.lang.Object,java.lang.Object>)
supr javax.swing.plaf.basic.BasicLookAndFeel supr javax.swing.plaf.basic.BasicLookAndFeel
hfds DESKTOPFONTHINTS,aquaLoaded,customDefaultsSources,desktopPropertyListener,desktopPropertyName,desktopPropertyName2,extraDefaults,globalExtraDefaults,mnemonicHandler,oldPopupFactory,postInitialization,subMenuUsabilityHelper,uiDefaultsGetters,updateUIPending hfds DESKTOPFONTHINTS,aquaLoaded,customDefaultsSources,desktopPropertyListener,desktopPropertyName,desktopPropertyName2,extraDefaults,getUIMethod,getUIMethodInitialized,globalExtraDefaults,mnemonicHandler,oldPopupFactory,postInitialization,subMenuUsabilityHelperInstalled,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
@@ -259,6 +262,7 @@ fld public final static java.lang.String NATIVE_LIBRARY_PATH = "flatlaf.nativeLi
fld public final static java.lang.String UI_SCALE = "flatlaf.uiScale" fld public final static java.lang.String UI_SCALE = "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_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"

View File

@@ -253,6 +253,19 @@ 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 --------------------------------------------------------------
/** /**

View File

@@ -34,6 +34,8 @@ 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,6 +33,8 @@ 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

@@ -34,6 +34,8 @@ 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,6 +30,9 @@ 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;
@@ -63,6 +66,7 @@ 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;
@@ -73,6 +77,7 @@ 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.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;
@@ -111,6 +116,8 @@ public abstract class FlatLaf
/** /**
* 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 {
@@ -274,6 +281,9 @@ 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();
@@ -571,6 +581,7 @@ public abstract class FlatLaf
// 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 ) {
@@ -1225,6 +1236,62 @@ 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;
//---- class FlatUIDefaults ----------------------------------------------- //---- class FlatUIDefaults -----------------------------------------------
private class FlatUIDefaults private class FlatUIDefaults

View File

@@ -33,6 +33,8 @@ 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

@@ -16,6 +16,7 @@
package com.formdev.flatlaf; package com.formdev.flatlaf;
import javax.swing.SwingUtilities;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
/** /**
@@ -140,9 +141,33 @@ public interface FlatSystemProperties
String USE_TEXT_Y_CORRECTION = "flatlaf.useTextYCorrection"; String USE_TEXT_Y_CORRECTION = "flatlaf.useTextYCorrection";
/** /**
* Specifies a directory in which the native FlatLaf library have been extracted. * 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 a directory in which the native FlatLaf libraries have been extracted.
* The path can be absolute or relative to current application working directory. * The path can be absolute or relative to current application working directory.
* This can be used to avoid extraction of the native libraries to the temporary directory at runtime. * 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 * @since 2
*/ */

View File

@@ -73,6 +73,8 @@ 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 {

View File

@@ -312,7 +312,7 @@ debug*/
if( window instanceof RootPaneContainer ) { if( window instanceof RootPaneContainer ) {
JLayeredPane layeredPane = ((RootPaneContainer)window).getLayeredPane(); JLayeredPane layeredPane = ((RootPaneContainer)window).getLayeredPane();
setSize( layeredPane.getSize() ); setSize( layeredPane.getSize() );
layeredPane.add( this, new Integer( JLayeredPane.POPUP_LAYER + 1 ) ); layeredPane.add( this, Integer.valueOf( JLayeredPane.POPUP_LAYER + 1 ) );
} }
} }

View File

@@ -1052,7 +1052,7 @@ class UIDefaultsLoader
* the alpha of this color is used as weight to mix the two colors * the alpha of this color is used as weight to mix the two colors
* - background: a background color (e.g. #f00) or a color function * - background: a background color (e.g. #f00) or a color function
*/ */
private static Object parseColorOver( List<String> params, Function<String, String> resolver, boolean reportError ) { private static ColorUIResource parseColorOver( List<String> params, Function<String, String> resolver, boolean reportError ) {
String foregroundStr = params.get( 0 ); String foregroundStr = params.get( 0 );
String backgroundStr = params.get( 1 ); String backgroundStr = params.get( 1 );
@@ -1061,7 +1061,8 @@ class UIDefaultsLoader
if( foreground == null || foreground.getAlpha() == 255 ) if( foreground == null || foreground.getAlpha() == 255 )
return foreground; return foreground;
Color foreground2 = new Color( foreground.getRGB() ); // foreground color without alpha
ColorUIResource foreground2 = new ColorUIResource( foreground.getRGB() );
// parse background color // parse background color
ColorUIResource background = (ColorUIResource) parseColorOrFunction( resolver.apply( backgroundStr ), resolver, reportError ); ColorUIResource background = (ColorUIResource) parseColorOrFunction( resolver.apply( backgroundStr ), resolver, reportError );

View File

@@ -49,6 +49,14 @@ 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 ) {
/* /*

View File

@@ -172,6 +172,11 @@ 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 );

View File

@@ -59,6 +59,11 @@ 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();

View File

@@ -69,6 +69,11 @@ 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( !ignoreButtonState && c instanceof AbstractButton ) {

View File

@@ -84,6 +84,11 @@ 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 ) {
/* /*

View File

@@ -61,6 +61,11 @@ 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 != null && !c.getComponentOrientation().isLeftToRight() )

View File

@@ -67,6 +67,11 @@ 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 ) {
/* /*

View File

@@ -76,6 +76,11 @@ 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

View File

@@ -25,6 +25,7 @@ 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;
@@ -82,15 +83,19 @@ 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();
} }
}
} ); } );
} }
} }

View File

@@ -101,6 +101,12 @@ 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

@@ -181,7 +181,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 ) return FlatUIUtils.canUseSharedUI( c ) && !FlatUIUtils.needsLightAWTPeer( c )
? FlatUIUtils.createSharedUI( FlatButtonUI.class, () -> new FlatButtonUI( true ) ) ? FlatUIUtils.createSharedUI( FlatButtonUI.class, () -> new FlatButtonUI( true ) )
: new FlatButtonUI( false ); : new FlatButtonUI( false );
} }
@@ -193,6 +193,13 @@ 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 );
@@ -366,6 +373,18 @@ 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();
} }
@@ -617,6 +636,9 @@ 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 ) )

View File

@@ -16,18 +16,20 @@
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;
/** /**
@@ -58,9 +60,15 @@ 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 implements StyleableUI, StyleableLookupProvider
{ {
private FlatMenuItemRenderer renderer; private FlatMenuItemRenderer renderer;
private Map<String, Object> oldStyleValues; private Map<String, Object> oldStyleValues;
@@ -119,29 +127,27 @@ public class FlatCheckBoxMenuItemUI
/** @since 2 */ /** @since 2 */
protected Object applyStyleProperty( String key, Object value ) { protected Object applyStyleProperty( String key, Object value ) {
try { return FlatMenuItemUI.applyStyleProperty( menuItem, this, renderer, key, value );
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( renderer ); return FlatMenuItemUI.getStyleableInfos( this, 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 ) return FlatUIUtils.canUseSharedUI( c ) && !FlatUIUtils.needsLightAWTPeer( c )
? FlatUIUtils.createSharedUI( FlatCheckBoxUI.class, () -> new FlatCheckBoxUI( true ) ) ? FlatUIUtils.createSharedUI( FlatCheckBoxUI.class, () -> new FlatCheckBoxUI( true ) )
: new FlatCheckBoxUI( false ); : new FlatCheckBoxUI( false );
} }

View File

@@ -42,6 +42,7 @@ 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;
@@ -70,6 +71,8 @@ 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.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;
@@ -117,9 +120,11 @@ import com.formdev.flatlaf.util.SystemInfo;
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@StyleableField( cls=BasicComboBoxUI.class, key="padding" )
public class FlatComboBoxUI public class FlatComboBoxUI
extends BasicComboBoxUI extends BasicComboBoxUI
implements StyleableUI implements StyleableUI, StyleableLookupProvider
{ {
@Styleable protected int minimumWidth; @Styleable protected int minimumWidth;
@Styleable protected int editorColumns; @Styleable protected int editorColumns;
@@ -127,6 +132,7 @@ public class FlatComboBoxUI
@Styleable protected String arrowType; @Styleable protected String arrowType;
protected boolean isIntelliJTheme; 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;
@@ -160,6 +166,13 @@ 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 );
installStyle(); installStyle();
@@ -222,6 +235,7 @@ public class FlatComboBoxUI
arrowType = UIManager.getString( "Component.arrowType" ); arrowType = UIManager.getString( "Component.arrowType" );
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" ); 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" );
@@ -254,6 +268,7 @@ 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;
@@ -293,11 +308,14 @@ public class FlatComboBoxUI
// 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( parent.getPreferredSize().height - insets.top - insets.bottom, maxButtonWidth ); int buttonWidth = Math.min( Math.max( parent.getHeight() - insets.top - insets.bottom, minButtonWidth ), maxButtonWidth );
if( buttonWidth != arrowButton.getWidth() ) { if( buttonWidth != arrowButton.getWidth() ) {
// set width of arrow button to preferred height of combobox // set width of arrow button
int xOffset = comboBox.getComponentOrientation().isLeftToRight() int xOffset = comboBox.getComponentOrientation().isLeftToRight()
? arrowButton.getWidth() - buttonWidth ? arrowButton.getWidth() - buttonWidth
: 0; : 0;
@@ -491,13 +509,6 @@ 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 );
@@ -506,11 +517,21 @@ public class FlatComboBoxUI
/** @since 2 */ /** @since 2 */
@Override @Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) { public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
Map<String, Class<?>> infos = new FlatStylingSupport.StyleableInfosMap<>(); return FlatStylingSupport.getAnnotatedStyleableInfos( this, comboBox.getBorder() );
infos.put( "padding", Insets.class ); }
FlatStylingSupport.collectAnnotatedStyleableInfos( this, infos );
FlatStylingSupport.collectStyleableInfos( comboBox.getBorder(), infos ); /** @since 2.5 */
return infos; @Override
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
@@ -623,6 +644,9 @@ 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

View File

@@ -107,6 +107,12 @@ 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

@@ -209,6 +209,12 @@ 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,

View File

@@ -76,4 +76,9 @@ 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

@@ -151,9 +151,9 @@ import com.formdev.flatlaf.util.UIScale;
* *
* @uiDefault FileChooser.shortcuts.buttonSize Dimension optional; default is 84,64 * @uiDefault FileChooser.shortcuts.buttonSize Dimension optional; default is 84,64
* @uiDefault FileChooser.shortcuts.iconSize Dimension optional; default is 32,32 * @uiDefault FileChooser.shortcuts.iconSize Dimension optional; default is 32,32
* @uiDefault FileChooser.shortcuts.filesFunction Function<File[], File[]> * @uiDefault FileChooser.shortcuts.filesFunction Function&lt;File[], File[]&gt;
* @uiDefault FileChooser.shortcuts.displayNameFunction Function<File, String> * @uiDefault FileChooser.shortcuts.displayNameFunction Function&lt;File, String&gt;
* @uiDefault FileChooser.shortcuts.iconFunction Function<File, Icon> * @uiDefault FileChooser.shortcuts.iconFunction Function&lt;File, Icon&gt;
* *
* @author Karl Tauber * @author Karl Tauber
*/ */

View File

@@ -179,6 +179,12 @@ 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 @Override
public void update( Graphics g, JComponent c ) { public void update( Graphics g, JComponent c ) {
// The internal frame actually should be opaque and fill its background, // The internal frame actually should be opaque and fill its background,
@@ -253,6 +259,23 @@ 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

@@ -158,6 +158,12 @@ 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

View File

@@ -90,6 +90,13 @@ 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();
@@ -209,6 +216,12 @@ 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.
* *

View File

@@ -51,6 +51,12 @@ 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

@@ -76,6 +76,8 @@ public class FlatMenuBarUI
// used in FlatMenuUI // used in FlatMenuUI
/** @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;
@@ -174,6 +176,12 @@ 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

View File

@@ -97,6 +97,7 @@ public class FlatMenuItemRenderer
@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 )
@@ -169,6 +170,19 @@ 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;
@@ -180,7 +194,8 @@ public class FlatMenuItemRenderer
// layout icon and text // layout icon and text
SwingUtilities.layoutCompoundLabel( menuItem, SwingUtilities.layoutCompoundLabel( menuItem,
menuItem.getFontMetrics( menuItem.getFont() ), menuItem.getText(), getIconForLayout(), menuItem.getFontMetrics( isTopLevelMenu ? getTopLevelFont() : menuItem.getFont() ),
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() ) );
@@ -282,7 +297,8 @@ public class FlatMenuItemRenderer
// layout icon and text // layout icon and text
SwingUtilities.layoutCompoundLabel( menuItem, SwingUtilities.layoutCompoundLabel( menuItem,
menuItem.getFontMetrics( menuItem.getFont() ), menuItem.getText(), getIconForLayout(), menuItem.getFontMetrics( isTopLevelMenu ? getTopLevelFont() : menuItem.getFont() ),
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() ) );
@@ -392,9 +408,10 @@ debug*/
} }
int mnemonicIndex = FlatLaf.isShowMnemonics() ? menuItem.getDisplayedMnemonicIndex() : -1; int mnemonicIndex = FlatLaf.isShowMnemonics() ? menuItem.getDisplayedMnemonicIndex() : -1;
Color foreground = (isTopLevelMenu( menuItem ) ? menuItem.getParent() : menuItem).getForeground(); boolean isTopLevelMenu = isTopLevelMenu( menuItem );
Color foreground = (isTopLevelMenu ? menuItem.getParent() : menuItem).getForeground();
paintText( g, menuItem, textRect, text, mnemonicIndex, menuItem.getFont(), paintText( g, menuItem, textRect, text, mnemonicIndex, isTopLevelMenu ? getTopLevelFont() : menuItem.getFont(),
foreground, isUnderlineSelection() ? foreground : selectionForeground, disabledForeground ); foreground, isUnderlineSelection() ? foreground : selectionForeground, disabledForeground );
} }
@@ -481,6 +498,15 @@ 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();

View File

@@ -16,16 +16,19 @@
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.JMenuItem;
import javax.swing.LookAndFeel; import javax.swing.LookAndFeel;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicMenuItemUI; 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.ui.FlatStylingSupport.UnknownStyleException;
import com.formdev.flatlaf.util.LoggingFacade; import com.formdev.flatlaf.util.LoggingFacade;
@@ -58,9 +61,15 @@ 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 FlatMenuItemUI public class FlatMenuItemUI
extends BasicMenuItemUI extends BasicMenuItemUI
implements StyleableUI implements StyleableUI, StyleableLookupProvider
{ {
private FlatMenuItemRenderer renderer; private FlatMenuItemRenderer renderer;
private Map<String, Object> oldStyleValues; private Map<String, Object> oldStyleValues;
@@ -119,42 +128,54 @@ public class FlatMenuItemUI
/** @since 2 */ /** @since 2 */
protected Object applyStyleProperty( String key, Object value ) { protected Object applyStyleProperty( String key, Object value ) {
return applyStyleProperty( menuItem, this, renderer, key, value );
}
static Object applyStyleProperty( JMenuItem menuItem, BasicMenuItemUI ui,
FlatMenuItemRenderer renderer, String key, Object value )
{
try { try {
return renderer.applyStyleProperty( key, value ); return renderer.applyStyleProperty( key, value );
} catch ( UnknownStyleException ex ) { } catch ( UnknownStyleException ex ) {
// ignore // ignore
} }
Object oldValue; return FlatStylingSupport.applyToAnnotatedObjectOrComponent( ui, menuItem, key, value );
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 getStyleableInfos( renderer ); return getStyleableInfos( this, renderer );
} }
static Map<String, Class<?>> getStyleableInfos( FlatMenuItemRenderer renderer ) { static Map<String, Class<?>> getStyleableInfos( BasicMenuItemUI ui, FlatMenuItemRenderer renderer ) {
Map<String, Class<?>> infos = new FlatStylingSupport.StyleableInfosMap<>(); Map<String, Class<?>> infos = FlatStylingSupport.getAnnotatedStyleableInfos( ui );
infos.put( "selectionBackground", Color.class );
infos.put( "selectionForeground", Color.class );
infos.put( "disabledForeground", Color.class );
infos.put( "acceleratorForeground", Color.class );
infos.put( "acceleratorSelectionForeground", Color.class );
infos.putAll( renderer.getStyleableInfos() ); infos.putAll( renderer.getStyleableInfos() );
return infos; return infos;
} }
/** @since 2.5 */
@Override
public Object getStyleableValue( JComponent c, String key ) {
return getStyleableValue( this, renderer, key );
}
static Object getStyleableValue( BasicMenuItemUI ui, FlatMenuItemRenderer renderer, String key ) {
Object value = renderer.getStyleableValue( key );
if( value == null )
value = FlatStylingSupport.getAnnotatedStyleableValue( ui, key );
return value;
}
/** @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
protected Dimension getPreferredMenuItemSize( JComponent c, Icon checkIcon, Icon arrowIcon, int defaultTextIconGap ) { protected Dimension getPreferredMenuItemSize( JComponent c, Icon checkIcon, Icon arrowIcon, int defaultTextIconGap ) {
return renderer.getPreferredMenuItemSize(); return renderer.getPreferredMenuItemSize();

View File

@@ -20,8 +20,10 @@ import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Font; import java.awt.Font;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.lang.invoke.MethodHandles;
import java.util.Map; import java.util.Map;
import java.util.function.Function; import java.util.function.Function;
import javax.swing.ButtonModel; import javax.swing.ButtonModel;
@@ -35,9 +37,11 @@ import javax.swing.UIManager;
import javax.swing.event.MouseInputListener; import javax.swing.event.MouseInputListener;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.MenuBarUI; import javax.swing.plaf.MenuBarUI;
import javax.swing.plaf.basic.BasicMenuItemUI;
import javax.swing.plaf.basic.BasicMenuUI; import javax.swing.plaf.basic.BasicMenuUI;
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;
/** /**
@@ -72,15 +76,23 @@ import com.formdev.flatlaf.util.LoggingFacade;
* <!-- FlatMenuRenderer --> * <!-- FlatMenuRenderer -->
* *
* @uiDefault MenuBar.hoverBackground Color * @uiDefault MenuBar.hoverBackground Color
* @uiDefault MenuBar.selectionBackground Color
* @uiDefault MenuBar.selectionForeground Color
* @uiDefault MenuBar.underlineSelectionBackground Color * @uiDefault MenuBar.underlineSelectionBackground Color
* @uiDefault MenuBar.underlineSelectionColor Color * @uiDefault MenuBar.underlineSelectionColor Color
* @uiDefault MenuBar.underlineSelectionHeight int * @uiDefault MenuBar.underlineSelectionHeight int
* *
* @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 FlatMenuUI public class FlatMenuUI
extends BasicMenuUI extends BasicMenuUI
implements StyleableUI implements StyleableUI, StyleableLookupProvider
{ {
private FlatMenuItemRenderer renderer; private FlatMenuItemRenderer renderer;
private Map<String, Object> oldStyleValues; private Map<String, Object> oldStyleValues;
@@ -166,29 +178,27 @@ public class FlatMenuUI
/** @since 2 */ /** @since 2 */
protected Object applyStyleProperty( String key, Object value ) { protected Object applyStyleProperty( String key, Object value ) {
try { return FlatMenuItemUI.applyStyleProperty( menuItem, this, renderer, key, value );
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( renderer ); return FlatMenuItemUI.getStyleableInfos( this, 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
@@ -216,6 +226,8 @@ public class FlatMenuUI
extends FlatMenuItemRenderer extends FlatMenuItemRenderer
{ {
protected Color hoverBackground = UIManager.getColor( "MenuBar.hoverBackground" ); protected Color hoverBackground = UIManager.getColor( "MenuBar.hoverBackground" );
protected Color menuBarSelectionBackground = UIManager.getColor( "MenuBar.selectionBackground" );
protected Color menuBarSelectionForeground = UIManager.getColor( "MenuBar.selectionForeground" );
protected Color menuBarUnderlineSelectionBackground = FlatUIUtils.getUIColor( "MenuBar.underlineSelectionBackground", underlineSelectionBackground ); protected Color menuBarUnderlineSelectionBackground = FlatUIUtils.getUIColor( "MenuBar.underlineSelectionBackground", underlineSelectionBackground );
protected Color menuBarUnderlineSelectionColor = FlatUIUtils.getUIColor( "MenuBar.underlineSelectionColor", underlineSelectionColor ); protected Color menuBarUnderlineSelectionColor = FlatUIUtils.getUIColor( "MenuBar.underlineSelectionColor", underlineSelectionColor );
protected int menuBarUnderlineSelectionHeight = FlatUIUtils.getUIInt( "MenuBar.underlineSelectionHeight", underlineSelectionHeight ); protected int menuBarUnderlineSelectionHeight = FlatUIUtils.getUIInt( "MenuBar.underlineSelectionHeight", underlineSelectionHeight );
@@ -231,6 +243,10 @@ public class FlatMenuUI
if( ((JMenu)menuItem).isTopLevelMenu() ) { if( ((JMenu)menuItem).isTopLevelMenu() ) {
if( isUnderlineSelection() ) if( isUnderlineSelection() )
selectionBackground = getStyleFromMenuBarUI( ui -> ui.underlineSelectionBackground, menuBarUnderlineSelectionBackground ); selectionBackground = getStyleFromMenuBarUI( ui -> ui.underlineSelectionBackground, menuBarUnderlineSelectionBackground );
else {
selectionBackground = getStyleFromMenuBarUI( ui -> ui.selectionBackground,
menuBarSelectionBackground != null ? menuBarSelectionBackground : selectionBackground );
}
ButtonModel model = menuItem.getModel(); ButtonModel model = menuItem.getModel();
if( model.isRollover() && !model.isArmed() && !model.isSelected() && model.isEnabled() ) { if( model.isRollover() && !model.isArmed() && !model.isSelected() && model.isEnabled() ) {
@@ -243,6 +259,16 @@ public class FlatMenuUI
super.paintBackground( g, selectionBackground ); super.paintBackground( g, selectionBackground );
} }
@Override
protected void paintText( Graphics g, Rectangle textRect, String text, Color selectionForeground, Color disabledForeground ) {
if( ((JMenu)menuItem).isTopLevelMenu() && !isUnderlineSelection() ) {
selectionForeground = getStyleFromMenuBarUI( ui -> ui.selectionForeground,
menuBarSelectionForeground != null ? menuBarSelectionForeground : selectionForeground );
}
super.paintText( g, textRect, text, selectionForeground, disabledForeground );
}
@Override @Override
protected void paintUnderlineSelection( Graphics g, Color underlineSelectionColor, int underlineSelectionHeight ) { protected void paintUnderlineSelection( Graphics g, Color underlineSelectionColor, int underlineSelectionHeight ) {
if( ((JMenu)menuItem).isTopLevelMenu() ) { if( ((JMenu)menuItem).isTopLevelMenu() ) {

View File

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

View File

@@ -0,0 +1,104 @@
/*
* Copyright 2022 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.ui;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import javax.swing.JDialog;
import javax.swing.JFrame;
/**
* Native methods for Linux.
* <p>
* <b>Note</b>: This is private API. Do not use!
*
* @author Karl Tauber
* @since 2.5
*/
class FlatNativeLinuxLibrary
{
static boolean isLoaded() {
return FlatNativeLibrary.isLoaded();
}
// direction for _NET_WM_MOVERESIZE message
// see https://specifications.freedesktop.org/wm-spec/wm-spec-latest.html
static final int MOVE = 8;
private static Boolean isXWindowSystem;
private static boolean isXWindowSystem() {
if( isXWindowSystem == null )
isXWindowSystem = Toolkit.getDefaultToolkit().getClass().getName().endsWith( ".XToolkit" );
return isXWindowSystem;
}
static boolean isWMUtilsSupported( Window window ) {
return hasCustomDecoration( window ) && isXWindowSystem() && isLoaded();
}
static boolean moveOrResizeWindow( Window window, MouseEvent e, int direction ) {
Point pt = scale( window, e.getLocationOnScreen() );
return xMoveOrResizeWindow( window, pt.x, pt.y, direction );
/*
try {
Class<?> cls = Class.forName( "com.formdev.flatlaf.natives.jna.linux.X11WmUtils" );
java.lang.reflect.Method m = cls.getMethod( "xMoveOrResizeWindow", Window.class, int.class, int.class, int.class );
return (Boolean) m.invoke( null, window, pt.x, pt.y, direction );
} catch (Exception ex) {
ex.printStackTrace();
return false;
}
*/
}
static boolean showWindowMenu( Window window, MouseEvent e ) {
Point pt = scale( window, e.getLocationOnScreen() );
return xShowWindowMenu( window, pt.x, pt.y );
/*
try {
Class<?> cls = Class.forName( "com.formdev.flatlaf.natives.jna.linux.X11WmUtils" );
java.lang.reflect.Method m = cls.getMethod( "xShowWindowMenu", Window.class, int.class, int.class );
return (Boolean) m.invoke( null, window, pt.x, pt.y );
} catch (Exception ex) {
ex.printStackTrace();
return false;
}
*/
}
private static Point scale( Window window, Point pt ) {
AffineTransform transform = window.getGraphicsConfiguration().getDefaultTransform();
int x = (int) Math.round( pt.x * transform.getScaleX() );
int y = (int) Math.round( pt.y * transform.getScaleY() );
return new Point( x, y );
}
// X Window System
private static native boolean xMoveOrResizeWindow( Window window, int x, int y, int direction );
private static native boolean xShowWindowMenu( Window window, int x, int y );
private static boolean hasCustomDecoration( Window window ) {
return (window instanceof JFrame && JFrame.isDefaultLookAndFeelDecorated() && ((JFrame)window).isUndecorated()) ||
(window instanceof JDialog && JDialog.isDefaultLookAndFeelDecorated() && ((JDialog)window).isUndecorated());
}
}

View File

@@ -127,6 +127,12 @@ public class FlatPanelUI
return FlatStylingSupport.getAnnotatedStyleableInfos( this ); return FlatStylingSupport.getAnnotatedStyleableInfos( this );
} }
/** @since 2.5 */
@Override
public Object getStyleableValue( JComponent c, String key ) {
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
}
@Override @Override
public void update( Graphics g, JComponent c ) { public void update( Graphics g, JComponent c ) {
// fill background // fill background

View File

@@ -23,6 +23,7 @@ import java.awt.Toolkit;
import java.awt.event.KeyAdapter; import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import java.awt.event.KeyListener; import java.awt.event.KeyListener;
import java.beans.PropertyChangeEvent;
import java.util.Map; import java.util.Map;
import javax.swing.Action; import javax.swing.Action;
import javax.swing.ActionMap; import javax.swing.ActionMap;
@@ -233,6 +234,14 @@ public class FlatPasswordFieldUI
return infos; return infos;
} }
@Override
public Object getStyleableValue( JComponent c, String key ) {
if( key.equals( "capsLockIconColor" ) && capsLockIcon instanceof FlatCapsLockIcon )
return ((FlatCapsLockIcon)capsLockIcon).getStyleableValue( key );
return super.getStyleableValue( c, key );
}
@Override @Override
public View create( Element elem ) { public View create( Element elem ) {
return new PasswordView( elem ); return new PasswordView( elem );
@@ -283,6 +292,7 @@ public class FlatPasswordFieldUI
protected void installRevealButton() { protected void installRevealButton() {
if( showRevealButton ) { if( showRevealButton ) {
revealButton = createRevealButton(); revealButton = createRevealButton();
updateRevealButton();
installLayout(); installLayout();
getComponent().add( revealButton ); getComponent().add( revealButton );
} }
@@ -290,28 +300,64 @@ public class FlatPasswordFieldUI
/** @since 2 */ /** @since 2 */
protected JToggleButton createRevealButton() { protected JToggleButton createRevealButton() {
JToggleButton button = new JToggleButton( revealIcon ); JPasswordField c = (JPasswordField) getComponent();
JToggleButton button = new JToggleButton( revealIcon, !c.echoCharIsSet() );
button.setName( "PasswordField.revealButton" ); button.setName( "PasswordField.revealButton" );
prepareLeadingOrTrailingComponent( button ); prepareLeadingOrTrailingComponent( button );
button.putClientProperty( FlatClientProperties.STYLE_CLASS, "inTextField revealButton" ); button.putClientProperty( FlatClientProperties.STYLE_CLASS, "inTextField revealButton" );
if( FlatClientProperties.clientPropertyBoolean( getComponent(), KEY_REVEAL_SELECTED, false ) ) { if( FlatClientProperties.clientPropertyBoolean( c, KEY_REVEAL_SELECTED, false ) ) {
button.setSelected( true ); button.setSelected( true );
updateEchoChar( true ); updateEchoChar( true );
} }
button.addActionListener( e -> { button.addActionListener( e -> {
boolean selected = button.isSelected(); boolean selected = button.isSelected();
updateEchoChar( selected ); updateEchoChar( selected );
getComponent().putClientProperty( KEY_REVEAL_SELECTED, selected ); c.putClientProperty( KEY_REVEAL_SELECTED, selected );
} ); } );
return button; return button;
} }
/** @since 2.5 */
protected void updateRevealButton() {
if( revealButton == null )
return;
JTextComponent c = getComponent();
boolean visible = c.isEnabled();
if( visible != revealButton.isVisible() ) {
revealButton.setVisible( visible );
c.revalidate();
c.repaint();
if( !visible ) {
revealButton.setSelected( false );
updateEchoChar( false );
getComponent().putClientProperty( KEY_REVEAL_SELECTED, null );
}
}
}
@Override
protected void propertyChange( PropertyChangeEvent e ) {
super.propertyChange( e );
switch( e.getPropertyName() ) {
case "enabled":
updateRevealButton();
break;
}
}
private void updateEchoChar( boolean selected ) { private void updateEchoChar( boolean selected ) {
char newEchoChar = selected char newEchoChar = selected
? 0 ? 0
: (echoChar != null ? echoChar : '*'); : (echoChar != null ? echoChar : '*');
JPasswordField c = (JPasswordField) getComponent(); JPasswordField c = (JPasswordField) getComponent();
if( newEchoChar == c.getEchoChar() )
return;
// set echo char
LookAndFeel.installProperty( c, "echoChar", newEchoChar ); LookAndFeel.installProperty( c, "echoChar", newEchoChar );
// check whether was able to set echo char via LookAndFeel.installProperty() // check whether was able to set echo char via LookAndFeel.installProperty()

View File

@@ -36,7 +36,9 @@ import java.awt.Window;
import java.awt.event.ComponentEvent; import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener; import java.awt.event.ComponentListener;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.lang.reflect.InvocationTargetException; 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 javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JLayeredPane; import javax.swing.JLayeredPane;
@@ -64,8 +66,8 @@ import com.formdev.flatlaf.util.UIScale;
public class FlatPopupFactory public class FlatPopupFactory
extends PopupFactory extends PopupFactory
{ {
private Method java8getPopupMethod; private MethodHandle java8getPopupMethod;
private Method java9getPopupMethod; private MethodHandle java9getPopupMethod;
@Override @Override
public Popup getPopup( Component owner, Component contents, int x, int y ) public Popup getPopup( Component owner, Component contents, int x, int y )
@@ -192,23 +194,25 @@ public class FlatPopupFactory
{ {
try { try {
if( SystemInfo.isJava_9_orLater ) { if( SystemInfo.isJava_9_orLater ) {
// Java 9: protected Popup getPopup( Component owner, Component contents, int x, int y, boolean isHeavyWeightPopup )
if( java9getPopupMethod == null ) { if( java9getPopupMethod == null ) {
java9getPopupMethod = PopupFactory.class.getDeclaredMethod( MethodType mt = MethodType.methodType( Popup.class, Component.class, Component.class, int.class, int.class, boolean.class );
"getPopup", Component.class, Component.class, int.class, int.class, boolean.class ); java9getPopupMethod = MethodHandles.lookup().findVirtual( PopupFactory.class, "getPopup", mt );
} }
return (Popup) java9getPopupMethod.invoke( this, owner, contents, x, y, true ); return (Popup) java9getPopupMethod.invoke( this, owner, contents, x, y, true );
} else { } else {
// Java 8 // Java 8: private Popup getPopup( Component owner, Component contents, int ownerX, int ownerY, int popupType )
if( java8getPopupMethod == null ) { if( java8getPopupMethod == null ) {
java8getPopupMethod = PopupFactory.class.getDeclaredMethod( Method m = PopupFactory.class.getDeclaredMethod(
"getPopup", Component.class, Component.class, int.class, int.class, int.class ); "getPopup", Component.class, Component.class, int.class, int.class, int.class );
java8getPopupMethod.setAccessible( true ); m.setAccessible( true );
java8getPopupMethod = MethodHandles.lookup().unreflect( m );
} }
return (Popup) java8getPopupMethod.invoke( this, owner, contents, x, y, /*HEAVY_WEIGHT_POPUP*/ 2 ); return (Popup) java8getPopupMethod.invoke( this, owner, contents, x, y, /*HEAVY_WEIGHT_POPUP*/ 2 );
} }
} catch( NoSuchMethodException | SecurityException | IllegalAccessException | InvocationTargetException ex ) { } catch( Throwable ex ) {
// ignore // fallback
return null; return super.getPopup( owner, contents, x, y );
} }
} }

View File

@@ -66,6 +66,16 @@ public class FlatPopupMenuBorder
return infos; return infos;
} }
/** @since 2.5 */
@Override
public Object getStyleableValue( String key ) {
switch( key ) {
case "borderInsets": return getStyleableValue();
case "borderColor": return borderColor;
}
return null;
}
@Override @Override
public Color getLineColor() { public Color getLineColor() {
return (borderColor != null) ? borderColor : super.getLineColor(); return (borderColor != null) ? borderColor : super.getLineColor();

View File

@@ -184,6 +184,12 @@ public class FlatPopupMenuUI
return FlatStylingSupport.getAnnotatedStyleableInfos( this, popupMenu.getBorder() ); return FlatStylingSupport.getAnnotatedStyleableInfos( this, popupMenu.getBorder() );
} }
/** @since 2.5 */
@Override
public Object getStyleableValue( JComponent c, String key ) {
return FlatStylingSupport.getAnnotatedStyleableValue( this, popupMenu.getBorder(), key );
}
@Override @Override
public Popup getPopup( JPopupMenu popup, int x, int y ) { public Popup getPopup( JPopupMenu popup, int x, int y ) {
// do not add scroller to combobox popups or to popups that already have a scroll pane // do not add scroller to combobox popups or to popups that already have a scroll pane

View File

@@ -160,6 +160,12 @@ public class FlatProgressBarUI
return FlatStylingSupport.getAnnotatedStyleableInfos( this ); return FlatStylingSupport.getAnnotatedStyleableInfos( this );
} }
/** @since 2.5 */
@Override
public Object getStyleableValue( JComponent c, String key ) {
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
}
@Override @Override
public Dimension getPreferredSize( JComponent c ) { public Dimension getPreferredSize( JComponent c ) {
Dimension size = super.getPreferredSize( c ); Dimension size = super.getPreferredSize( c );

View File

@@ -16,18 +16,20 @@
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.BasicMenuItemUI;
import javax.swing.plaf.basic.BasicRadioButtonMenuItemUI; import javax.swing.plaf.basic.BasicRadioButtonMenuItemUI;
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;
/** /**
@@ -58,9 +60,15 @@ 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 FlatRadioButtonMenuItemUI public class FlatRadioButtonMenuItemUI
extends BasicRadioButtonMenuItemUI extends BasicRadioButtonMenuItemUI
implements StyleableUI implements StyleableUI, StyleableLookupProvider
{ {
private FlatMenuItemRenderer renderer; private FlatMenuItemRenderer renderer;
private Map<String, Object> oldStyleValues; private Map<String, Object> oldStyleValues;
@@ -119,29 +127,27 @@ public class FlatRadioButtonMenuItemUI
/** @since 2 */ /** @since 2 */
protected Object applyStyleProperty( String key, Object value ) { protected Object applyStyleProperty( String key, Object value ) {
try { return FlatMenuItemUI.applyStyleProperty( menuItem, this, renderer, key, value );
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( renderer ); return FlatMenuItemUI.getStyleableInfos( this, 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

@@ -18,12 +18,16 @@ 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.Container; import java.awt.Container;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Insets; import java.awt.Insets;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import javax.swing.AbstractButton; import javax.swing.AbstractButton;
@@ -31,6 +35,7 @@ import javax.swing.CellRendererPane;
import javax.swing.Icon; import javax.swing.Icon;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.LookAndFeel; import javax.swing.LookAndFeel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicButtonListener; import javax.swing.plaf.basic.BasicButtonListener;
@@ -78,7 +83,7 @@ public class FlatRadioButtonUI
private Map<String, Object> oldStyleValues; private Map<String, Object> oldStyleValues;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return FlatUIUtils.canUseSharedUI( c ) return FlatUIUtils.canUseSharedUI( c ) && !FlatUIUtils.needsLightAWTPeer( c )
? FlatUIUtils.createSharedUI( FlatRadioButtonUI.class, () -> new FlatRadioButtonUI( true ) ) ? FlatUIUtils.createSharedUI( FlatRadioButtonUI.class, () -> new FlatRadioButtonUI( true ) )
: new FlatRadioButtonUI( false ); : new FlatRadioButtonUI( false );
} }
@@ -90,11 +95,29 @@ public class FlatRadioButtonUI
@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 );
if( FlatUIUtils.isAWTPeer( c ) )
AWTPeerMouseExitedFix.install( c );
installStyle( (AbstractButton) c ); installStyle( (AbstractButton) c );
} }
@Override
public void uninstallUI( JComponent c ) {
super.uninstallUI( c );
if( FlatUIUtils.isAWTPeer( c ) )
AWTPeerMouseExitedFix.uninstall( c );
}
@Override @Override
public void installDefaults( AbstractButton b ) { public void installDefaults( AbstractButton b ) {
super.installDefaults( b ); super.installDefaults( b );
@@ -199,6 +222,19 @@ public class FlatRadioButtonUI
return infos; return infos;
} }
/** @since 2.5 */
@Override
public Object getStyleableValue( JComponent c, String key ) {
// style icon
if( key.startsWith( "icon." ) ) {
return (icon instanceof FlatCheckBoxIcon)
? ((FlatCheckBoxIcon)icon).getStyleableValue( key.substring( "icon.".length() ) )
: null;
}
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
}
private static final Insets tempInsets = new Insets( 0, 0, 0, 0 ); private static final Insets tempInsets = new Insets( 0, 0, 0, 0 );
@Override @Override
@@ -308,4 +344,69 @@ public class FlatRadioButtonUI
FlatRadioButtonUI.this.propertyChange( b, e ); FlatRadioButtonUI.this.propertyChange( b, e );
} }
} }
//---- class AWTPeerMouseExitedFix ----------------------------------------
/**
* Hack for missing mouse-exited event for java.awt.Checkbox on macOS (to fix hover effect).
*
* On macOS, AWT components internally use Swing components.
* This is implemented in class sun.lwawt.LWCheckboxPeer, which uses
* a container component CheckboxDelegate that has a JCheckBox and a JRadioButton
* as children. Only one of them is visible.
*
* The reason that mouse-exited event is not sent to the JCheckBox or JRadioButton
* is that sun.lwawt.LWComponentPeer.createDelegateEvent() uses
* SwingUtilities.getDeepestComponentAt() to find the event target,
* which finds the container component CheckboxDelegate,
* which receives the mouse-exited event.
*
* This class adds listeners and forwards the mouse-exited event
* from CheckboxDelegate to JCheckBox or JRadioButton.
*/
private static class AWTPeerMouseExitedFix
extends MouseAdapter
implements PropertyChangeListener
{
private final JComponent button;
static void install( JComponent button ) {
AWTPeerMouseExitedFix l = new AWTPeerMouseExitedFix( button );
button.addPropertyChangeListener( "ancestor", l );
Container parent = button.getParent();
if( parent != null )
parent.addMouseListener( l );
}
static void uninstall( JComponent button ) {
for( PropertyChangeListener l : button.getPropertyChangeListeners( "ancestor" ) ) {
if( l instanceof AWTPeerMouseExitedFix ) {
button.removePropertyChangeListener( "ancestor", l );
Container parent = button.getParent();
if( parent != null )
parent.removeMouseListener( (AWTPeerMouseExitedFix) l );
break;
}
}
}
AWTPeerMouseExitedFix( JComponent button ) {
this.button = button;
}
@Override
public void propertyChange( PropertyChangeEvent e ) {
if( e.getOldValue() instanceof Component )
((Component)e.getOldValue()).removeMouseListener( this );
if( e.getNewValue() instanceof Component ) {
((Component)e.getNewValue()).removeMouseListener( this ); // avoid duplicate listeners
((Component)e.getNewValue()).addMouseListener( this );
}
}
@Override
public void mouseExited( MouseEvent e ) {
button.dispatchEvent( SwingUtilities.convertMouseEvent( e.getComponent(), e, button ) );
}
}
} }

View File

@@ -17,6 +17,7 @@
package com.formdev.flatlaf.ui; package com.formdev.flatlaf.ui;
import java.awt.Color; import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Insets; import java.awt.Insets;
@@ -24,6 +25,7 @@ import java.awt.Rectangle;
import java.awt.event.MouseAdapter; import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.lang.invoke.MethodHandles;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import javax.swing.InputMap; import javax.swing.InputMap;
@@ -36,9 +38,13 @@ import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicScrollBarUI; import javax.swing.plaf.basic.BasicScrollBarUI;
import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.FlatClientProperties;
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.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.UIScale; import com.formdev.flatlaf.util.UIScale;
/** /**
@@ -77,9 +83,15 @@ import com.formdev.flatlaf.util.UIScale;
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@StyleableField( cls=BasicScrollBarUI.class, key="track", fieldName="trackColor" )
@StyleableField( cls=BasicScrollBarUI.class, key="thumb", fieldName="thumbColor" )
@StyleableField( cls=BasicScrollBarUI.class, key="width", fieldName="scrollBarWidth" )
@StyleableField( cls=BasicScrollBarUI.class, key="minimumThumbSize" )
@StyleableField( cls=BasicScrollBarUI.class, key="maximumThumbSize" )
public class FlatScrollBarUI public class FlatScrollBarUI
extends BasicScrollBarUI extends BasicScrollBarUI
implements StyleableUI implements StyleableUI, StyleableLookupProvider
{ {
// overrides BasicScrollBarUI.supportsAbsolutePositioning (which is private) // overrides BasicScrollBarUI.supportsAbsolutePositioning (which is private)
@Styleable protected boolean allowsAbsolutePositioning; @Styleable protected boolean allowsAbsolutePositioning;
@@ -108,6 +120,7 @@ public class FlatScrollBarUI
protected boolean hoverThumb; protected boolean hoverThumb;
private Map<String, Object> oldStyleValues; private Map<String, Object> oldStyleValues;
private boolean isAWTPeer;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatScrollBarUI(); return new FlatScrollBarUI();
@@ -221,6 +234,37 @@ public class FlatScrollBarUI
} }
SwingUtilities.replaceUIInputMap( scrollbar, JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, inputMap ); SwingUtilities.replaceUIInputMap( scrollbar, JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, inputMap );
break; break;
case "ancestor":
// check whether scroll bar is used as AWT peer on macOS
if( SystemInfo.isMacOS ) {
Container p = scrollbar.getParent();
for( int i = 0; i < 2 && p != null; i++, p = p.getParent() ) {
if( FlatUIUtils.isAWTPeer( p ) ) {
// Used to disable hover, which does not work correctly
// because scroll bars do not receive mouse exited event.
// The scroll pane, including its scroll bars, is not part
// of the component hierarchy and does not receive mouse events
// directly. Instead LWComponentPeer receives mouse events
// and delegates them to peers, but entered/exited events
// are sent only for the whole scroll pane.
// Exited event is only sent when mouse leaves scroll pane.
// If mouse enters/exits scroll bar, no entered/exited events are sent.
isAWTPeer = true;
// if dark theme is active, reinstall using light theme
if( FlatLaf.isLafDark() ) {
FlatUIUtils.runWithLightAWTPeerUIDefaults( () -> {
JScrollBar scrollbar = this.scrollbar;
uninstallUI( scrollbar );
installUI( scrollbar );
} );
}
break;
}
}
}
break;
} }
}; };
} }
@@ -246,30 +290,27 @@ public class FlatScrollBarUI
/** @since 2 */ /** @since 2 */
protected Object applyStyleProperty( String key, Object value ) { protected Object applyStyleProperty( String key, Object value ) {
Object oldValue;
switch( key ) {
// BasicScrollBarUI
case "track": oldValue = trackColor; trackColor = (Color) value; return oldValue;
case "thumb": oldValue = thumbColor; thumbColor = (Color) value; return oldValue;
case "width": oldValue = scrollBarWidth; scrollBarWidth = (int) value; return oldValue;
case "minimumThumbSize": oldValue = minimumThumbSize; minimumThumbSize = (Dimension) value; return oldValue;
case "maximumThumbSize": oldValue = maximumThumbSize; maximumThumbSize = (Dimension) value; return oldValue;
}
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, scrollbar, key, value ); return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, scrollbar, key, value );
} }
/** @since 2 */ /** @since 2 */
@Override @Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) { public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
Map<String, Class<?>> infos = new FlatStylingSupport.StyleableInfosMap<>(); return FlatStylingSupport.getAnnotatedStyleableInfos( this );
infos.put( "track", Color.class ); }
infos.put( "thumb", Color.class );
infos.put( "width", int.class ); /** @since 2.5 */
infos.put( "minimumThumbSize", Dimension.class ); @Override
infos.put( "maximumThumbSize", Dimension.class ); public Object getStyleableValue( JComponent c, String key ) {
FlatStylingSupport.collectAnnotatedStyleableInfos( this, infos ); return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
return infos; }
/** @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
@@ -311,6 +352,9 @@ public class FlatScrollBarUI
@Override @Override
protected void paintTrack( Graphics g, JComponent c, Rectangle trackBounds ) { protected void paintTrack( Graphics g, JComponent c, Rectangle trackBounds ) {
if( trackBounds.isEmpty() || !scrollbar.isEnabled() )
return;
g.setColor( getTrackColor( c, hoverTrack, isPressed && hoverTrack && !hoverThumb ) ); g.setColor( getTrackColor( c, hoverTrack, isPressed && hoverTrack && !hoverThumb ) );
paintTrackOrThumb( g, c, trackBounds, trackInsets, trackArc ); paintTrackOrThumb( g, c, trackBounds, trackInsets, trackArc );
} }
@@ -357,7 +401,7 @@ public class FlatScrollBarUI
Color trackColor = FlatUIUtils.deriveColor( this.trackColor, c.getBackground() ); Color trackColor = FlatUIUtils.deriveColor( this.trackColor, c.getBackground() );
return (pressed && pressedTrackColor != null) return (pressed && pressedTrackColor != null)
? FlatUIUtils.deriveColor( pressedTrackColor, trackColor ) ? FlatUIUtils.deriveColor( pressedTrackColor, trackColor )
: ((hover && hoverTrackColor != null) : ((hover && hoverTrackColor != null && !isAWTPeer)
? FlatUIUtils.deriveColor( hoverTrackColor, trackColor ) ? FlatUIUtils.deriveColor( hoverTrackColor, trackColor )
: trackColor); : trackColor);
} }
@@ -367,7 +411,7 @@ public class FlatScrollBarUI
Color thumbColor = FlatUIUtils.deriveColor( this.thumbColor, trackColor ); Color thumbColor = FlatUIUtils.deriveColor( this.thumbColor, trackColor );
return (pressed && pressedThumbColor != null) return (pressed && pressedThumbColor != null)
? FlatUIUtils.deriveColor( pressedThumbColor, thumbColor ) ? FlatUIUtils.deriveColor( pressedThumbColor, thumbColor )
: ((hover && hoverThumbColor != null) : ((hover && hoverThumbColor != null && !isAWTPeer)
? FlatUIUtils.deriveColor( hoverThumbColor, thumbColor ) ? FlatUIUtils.deriveColor( hoverThumbColor, thumbColor )
: thumbColor); : thumbColor);
} }
@@ -411,18 +455,31 @@ public class FlatScrollBarUI
@Override @Override
public void mousePressed( MouseEvent e ) { public void mousePressed( MouseEvent e ) {
if( SwingUtilities.isLeftMouseButton( e ) || isAbsolutePositioning( e ) ) {
isPressed = true; isPressed = true;
repaint(); repaint();
// update hover because BasicScrollBarUI.TrackListener.mousePressed()
// moves the track on middle-click (if absolute positioning is enabled)
if( isAbsolutePositioning( e ) )
update( e.getX(), e.getY() );
}
} }
@Override @Override
public void mouseReleased( MouseEvent e ) { public void mouseReleased( MouseEvent e ) {
if( SwingUtilities.isLeftMouseButton( e ) || isAbsolutePositioning( e ) ) {
isPressed = false; isPressed = false;
repaint(); repaint();
}
update( e.getX(), e.getY() ); update( e.getX(), e.getY() );
} }
private boolean isAbsolutePositioning( MouseEvent e ) {
return getSupportsAbsolutePositioning() && SwingUtilities.isMiddleMouseButton( e );
}
private void update( int x, int y ) { private void update( int x, int y ) {
boolean inTrack = getTrackBounds().contains( x, y ); boolean inTrack = getTrackBounds().contains( x, y );
boolean inThumb = getThumbBounds().contains( x, y ); boolean inThumb = getThumbBounds().contains( x, y );

View File

@@ -87,6 +87,13 @@ public class FlatScrollPaneUI
@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 );
int focusWidth = UIManager.getInt( "Component.focusWidth" ); int focusWidth = UIManager.getInt( "Component.focusWidth" );
@@ -343,6 +350,12 @@ public class FlatScrollPaneUI
return FlatStylingSupport.getAnnotatedStyleableInfos( this, scrollpane.getBorder() ); return FlatStylingSupport.getAnnotatedStyleableInfos( this, scrollpane.getBorder() );
} }
/** @since 2.5 */
@Override
public Object getStyleableValue( JComponent c, String key ) {
return FlatStylingSupport.getAnnotatedStyleableValue( this, scrollpane.getBorder(), key );
}
@Override @Override
protected void updateViewport( PropertyChangeEvent e ) { protected void updateViewport( PropertyChangeEvent e ) {
super.updateViewport( e ); super.updateViewport( e );

View File

@@ -170,6 +170,12 @@ public class FlatSeparatorUI
return FlatStylingSupport.getAnnotatedStyleableInfos( this ); return FlatStylingSupport.getAnnotatedStyleableInfos( this );
} }
/** @since 2.5 */
@Override
public Object getStyleableValue( JComponent c, String key ) {
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
}
@Override @Override
public void paint( Graphics g, JComponent c ) { public void paint( Graphics g, JComponent c ) {
Graphics2D g2 = (Graphics2D) g.create(); Graphics2D g2 = (Graphics2D) g.create();

View File

@@ -222,6 +222,12 @@ public class FlatSliderUI
return FlatStylingSupport.getAnnotatedStyleableInfos( this ); return FlatStylingSupport.getAnnotatedStyleableInfos( this );
} }
/** @since 2.5 */
@Override
public Object getStyleableValue( JComponent c, String key ) {
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
}
@Override @Override
public int getBaseline( JComponent c, int width, int height ) { public int getBaseline( JComponent c, int width, int height ) {
if( c == null ) if( c == null )

View File

@@ -223,6 +223,12 @@ public class FlatSpinnerUI
return FlatStylingSupport.getAnnotatedStyleableInfos( this, spinner.getBorder() ); return FlatStylingSupport.getAnnotatedStyleableInfos( this, spinner.getBorder() );
} }
/** @since 2.5 */
@Override
public Object getStyleableValue( JComponent c, String key ) {
return FlatStylingSupport.getAnnotatedStyleableValue( this, spinner.getBorder(), key );
}
@Override @Override
protected JComponent createEditor() { protected JComponent createEditor() {
JComponent editor = super.createEditor(); JComponent editor = super.createEditor();
@@ -477,9 +483,10 @@ public class FlatSpinnerUI
// limit buttons width to height of a raw spinner (without insets) // limit buttons width to height of a raw spinner (without insets)
FontMetrics fm = spinner.getFontMetrics( spinner.getFont() ); FontMetrics fm = spinner.getFontMetrics( spinner.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 area square (if spinner has preferred height) // make button area square (except if width is limited)
int buttonsWidth = Math.min( parent.getPreferredSize().height - insets.top - insets.bottom, maxButtonWidth ); int buttonsWidth = Math.min( Math.max( buttonsRect.height, minButtonWidth ), maxButtonWidth );
buttonsRect.width = buttonsWidth; buttonsRect.width = buttonsWidth;
if( parent.getComponentOrientation().isLeftToRight() ) { if( parent.getComponentOrientation().isLeftToRight() ) {

View File

@@ -183,6 +183,17 @@ public class FlatSplitPaneUI
return infos; return infos;
} }
/** @since 2.5 */
@Override
public Object getStyleableValue( JComponent c, String key ) {
if( divider instanceof FlatSplitPaneDivider ) {
Object value = ((FlatSplitPaneDivider)divider).getStyleableValue( key );
if( value != null )
return value;
}
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
}
//---- class FlatSplitPaneDivider ----------------------------------------- //---- class FlatSplitPaneDivider -----------------------------------------
protected class FlatSplitPaneDivider protected class FlatSplitPaneDivider
@@ -200,20 +211,21 @@ public class FlatSplitPaneUI
setLayout( new FlatDividerLayout() ); setLayout( new FlatDividerLayout() );
} }
/** /** @since 2 */
* @since 2
*/
protected Object applyStyleProperty( String key, Object value ) { protected Object applyStyleProperty( String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObject( this, key, value ); return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
} }
/** /** @since 2 */
* @since 2
*/
public Map<String, Class<?>> getStyleableInfos() { public Map<String, Class<?>> getStyleableInfos() {
return FlatStylingSupport.getAnnotatedStyleableInfos( this ); return FlatStylingSupport.getAnnotatedStyleableInfos( this );
} }
/** @since 2.5 */
public Object getStyleableValue( String key ) {
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
}
void updateStyle() { void updateStyle() {
if( leftButton instanceof FlatOneTouchButton ) if( leftButton instanceof FlatOneTouchButton )
((FlatOneTouchButton)leftButton).updateStyle(); ((FlatOneTouchButton)leftButton).updateStyle();

View File

@@ -18,9 +18,11 @@ package com.formdev.flatlaf.ui;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
@@ -63,15 +65,55 @@ public class FlatStylingSupport
Class<?> type() default Void.class; Class<?> type() default Void.class;
} }
/**
* Indicates that a field in the specified (super) class
* is intended to be used by FlatLaf styling support.
* <p>
* Use this annotation, instead of {@link Styleable}, to style fields
* in superclasses, where it is not possible to use {@link Styleable}.
* <p>
* Classes using this annotation may implement {@link StyleableLookupProvider}
* to give access to protected fields (in JRE) in modular applications.
*
* @since 2.5
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(StyleableFields.class)
public @interface StyleableField {
Class<?> cls();
String key();
String fieldName() default "";
}
/**
* Container annotation for {@link StyleableField}.
*
* @since 2.5
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface StyleableFields {
StyleableField[] value();
}
/** @since 2 */ /** @since 2 */
public interface StyleableUI { public interface StyleableUI {
Map<String, Class<?>> getStyleableInfos( JComponent c ); Map<String, Class<?>> getStyleableInfos( JComponent c );
/** @since 2.5 */ Object getStyleableValue( JComponent c, String key );
} }
/** @since 2 */ /** @since 2 */
public interface StyleableBorder { public interface StyleableBorder {
Object applyStyleProperty( String key, Object value ); Object applyStyleProperty( String key, Object value );
Map<String, Class<?>> getStyleableInfos(); Map<String, Class<?>> getStyleableInfos();
/** @since 2.5 */ Object getStyleableValue( String key );
}
/** @since 2.5 */
public interface StyleableLookupProvider {
MethodHandles.Lookup getLookupForStyling();
} }
@@ -365,21 +407,25 @@ public class FlatStylingSupport
public static Object applyToAnnotatedObject( Object obj, String key, Object value ) public static Object applyToAnnotatedObject( Object obj, String key, Object value )
throws UnknownStyleException, IllegalArgumentException throws UnknownStyleException, IllegalArgumentException
{ {
String fieldName = key; String fieldName = keyToFieldName( key );
int dotIndex = key.indexOf( '.' );
if( dotIndex >= 0 ) {
// remove first dot in key and change subsequent character to uppercase
fieldName = key.substring( 0, dotIndex )
+ Character.toUpperCase( key.charAt( dotIndex + 1 ) )
+ key.substring( dotIndex + 2 );
}
return applyToField( obj, fieldName, key, value, field -> { return applyToField( obj, fieldName, key, value, field -> {
Styleable styleable = field.getAnnotation( Styleable.class ); Styleable styleable = field.getAnnotation( Styleable.class );
return styleable != null && styleable.dot() == (dotIndex >= 0); return styleable != null && styleable.dot() == (fieldName != key);
} ); } );
} }
private static String keyToFieldName( String key ) {
int dotIndex = key.indexOf( '.' );
if( dotIndex < 0 )
return key;
// remove first dot in key and change subsequent character to uppercase
return key.substring( 0, dotIndex )
+ Character.toUpperCase( key.charAt( dotIndex + 1 ) )
+ key.substring( dotIndex + 2 );
}
/** /**
* Applies the given value to a field of the given object. * Applies the given value to a field of the given object.
* *
@@ -405,26 +451,17 @@ public class FlatStylingSupport
for(;;) { for(;;) {
try { try {
Field f = cls.getDeclaredField( fieldName ); Field f = cls.getDeclaredField( fieldName );
if( predicate == null || predicate.test( f ) ) { if( predicate == null || predicate.test( f ) )
if( !isValidField( f ) ) return applyToField( f, obj, value, false );
throw new IllegalArgumentException( "field '" + cls.getName() + "." + fieldName + "' is final or static" );
try {
// necessary to access protected fields in other packages
f.setAccessible( true );
// get old value and set new value
Object oldValue = f.get( obj );
f.set( obj, convertToEnum( value, f.getType() ) );
return oldValue;
} catch( IllegalAccessException ex ) {
throw new IllegalArgumentException( "failed to access field '" + cls.getName() + "." + fieldName + "'", ex );
}
}
} catch( NoSuchFieldException ex ) { } catch( NoSuchFieldException ex ) {
// field not found in class --> try superclass // field not found in class --> try superclass
} }
for( StyleableField styleableField : cls.getAnnotationsByType( StyleableField.class ) ) {
if( key.equals( styleableField.key() ) )
return applyToField( getStyleableField( styleableField ), obj, value, true );
}
cls = cls.getSuperclass(); cls = cls.getSuperclass();
if( cls == null ) if( cls == null )
throw new UnknownStyleException( key ); throw new UnknownStyleException( key );
@@ -437,11 +474,83 @@ public class FlatStylingSupport
} }
} }
private static Object applyToField( Field f, Object obj, Object value, boolean useMethodHandles ) {
checkValidField( f );
if( useMethodHandles && obj instanceof StyleableLookupProvider ) {
try {
// use method handles to access protected fields in JRE in modular applications
MethodHandles.Lookup lookup = ((StyleableLookupProvider)obj).getLookupForStyling();
// get old value and set new value
Object oldValue = lookup.unreflectGetter( f ).invoke( obj );
lookup.unreflectSetter( f ).invoke( obj, convertToEnum( value, f.getType() ) );
return oldValue;
} catch( Throwable ex ) {
throw newFieldAccessFailed( f, ex );
}
}
try {
// necessary to access protected fields in other packages
f.setAccessible( true );
// get old value and set new value
Object oldValue = f.get( obj );
f.set( obj, convertToEnum( value, f.getType() ) );
return oldValue;
} catch( IllegalAccessException ex ) {
throw newFieldAccessFailed( f, ex );
}
}
private static Object getFieldValue( Field f, Object obj, boolean useMethodHandles ) {
checkValidField( f );
if( useMethodHandles && obj instanceof StyleableLookupProvider ) {
// use method handles to access protected fields in JRE in modular applications
try {
MethodHandles.Lookup lookup = ((StyleableLookupProvider)obj).getLookupForStyling();
return lookup.unreflectGetter( f ).invoke( obj );
} catch( Throwable ex ) {
throw newFieldAccessFailed( f, ex );
}
}
try {
f.setAccessible( true );
return f.get( obj );
} catch( IllegalAccessException ex ) {
throw newFieldAccessFailed( f, ex );
}
}
private static IllegalArgumentException newFieldAccessFailed( Field f, Throwable ex ) {
return new IllegalArgumentException( "failed to access field '" + f.getDeclaringClass().getName() + "." + f.getName() + "'", ex );
}
private static void checkValidField( Field f ) {
if( !isValidField( f ) )
throw new IllegalArgumentException( "field '" + f.getDeclaringClass().getName() + "." + f.getName() + "' is final or static" );
}
private static boolean isValidField( Field f ) { private static boolean isValidField( Field f ) {
int modifiers = f.getModifiers(); int modifiers = f.getModifiers();
return (modifiers & (Modifier.FINAL|Modifier.STATIC)) == 0 && !f.isSynthetic(); return (modifiers & (Modifier.FINAL|Modifier.STATIC)) == 0 && !f.isSynthetic();
} }
private static Field getStyleableField( StyleableField styleableField ) {
String fieldName = styleableField.fieldName();
if( fieldName.isEmpty() )
fieldName = styleableField.key();
try {
return styleableField.cls().getDeclaredField( fieldName );
} catch( NoSuchFieldException ex ) {
throw new IllegalArgumentException( "field '" + styleableField.cls().getName() + "." + fieldName + "' not found", ex );
}
}
/** /**
* Applies the given value to a property of the given object. * Applies the given value to a property of the given object.
* Works only for properties that have public getter and setter methods. * Works only for properties that have public getter and setter methods.
@@ -628,6 +737,7 @@ public class FlatStylingSupport
Class<?> cls = obj.getClass(); Class<?> cls = obj.getClass();
for(;;) { for(;;) {
// find fields annotated with 'Styleable'
for( Field f : cls.getDeclaredFields() ) { for( Field f : cls.getDeclaredFields() ) {
if( !isValidField( f ) ) if( !isValidField( f ) )
continue; continue;
@@ -666,6 +776,20 @@ public class FlatStylingSupport
infos.put( name, type ); infos.put( name, type );
} }
// get fields specified in 'StyleableField' annotation
for( StyleableField styleableField : cls.getAnnotationsByType( StyleableField.class ) ) {
String name = styleableField.key();
// for the case that the same field name is used in a class and in
// one of its superclasses, do not process field in superclass
if( processedFields.contains( name ) )
continue;
processedFields.add( name );
Field f = getStyleableField( styleableField );
infos.put( name, f.getType() );
}
cls = cls.getSuperclass(); cls = cls.getSuperclass();
if( cls == null ) if( cls == null )
return; return;
@@ -686,6 +810,52 @@ public class FlatStylingSupport
infos.put( keyPrefix.concat( e.getKey() ), e.getValue() ); infos.put( keyPrefix.concat( e.getKey() ), e.getValue() );
} }
public static Object getAnnotatedStyleableValue( Object obj, String key ) {
String fieldName = keyToFieldName( key );
Class<?> cls = obj.getClass();
for(;;) {
try {
// find field annotated with 'Styleable'
Field f = cls.getDeclaredField( fieldName );
Styleable styleable = f.getAnnotation( Styleable.class );
if( styleable != null ) {
if( styleable.dot() != (fieldName != key) )
throw new IllegalArgumentException( "'Styleable.dot' on field '" + fieldName + "' does not match key '" + key + "'" );
if( styleable.type() != Void.class )
throw new IllegalArgumentException( "'Styleable.type' on field '" + fieldName + "' not supported" );
return getFieldValue( f, obj, false );
}
} catch( NoSuchFieldException ex ) {
// field not found in class --> try superclass
}
// find field specified in 'StyleableField' annotation
for( StyleableField styleableField : cls.getAnnotationsByType( StyleableField.class ) ) {
if( key.equals( styleableField.key() ) )
return getFieldValue( getStyleableField( styleableField ), obj, true );
}
cls = cls.getSuperclass();
if( cls == null )
return null;
String superclassName = cls.getName();
if( superclassName.startsWith( "java." ) || superclassName.startsWith( "javax." ) )
return null;
}
}
public static Object getAnnotatedStyleableValue( Object obj, Border border, String key ) {
if( border instanceof StyleableBorder ) {
Object value = ((StyleableBorder)border).getStyleableValue( key );
if( value != null )
return value;
}
return getAnnotatedStyleableValue( obj, key );
}
//---- class UnknownStyleException ---------------------------------------- //---- class UnknownStyleException ----------------------------------------
public static class UnknownStyleException public static class UnknownStyleException

View File

@@ -145,7 +145,7 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault TabbedPane.showTabSeparators boolean * @uiDefault TabbedPane.showTabSeparators boolean
* @uiDefault TabbedPane.tabSeparatorsFullHeight boolean * @uiDefault TabbedPane.tabSeparatorsFullHeight boolean
* @uiDefault TabbedPane.hasFullBorder boolean * @uiDefault TabbedPane.hasFullBorder boolean
* @uiDefault TabbedPane.activeTabBorder boolean * @uiDefault TabbedPane.rotateTabRuns boolean
* *
* @uiDefault TabbedPane.tabLayoutPolicy String wrap (default) or scroll * @uiDefault TabbedPane.tabLayoutPolicy String wrap (default) or scroll
* @uiDefault TabbedPane.tabType String underlined (default) or card * @uiDefault TabbedPane.tabType String underlined (default) or card
@@ -220,6 +220,7 @@ public class FlatTabbedPaneUI
@Styleable protected boolean tabSeparatorsFullHeight; @Styleable protected boolean tabSeparatorsFullHeight;
@Styleable protected boolean hasFullBorder; @Styleable protected boolean hasFullBorder;
@Styleable protected boolean tabsOpaque = true; @Styleable protected boolean tabsOpaque = true;
/** @since 2.5 */ @Styleable protected boolean rotateTabRuns = true;
@Styleable(type=String.class) private int tabType; @Styleable(type=String.class) private int tabType;
@Styleable(type=String.class) private int tabsPopupPolicy; @Styleable(type=String.class) private int tabsPopupPolicy;
@@ -342,6 +343,7 @@ public class FlatTabbedPaneUI
tabSeparatorsFullHeight = UIManager.getBoolean( "TabbedPane.tabSeparatorsFullHeight" ); tabSeparatorsFullHeight = UIManager.getBoolean( "TabbedPane.tabSeparatorsFullHeight" );
hasFullBorder = UIManager.getBoolean( "TabbedPane.hasFullBorder" ); hasFullBorder = UIManager.getBoolean( "TabbedPane.hasFullBorder" );
tabsOpaque = UIManager.getBoolean( "TabbedPane.tabsOpaque" ); tabsOpaque = UIManager.getBoolean( "TabbedPane.tabsOpaque" );
rotateTabRuns = FlatUIUtils.getUIBoolean( "TabbedPane.rotateTabRuns", true );
tabType = parseTabType( UIManager.getString( "TabbedPane.tabType" ) ); tabType = parseTabType( UIManager.getString( "TabbedPane.tabType" ) );
tabsPopupPolicy = parseTabsPopupPolicy( UIManager.getString( "TabbedPane.tabsPopupPolicy" ) ); tabsPopupPolicy = parseTabsPopupPolicy( UIManager.getString( "TabbedPane.tabsPopupPolicy" ) );
@@ -687,6 +689,76 @@ public class FlatTabbedPaneUI
return infos; return infos;
} }
/** @since 2.5 */
@Override
public Object getStyleableValue( JComponent c, String key ) {
// close icon
if( key.startsWith( "close" ) ) {
return (closeIcon instanceof FlatTabbedPaneCloseIcon)
? ((FlatTabbedPaneCloseIcon)closeIcon).getStyleableValue( key )
: null;
}
switch( key ) {
// BasicTabbedPaneUI
case "tabInsets": return tabInsets;
case "tabAreaInsets": return tabAreaInsets;
case "textIconGap": return textIconGapUnscaled;
// FlatTabbedPaneUI
case "tabType":
switch( tabType ) {
default:
case TAB_TYPE_UNDERLINED: return TABBED_PANE_TAB_TYPE_UNDERLINED;
case TAB_TYPE_CARD: return TABBED_PANE_TAB_TYPE_CARD;
}
case "tabsPopupPolicy":
switch( tabsPopupPolicy ) {
default:
case AS_NEEDED: return TABBED_PANE_POLICY_AS_NEEDED;
case NEVER: return TABBED_PANE_POLICY_NEVER;
}
case "scrollButtonsPolicy":
switch( scrollButtonsPolicy ) {
default:
case AS_NEEDED_SINGLE: return TABBED_PANE_POLICY_AS_NEEDED_SINGLE;
case AS_NEEDED: return TABBED_PANE_POLICY_AS_NEEDED;
case NEVER: return TABBED_PANE_POLICY_NEVER;
}
case "scrollButtonsPlacement":
switch( scrollButtonsPlacement ) {
default:
case BOTH: return TABBED_PANE_PLACEMENT_BOTH;
case TRAILING: return TABBED_PANE_PLACEMENT_TRAILING;
}
case "tabAreaAlignment": return alignmentToString( tabAreaAlignment, TABBED_PANE_ALIGN_LEADING );
case "tabAlignment": return alignmentToString( tabAlignment, TABBED_PANE_ALIGN_CENTER );
case "tabWidthMode":
switch( tabWidthMode ) {
default:
case WIDTH_MODE_PREFERRED: return TABBED_PANE_TAB_WIDTH_MODE_PREFERRED;
case WIDTH_MODE_EQUAL: return TABBED_PANE_TAB_WIDTH_MODE_EQUAL;
case WIDTH_MODE_COMPACT: return TABBED_PANE_TAB_WIDTH_MODE_COMPACT;
}
case "tabIconPlacement":
switch( tabIconPlacement ) {
default:
case LEADING: return "leading";
case TRAILING: return "trailing";
case TOP: return "top";
case BOTTOM: return "bottom";
}
}
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
}
protected void setRolloverTab( int x, int y ) { protected void setRolloverTab( int x, int y ) {
setRolloverTab( tabForCoordinate( tabPane, x, y ) ); setRolloverTab( tabForCoordinate( tabPane, x, y ) );
} }
@@ -1022,7 +1094,7 @@ public class FlatTabbedPaneUI
// paint selection indicator // paint selection indicator
if( isSelected ) if( isSelected )
paintTabSelection( g, tabPlacement, x, y, w, h ); paintTabSelection( g, tabPlacement, tabIndex, x, y, w, h );
if( tabPane.getTabComponentAt( tabIndex ) != null ) if( tabPane.getTabComponentAt( tabIndex ) != null )
return; return;
@@ -1211,14 +1283,19 @@ public class FlatTabbedPaneUI
} }
} }
protected void paintTabSelection( Graphics g, int tabPlacement, int x, int y, int w, int h ) { protected void paintTabSelection( Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h ) {
g.setColor( tabPane.isEnabled() g.setColor( tabPane.isEnabled()
? (isTabbedPaneOrChildFocused() ? underlineColor : inactiveUnderlineColor) ? (isTabbedPaneOrChildFocused() ? underlineColor : inactiveUnderlineColor)
: disabledUnderlineColor ); : disabledUnderlineColor );
// paint underline selection // paint underline selection
boolean atBottom = (getTabType() != TAB_TYPE_CARD); boolean atBottom = (getTabType() != TAB_TYPE_CARD);
Insets contentInsets = getContentBorderInsets( tabPlacement ); Insets contentInsets = atBottom
? ((!rotateTabRuns && runCount > 1 && !isScrollTabLayout() && getRunForTab( tabPane.getTabCount(), tabIndex ) > 0)
? new Insets( 0, 0, 0, 0 )
: getContentBorderInsets( tabPlacement ))
: null;
int tabSelectionHeight = scale( atBottom ? this.tabSelectionHeight : cardTabSelectionHeight ); int tabSelectionHeight = scale( atBottom ? this.tabSelectionHeight : cardTabSelectionHeight );
int sx, sy; int sx, sy;
switch( tabPlacement ) { switch( tabPlacement ) {
@@ -1377,7 +1454,7 @@ public class FlatTabbedPaneUI
else else
g.clipRect( 0, vr.y, tabPane.getWidth(), vr.height ); g.clipRect( 0, vr.y, tabPane.getWidth(), vr.height );
paintTabSelection( g, tabPlacement, tabRect.x, tabRect.y, tabRect.width, tabRect.height ); paintTabSelection( g, tabPlacement, selectedIndex, tabRect.x, tabRect.y, tabRect.width, tabRect.height );
g.setClip( oldClip ); g.setClip( oldClip );
} }
} }
@@ -1530,6 +1607,11 @@ public class FlatTabbedPaneUI
super.getTabRunCount( tabPane ); super.getTabRunCount( tabPane );
} }
@Override
protected boolean shouldRotateTabRuns( int tabPlacement ) {
return rotateTabRuns;
}
private boolean isLastInRun( int tabIndex ) { private boolean isLastInRun( int tabIndex ) {
int run = getRunForTab( tabPane.getTabCount(), tabIndex ); int run = getRunForTab( tabPane.getTabCount(), tabIndex );
return lastTabInRun( tabPane.getTabCount(), run ) == tabIndex; return lastTabInRun( tabPane.getTabCount(), run ) == tabIndex;
@@ -1685,6 +1767,16 @@ public class FlatTabbedPaneUI
} }
} }
private static String alignmentToString( int value, String defaultValue ) {
switch( value ) {
case LEADING: return TABBED_PANE_ALIGN_LEADING;
case TRAILING: return TABBED_PANE_ALIGN_TRAILING;
case CENTER: return TABBED_PANE_ALIGN_CENTER;
case FILL: return TABBED_PANE_ALIGN_FILL;
default: return defaultValue;
}
}
protected static int parseTabWidthMode( String str ) { protected static int parseTabWidthMode( String str ) {
if( str == null ) if( str == null )
return WIDTH_MODE_PREFERRED; return WIDTH_MODE_PREFERRED;
@@ -2497,7 +2589,7 @@ public class FlatTabbedPaneUI
public void mousePressed( MouseEvent e ) { public void mousePressed( MouseEvent e ) {
updateRollover( e ); updateRollover( e );
if( !isPressedTabClose() ) if( !isPressedTabClose() && SwingUtilities.isLeftMouseButton( e ) )
mouseDelegate.mousePressed( e ); mouseDelegate.mousePressed( e );
} }
@@ -2552,7 +2644,7 @@ public class FlatTabbedPaneUI
// check whether mouse hit tab close area // check whether mouse hit tab close area
boolean hitClose = isTabClosable( tabIndex ) && getTabCloseHitArea( tabIndex ).contains( x, y ); boolean hitClose = isTabClosable( tabIndex ) && getTabCloseHitArea( tabIndex ).contains( x, y );
if( e.getID() == MouseEvent.MOUSE_PRESSED ) if( e.getID() == MouseEvent.MOUSE_PRESSED && SwingUtilities.isLeftMouseButton( e ) )
pressedTabIndex = hitClose ? tabIndex : -1; pressedTabIndex = hitClose ? tabIndex : -1;
setRolloverTabClose( hitClose ); setRolloverTabClose( hitClose );
setPressedTabClose( hitClose && tabIndex == pressedTabIndex ); setPressedTabClose( hitClose && tabIndex == pressedTabIndex );

View File

@@ -171,6 +171,22 @@ public class FlatTableHeaderUI
return FlatStylingSupport.getAnnotatedStyleableInfos( this ); return FlatStylingSupport.getAnnotatedStyleableInfos( this );
} }
/** @since 2.5 */
@Override
public Object getStyleableValue( JComponent c, String key ) {
if( key.equals( "sortIconPosition" ) ) {
switch( sortIconPosition ) {
default:
case SwingConstants.RIGHT: return "right";
case SwingConstants.LEFT: return "left";
case SwingConstants.TOP: return "top";
case SwingConstants.BOTTOM: return "bottom";
}
}
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
}
private static int parseSortIconPosition( String str ) { private static int parseSortIconPosition( String str ) {
if( str == null ) if( str == null )
str = ""; str = "";

View File

@@ -286,6 +286,12 @@ public class FlatTableUI
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.
* *

View File

@@ -86,6 +86,13 @@ public class FlatTextAreaUI
@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();
@@ -183,6 +190,12 @@ public class FlatTextAreaUI
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,

View File

@@ -128,6 +128,13 @@ public class FlatTextFieldUI
@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 );
leadingIcon = clientProperty( c, TEXT_FIELD_LEADING_ICON, null, Icon.class ); leadingIcon = clientProperty( c, TEXT_FIELD_LEADING_ICON, null, Icon.class );
@@ -354,6 +361,12 @@ public class FlatTextFieldUI
return FlatStylingSupport.getAnnotatedStyleableInfos( this, getComponent().getBorder() ); return FlatStylingSupport.getAnnotatedStyleableInfos( this, getComponent().getBorder() );
} }
/** @since 2.5 */
@Override
public Object getStyleableValue( JComponent c, String key ) {
return FlatStylingSupport.getAnnotatedStyleableValue( this, getComponent().getBorder(), key );
}
private void updateBackground() { private void updateBackground() {
updateBackground( getComponent(), background, updateBackground( getComponent(), background,
disabledBackground, inactiveBackground, disabledBackground, inactiveBackground,

View File

@@ -191,6 +191,12 @@ public class FlatTextPaneUI
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,

View File

@@ -24,6 +24,7 @@ import java.awt.Container;
import java.awt.Dialog; import java.awt.Dialog;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.EventQueue; import java.awt.EventQueue;
import java.awt.Font;
import java.awt.FontMetrics; import java.awt.FontMetrics;
import java.awt.Frame; import java.awt.Frame;
import java.awt.Graphics; import java.awt.Graphics;
@@ -32,6 +33,7 @@ import java.awt.Image;
import java.awt.Insets; import java.awt.Insets;
import java.awt.Point; import java.awt.Point;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window; import java.awt.Window;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent; import java.awt.event.ComponentEvent;
@@ -54,6 +56,7 @@ import javax.swing.BoxLayout;
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.JDialog;
import javax.swing.JLabel; import javax.swing.JLabel;
import javax.swing.JMenuBar; import javax.swing.JMenuBar;
import javax.swing.JPanel; import javax.swing.JPanel;
@@ -71,6 +74,7 @@ import com.formdev.flatlaf.util.UIScale;
/** /**
* Provides the Flat LaF title bar. * Provides the Flat LaF title bar.
* *
* @uiDefault TitlePane.font Font
* @uiDefault TitlePane.background Color * @uiDefault TitlePane.background Color
* @uiDefault TitlePane.inactiveBackground Color * @uiDefault TitlePane.inactiveBackground Color
* @uiDefault TitlePane.foreground Color * @uiDefault TitlePane.foreground Color
@@ -79,6 +83,7 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault TitlePane.borderColor Color optional * @uiDefault TitlePane.borderColor Color optional
* @uiDefault TitlePane.unifiedBackground boolean * @uiDefault TitlePane.unifiedBackground boolean
* @uiDefault TitlePane.showIcon boolean * @uiDefault TitlePane.showIcon boolean
* @uiDefault TitlePane.showIconInDialogs boolean
* @uiDefault TitlePane.noIconLeftGap int * @uiDefault TitlePane.noIconLeftGap int
* @uiDefault TitlePane.iconSize Dimension * @uiDefault TitlePane.iconSize Dimension
* @uiDefault TitlePane.iconMargins Insets * @uiDefault TitlePane.iconMargins Insets
@@ -102,6 +107,7 @@ import com.formdev.flatlaf.util.UIScale;
public class FlatTitlePane public class FlatTitlePane
extends JComponent extends JComponent
{ {
/** @since 2.5 */ protected final Font titleFont = UIManager.getFont( "TitlePane.font" );
protected final Color activeBackground = UIManager.getColor( "TitlePane.background" ); protected final Color activeBackground = UIManager.getColor( "TitlePane.background" );
protected final Color inactiveBackground = UIManager.getColor( "TitlePane.inactiveBackground" ); protected final Color inactiveBackground = UIManager.getColor( "TitlePane.inactiveBackground" );
protected final Color activeForeground = UIManager.getColor( "TitlePane.foreground" ); protected final Color activeForeground = UIManager.getColor( "TitlePane.foreground" );
@@ -110,6 +116,7 @@ public class FlatTitlePane
protected final Color borderColor = UIManager.getColor( "TitlePane.borderColor" ); protected final Color borderColor = UIManager.getColor( "TitlePane.borderColor" );
/** @since 2 */ protected final boolean showIcon = FlatUIUtils.getUIBoolean( "TitlePane.showIcon", true ); /** @since 2 */ protected final boolean showIcon = FlatUIUtils.getUIBoolean( "TitlePane.showIcon", true );
/** @since 2.5 */ protected final boolean showIconInDialogs = FlatUIUtils.getUIBoolean( "TitlePane.showIconInDialogs", true );
/** @since 2 */ protected final int noIconLeftGap = FlatUIUtils.getUIInt( "TitlePane.noIconLeftGap", 8 ); /** @since 2 */ protected final int noIconLeftGap = FlatUIUtils.getUIInt( "TitlePane.noIconLeftGap", 8 );
protected final Dimension iconSize = UIManager.getDimension( "TitlePane.iconSize" ); protected final Dimension iconSize = UIManager.getDimension( "TitlePane.iconSize" );
/** @since 2.4 */ protected final int titleMinimumWidth = FlatUIUtils.getUIInt( "TitlePane.titleMinimumWidth", 60 ); /** @since 2.4 */ protected final int titleMinimumWidth = FlatUIUtils.getUIInt( "TitlePane.titleMinimumWidth", 60 );
@@ -357,6 +364,7 @@ public class FlatTitlePane
restoreButton.setVisible( resizable && maximized ); restoreButton.setVisible( resizable && maximized );
if( maximized && if( maximized &&
!(SystemInfo.isLinux && FlatNativeLinuxLibrary.isWMUtilsSupported( window )) &&
rootPane.getClientProperty( "_flatlaf.maximizedBoundsUpToDate" ) == null ) rootPane.getClientProperty( "_flatlaf.maximizedBoundsUpToDate" ) == null )
{ {
rootPane.putClientProperty( "_flatlaf.maximizedBoundsUpToDate", null ); rootPane.putClientProperty( "_flatlaf.maximizedBoundsUpToDate", null );
@@ -387,9 +395,13 @@ public class FlatTitlePane
} }
protected void updateIcon() { protected void updateIcon() {
boolean defaultShowIcon = showIcon;
if( !showIconInDialogs && rootPane.getParent() instanceof JDialog )
defaultShowIcon = false;
// get window images // get window images
List<Image> images = null; List<Image> images = null;
if( clientPropertyBoolean( rootPane, TITLE_BAR_SHOW_ICON, showIcon ) ) { if( clientPropertyBoolean( rootPane, TITLE_BAR_SHOW_ICON, defaultShowIcon ) ) {
images = window.getIconImages(); images = window.getIconImages();
if( images.isEmpty() ) { if( images.isEmpty() ) {
// search in owners // search in owners
@@ -737,6 +749,17 @@ debug*/
} }
} }
private void maximizeOrRestore() {
if( !(window instanceof Frame) || !((Frame)window).isResizable() )
return;
Frame frame = (Frame) window;
if( (frame.getExtendedState() & Frame.MAXIMIZED_BOTH) != 0 )
restore();
else
maximize();
}
/** /**
* Closes the window. * Closes the window.
*/ */
@@ -861,14 +884,18 @@ debug*/
r.height -= resizeHeight; r.height -= resizeHeight;
} }
Component horizontalGlue = findHorizontalGlue( menuBar ); int count = menuBar.getComponentCount();
if( horizontalGlue != null ) { for( int i = count - 1; i >= 0; i-- ) {
// If menu bar is embedded and contains a horizontal glue component, Component c = menuBar.getComponent( i );
// then split the hit test spot into two spots so that if( c instanceof Box.Filler ||
// the glue component area can be used to move the window. (c instanceof JComponent && clientPropertyBoolean( (JComponent) c, COMPONENT_TITLE_BAR_CAPTION, false ) ) )
{
// If menu bar is embedded and contains a horizontal glue or caption component,
// then split the hit test spot so that
// the glue/caption component area can be used to move the window.
Point glueLocation = SwingUtilities.convertPoint( horizontalGlue, 0, 0, window ); Point glueLocation = SwingUtilities.convertPoint( c, 0, 0, window );
int x2 = glueLocation.x + horizontalGlue.getWidth(); int x2 = glueLocation.x + c.getWidth();
Rectangle r2; Rectangle r2;
if( getComponentOrientation().isLeftToRight() ) { if( getComponentOrientation().isLeftToRight() ) {
r2 = new Rectangle( x2, r.y, (r.x + r.width) - x2, r.height ); r2 = new Rectangle( x2, r.y, (r.x + r.width) - x2, r.height );
@@ -880,8 +907,10 @@ debug*/
r.width = (r.x + r.width) - x2; r.width = (r.x + r.width) - x2;
r.x = x2; r.x = x2;
} }
if( r2.width > 0 )
hitTestSpots.add( r2 ); hitTestSpots.add( r2 );
} }
}
hitTestSpots.add( r ); hitTestSpots.add( r );
} }
@@ -986,6 +1015,14 @@ debug*/
super( false ); super( false );
} }
@Override
protected void installDefaults( JLabel c ) {
super.installDefaults( c );
if( titleFont != null )
c.setFont( titleFont );
}
@Override @Override
protected String layoutCL( JLabel label, FontMetrics fontMetrics, String text, Icon icon, protected String layoutCL( JLabel label, FontMetrics fontMetrics, String text, Icon icon,
Rectangle viewR, Rectangle iconR, Rectangle textR ) Rectangle viewR, Rectangle iconR, Rectangle textR )
@@ -1148,23 +1185,30 @@ debug*/
//---- interface MouseListener ---- //---- interface MouseListener ----
private Point dragOffset; private Point dragOffset;
private boolean nativeMove;
private long lastSingleClickWhen;
@Override @Override
public void mouseClicked( MouseEvent e ) { public void mouseClicked( MouseEvent e ) {
// on Linux, when using native library, the mouse clicked event
// is usually not sent and maximize/restore is done in mouse pressed event
// this check is here for the case that a mouse clicked event comes thru for some reason
if( SystemInfo.isLinux && FlatNativeLinuxLibrary.isWMUtilsSupported( window ) ) {
// see comment in mousePressed()
if( lastSingleClickWhen != 0 && (e.getWhen() - lastSingleClickWhen) <= getMultiClickInterval() ) {
lastSingleClickWhen = 0;
maximizeOrRestore();
}
return;
}
if( e.getClickCount() == 2 && SwingUtilities.isLeftMouseButton( e ) ) { if( e.getClickCount() == 2 && SwingUtilities.isLeftMouseButton( e ) ) {
if( e.getSource() == iconLabel ) { if( e.getSource() == iconLabel ) {
// double-click on icon closes window // double-click on icon closes window
close(); close();
} else if( !hasNativeCustomDecoration() && } else if( !hasNativeCustomDecoration() ) {
window instanceof Frame &&
((Frame)window).isResizable() )
{
// maximize/restore on double-click // maximize/restore on double-click
Frame frame = (Frame) window; maximizeOrRestore();
if( (frame.getExtendedState() & Frame.MAXIMIZED_BOTH) != 0 )
restore();
else
maximize();
} }
} }
} }
@@ -1174,10 +1218,56 @@ debug*/
if( window == null ) if( window == null )
return; // should newer occur return; // should newer occur
// on Linux, show window menu
if( SwingUtilities.isRightMouseButton( e ) &&
SystemInfo.isLinux && FlatNativeLinuxLibrary.isWMUtilsSupported( window ) )
{
e.consume();
FlatNativeLinuxLibrary.showWindowMenu( window, e );
return;
}
if( !SwingUtilities.isLeftMouseButton( e ) ) if( !SwingUtilities.isLeftMouseButton( e ) )
return; return;
dragOffset = SwingUtilities.convertPoint( FlatTitlePane.this, e.getPoint(), window ); dragOffset = SwingUtilities.convertPoint( FlatTitlePane.this, e.getPoint(), window );
nativeMove = false;
// on Linux, move or maximize/restore window
if( SystemInfo.isLinux && FlatNativeLinuxLibrary.isWMUtilsSupported( window ) ) {
// The fired Java mouse events, when doing a double-click and the first click
// sends a _NET_WM_MOVERESIZE message, are different for various Linux distributions:
// CentOS 7 (GNOME 3.28.2, X11): PRESSED(clickCount=1) PRESSED(clickCount=2) RELEASED(clickCount=2)
// Ubuntu 20.04 (GNOME 3.36.1, X11): PRESSED(clickCount=1) PRESSED(clickCount=2) RELEASED(clickCount=2)
// Ubuntu 22.04 (GNOME 42.2, Wayland): PRESSED(clickCount=1) RELEASED(clickCount=1) CLICKED(clickCount=1)
// Kubuntu 22.04 (KDE 5.24.4, X11): PRESSED(clickCount=1) PRESSED(clickCount=1) RELEASED(clickCount=1)
// double-click is not always recognized in Java when using _NET_WM_MOVERESIZE message
int clickCount = e.getClickCount();
if( clickCount == 1 && lastSingleClickWhen != 0 && (e.getWhen() - lastSingleClickWhen) <= getMultiClickInterval() )
clickCount = 2;
switch( clickCount ) {
case 1:
// move window via _NET_WM_MOVERESIZE message
e.consume();
nativeMove = FlatNativeLinuxLibrary.moveOrResizeWindow( window, e, FlatNativeLinuxLibrary.MOVE );
lastSingleClickWhen = e.getWhen();
break;
case 2:
// maximize/restore on double-click
// also done here because no mouse clicked event is sent when using _NET_WM_MOVERESIZE message
lastSingleClickWhen = 0;
maximizeOrRestore();
break;
}
}
}
private int getMultiClickInterval() {
Object value = Toolkit.getDefaultToolkit().getDesktopProperty( "awt.multiClickInterval" );
return (value instanceof Integer) ? (Integer) value : 500;
} }
@Override public void mouseReleased( MouseEvent e ) {} @Override public void mouseReleased( MouseEvent e ) {}
@@ -1188,9 +1278,12 @@ debug*/
@Override @Override
public void mouseDragged( MouseEvent e ) { public void mouseDragged( MouseEvent e ) {
if( window == null ) if( window == null || dragOffset == null )
return; // should newer occur return; // should newer occur
if( nativeMove )
return;
if( !SwingUtilities.isLeftMouseButton( e ) ) if( !SwingUtilities.isLeftMouseButton( e ) )
return; return;

View File

@@ -160,6 +160,12 @@ public class FlatToolBarSeparatorUI
return FlatStylingSupport.getAnnotatedStyleableInfos( this ); return FlatStylingSupport.getAnnotatedStyleableInfos( this );
} }
/** @since 2.5 */
@Override
public Object getStyleableValue( JComponent c, String key ) {
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
}
@Override @Override
public Dimension getPreferredSize( JComponent c ) { public Dimension getPreferredSize( JComponent c ) {
Dimension size = ((JToolBar.Separator)c).getSeparatorSize(); Dimension size = ((JToolBar.Separator)c).getSeparatorSize();

View File

@@ -201,6 +201,12 @@ public class FlatToolBarUI
return FlatStylingSupport.getAnnotatedStyleableInfos( this ); return FlatStylingSupport.getAnnotatedStyleableInfos( this );
} }
/** @since 2.5 */
@Override
public Object getStyleableValue( JComponent c, String key ) {
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
}
/** @since 1.4 */ /** @since 1.4 */
protected void setButtonsFocusable( boolean focusable ) { protected void setButtonsFocusable( boolean focusable ) {
for( Component c : toolBar.getComponents() ) for( Component c : toolBar.getComponents() )

View File

@@ -340,6 +340,12 @@ public class FlatTreeUI
return FlatStylingSupport.getAnnotatedStyleableInfos( this ); return FlatStylingSupport.getAnnotatedStyleableInfos( this );
} }
/** @since 2.5 */
@Override
public Object getStyleableValue( JComponent c, String key ) {
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
}
/** /**
* Same as super.paintRow(), but supports wide selection and uses * Same as super.paintRow(), but supports wide selection and uses
* inactive selection background/foreground if tree is not focused. * inactive selection background/foreground if tree is not focused.

View File

@@ -33,6 +33,7 @@ import java.awt.Rectangle;
import java.awt.RenderingHints; import java.awt.RenderingHints;
import java.awt.Shape; import java.awt.Shape;
import java.awt.Stroke; import java.awt.Stroke;
import java.awt.SystemColor;
import java.awt.Window; import java.awt.Window;
import java.awt.event.FocusEvent; import java.awt.event.FocusEvent;
import java.awt.event.FocusListener; import java.awt.event.FocusListener;
@@ -45,20 +46,27 @@ import java.util.WeakHashMap;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.function.Supplier; import java.util.function.Supplier;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JScrollPane;
import javax.swing.JTable; import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.LookAndFeel; import javax.swing.LookAndFeel;
import javax.swing.SwingConstants; import javax.swing.SwingConstants;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import javax.swing.UIDefaults;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.border.Border; import javax.swing.border.Border;
import javax.swing.border.CompoundBorder; import javax.swing.border.CompoundBorder;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource; import javax.swing.plaf.UIResource;
import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatIntelliJLaf;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.FlatLightLaf;
import com.formdev.flatlaf.FlatSystemProperties; import com.formdev.flatlaf.FlatSystemProperties;
import com.formdev.flatlaf.util.DerivedColor; import com.formdev.flatlaf.util.DerivedColor;
import com.formdev.flatlaf.util.Graphics2DProxy; import com.formdev.flatlaf.util.Graphics2DProxy;
import com.formdev.flatlaf.util.HiDPIUtils; import com.formdev.flatlaf.util.HiDPIUtils;
import com.formdev.flatlaf.util.SystemInfo;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
/** /**
@@ -202,6 +210,9 @@ public class FlatUIUtils
} }
public static boolean isCellEditor( Component c ) { public static boolean isCellEditor( Component c ) {
if( c == null )
return false;
// check whether used in cell editor (check 3 levels up) // check whether used in cell editor (check 3 levels up)
Component c2 = c; Component c2 = c;
for( int i = 0; i <= 2 && c2 != null; i++ ) { for( int i = 0; i <= 2 && c2 != null; i++ ) {
@@ -241,6 +252,11 @@ public class FlatUIUtils
} }
} }
// invoke hasFocus() here because components may have overridden this method
// (e.g. Swing delegate components used for AWT components on macOS)
if( c.hasFocus() )
return true;
return keyboardFocusManager.getPermanentFocusOwner() == c && return keyboardFocusManager.getPermanentFocusOwner() == c &&
isInActiveWindow( c, keyboardFocusManager.getActiveWindow() ); isInActiveWindow( c, keyboardFocusManager.getActiveWindow() );
} }
@@ -251,6 +267,38 @@ public class FlatUIUtils
(window != null && window.getType() == Window.Type.POPUP && window.getOwner() == activeWindow); (window != null && window.getType() == Window.Type.POPUP && window.getOwner() == activeWindow);
} }
static boolean isAWTPeer( Component c ) {
// on macOS, Swing components are used for AWT components
if( SystemInfo.isMacOS )
return c.getClass().getName().startsWith( "sun.lwawt.LW" );
return false;
}
/**
* Checks whether component is used as peer for AWT (on macOS) and
* whether a dark FlatLaf theme is active, which requires special handling
* because AWT always uses light colors.
*/
static boolean needsLightAWTPeer( JComponent c ) {
return FlatUIUtils.isAWTPeer( c ) && FlatLaf.isLafDark();
}
private static UIDefaults lightAWTPeerDefaults;
static void runWithLightAWTPeerUIDefaults( Runnable runnable ) {
if( lightAWTPeerDefaults == null ) {
FlatLaf lightLaf = UIManager.getInt( "Component.focusWidth" ) >= 2
? new FlatIntelliJLaf()
: new FlatLightLaf();
lightAWTPeerDefaults = lightLaf.getDefaults();
}
FlatLaf.runWithUIDefaultsGetter( key -> {
Object value = lightAWTPeerDefaults.get( key );
return (value != null) ? value : FlatLaf.NULL_VALUE;
}, runnable );
}
/** /**
* Returns whether the given component is in a window that is in full-screen mode. * Returns whether the given component is in a window that is in full-screen mode.
*/ */
@@ -335,7 +383,7 @@ public class FlatUIUtils
*/ */
public static Object[] setRenderingHints( Graphics g ) { public static Object[] setRenderingHints( Graphics g ) {
Graphics2D g2 = (Graphics2D) g; Graphics2D g2 = (Graphics2D) g;
Object[] oldRenderingHints = new Object[] { Object[] oldRenderingHints = {
g2.getRenderingHint( RenderingHints.KEY_ANTIALIASING ), g2.getRenderingHint( RenderingHints.KEY_ANTIALIASING ),
g2.getRenderingHint( RenderingHints.KEY_STROKE_CONTROL ), g2.getRenderingHint( RenderingHints.KEY_STROKE_CONTROL ),
}; };
@@ -352,7 +400,9 @@ public class FlatUIUtils
*/ */
public static void resetRenderingHints( Graphics g, Object[] oldRenderingHints ) { public static void resetRenderingHints( Graphics g, Object[] oldRenderingHints ) {
Graphics2D g2 = (Graphics2D) g; Graphics2D g2 = (Graphics2D) g;
if( oldRenderingHints[0] != null )
g2.setRenderingHint( RenderingHints.KEY_ANTIALIASING, oldRenderingHints[0] ); g2.setRenderingHint( RenderingHints.KEY_ANTIALIASING, oldRenderingHints[0] );
if( oldRenderingHints[1] != null )
g2.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, oldRenderingHints[1] ); g2.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, oldRenderingHints[1] );
} }
@@ -376,7 +426,7 @@ public class FlatUIUtils
} }
Graphics2D g2 = (Graphics2D) g; Graphics2D g2 = (Graphics2D) g;
Object[] oldRenderingHints2 = new Object[] { Object[] oldRenderingHints2 = {
g2.getRenderingHint( RenderingHints.KEY_ANTIALIASING ), g2.getRenderingHint( RenderingHints.KEY_ANTIALIASING ),
g2.getRenderingHint( RenderingHints.KEY_STROKE_CONTROL ), g2.getRenderingHint( RenderingHints.KEY_STROKE_CONTROL ),
}; };
@@ -664,9 +714,9 @@ public class FlatUIUtils
* is smaller than its bounds (for the focus decoration). * is smaller than its bounds (for the focus decoration).
*/ */
public static void paintParentBackground( Graphics g, JComponent c ) { public static void paintParentBackground( Graphics g, JComponent c ) {
Container parent = findOpaqueParent( c ); Color background = getParentBackground( c );
if( parent != null ) { if( background != null ) {
g.setColor( parent.getBackground() ); g.setColor( background );
g.fillRect( 0, 0, c.getWidth(), c.getHeight() ); g.fillRect( 0, 0, c.getWidth(), c.getHeight() );
} }
} }
@@ -676,9 +726,20 @@ public class FlatUIUtils
*/ */
public static Color getParentBackground( JComponent c ) { public static Color getParentBackground( JComponent c ) {
Container parent = findOpaqueParent( c ); Container parent = findOpaqueParent( c );
return (parent != null) // parent.getBackground() may return null
? parent.getBackground() // (e.g. for Swing delegate components used for AWT components on macOS)
: UIManager.getColor( "Panel.background" ); // fallback, probably never used Color background = (parent != null) ? parent.getBackground() : null;
if( background != null )
return background;
if( isAWTPeer( c ) ) {
// AWT peers usually use component background, except for TextField and ScrollPane
return c instanceof JTextField || c instanceof JScrollPane || c.getBackground() == null
? SystemColor.window
: c.getBackground();
}
return UIManager.getColor( "Panel.background" );
} }
/** /**

View File

@@ -19,8 +19,9 @@ package com.formdev.flatlaf.util;
import java.awt.FontMetrics; import java.awt.FontMetrics;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.lang.reflect.InvocationTargetException; import java.lang.invoke.MethodHandle;
import java.lang.reflect.Method; import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import javax.swing.JComponent; import javax.swing.JComponent;
/** /**
@@ -32,8 +33,8 @@ import javax.swing.JComponent;
*/ */
public class JavaCompatibility public class JavaCompatibility
{ {
private static Method drawStringUnderlineCharAtMethod; private static MethodHandle drawStringUnderlineCharAtMethod;
private static Method getClippedStringMethod; private static MethodHandle getClippedStringMethod;
/** /**
* Java 8: sun.swing.SwingUtilities2.drawStringUnderlineCharAt( JComponent c, * Java 8: sun.swing.SwingUtilities2.drawStringUnderlineCharAt( JComponent c,
@@ -51,9 +52,10 @@ public class JavaCompatibility
Class<?> cls = Class.forName( SystemInfo.isJava_9_orLater Class<?> cls = Class.forName( SystemInfo.isJava_9_orLater
? "javax.swing.plaf.basic.BasicGraphicsUtils" ? "javax.swing.plaf.basic.BasicGraphicsUtils"
: "sun.swing.SwingUtilities2" ); : "sun.swing.SwingUtilities2" );
drawStringUnderlineCharAtMethod = cls.getMethod( "drawStringUnderlineCharAt", SystemInfo.isJava_9_orLater MethodType mt = MethodType.methodType( void.class, SystemInfo.isJava_9_orLater
? new Class[] { JComponent.class, Graphics2D.class, String.class, int.class, float.class, float.class } ? new Class[] { JComponent.class, Graphics2D.class, String.class, int.class, float.class, float.class }
: new Class[] { JComponent.class, Graphics.class, String.class, int.class, int.class, int.class } ); : new Class[] { JComponent.class, Graphics.class, String.class, int.class, int.class, int.class } );
drawStringUnderlineCharAtMethod = MethodHandles.publicLookup().findStatic( cls, "drawStringUnderlineCharAt", mt );
} catch( Exception ex ) { } catch( Exception ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex ); LoggingFacade.INSTANCE.logSevere( null, ex );
throw new RuntimeException( ex ); throw new RuntimeException( ex );
@@ -63,10 +65,10 @@ public class JavaCompatibility
try { try {
if( SystemInfo.isJava_9_orLater ) if( SystemInfo.isJava_9_orLater )
drawStringUnderlineCharAtMethod.invoke( null, c, g, text, underlinedIndex, (float) x, (float) y ); drawStringUnderlineCharAtMethod.invoke( c, (Graphics2D) g, text, underlinedIndex, (float) x, (float) y );
else else
drawStringUnderlineCharAtMethod.invoke( null, c, g, text, underlinedIndex, x, y ); drawStringUnderlineCharAtMethod.invoke( c, g, text, underlinedIndex, x, y );
} catch( IllegalAccessException | IllegalArgumentException | InvocationTargetException ex ) { } catch( Throwable ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex ); LoggingFacade.INSTANCE.logSevere( null, ex );
throw new RuntimeException( ex ); throw new RuntimeException( ex );
} }
@@ -86,10 +88,11 @@ public class JavaCompatibility
Class<?> cls = Class.forName( SystemInfo.isJava_9_orLater Class<?> cls = Class.forName( SystemInfo.isJava_9_orLater
? "javax.swing.plaf.basic.BasicGraphicsUtils" ? "javax.swing.plaf.basic.BasicGraphicsUtils"
: "sun.swing.SwingUtilities2" ); : "sun.swing.SwingUtilities2" );
getClippedStringMethod = cls.getMethod( SystemInfo.isJava_9_orLater MethodType mt = MethodType.methodType( String.class, JComponent.class, FontMetrics.class, String.class, int.class );
getClippedStringMethod = MethodHandles.publicLookup().findStatic( cls, SystemInfo.isJava_9_orLater
? "getClippedString" ? "getClippedString"
: "clipStringIfNecessary", : "clipStringIfNecessary",
JComponent.class, FontMetrics.class, String.class, int.class ); mt );
} catch( Exception ex ) { } catch( Exception ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex ); LoggingFacade.INSTANCE.logSevere( null, ex );
throw new RuntimeException( ex ); throw new RuntimeException( ex );
@@ -98,8 +101,8 @@ public class JavaCompatibility
} }
try { try {
return (String) getClippedStringMethod.invoke( null, c, fm, string, availTextWidth ); return (String) getClippedStringMethod.invoke( c, fm, string, availTextWidth );
} catch( IllegalAccessException | IllegalArgumentException | InvocationTargetException ex ) { } catch( Throwable ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex ); LoggingFacade.INSTANCE.logSevere( null, ex );
throw new RuntimeException( ex ); throw new RuntimeException( ex );
} }

View File

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

View File

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

View File

@@ -442,8 +442,8 @@ MenuItem.iconTextGap = 6
MenuItem.textAcceleratorGap = 24 MenuItem.textAcceleratorGap = 24
MenuItem.textNoAcceleratorGap = 6 MenuItem.textNoAcceleratorGap = 6
MenuItem.acceleratorArrowGap = 2 MenuItem.acceleratorArrowGap = 2
MenuItem.acceleratorDelimiter = + MenuItem.acceleratorDelimiter = "+"
[mac]MenuItem.acceleratorDelimiter = [mac]MenuItem.acceleratorDelimiter = ""
# for MenuItem.selectionType = underline # for MenuItem.selectionType = underline
MenuItem.underlineSelectionBackground = @menuHoverBackground MenuItem.underlineSelectionBackground = @menuHoverBackground
@@ -785,6 +785,7 @@ TitlePane.useWindowDecorations = true
TitlePane.menuBarEmbedded = true TitlePane.menuBarEmbedded = true
TitlePane.unifiedBackground = true TitlePane.unifiedBackground = true
TitlePane.showIcon = true TitlePane.showIcon = true
TitlePane.showIconInDialogs = true
TitlePane.noIconLeftGap = 8 TitlePane.noIconLeftGap = 8
TitlePane.iconSize = 16,16 TitlePane.iconSize = 16,16
TitlePane.iconMargins = 3,8,3,8 TitlePane.iconMargins = 3,8,3,8

View File

@@ -284,6 +284,8 @@ public class TestFlatStyleableInfo
Map<String, Class<?>> expected = expectedMap( Map<String, Class<?>> expected = expectedMap(
"itemMargins", Insets.class, "itemMargins", Insets.class,
"hoverBackground", Color.class, "hoverBackground", Color.class,
"selectionBackground", Color.class,
"selectionForeground", Color.class,
"underlineSelectionBackground", Color.class, "underlineSelectionBackground", Color.class,
"underlineSelectionColor", Color.class, "underlineSelectionColor", Color.class,
"underlineSelectionHeight", int.class, "underlineSelectionHeight", int.class,
@@ -722,6 +724,7 @@ public class TestFlatStyleableInfo
"tabSeparatorsFullHeight", boolean.class, "tabSeparatorsFullHeight", boolean.class,
"hasFullBorder", boolean.class, "hasFullBorder", boolean.class,
"tabsOpaque", boolean.class, "tabsOpaque", boolean.class,
"rotateTabRuns", boolean.class,
"tabType", String.class, "tabType", String.class,
"tabsPopupPolicy", String.class, "tabsPopupPolicy", String.class,

File diff suppressed because it is too large Load Diff

View File

@@ -436,6 +436,8 @@ public class TestFlatStyling
ui.applyStyle( "itemMargins: 1,2,3,4" ); ui.applyStyle( "itemMargins: 1,2,3,4" );
ui.applyStyle( "hoverBackground: #fff" ); ui.applyStyle( "hoverBackground: #fff" );
ui.applyStyle( "selectionBackground: #fff" );
ui.applyStyle( "selectionForeground: #fff" );
ui.applyStyle( "underlineSelectionBackground: #fff" ); ui.applyStyle( "underlineSelectionBackground: #fff" );
ui.applyStyle( "underlineSelectionColor: #fff" ); ui.applyStyle( "underlineSelectionColor: #fff" );
ui.applyStyle( "underlineSelectionHeight: 3" ); ui.applyStyle( "underlineSelectionHeight: 3" );
@@ -891,6 +893,7 @@ public class TestFlatStyling
ui.applyStyle( "tabSeparatorsFullHeight: false" ); ui.applyStyle( "tabSeparatorsFullHeight: false" );
ui.applyStyle( "hasFullBorder: false" ); ui.applyStyle( "hasFullBorder: false" );
ui.applyStyle( "tabsOpaque: false" ); ui.applyStyle( "tabsOpaque: false" );
ui.applyStyle( "rotateTabRuns: false" );
ui.applyStyle( "tabType: card" ); ui.applyStyle( "tabType: card" );
ui.applyStyle( "tabsPopupPolicy: asNeeded" ); ui.applyStyle( "tabsPopupPolicy: asNeeded" );

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="4" viewBox="0 0 8 4">
<polyline fill="none" stroke="#6E6E6E" points="0 4 4 0 8 4"/>
</svg>

After

Width:  |  Height:  |  Size: 151 B

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="9" height="5" viewBox="0 0 9 5">
<polygon fill="#6E6E6E" fill-rule="evenodd" points="0 5 4.5 0 9 5"/>
</svg>

After

Width:  |  Height:  |  Size: 158 B

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="10" height="5" viewBox="0 0 10 5">
<polyline fill="none" stroke="#6E6E6E" points="1 4 5 0 9 4"/>
</svg>

After

Width:  |  Height:  |  Size: 153 B

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="10" height="5" viewBox="0 0 10 5">
<polygon fill="#6E6E6E" fill-rule="evenodd" points=".5 5 5 0 9.5 5"/>
</svg>

After

Width:  |  Height:  |  Size: 161 B

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="6" height="10" viewBox="0 0 6 10">
<polyline fill="none" stroke="#6E6E6E" points="1 1 5 5 1 9"/>
</svg>

After

Width:  |  Height:  |  Size: 153 B

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="6" height="10" viewBox="0 0 6 10">
<polygon fill="#6E6E6E" fill-rule="evenodd" points="0 .5 5 5 0 9.5"/>
</svg>

After

Width:  |  Height:  |  Size: 161 B

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="11" height="11" viewBox="0 0 11 11">
<polygon fill="#6E6E6E" fill-rule="evenodd" points="3 1 3 2.5 6 5.5 3 8.5 3 10 4.5 10 9 5.5 4.5 1"/>
</svg>

After

Width:  |  Height:  |  Size: 194 B

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="11" height="11" viewBox="0 0 11 11">
<polygon fill="#6E6E6E" fill-rule="evenodd" points="2 1 2 10 10 5.5"/>
</svg>

After

Width:  |  Height:  |  Size: 164 B

View File

@@ -16,6 +16,7 @@
plugins { plugins {
`java-library` `java-library`
`flatlaf-toolchain`
} }
dependencies { dependencies {

View File

@@ -16,6 +16,7 @@
plugins { plugins {
`java-library` `java-library`
`flatlaf-toolchain`
`flatlaf-module-info` `flatlaf-module-info`
`flatlaf-publish` `flatlaf-publish`
} }

View File

@@ -16,6 +16,7 @@
plugins { plugins {
`java-library` `java-library`
`flatlaf-toolchain`
`flatlaf-module-info` `flatlaf-module-info`
`flatlaf-publish` `flatlaf-publish`
} }

View File

@@ -2,6 +2,23 @@
"name": "Hiberbee Dark", "name": "Hiberbee Dark",
"author": "Vlad Volkov", "author": "Vlad Volkov",
"dark": true, "dark": true,
"icons": {
"ColorPalette": {
"Actions.Blue": "#78dce8",
"Actions.Green": "#92d923",
"Actions.Grey": "#93918c",
"Actions.Red": "#fb3b45",
"Actions.Yellow": "#FFD866",
"Objects.Blue": "#78dce8",
"Objects.Green": "#92d923",
"Objects.Pink": "#ff6188",
"Objects.Purple": "#ab9df2",
"Objects.Red": "#fb3b45",
"Objects.RedStatus": "#fb3b45",
"Objects.Yellow": "#FFD866",
"Objects.YellowDark": "#FFB900"
}
},
"editorScheme": "/colors/Dark.xml", "editorScheme": "/colors/Dark.xml",
"colors": { "colors": {
"black": "#000000", "black": "#000000",
@@ -22,7 +39,7 @@
"deepBlue": "#3199b3", "deepBlue": "#3199b3",
"orangeMonokaiPro": "#fc9867", "orangeMonokaiPro": "#fc9867",
"greenMonokaiPro": "#a9dc76", "greenMonokaiPro": "#a9dc76",
"yellow": "#FFB900", "yellow": "#ffd64c",
"purpleWinPalette": "#b4a0ff", "purpleWinPalette": "#b4a0ff",
"purpleMonokaiPro": "#ab9df2", "purpleMonokaiPro": "#ab9df2",
"greenWinPalette": "#40c5af", "greenWinPalette": "#40c5af",
@@ -49,7 +66,7 @@
"transparentGreen": "#5B80217f", "transparentGreen": "#5B80217f",
"transparentRed": "#F250227f", "transparentRed": "#F250227f",
"transparentViolet": "#242221ff", "transparentViolet": "#242221ff",
"transparentYellow": "#FFB9007f" "transparentYellow": "#FFB9007a"
}, },
"ui": { "ui": {
"*": { "*": {
@@ -78,7 +95,6 @@
"color": "border" "color": "border"
}, },
"Button": { "Button": {
"arc": 5,
"default": { "default": {
"endBackground": "greyDot80", "endBackground": "greyDot80",
"endBorderColor": "greyDot70", "endBorderColor": "greyDot70",
@@ -125,7 +141,6 @@
"selectionInactiveBackground": "greyDot85" "selectionInactiveBackground": "greyDot85"
}, },
"Component": { "Component": {
"arc": "4",
"iconColor": "yellow", "iconColor": "yellow",
"disabledBorderColor": "greyDot75", "disabledBorderColor": "greyDot75",
"infoForeground": "greyDot50", "infoForeground": "greyDot50",
@@ -160,22 +175,25 @@
}, },
"EditorTabs": { "EditorTabs": {
"underlineHeight": 1, "underlineHeight": 1,
"borderColor": "editorDarkerBg", "hoverBackground": "greyDot95",
"hoverBackground": "editorBg", "borderColor": "border",
"background": "editorPaneBg", "background": "editorPaneBg",
"inactiveColoredFileBackground": "editorPaneBg",
"inactiveUnderlineColor": "editorPaneBg", "inactiveUnderlineColor": "editorPaneBg",
"underlinedTabForeground": "textColor" "underlinedTabBackground": "editorPaneBg",
"underlinedTabForeground": "yellow"
}, },
"EditorTabs.inactiveColoredFileBackground": true,
"FileColor": { "FileColor": {
"Gray": "greyDot70",
"Blue": "#23282d", "Blue": "#23282d",
"Green": "#232d28", "Green": "#232d28",
"Orange": "#2d2823", "Orange": "#2d2823",
"Rose": "#2d2323", "Rose": "#2d2323",
"Violet": "#2D232D", "Violet": "#2D232D",
"Yellow": "#2d2d23" "Yellow": "#3b3b19"
}, },
"FormattedTextField": { "FormattedTextField": {
"caretForeground": "yellow",
"foreground": "textColor", "foreground": "textColor",
"selectionBackground": "greyDot95", "selectionBackground": "greyDot95",
"inactiveBackground": "greyDot80", "inactiveBackground": "greyDot80",
@@ -186,14 +204,23 @@
"infoForeground": "greyDot33", "infoForeground": "greyDot33",
"lineSeparatorColor": "greyDot70" "lineSeparatorColor": "greyDot70"
}, },
"InformationHint.borderColor": "greyDot75", "InformationHint": {
"InplaceRefactoringPopup.borderColor": "greyDot75", "borderColor": "border"
},
"InplaceRefactoringPopup.borderColor": "border",
"Label": { "Label": {
"disabledForeground": "greyDot33", "disabledForeground": "greyDot33",
"disabledText": "greyDot33", "disabledText": "greyDot33",
"foreground": "greyDot20", "foreground": "greyDot20",
"infoForeground": "greyDot50" "infoForeground": "greyDot50"
}, },
"Link": {
"activeForeground": "blue",
"hoverForeground": "yellow",
"secondaryForeground": "lightBlue",
"visitedForeground": "purpleMonokaiPro",
"pressedForeground": "deepBlue"
},
"Link.hoverForeground": "yellow", "Link.hoverForeground": "yellow",
"MemoryIndicator.allocatedBackground": "green", "MemoryIndicator.allocatedBackground": "green",
"MemoryIndicator.usedBackground": "red", "MemoryIndicator.usedBackground": "red",
@@ -209,16 +236,20 @@
"Notification.ToolWindow.errorBackground": "greyDot95", "Notification.ToolWindow.errorBackground": "greyDot95",
"Notification.ToolWindow.errorBorderColor": "red", "Notification.ToolWindow.errorBorderColor": "red",
"Notification.ToolWindow.errorForeground": "#EE7762", "Notification.ToolWindow.errorForeground": "#EE7762",
"Notification.ToolWindow.informativeBackground": "greyDot95", "Notification.ToolWindow.informativeBackground": "editorPaneBg",
"Notification.ToolWindow.informativeBorderColor": "#92D923", "Notification.ToolWindow.informativeBorderColor": "border",
"Notification.ToolWindow.informativeForeground": "#92D923", "Notification.ToolWindow.informativeForeground": "textColor",
"Notification.ToolWindow.warningBackground": "greyDot95", "Notification.ToolWindow.warningBackground": "greyDot95",
"Notification.ToolWindow.warningBorderColor": "yellow", "Notification.ToolWindow.warningBorderColor": "yellow",
"Notification.ToolWindow.warningForeground": "yellow", "Notification.ToolWindow.warningForeground": "yellow",
"Notification.background": "greyDot95", "Notification.background": "editorPaneBg",
"Notification.borderColor": "border",
"Notification.errorBackground": "greyDot95", "Notification.errorBackground": "greyDot95",
"Notification.errorBorderColor": "red", "Notification.errorBorderColor": "red",
"Notification.errorForeground": "#EE7762", "Notification.errorForeground": "#EE7762",
"Notification.foreground": "textColor",
"NotificationsToolwindow.newNotification.background": "editorPaneBg",
"NotificationsToolwindow.newNotification.hoverBackground": "greyDot95",
"OptionPane": { "OptionPane": {
"background": "editorPaneBg", "background": "editorPaneBg",
"foreground": "greyDot20" "foreground": "greyDot20"
@@ -245,11 +276,11 @@
"Plugins.Tab.hoverBackground": "editorBg", "Plugins.Tab.hoverBackground": "editorBg",
"Plugins.Tab.selectedBackground": "editorPaneBg", "Plugins.Tab.selectedBackground": "editorPaneBg",
"Plugins.background": "editorPaneBg", "Plugins.background": "editorPaneBg",
"Plugins.lightSelectionBackground": "#242220",
"Plugins.disabledForeground": "greyDot50", "Plugins.disabledForeground": "greyDot50",
"Plugins.hoverBackground": "editorBg",
"Plugins.lightSelectionBackground": "#242220",
"Plugins.tagBackground": "editorBg", "Plugins.tagBackground": "editorBg",
"Plugins.tagForeground": "greyDot33", "Plugins.tagForeground": "greyDot33",
"Plugins.hoverBackground": "editorBg",
"Popup.Advertiser.background": "greyDot85", "Popup.Advertiser.background": "greyDot85",
"Popup.Advertiser.foreground": "greyDot50", "Popup.Advertiser.foreground": "greyDot50",
"Popup.Header.activeBackground": "greyDot75", "Popup.Header.activeBackground": "greyDot75",

View File

@@ -97,9 +97,10 @@
}, },
"EditorPane.inactiveBackground": "#2b303b", "EditorPane.inactiveBackground": "#2b303b",
"EditorTabs": { "EditorTabs": {
"underlinedTabBackground": "#2b303b", "borderColor": "#2b303b",
"underlineHeight": "0", "underlinedTabBackground": "2b303b",
"borderColor": "#2b303b" "background": "#1c1f26",
"underlineHeight": "2"
}, },
"Link": { "Link": {
"activeForeground": "#7FA1B3", "activeForeground": "#7FA1B3",

View File

@@ -7,23 +7,23 @@
"bg30": "#2f343f30", "bg30": "#2f343f30",
"fg": "#D3DAE3", "fg": "#D3DAE3",
"text": "#8b9eb5", "text": "#8b9eb5",
"selBg": "#8888FF", "selBg": "#414181",
"selBg20": "#8888FF20", "selBg20": "#41418120",
"selFg": "#FFFFFF", "selFg": "#FFFFFF",
"activeFg": "#FFFFFF", "activeFg": "#FFFFFF",
"border": "#404552", "border": "#404552",
"excl": "#37373d", "excl": "#37373d",
"second": "#393f4c45", "second": "#393f4c",
"dis": "#D3DAE3", "dis": "#a2a2a2",
"accent": "#42A5F5", "accent": "#5294E2",
"accent2": "#42A5F52", "accent2": "#5294E22",
"accent50": "#42A5F550", "accent50": "#5294E250",
"accent70": "#42A5F570", "accent70": "#5294E270",
"cs": "#262b33", "cs": "#262b33",
"button": "#383C4A", "button": "#383C4A",
"table": "#41416A", "table": "#41416A",
"tree": "#09477170", "tree": "#09477170",
"hl": "#393f4c", "hl": "#444A58",
"notif": "#262a33", "notif": "#262a33",
"hc": "#262b33", "hc": "#262b33",
"shadow": "undefined", "shadow": "undefined",
@@ -76,6 +76,11 @@
"ActionToolbar": { "ActionToolbar": {
"background": "hc" "background": "hc"
}, },
"AppInspector.GraphNode": {
"background": "second",
"borderColor": "border",
"focusedBorderColor": "accent"
},
"AssignedMnemonic": { "AssignedMnemonic": {
"background": "hl", "background": "hl",
"borderColor": "selBg", "borderColor": "selBg",
@@ -599,7 +604,7 @@
"link.pressed.foreground": "accent", "link.pressed.foreground": "accent",
"link.visited.foreground": "accent", "link.visited.foreground": "accent",
"List": { "List": {
"background": "second", "background": "bg",
"foreground": "fg", "foreground": "fg",
"hoverBackground": "hl", "hoverBackground": "hl",
"hoverInactiveBackground": "table", "hoverInactiveBackground": "table",
@@ -884,6 +889,9 @@
"selectionBackground": "hl", "selectionBackground": "hl",
"trackColor": "hl" "trackColor": "hl"
}, },
"ProgressIcon": {
"color": "accent"
},
"PsiViewer": { "PsiViewer": {
"referenceHighlightColor": "accent" "referenceHighlightColor": "accent"
}, },
@@ -914,6 +922,13 @@
"selectionBackground": "selBg", "selectionBackground": "selBg",
"selectionForeground": "selFg" "selectionForeground": "selFg"
}, },
"RunWidget": {
"Running": {
"background": "accent",
"leftHoverBackground": "accent70",
"leftPressedBackground": "accent"
}
},
"ScreenView.borderColor": "border", "ScreenView.borderColor": "border",
"scrollbar": "bg", "scrollbar": "bg",
"ScrollBar": { "ScrollBar": {
@@ -1008,6 +1023,8 @@
"Repeated.File.Foreground": "fg" "Repeated.File.Foreground": "fg"
}, },
"SegmentedButton": { "SegmentedButton": {
"focusedSelectedButtonColor": "hl",
"selectedButtonColor": "button",
"selectedStartBorderColor": "border", "selectedStartBorderColor": "border",
"selectedEndBorderColor": "border" "selectedEndBorderColor": "border"
}, },

View File

@@ -7,23 +7,23 @@
"bg30": "#2f343f30", "bg30": "#2f343f30",
"fg": "#D3DAE3", "fg": "#D3DAE3",
"text": "#8b9eb5", "text": "#8b9eb5",
"selBg": "#8888FF", "selBg": "#414181",
"selBg20": "#8888FF20", "selBg20": "#41418120",
"selFg": "#FFFFFF", "selFg": "#FFFFFF",
"activeFg": "#FFFFFF", "activeFg": "#FFFFFF",
"border": "#404552", "border": "#404552",
"excl": "#37373d", "excl": "#37373d",
"second": "#393f4c45", "second": "#393f4c",
"dis": "#D3DAE3", "dis": "#a2a2a2",
"accent": "#42A5F5", "accent": "#5294E2",
"accent2": "#42A5F52", "accent2": "#5294E22",
"accent50": "#42A5F550", "accent50": "#5294E250",
"accent70": "#42A5F570", "accent70": "#5294E270",
"cs": "#262b33", "cs": "#262b33",
"button": "#383C4A", "button": "#383C4A",
"table": "#41416A", "table": "#41416A",
"tree": "#09477170", "tree": "#09477170",
"hl": "#393f4c", "hl": "#444A58",
"notif": "#262a33", "notif": "#262a33",
"hc": "#2f343f", "hc": "#2f343f",
"shadow": "undefined", "shadow": "undefined",
@@ -76,6 +76,11 @@
"ActionToolbar": { "ActionToolbar": {
"background": "hc" "background": "hc"
}, },
"AppInspector.GraphNode": {
"background": "second",
"borderColor": "border",
"focusedBorderColor": "accent"
},
"AssignedMnemonic": { "AssignedMnemonic": {
"background": "hl", "background": "hl",
"borderColor": "selBg", "borderColor": "selBg",
@@ -599,7 +604,7 @@
"link.pressed.foreground": "accent", "link.pressed.foreground": "accent",
"link.visited.foreground": "accent", "link.visited.foreground": "accent",
"List": { "List": {
"background": "second", "background": "bg",
"foreground": "fg", "foreground": "fg",
"hoverBackground": "hl", "hoverBackground": "hl",
"hoverInactiveBackground": "table", "hoverInactiveBackground": "table",
@@ -884,6 +889,9 @@
"selectionBackground": "hl", "selectionBackground": "hl",
"trackColor": "hl" "trackColor": "hl"
}, },
"ProgressIcon": {
"color": "accent"
},
"PsiViewer": { "PsiViewer": {
"referenceHighlightColor": "accent" "referenceHighlightColor": "accent"
}, },
@@ -914,6 +922,13 @@
"selectionBackground": "selBg", "selectionBackground": "selBg",
"selectionForeground": "selFg" "selectionForeground": "selFg"
}, },
"RunWidget": {
"Running": {
"background": "accent",
"leftHoverBackground": "accent70",
"leftPressedBackground": "accent"
}
},
"ScreenView.borderColor": "border", "ScreenView.borderColor": "border",
"scrollbar": "bg", "scrollbar": "bg",
"ScrollBar": { "ScrollBar": {
@@ -1008,6 +1023,8 @@
"Repeated.File.Foreground": "fg" "Repeated.File.Foreground": "fg"
}, },
"SegmentedButton": { "SegmentedButton": {
"focusedSelectedButtonColor": "hl",
"selectedButtonColor": "button",
"selectedStartBorderColor": "border", "selectedStartBorderColor": "border",
"selectedEndBorderColor": "border" "selectedEndBorderColor": "border"
}, },

View File

@@ -76,6 +76,11 @@
"ActionToolbar": { "ActionToolbar": {
"background": "hc" "background": "hc"
}, },
"AppInspector.GraphNode": {
"background": "second",
"borderColor": "border",
"focusedBorderColor": "accent"
},
"AssignedMnemonic": { "AssignedMnemonic": {
"background": "hl", "background": "hl",
"borderColor": "selBg", "borderColor": "selBg",
@@ -599,7 +604,7 @@
"link.pressed.foreground": "accent", "link.pressed.foreground": "accent",
"link.visited.foreground": "accent", "link.visited.foreground": "accent",
"List": { "List": {
"background": "second", "background": "bg",
"foreground": "fg", "foreground": "fg",
"hoverBackground": "hl", "hoverBackground": "hl",
"hoverInactiveBackground": "table", "hoverInactiveBackground": "table",
@@ -884,6 +889,9 @@
"selectionBackground": "hl", "selectionBackground": "hl",
"trackColor": "hl" "trackColor": "hl"
}, },
"ProgressIcon": {
"color": "accent"
},
"PsiViewer": { "PsiViewer": {
"referenceHighlightColor": "accent" "referenceHighlightColor": "accent"
}, },
@@ -914,6 +922,13 @@
"selectionBackground": "selBg", "selectionBackground": "selBg",
"selectionForeground": "selFg" "selectionForeground": "selFg"
}, },
"RunWidget": {
"Running": {
"background": "accent",
"leftHoverBackground": "accent70",
"leftPressedBackground": "accent"
}
},
"ScreenView.borderColor": "border", "ScreenView.borderColor": "border",
"scrollbar": "bg", "scrollbar": "bg",
"ScrollBar": { "ScrollBar": {
@@ -1008,6 +1023,8 @@
"Repeated.File.Foreground": "fg" "Repeated.File.Foreground": "fg"
}, },
"SegmentedButton": { "SegmentedButton": {
"focusedSelectedButtonColor": "hl",
"selectedButtonColor": "button",
"selectedStartBorderColor": "border", "selectedStartBorderColor": "border",
"selectedEndBorderColor": "border" "selectedEndBorderColor": "border"
}, },

View File

@@ -76,6 +76,11 @@
"ActionToolbar": { "ActionToolbar": {
"background": "hc" "background": "hc"
}, },
"AppInspector.GraphNode": {
"background": "second",
"borderColor": "border",
"focusedBorderColor": "accent"
},
"AssignedMnemonic": { "AssignedMnemonic": {
"background": "hl", "background": "hl",
"borderColor": "selBg", "borderColor": "selBg",
@@ -599,7 +604,7 @@
"link.pressed.foreground": "accent", "link.pressed.foreground": "accent",
"link.visited.foreground": "accent", "link.visited.foreground": "accent",
"List": { "List": {
"background": "second", "background": "bg",
"foreground": "fg", "foreground": "fg",
"hoverBackground": "hl", "hoverBackground": "hl",
"hoverInactiveBackground": "table", "hoverInactiveBackground": "table",
@@ -884,6 +889,9 @@
"selectionBackground": "hl", "selectionBackground": "hl",
"trackColor": "hl" "trackColor": "hl"
}, },
"ProgressIcon": {
"color": "accent"
},
"PsiViewer": { "PsiViewer": {
"referenceHighlightColor": "accent" "referenceHighlightColor": "accent"
}, },
@@ -914,6 +922,13 @@
"selectionBackground": "selBg", "selectionBackground": "selBg",
"selectionForeground": "selFg" "selectionForeground": "selFg"
}, },
"RunWidget": {
"Running": {
"background": "accent",
"leftHoverBackground": "accent70",
"leftPressedBackground": "accent"
}
},
"ScreenView.borderColor": "border", "ScreenView.borderColor": "border",
"scrollbar": "bg", "scrollbar": "bg",
"ScrollBar": { "ScrollBar": {
@@ -1008,6 +1023,8 @@
"Repeated.File.Foreground": "fg" "Repeated.File.Foreground": "fg"
}, },
"SegmentedButton": { "SegmentedButton": {
"focusedSelectedButtonColor": "hl",
"selectedButtonColor": "button",
"selectedStartBorderColor": "border", "selectedStartBorderColor": "border",
"selectedEndBorderColor": "border" "selectedEndBorderColor": "border"
}, },

View File

@@ -19,13 +19,13 @@
"accent2": "#2979ff2", "accent2": "#2979ff2",
"accent50": "#2979ff50", "accent50": "#2979ff50",
"accent70": "#2979ff70", "accent70": "#2979ff70",
"cs": "#eaeae", "cs": "#eaeaeb",
"button": "#DBDBDC", "button": "#DBDBDC",
"table": "#DBDBDC", "table": "#DBDBDC",
"tree": "#DBDBDC80", "tree": "#DBDBDC80",
"hl": "#FFFFFF", "hl": "#FFFFFF",
"notif": "#F2F2F2", "notif": "#F2F2F2",
"hc": "#eaeae", "hc": "#eaeaeb",
"shadow": "undefined", "shadow": "undefined",
"white": "#986801", "white": "#986801",
"blue": "#4078F2", "blue": "#4078F2",
@@ -76,6 +76,11 @@
"ActionToolbar": { "ActionToolbar": {
"background": "hc" "background": "hc"
}, },
"AppInspector.GraphNode": {
"background": "second",
"borderColor": "border",
"focusedBorderColor": "accent"
},
"AssignedMnemonic": { "AssignedMnemonic": {
"background": "hl", "background": "hl",
"borderColor": "selBg", "borderColor": "selBg",
@@ -599,7 +604,7 @@
"link.pressed.foreground": "accent", "link.pressed.foreground": "accent",
"link.visited.foreground": "accent", "link.visited.foreground": "accent",
"List": { "List": {
"background": "second", "background": "bg",
"foreground": "fg", "foreground": "fg",
"hoverBackground": "hl", "hoverBackground": "hl",
"hoverInactiveBackground": "table", "hoverInactiveBackground": "table",
@@ -884,6 +889,9 @@
"selectionBackground": "hl", "selectionBackground": "hl",
"trackColor": "hl" "trackColor": "hl"
}, },
"ProgressIcon": {
"color": "accent"
},
"PsiViewer": { "PsiViewer": {
"referenceHighlightColor": "accent" "referenceHighlightColor": "accent"
}, },
@@ -914,6 +922,13 @@
"selectionBackground": "selBg", "selectionBackground": "selBg",
"selectionForeground": "selFg" "selectionForeground": "selFg"
}, },
"RunWidget": {
"Running": {
"background": "accent",
"leftHoverBackground": "accent70",
"leftPressedBackground": "accent"
}
},
"ScreenView.borderColor": "border", "ScreenView.borderColor": "border",
"scrollbar": "bg", "scrollbar": "bg",
"ScrollBar": { "ScrollBar": {
@@ -1008,6 +1023,8 @@
"Repeated.File.Foreground": "fg" "Repeated.File.Foreground": "fg"
}, },
"SegmentedButton": { "SegmentedButton": {
"focusedSelectedButtonColor": "hl",
"selectedButtonColor": "button",
"selectedStartBorderColor": "border", "selectedStartBorderColor": "border",
"selectedEndBorderColor": "border" "selectedEndBorderColor": "border"
}, },

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