mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2026-02-11 06:27:13 -06:00
Compare commits
253 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
14c837ad05 | ||
|
|
9da634e225 | ||
|
|
0d91116e62 | ||
|
|
a31a8a03c1 | ||
|
|
e8d5210606 | ||
|
|
7b11e29122 | ||
|
|
df7f693cf4 | ||
|
|
14ddc2f629 | ||
|
|
6669d0e59d | ||
|
|
8d80176a79 | ||
|
|
e1dc302592 | ||
|
|
84dbe39185 | ||
|
|
4af2c31dab | ||
|
|
332f05b6e1 | ||
|
|
8b4786ad18 | ||
|
|
7e8aaffb92 | ||
|
|
7720d42584 | ||
|
|
293b76f04b | ||
|
|
a1b0c0bbd4 | ||
|
|
46d3204bc3 | ||
|
|
c25ff57b61 | ||
|
|
71e61f8f27 | ||
|
|
6914a6132c | ||
|
|
b72916187a | ||
|
|
7c9bbe6aef | ||
|
|
27eeb0a636 | ||
|
|
cf436962f8 | ||
|
|
7fb7a1ac85 | ||
|
|
15a714faed | ||
|
|
ea2412d3a7 | ||
|
|
40321856f2 | ||
|
|
262ae7865b | ||
|
|
84cc86bef7 | ||
|
|
1ba27730d6 | ||
|
|
6568cee2e8 | ||
|
|
5496a60f62 | ||
|
|
5c7378cf94 | ||
|
|
fe15f44e96 | ||
|
|
273d762cd3 | ||
|
|
211030b5b6 | ||
|
|
212c553904 | ||
|
|
dffe4f4451 | ||
|
|
fd99af5fe6 | ||
|
|
aee539bbef | ||
|
|
e7cdc9cf8c | ||
|
|
2443547b3b | ||
|
|
8424300b5f | ||
|
|
81822cf7f6 | ||
|
|
907956994f | ||
|
|
9246cc0607 | ||
|
|
9f81d147d1 | ||
|
|
b9bd26b2fb | ||
|
|
1838174678 | ||
|
|
0880a3380c | ||
|
|
2aad301938 | ||
|
|
e18e8e3158 | ||
|
|
ff55cc1a2a | ||
|
|
d081b9e182 | ||
|
|
5e5b9f0990 | ||
|
|
97577e835e | ||
|
|
732ca8be56 | ||
|
|
1381a34752 | ||
|
|
dd96712c2a | ||
|
|
2ad0aba382 | ||
|
|
8e77eb0519 | ||
|
|
049dae6584 | ||
|
|
1fffc67d13 | ||
|
|
8500781cd5 | ||
|
|
6a8bf2acc5 | ||
|
|
c45a769aa3 | ||
|
|
16d2e27d05 | ||
|
|
10c948d33c | ||
|
|
7ccd32dfbd | ||
|
|
99c99b9218 | ||
|
|
e0b0617ad2 | ||
|
|
5add723852 | ||
|
|
14ec6f6471 | ||
|
|
c4a1341aa9 | ||
|
|
fc68dfd7bc | ||
|
|
436fc545c0 | ||
|
|
023d781daf | ||
|
|
576c0048d0 | ||
|
|
4f79cdad50 | ||
|
|
954cae8738 | ||
|
|
b203ad63ee | ||
|
|
a560be11ed | ||
|
|
506a1e6b62 | ||
|
|
626601f6aa | ||
|
|
9ad32125c0 | ||
|
|
ebd6375672 | ||
|
|
502731d3b0 | ||
|
|
283535c429 | ||
|
|
5cef1f6730 | ||
|
|
7d14fbe739 | ||
|
|
e9e1e350eb | ||
|
|
566e42cc40 | ||
|
|
0abfb5922a | ||
|
|
4af8d2f1c5 | ||
|
|
d2d4f73834 | ||
|
|
53fce4e81d | ||
|
|
08c439b46e | ||
|
|
934eb9fc1d | ||
|
|
fd208a3879 | ||
|
|
10b131e111 | ||
|
|
c4c6faa943 | ||
|
|
c7a8d1e1b7 | ||
|
|
b36ac1b824 | ||
|
|
bc6cb492f1 | ||
|
|
ce503cedc3 | ||
|
|
c900c9cc82 | ||
|
|
87b73f26f5 | ||
|
|
be529655d6 | ||
|
|
2a0403a988 | ||
|
|
815e23b930 | ||
|
|
f1c08e7769 | ||
|
|
571f028ca3 | ||
|
|
16d51fe6b4 | ||
|
|
ddf9ed06ab | ||
|
|
1907f80024 | ||
|
|
8c0ccdd227 | ||
|
|
dc098025b6 | ||
|
|
c11222b5c7 | ||
|
|
03bc6eb69b | ||
|
|
1aa339de02 | ||
|
|
531bb2a968 | ||
|
|
800dbf3ba9 | ||
|
|
ff545e6ecd | ||
|
|
961fe38c7e | ||
|
|
19426394e2 | ||
|
|
069a4e8f0b | ||
|
|
a76b02b828 | ||
|
|
fbb9bf5f0c | ||
|
|
f632c355e8 | ||
|
|
e75caf5833 | ||
|
|
b0c8f2cefd | ||
|
|
2136d9f13d | ||
|
|
83fdeb7e0c | ||
|
|
26c77b3118 | ||
|
|
578d445ecb | ||
|
|
3bbc9517af | ||
|
|
a4d7f278cf | ||
|
|
bf0ffc6ac2 | ||
|
|
ace07cd9cb | ||
|
|
a341179426 | ||
|
|
298f0dfd63 | ||
|
|
b8f953cd26 | ||
|
|
a9cfe69ba7 | ||
|
|
b3e0b99e8d | ||
|
|
5bd40baed2 | ||
|
|
d3a70b8bb2 | ||
|
|
71e698603d | ||
|
|
659ead903c | ||
|
|
070c435f40 | ||
|
|
b668a526e3 | ||
|
|
01287d0669 | ||
|
|
ff481d759f | ||
|
|
71248f1708 | ||
|
|
0a0f834f23 | ||
|
|
06cad7ecd8 | ||
|
|
ceba3e2f95 | ||
|
|
61c2fd8794 | ||
|
|
db933fee4f | ||
|
|
2656c2dc40 | ||
|
|
01cfe33865 | ||
|
|
d79a31cc79 | ||
|
|
9efab8b892 | ||
|
|
aae845247a | ||
|
|
3f45a9a75f | ||
|
|
c9016155ae | ||
|
|
1019e8f4af | ||
|
|
8e423b4552 | ||
|
|
0e288c955c | ||
|
|
465dc8a66c | ||
|
|
7e5c599cc0 | ||
|
|
a961001a4b | ||
|
|
0a181f6407 | ||
|
|
27a347db34 | ||
|
|
b228dbb2df | ||
|
|
09cffc4340 | ||
|
|
e79880d305 | ||
|
|
34266761d1 | ||
|
|
77f17eaa3e | ||
|
|
ac70342cb3 | ||
|
|
d2f16dcaf3 | ||
|
|
abcce2bf68 | ||
|
|
514487074b | ||
|
|
f014e2473f | ||
|
|
80981f7027 | ||
|
|
8e6e971b51 | ||
|
|
4bd3b889dc | ||
|
|
464787dc1e | ||
|
|
a2541a9659 | ||
|
|
099dd87241 | ||
|
|
38eb914420 | ||
|
|
162215b1cf | ||
|
|
c6883f7a92 | ||
|
|
584286b794 | ||
|
|
a48713b7ca | ||
|
|
8f10c2d8bf | ||
|
|
5c0de9aa1c | ||
|
|
5553fd6538 | ||
|
|
e3ed47b37c | ||
|
|
976353d770 | ||
|
|
6fc216dff5 | ||
|
|
3f3961d255 | ||
|
|
875637bc6d | ||
|
|
395333cb3d | ||
|
|
870d039541 | ||
|
|
e8c8bece3f | ||
|
|
bd2f5dd6fe | ||
|
|
73f78d47ae | ||
|
|
8f60755f02 | ||
|
|
44c455419b | ||
|
|
129bc9b3ae | ||
|
|
08ba7dd065 | ||
|
|
dd2cf50a39 | ||
|
|
06eeced5b2 | ||
|
|
be23e5709d | ||
|
|
2735185eb9 | ||
|
|
41dd0acfa3 | ||
|
|
115a2df2b0 | ||
|
|
fcbb3aeed1 | ||
|
|
e9cb85127a | ||
|
|
c9c703fe98 | ||
|
|
0141dfbea2 | ||
|
|
fb7dafbc39 | ||
|
|
0660f9a511 | ||
|
|
a39ae5a8c5 | ||
|
|
03e22e3dbf | ||
|
|
d5e9fd0e5c | ||
|
|
141138ebea | ||
|
|
9026efeb26 | ||
|
|
2ab023beb0 | ||
|
|
8e471fd720 | ||
|
|
13cbbd8bc1 | ||
|
|
b08ccc9767 | ||
|
|
801a7023a4 | ||
|
|
dd06b554da | ||
|
|
23f0504b30 | ||
|
|
262d172cde | ||
|
|
be81cb7876 | ||
|
|
aaf9bd33cb | ||
|
|
7381e2141f | ||
|
|
3923d941c1 | ||
|
|
37ecd9bd4f | ||
|
|
2250185487 | ||
|
|
73cb63c9f9 | ||
|
|
f61f6b6006 | ||
|
|
a8f659f2ac | ||
|
|
a878ebc368 | ||
|
|
8ee6588d46 | ||
|
|
7c25f087fb | ||
|
|
d0b0f098d9 |
@@ -5,7 +5,7 @@ jdk:
|
||||
- openjdk8
|
||||
- openjdk9
|
||||
- openjdk11
|
||||
- openjdk13
|
||||
- openjdk14
|
||||
|
||||
before_cache:
|
||||
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
|
||||
|
||||
126
CHANGELOG.md
126
CHANGELOG.md
@@ -1,6 +1,132 @@
|
||||
FlatLaf Change Log
|
||||
==================
|
||||
|
||||
## 0.37
|
||||
|
||||
- Custom window decorations (Windows 10 only; PR #108; issues #47 and #82)
|
||||
support:
|
||||
- dark window title panes
|
||||
- embedding menu bar into window title pane
|
||||
- native Windows 10 borders and behavior when running in
|
||||
[JetBrains Runtime 11](https://confluence.jetbrains.com/display/JBR/JetBrains+Runtime)
|
||||
or later (the JRE that IntelliJ IDEA uses)
|
||||
- CheckBox and RadioButton: Support changing selected icon style from outline to
|
||||
filled (as in FlatLaf IntelliJ theme) with `UIManager.put(
|
||||
"CheckBox.icon.style", "filled" );`.
|
||||
- Button and ToggleButton: Support disabled background color (use UI values
|
||||
`Button.disabledBackground` and `ToggleButton.disabledBackground`). (issue
|
||||
#112)
|
||||
- Button and ToggleButton: Support making buttons square (set client property
|
||||
`JButton.squareSize` to `true`). (issue #118)
|
||||
- ScrollBar: Support pressed track, thumb and button colors (use UI values
|
||||
`ScrollBar.pressedTrackColor`, `ScrollBar.pressedThumbColor` and
|
||||
`ScrollBar.pressedButtonBackground`). (issue #115)
|
||||
- ComboBox: Support changing arrow button style (set UI value
|
||||
`ComboBox.buttonStyle` to `auto` (default), `button` or `none`). (issue #114)
|
||||
- Spinner: Support changing arrows button style (set UI value
|
||||
`Spinner.buttonStyle` to `button` (default) or `none`).
|
||||
- TableHeader: Support top/bottom/left positioned sort arrow when using
|
||||
[Glazed Lists](https://github.com/glazedlists/glazedlists). (issue #113)
|
||||
- Button, CheckBox, RadioButton and ToggleButton: Do not paint focus indicator
|
||||
if `AbstractButton.isFocusPainted()` returns `false`.
|
||||
- ComboBox: Increase maximum row count of popup list to 20 (was 8). Set UI value
|
||||
`ComboBox.maximumRowCount` to any integer to use a different value.
|
||||
- Fixed/improved vertical position of text when scaled on HiDPI screens on
|
||||
Windows.
|
||||
- IntelliJ Themes: Updated Gradianto Themes.
|
||||
- IntelliJ Themes: Fixed menu bar and menu item margins in all Material UI Lite
|
||||
themes.
|
||||
|
||||
|
||||
## 0.36
|
||||
|
||||
- ScrollBar: Made styling more flexible by supporting insets and arc for track
|
||||
and thumb. (issue #103)
|
||||
- ScrollBar: Use round thumb on macOS and Linux to make it look similar to
|
||||
native platform scroll bars. (issue #103)
|
||||
- ComboBox: Minimum width is now 72 pixels (was ~50 for non-editable and ~130
|
||||
for editable comboboxes).
|
||||
- ComboBox: Support custom borders in combobox editors. (issue #102)
|
||||
- Button: Support non-square icon-only buttons. (issue #110)
|
||||
- Ubuntu Linux: Fixed poorly rendered font. (issue #105)
|
||||
- macOS Catalina: Use Helvetica Neue font.
|
||||
- `FlatInspector` added (see [FlatLaf Extras](flatlaf-extras)).
|
||||
|
||||
|
||||
## 0.35
|
||||
|
||||
- Added drop shadows to popup menus, combobox popups, tooltips and internal
|
||||
frames. (issue #94)
|
||||
- Support different component border colors to indicate errors, warnings or
|
||||
custom state (set client property `JComponent.outline` to `error`, `warning`
|
||||
or any `java.awt.Color`).
|
||||
- Button and ToggleButton: Support round button style (set client property
|
||||
`JButton.buttonType` to `roundRect`).
|
||||
- ComboBox, Spinner and TextField: Support round border style (set client
|
||||
property `JComponent.roundRect` to `true`).
|
||||
- Paint nicely rounded buttons, comboboxes, spinners and text fields when
|
||||
setting `Button.arc`, `Component.arc` or `TextComponent.arc` to a large value
|
||||
(e.g. 1000).
|
||||
- Added Java 9 module descriptor to `flatlaf-extras-<version>.jar` and
|
||||
`flatlaf-swingx-<version>.jar`.
|
||||
- CheckBox and RadioButton: Flag `opaque` is no longer ignored when checkbox or
|
||||
radio button is used as table cell renderer. (issue #77)
|
||||
- FileChooser: Use system icons. (issue #100)
|
||||
- FileChooser: Fixed missing labels in file chooser when running on Java 9 or
|
||||
later. (issue #98)
|
||||
- PasswordField: Do not apply minimum width if `columns` property is greater
|
||||
than zero.
|
||||
|
||||
|
||||
## 0.34
|
||||
|
||||
- Menus: New menu item renderer brings stable left margins, right aligned
|
||||
accelerators and larger gap between text and accelerator. This makes menus
|
||||
look more modern and more similar to native platform menus.
|
||||
- New underline menu selection style that displays selected menu items similar
|
||||
to tabs (to enable use `UIManager.put( "MenuItem.selectionType", "underline"
|
||||
);`).
|
||||
- Menus: Fixed text color of selected menu items that use HTML. (issue #87)
|
||||
- Menus: On Windows, pressing <kbd>F10</kbd> now activates the menu bar without
|
||||
showing a menu popup (as usual on Windows platform). On other platforms the
|
||||
first menu popup is shown.
|
||||
- Menus: On Windows, releasing <kbd>Alt</kbd> key now activates the menu bar (as
|
||||
usual on Windows platform). (issue #43)
|
||||
- Menus: Fixed inconsistent left padding in menu items. (issue #3)
|
||||
- Menus: Fixed: Setting `iconTextGap` property on a menu item did increase left
|
||||
and right margins. (issue #54)
|
||||
- Hide mnemonics if window is deactivated (e.g. <kbd>Alt+Tab</kbd> to another
|
||||
window). (issue #43)
|
||||
- macOS: Enabled drop shadows for popup menus and combobox popups. (issue #94)
|
||||
- macOS: Fixed NPE if using `JMenuBar` in `JInternalFrame` and macOS screen menu
|
||||
bar is enabled (with `-Dapple.laf.useScreenMenuBar=true`). (issue #90)
|
||||
|
||||
|
||||
## 0.33
|
||||
|
||||
- Improved creation of disabled grayscale icons used in disabled buttons, labels
|
||||
and tabs. They now have more contrast and are lighter in light themes and
|
||||
darker in dark themes. (issue #70)
|
||||
- IntelliJ Themes: Fixed ComboBox size and Spinner border in all Material UI
|
||||
Lite themes and limit tree row height in all Material UI Lite themes and some
|
||||
other themes.
|
||||
- IntelliJ Themes: Material UI Lite themes did not work when using
|
||||
[IntelliJ Themes Pack](flatlaf-intellij-themes) addon. (PR #88, issue #89)
|
||||
- IntelliJ Themes: Added Java 9 module descriptor to
|
||||
`flatlaf-intellij-themes-<version>.jar`.
|
||||
|
||||
|
||||
## 0.32
|
||||
|
||||
- New [IntelliJ Themes Pack](flatlaf-intellij-themes) addon bundles many popular
|
||||
open-source 3rd party themes from JetBrains Plugins Repository into a JAR and
|
||||
provides Java classes to use them.
|
||||
- IntelliJ Themes: Fixed button and toggle button colors. (issue #86)
|
||||
- Updated IntelliJ Themes in demo to the latest versions.
|
||||
- ToggleButton: Compute selected background color based on current component
|
||||
background. (issue #32)
|
||||
|
||||
|
||||
## 0.31
|
||||
|
||||
- Focus indication border (or background) no longer hidden when temporary
|
||||
|
||||
@@ -19,7 +19,8 @@ IntelliJ IDEA 2019.2+ and uses almost the same colors and icons.
|
||||
IntelliJ Platform Themes
|
||||
------------------------
|
||||
|
||||
FlatLaf can use 3rd party themes created for IntelliJ Platform:
|
||||
FlatLaf can use 3rd party themes created for IntelliJ Platform (see
|
||||
[IntelliJ Themes Pack](flatlaf-intellij-themes)):
|
||||
|
||||

|
||||
|
||||
@@ -68,6 +69,8 @@ docs).
|
||||
Addons
|
||||
------
|
||||
|
||||
- [IntelliJ Themes Pack](flatlaf-intellij-themes)
|
||||
- [Extras](flatlaf-extras)
|
||||
- [SwingX](flatlaf-swingx)
|
||||
- [JIDE Common Layer](flatlaf-jide-oss)
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
val releaseVersion = "0.31"
|
||||
val developmentVersion = "0.32-SNAPSHOT"
|
||||
val releaseVersion = "0.37"
|
||||
val developmentVersion = "0.38-SNAPSHOT"
|
||||
|
||||
version = if( java.lang.Boolean.getBoolean( "release" ) ) releaseVersion else developmentVersion
|
||||
|
||||
|
||||
34
buildSrc/build.gradle.kts
Normal file
34
buildSrc/build.gradle.kts
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2020 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 {
|
||||
`kotlin-dsl`
|
||||
}
|
||||
|
||||
// required for kotlin-dsl or embedded-kotlin plugins
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// NOTE: keep plugin versions in sync with settings.gradle.kts
|
||||
|
||||
// "com.jfrog.bintray" plugin
|
||||
implementation( "com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4" )
|
||||
|
||||
// "com.jfrog.artifactory" plugin
|
||||
implementation( "org.jfrog.buildinfo:build-info-extractor-gradle:4.13.0" )
|
||||
}
|
||||
80
buildSrc/src/main/java/ReorderJarEntries.java
Normal file
80
buildSrc/src/main/java/ReorderJarEntries.java
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2020 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.
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
/**
|
||||
* Reorders entries in a JAR file so that .properties files are placed before .class files,
|
||||
* which is necessary to workaround an issue in NetBeans 11.3 (and older).
|
||||
* See issues #13 and #93.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class ReorderJarEntries
|
||||
{
|
||||
public static void reorderJarEntries( File jarFile )
|
||||
throws IOException
|
||||
{
|
||||
ByteArrayOutputStream outStream = new ByteArrayOutputStream( (int) jarFile.length() + 1000 );
|
||||
|
||||
try( ZipOutputStream zipOutStream = new ZipOutputStream( outStream ) ) {
|
||||
// 1st pass: copy .properties files
|
||||
copyFiles( zipOutStream, jarFile, name -> name.endsWith( ".properties" ) );
|
||||
|
||||
// 2st pass: copy other files
|
||||
copyFiles( zipOutStream, jarFile, name -> !name.endsWith( ".properties" ) );
|
||||
}
|
||||
|
||||
// replace JAR
|
||||
Files.write( jarFile.toPath(), outStream.toByteArray(),
|
||||
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING );
|
||||
}
|
||||
|
||||
private static void copyFiles( ZipOutputStream dest, File jarFile, Predicate<String> filter )
|
||||
throws IOException
|
||||
{
|
||||
try( ZipInputStream zipInputStream = new ZipInputStream( new FileInputStream( jarFile ) ) ) {
|
||||
ZipEntry entry;
|
||||
while( (entry = zipInputStream.getNextEntry()) != null ) {
|
||||
if( filter.test( entry.getName() ) ) {
|
||||
dest.putNextEntry( entry );
|
||||
copyFile( zipInputStream, dest );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void copyFile( InputStream src, OutputStream dest )
|
||||
throws IOException
|
||||
{
|
||||
byte[] buf = new byte[8*1024];
|
||||
int len;
|
||||
while( (len = src.read( buf )) > 0 )
|
||||
dest.write( buf, 0, len );
|
||||
dest.flush();
|
||||
}
|
||||
}
|
||||
44
buildSrc/src/main/kotlin/flatlaf-java9.gradle.kts
Normal file
44
buildSrc/src/main/kotlin/flatlaf-java9.gradle.kts
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2020 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
|
||||
}
|
||||
|
||||
if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) {
|
||||
sourceSets {
|
||||
create( "java9" ) {
|
||||
java {
|
||||
setSrcDirs( listOf( "src/main/java9" ) )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks {
|
||||
named<JavaCompile>( "compileJava9Java" ) {
|
||||
sourceCompatibility = "9"
|
||||
targetCompatibility = "9"
|
||||
}
|
||||
|
||||
jar {
|
||||
manifest.attributes( "Multi-Release" to "true" )
|
||||
|
||||
into( "META-INF/versions/9" ) {
|
||||
from( sourceSets["java9"].output )
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
64
buildSrc/src/main/kotlin/flatlaf-module-info.gradle.kts
Normal file
64
buildSrc/src/main/kotlin/flatlaf-module-info.gradle.kts
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2020 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 ModuleInfoExtension {
|
||||
var paths: ArrayList<String> = ArrayList()
|
||||
|
||||
fun dependsOn( vararg paths: String ) {
|
||||
this.paths.addAll( paths )
|
||||
}
|
||||
}
|
||||
|
||||
val extension = project.extensions.create<ModuleInfoExtension>( "flatlafModuleInfo" )
|
||||
|
||||
|
||||
plugins {
|
||||
java
|
||||
}
|
||||
|
||||
if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) {
|
||||
sourceSets {
|
||||
create( "module-info" ) {
|
||||
java {
|
||||
// include "src/main/java" here to get compile errors if classes are
|
||||
// used from other modules that are not specified in module dependencies
|
||||
setSrcDirs( listOf( "src/main/module-info", "src/main/java" ) )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks {
|
||||
named<JavaCompile>( "compileModuleInfoJava" ) {
|
||||
sourceCompatibility = "9"
|
||||
targetCompatibility = "9"
|
||||
|
||||
dependsOn( extension.paths )
|
||||
|
||||
options.compilerArgs.add( "--module-path" )
|
||||
options.compilerArgs.add( configurations.runtimeClasspath.get().asPath )
|
||||
}
|
||||
|
||||
jar {
|
||||
manifest.attributes( "Multi-Release" to "true" )
|
||||
|
||||
into( "META-INF/versions/9" ) {
|
||||
from( sourceSets["module-info"].output ) {
|
||||
include( "module-info.class" )
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
116
buildSrc/src/main/kotlin/flatlaf-publish.gradle.kts
Normal file
116
buildSrc/src/main/kotlin/flatlaf-publish.gradle.kts
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright 2020 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 PublishExtension {
|
||||
var artifactId: String? = null
|
||||
var name: String? = null
|
||||
var description: String? = null
|
||||
}
|
||||
|
||||
val extension = project.extensions.create<PublishExtension>( "flatlafPublish" )
|
||||
|
||||
|
||||
plugins {
|
||||
`maven-publish`
|
||||
id( "com.jfrog.bintray" )
|
||||
id( "com.jfrog.artifactory" )
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create<MavenPublication>( "maven" ) {
|
||||
afterEvaluate {
|
||||
artifactId = extension.artifactId
|
||||
}
|
||||
groupId = "com.formdev"
|
||||
|
||||
from( components["java"] )
|
||||
|
||||
pom {
|
||||
afterEvaluate {
|
||||
this@pom.name.set( extension.name )
|
||||
this@pom.description.set( extension.description )
|
||||
}
|
||||
url.set( "https://github.com/JFormDesigner/FlatLaf" )
|
||||
|
||||
licenses {
|
||||
license {
|
||||
name.set( "The Apache License, Version 2.0" )
|
||||
url.set( "https://www.apache.org/licenses/LICENSE-2.0.txt" )
|
||||
}
|
||||
}
|
||||
|
||||
developers {
|
||||
developer {
|
||||
name.set( "Karl Tauber" )
|
||||
organization.set( "FormDev Software GmbH" )
|
||||
organizationUrl.set( "https://www.formdev.com/" )
|
||||
}
|
||||
}
|
||||
|
||||
scm {
|
||||
url.set( "https://github.com/JFormDesigner/FlatLaf" )
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bintray {
|
||||
user = rootProject.extra["bintray.user"] as String?
|
||||
key = rootProject.extra["bintray.key"] as String?
|
||||
|
||||
setPublications( "maven" )
|
||||
|
||||
with( pkg ) {
|
||||
repo = "flatlaf"
|
||||
afterEvaluate {
|
||||
this@with.name = extension.artifactId
|
||||
}
|
||||
setLicenses( "Apache-2.0" )
|
||||
vcsUrl = "https://github.com/JFormDesigner/FlatLaf"
|
||||
|
||||
with( version ) {
|
||||
name = project.version.toString()
|
||||
}
|
||||
|
||||
publish = rootProject.extra["bintray.publish"] as Boolean
|
||||
dryRun = rootProject.extra["bintray.dryRun"] as Boolean
|
||||
}
|
||||
}
|
||||
|
||||
artifactory {
|
||||
setContextUrl( "https://oss.jfrog.org" )
|
||||
|
||||
publish( closureOf<org.jfrog.gradle.plugin.artifactory.dsl.PublisherConfig> {
|
||||
repository( delegateClosureOf<groovy.lang.GroovyObject> {
|
||||
setProperty( "repoKey", "oss-snapshot-local" )
|
||||
setProperty( "username", rootProject.extra["bintray.user"] as String? )
|
||||
setProperty( "password", rootProject.extra["bintray.key"] as String? )
|
||||
} )
|
||||
|
||||
defaults( delegateClosureOf<groovy.lang.GroovyObject> {
|
||||
invokeMethod( "publications", "maven" )
|
||||
setProperty( "publishArtifacts", true )
|
||||
setProperty( "publishPom", true )
|
||||
} )
|
||||
} )
|
||||
|
||||
resolve( delegateClosureOf<org.jfrog.gradle.plugin.artifactory.dsl.ResolverConfig> {
|
||||
setProperty( "repoKey", "jcenter" )
|
||||
} )
|
||||
}
|
||||
377
flatlaf-core/.settings/org.eclipse.jdt.core.prefs
Normal file
377
flatlaf-core/.settings/org.eclipse.jdt.core.prefs
Normal file
@@ -0,0 +1,377 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false
|
||||
org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
|
||||
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
|
||||
org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns=false
|
||||
org.eclipse.jdt.core.formatter.align_with_spaces=false
|
||||
org.eclipse.jdt.core.formatter.alignment_for_additive_operator=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_assignment=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_compact_loops=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=48
|
||||
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_enum_constants=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_logical_operator=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_module_statements=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_record_components=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_relational_operator=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
|
||||
org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_shift_operator=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_string_concatenation=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=33
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=33
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_record_declaration=33
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=33
|
||||
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=32
|
||||
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=32
|
||||
org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
|
||||
org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_after_package=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_field=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_method=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_package=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_block=next_line_on_wrap
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=next_line_on_wrap
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=next_line_on_wrap
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_record_constructor=next_line_on_wrap
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_record_declaration=next_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=next_line
|
||||
org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped=true
|
||||
org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions=false
|
||||
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=true
|
||||
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
|
||||
org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_block_comments=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_header=false
|
||||
org.eclipse.jdt.core.formatter.comment.format_html=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_line_comments=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_source_code=true
|
||||
org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false
|
||||
org.eclipse.jdt.core.formatter.comment.indent_root_tags=false
|
||||
org.eclipse.jdt.core.formatter.comment.indent_tag_description=false
|
||||
org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
|
||||
org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags=do not insert
|
||||
org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
|
||||
org.eclipse.jdt.core.formatter.comment.line_length=80
|
||||
org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
|
||||
org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
|
||||
org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
|
||||
org.eclipse.jdt.core.formatter.compact_else_if=true
|
||||
org.eclipse.jdt.core.formatter.continuation_indentation=1
|
||||
org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=1
|
||||
org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
|
||||
org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
|
||||
org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=false
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_record_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
|
||||
org.eclipse.jdt.core.formatter.indent_empty_lines=false
|
||||
org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
|
||||
org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
|
||||
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
|
||||
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true
|
||||
org.eclipse.jdt.core.formatter.indentation.size=4
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_additive_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_record_components=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_logical_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_not_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_record_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_relational_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_shift_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_additive_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_record_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_record_components=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_logical_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_constructor=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_record_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_relational_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_shift_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.join_lines_in_comments=true
|
||||
org.eclipse.jdt.core.formatter.join_wrapped_lines=true
|
||||
org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line=one_line_never
|
||||
org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line=one_line_never
|
||||
org.eclipse.jdt.core.formatter.keep_code_block_on_one_line=one_line_never
|
||||
org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line=one_line_never
|
||||
org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line=one_line_never
|
||||
org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line=one_line_never
|
||||
org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line=one_line_never
|
||||
org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line=one_line_never
|
||||
org.eclipse.jdt.core.formatter.keep_method_body_on_one_line=one_line_never
|
||||
org.eclipse.jdt.core.formatter.keep_record_constructor_on_one_line=one_line_never
|
||||
org.eclipse.jdt.core.formatter.keep_record_declaration_on_one_line=one_line_never
|
||||
org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line=one_line_never
|
||||
org.eclipse.jdt.core.formatter.lineSplit=120
|
||||
org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
|
||||
org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
|
||||
org.eclipse.jdt.core.formatter.number_of_blank_lines_after_code_block=0
|
||||
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block=0
|
||||
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
|
||||
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block=0
|
||||
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body=0
|
||||
org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block=0
|
||||
org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_record_declaration=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines
|
||||
org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
|
||||
org.eclipse.jdt.core.formatter.tabulation.char=tab
|
||||
org.eclipse.jdt.core.formatter.tabulation.size=4
|
||||
org.eclipse.jdt.core.formatter.text_block_indentation=0
|
||||
org.eclipse.jdt.core.formatter.use_on_off_tags=false
|
||||
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
|
||||
org.eclipse.jdt.core.formatter.wrap_before_additive_operator=true
|
||||
org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false
|
||||
org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator=true
|
||||
org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true
|
||||
org.eclipse.jdt.core.formatter.wrap_before_logical_operator=false
|
||||
org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator=true
|
||||
org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
|
||||
org.eclipse.jdt.core.formatter.wrap_before_relational_operator=true
|
||||
org.eclipse.jdt.core.formatter.wrap_before_shift_operator=true
|
||||
org.eclipse.jdt.core.formatter.wrap_before_string_concatenation=true
|
||||
org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
|
||||
org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
|
||||
3
flatlaf-core/.settings/org.eclipse.jdt.ui.prefs
Normal file
3
flatlaf-core/.settings/org.eclipse.jdt.ui.prefs
Normal file
@@ -0,0 +1,3 @@
|
||||
eclipse.preferences.version=1
|
||||
formatter_profile=_FlatLaf
|
||||
formatter_settings_version=19
|
||||
@@ -16,150 +16,46 @@
|
||||
|
||||
plugins {
|
||||
`java-library`
|
||||
`maven-publish`
|
||||
id( "com.jfrog.bintray" )
|
||||
id( "com.jfrog.artifactory" )
|
||||
`flatlaf-module-info`
|
||||
`flatlaf-java9`
|
||||
`flatlaf-publish`
|
||||
}
|
||||
|
||||
if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) {
|
||||
sourceSets {
|
||||
create( "module-info" ) {
|
||||
java {
|
||||
// include "src/main/java" here to get compile errors if classes are
|
||||
// used from other modules that are not specified in module dependencies
|
||||
setSrcDirs( listOf( "src/main/module-info", "src/main/java" ) )
|
||||
}
|
||||
}
|
||||
}
|
||||
java {
|
||||
withSourcesJar()
|
||||
withJavadocJar()
|
||||
}
|
||||
|
||||
tasks {
|
||||
assemble {
|
||||
dependsOn(
|
||||
"sourcesJar",
|
||||
"javadocJar"
|
||||
)
|
||||
}
|
||||
|
||||
if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) {
|
||||
named<JavaCompile>( "compileModuleInfoJava" ) {
|
||||
sourceCompatibility = "9"
|
||||
targetCompatibility = "9"
|
||||
}
|
||||
}
|
||||
|
||||
jar {
|
||||
archiveBaseName.set( "flatlaf" )
|
||||
|
||||
if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) {
|
||||
from( sourceSets["module-info"].output ) {
|
||||
include( "module-info.class" )
|
||||
}
|
||||
doLast {
|
||||
ReorderJarEntries.reorderJarEntries( outputs.files.singleFile );
|
||||
}
|
||||
}
|
||||
|
||||
javadoc {
|
||||
options {
|
||||
this as StandardJavadocDocletOptions
|
||||
use( true )
|
||||
tags = listOf( "uiDefault", "clientProperty" )
|
||||
addStringOption( "Xdoclint:all,-missing", "-Xdoclint:all,-missing" )
|
||||
}
|
||||
isFailOnError = false
|
||||
}
|
||||
|
||||
register( "sourcesJar", Jar::class ) {
|
||||
named<Jar>("sourcesJar" ) {
|
||||
archiveBaseName.set( "flatlaf" )
|
||||
archiveClassifier.set( "sources" )
|
||||
|
||||
from( sourceSets.main.get().allJava )
|
||||
}
|
||||
|
||||
register( "javadocJar", Jar::class ) {
|
||||
named<Jar>("javadocJar" ) {
|
||||
archiveBaseName.set( "flatlaf" )
|
||||
archiveClassifier.set( "javadoc" )
|
||||
|
||||
from( javadoc )
|
||||
}
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create<MavenPublication>( "maven" ) {
|
||||
artifactId = "flatlaf"
|
||||
groupId = "com.formdev"
|
||||
|
||||
from( components["java"] )
|
||||
|
||||
artifact( tasks["sourcesJar"] )
|
||||
artifact( tasks["javadocJar"] )
|
||||
|
||||
pom {
|
||||
name.set( "FlatLaf" )
|
||||
description.set( "Flat Look and Feel" )
|
||||
url.set( "https://github.com/JFormDesigner/FlatLaf" )
|
||||
|
||||
licenses {
|
||||
license {
|
||||
name.set( "The Apache License, Version 2.0" )
|
||||
url.set( "https://www.apache.org/licenses/LICENSE-2.0.txt" )
|
||||
}
|
||||
}
|
||||
|
||||
developers {
|
||||
developer {
|
||||
name.set( "Karl Tauber" )
|
||||
organization.set( "FormDev Software GmbH" )
|
||||
organizationUrl.set( "https://www.formdev.com/" )
|
||||
}
|
||||
}
|
||||
|
||||
scm {
|
||||
url.set( "https://github.com/JFormDesigner/FlatLaf" )
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bintray {
|
||||
user = rootProject.extra["bintray.user"] as String?
|
||||
key = rootProject.extra["bintray.key"] as String?
|
||||
|
||||
setPublications( "maven" )
|
||||
|
||||
with( pkg ) {
|
||||
repo = "flatlaf"
|
||||
name = "flatlaf"
|
||||
setLicenses( "Apache-2.0" )
|
||||
vcsUrl = "https://github.com/JFormDesigner/FlatLaf"
|
||||
|
||||
with( version ) {
|
||||
name = project.version.toString()
|
||||
}
|
||||
|
||||
publish = rootProject.extra["bintray.publish"] as Boolean
|
||||
dryRun = rootProject.extra["bintray.dryRun"] as Boolean
|
||||
}
|
||||
}
|
||||
|
||||
artifactory {
|
||||
setContextUrl( "https://oss.jfrog.org" )
|
||||
|
||||
publish( closureOf<org.jfrog.gradle.plugin.artifactory.dsl.PublisherConfig> {
|
||||
repository( delegateClosureOf<groovy.lang.GroovyObject> {
|
||||
setProperty( "repoKey", "oss-snapshot-local" )
|
||||
setProperty( "username", rootProject.extra["bintray.user"] as String? )
|
||||
setProperty( "password", rootProject.extra["bintray.key"] as String? )
|
||||
} )
|
||||
|
||||
defaults( delegateClosureOf<groovy.lang.GroovyObject> {
|
||||
invokeMethod( "publications", "maven" )
|
||||
setProperty( "publishArtifacts", true )
|
||||
setProperty( "publishPom", true )
|
||||
} )
|
||||
} )
|
||||
|
||||
resolve( delegateClosureOf<org.jfrog.gradle.plugin.artifactory.dsl.ResolverConfig> {
|
||||
setProperty( "repoKey", "jcenter" )
|
||||
} )
|
||||
flatlafPublish {
|
||||
artifactId = "flatlaf"
|
||||
name = "FlatLaf"
|
||||
description = "Flat Look and Feel"
|
||||
}
|
||||
|
||||
@@ -30,7 +30,8 @@ public interface FlatClientProperties
|
||||
* <p>
|
||||
* <strong>Components</strong> {@link javax.swing.JButton} and {@link javax.swing.JToggleButton}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.String}<br>
|
||||
* <strong>Allowed Values</strong> {@link #BUTTON_TYPE_SQUARE} and {@link #BUTTON_TYPE_HELP}
|
||||
* <strong>Allowed Values</strong> {@link #BUTTON_TYPE_SQUARE}, {@link #BUTTON_TYPE_ROUND_RECT},
|
||||
* {@link #BUTTON_TYPE_TAB}, {@link #BUTTON_TYPE_HELP} and {@link BUTTON_TYPE_TOOLBAR_BUTTON}
|
||||
*/
|
||||
String BUTTON_TYPE = "JButton.buttonType";
|
||||
|
||||
@@ -43,6 +44,15 @@ public interface FlatClientProperties
|
||||
*/
|
||||
String BUTTON_TYPE_SQUARE = "square";
|
||||
|
||||
/**
|
||||
* Paint the button with round edges.
|
||||
* <p>
|
||||
* <strong>Components</strong> {@link javax.swing.JButton} and {@link javax.swing.JToggleButton}
|
||||
*
|
||||
* @see #BUTTON_TYPE
|
||||
*/
|
||||
String BUTTON_TYPE_ROUND_RECT = "roundRect";
|
||||
|
||||
/**
|
||||
* Paint the toggle button in tab style.
|
||||
* <p>
|
||||
@@ -61,6 +71,15 @@ public interface FlatClientProperties
|
||||
*/
|
||||
String BUTTON_TYPE_HELP = "help";
|
||||
|
||||
/**
|
||||
* Paint the button in toolbar style.
|
||||
* <p>
|
||||
* <strong>Components</strong> {@link javax.swing.JButton} and {@link javax.swing.JToggleButton}
|
||||
*
|
||||
* @see #BUTTON_TYPE
|
||||
*/
|
||||
String BUTTON_TYPE_TOOLBAR_BUTTON = "toolBarButton";
|
||||
|
||||
/**
|
||||
* Specifies selected state of a checkbox.
|
||||
* <p>
|
||||
@@ -77,10 +96,19 @@ public interface FlatClientProperties
|
||||
*/
|
||||
String SELECTED_STATE_INDETERMINATE = "indeterminate";
|
||||
|
||||
/**
|
||||
* Specifies whether the button preferred size will be made square (quadratically).
|
||||
* <p>
|
||||
* <strong>Components</strong> {@link javax.swing.JButton} and {@link javax.swing.JToggleButton}
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
*/
|
||||
String SQUARE_SIZE = "JButton.squareSize";
|
||||
|
||||
/**
|
||||
* Specifies minimum width of a component.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JButton}, {@link javax.swing.JToggleButton} and {@link javax.swing.text.JTextComponent}<br>
|
||||
* <strong>Component</strong> {@link javax.swing.JButton}, {@link javax.swing.JToggleButton},
|
||||
* {@link javax.swing.JComboBox}, {@link javax.swing.JSpinner} and {@link javax.swing.text.JTextComponent}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Integer}<br>
|
||||
*/
|
||||
String MINIMUM_WIDTH = "JComponent.minimumWidth";
|
||||
@@ -93,6 +121,52 @@ public interface FlatClientProperties
|
||||
*/
|
||||
String MINIMUM_HEIGHT = "JComponent.minimumHeight";
|
||||
|
||||
/**
|
||||
* Specifies the outline color of the component border.
|
||||
* <p>
|
||||
* <strong>Components</strong> {@link javax.swing.JButton}, {@link javax.swing.JComboBox},
|
||||
* {@link javax.swing.JFormattedTextField}, {@link javax.swing.JPasswordField},
|
||||
* {@link javax.swing.JScrollPane}, {@link javax.swing.JSpinner},
|
||||
* {@link javax.swing.JTextField} and {@link javax.swing.JToggleButton}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.String} or {@link java.awt.Color} or {@link java.awt.Color}[2]<br>
|
||||
* <strong>Allowed Values</strong> {@link #OUTLINE_ERROR}, {@link #OUTLINE_WARNING},
|
||||
* any color (type {@link java.awt.Color}) or an array of two colors (type {@link java.awt.Color}[2])
|
||||
* where the first color is for focused state and the second for unfocused state
|
||||
*/
|
||||
String OUTLINE = "JComponent.outline";
|
||||
|
||||
/**
|
||||
* Paint the component border in another color (usually reddish) to indicate an error.
|
||||
*
|
||||
* @see #OUTLINE
|
||||
*/
|
||||
String OUTLINE_ERROR = "error";
|
||||
|
||||
/**
|
||||
* Paint the component border in another color (usually yellowish) to indicate a warning.
|
||||
*
|
||||
* @see #OUTLINE
|
||||
*/
|
||||
String OUTLINE_WARNING = "warning";
|
||||
|
||||
/**
|
||||
* Paint the component with round edges.
|
||||
* <p>
|
||||
* <strong>Components</strong> {@link javax.swing.JComboBox}, {@link javax.swing.JSpinner},
|
||||
* {@link javax.swing.JTextField}, {@link javax.swing.JFormattedTextField} and {@link javax.swing.JPasswordField}
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
*/
|
||||
String COMPONENT_ROUND_RECT = "JComponent.roundRect";
|
||||
|
||||
/**
|
||||
* Specifies whether a drop shadow is painted if the component is shown in a popup
|
||||
* or if the component is the owner of another component that is shown in a popup.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JComponent}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
*/
|
||||
String POPUP_DROP_SHADOW_PAINTED = "Popup.dropShadowPainted";
|
||||
|
||||
/**
|
||||
* Specifies whether the progress bar has always the larger height even if no string is painted.
|
||||
* <p>
|
||||
@@ -109,6 +183,15 @@ public interface FlatClientProperties
|
||||
*/
|
||||
String PROGRESS_BAR_SQUARE = "JProgressBar.square";
|
||||
|
||||
/**
|
||||
* Specifies whether the menu bar is embedded into the title pane if custom
|
||||
* window decorations are enabled. Default is {@code true}.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
*/
|
||||
String MENU_BAR_EMBEDDED = "JRootPane.menuBarEmbedded";
|
||||
|
||||
/**
|
||||
* Specifies whether the decrease/increase arrow buttons of a scrollbar are shown.
|
||||
* <p>
|
||||
@@ -240,4 +323,14 @@ public interface FlatClientProperties
|
||||
Object value = c.getClientProperty( key );
|
||||
return (value instanceof Color) ? (Color) value : defaultValue;
|
||||
}
|
||||
|
||||
static int clientPropertyChoice( JComponent c, String key, String... choices ) {
|
||||
Object value = c.getClientProperty( key );
|
||||
for( int i = 0; i < choices.length; i++ ) {
|
||||
if( choices[i].equals( value ) )
|
||||
return i;
|
||||
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,11 +32,11 @@ public class FlatDarculaLaf
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Flat Darcula";
|
||||
return "FlatLaf Darcula";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Flat Darcula Look and Feel";
|
||||
return "FlatLaf Darcula Look and Feel";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,12 +32,12 @@ public class FlatDarkLaf
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Flat Dark";
|
||||
return "FlatLaf Dark";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Flat Dark Look and Feel";
|
||||
return "FlatLaf Dark Look and Feel";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2020 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;
|
||||
|
||||
/**
|
||||
* Default color palette for action icons and object icons.
|
||||
* <p>
|
||||
* The idea is to use only this well defined set of colors in SVG icons and
|
||||
* then they are replaced at runtime to dark variants or to other theme colors.
|
||||
* Then a single SVG icon (light variant) can be used for dark themes too.
|
||||
* IntelliJ Platform uses this mechanism to allow themes to change IntelliJ Platform icons.
|
||||
* <p>
|
||||
* Use the {@code *_DARK} colors only in {@code *_dark.svg} files.
|
||||
* <p>
|
||||
* The colors are based on IntelliJ Platform
|
||||
* <a href="https://jetbrains.design/intellij/principles/icons/#action-icons">Action icons</a>
|
||||
* and
|
||||
* <a href="https://jetbrains.design/intellij/principles/icons/#noun-icons">Noun icons</a>
|
||||
* <p>
|
||||
* These colors may be changed by IntelliJ Platform themes.
|
||||
* <p>
|
||||
* You may use these colors also in your application (outside of SVG icons), but do
|
||||
* not use the RGB values defined in this enum.<br>
|
||||
* Instead use {@code UIManager.getColor( FlatIconColors.ACTIONS_GREY.key )}.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public enum FlatIconColors
|
||||
{
|
||||
// colors for action icons
|
||||
// see https://jetbrains.design/intellij/principles/icons/#action-icons
|
||||
ACTIONS_RED ( 0xDB5860, "Actions.Red", true, false ),
|
||||
ACTIONS_RED_DARK ( 0xC75450, "Actions.Red", false, true ),
|
||||
ACTIONS_YELLOW ( 0xEDA200, "Actions.Yellow", true, false ),
|
||||
ACTIONS_YELLOW_DARK ( 0xF0A732, "Actions.Yellow", false, true ),
|
||||
ACTIONS_GREEN ( 0x59A869, "Actions.Green", true, false ),
|
||||
ACTIONS_GREEN_DARK ( 0x499C54, "Actions.Green", false, true ),
|
||||
ACTIONS_BLUE ( 0x389FD6, "Actions.Blue", true, false ),
|
||||
ACTIONS_BLUE_DARK ( 0x3592C4, "Actions.Blue", false, true ),
|
||||
ACTIONS_GREY ( 0x6E6E6E, "Actions.Grey", true, false ),
|
||||
ACTIONS_GREY_DARK ( 0xAFB1B3, "Actions.Grey", false, true ),
|
||||
ACTIONS_GREYINLINE ( 0x7F8B91, "Actions.GreyInline", true, false ),
|
||||
ACTIONS_GREYINLINE_DARK ( 0x7F8B91, "Actions.GreyInline", false, true ),
|
||||
|
||||
// colors for object icons
|
||||
// see https://jetbrains.design/intellij/principles/icons/#noun-icons
|
||||
OBJECTS_GREY ( 0x9AA7B0, "Objects.Grey" ),
|
||||
OBJECTS_BLUE ( 0x40B6E0, "Objects.Blue" ),
|
||||
OBJECTS_GREEN ( 0x62B543, "Objects.Green" ),
|
||||
OBJECTS_YELLOW ( 0xF4AF3D, "Objects.Yellow" ),
|
||||
OBJECTS_YELLOW_DARK ( 0xD9A343, "Objects.YellowDark" ),
|
||||
OBJECTS_PURPLE ( 0xB99BF8, "Objects.Purple" ),
|
||||
OBJECTS_PINK ( 0xF98B9E, "Objects.Pink" ),
|
||||
OBJECTS_RED ( 0xF26522, "Objects.Red" ),
|
||||
OBJECTS_RED_STATUS ( 0xE05555, "Objects.RedStatus" ),
|
||||
OBJECTS_GREEN_ANDROID ( 0xA4C639, "Objects.GreenAndroid" ),
|
||||
OBJECTS_BLACK_TEXT ( 0x231F20, "Objects.BlackText" );
|
||||
|
||||
public final int rgb;
|
||||
public final String key;
|
||||
|
||||
public final boolean light;
|
||||
public final boolean dark;
|
||||
|
||||
FlatIconColors( int rgb, String key ) {
|
||||
this( rgb, key, true, true );
|
||||
}
|
||||
|
||||
FlatIconColors( int rgb, String key, boolean light, boolean dark ) {
|
||||
this.rgb = rgb;
|
||||
this.key = key;
|
||||
this.light = light;
|
||||
this.dark = dark;
|
||||
}
|
||||
}
|
||||
@@ -85,8 +85,12 @@ class FlatInputMaps
|
||||
// swap to make it consistent with List and Tree
|
||||
"HOME", "selectFirstRow",
|
||||
"END", "selectLastRow",
|
||||
"shift HOME", "selectFirstRowExtendSelection",
|
||||
"shift END", "selectLastRowExtendSelection",
|
||||
mac( "ctrl HOME", null ), "selectFirstColumn",
|
||||
mac( "ctrl END", null ), "selectLastColumn"
|
||||
mac( "ctrl END", null ), "selectLastColumn",
|
||||
mac( "shift ctrl HOME", null ), "selectFirstColumnExtendSelection",
|
||||
mac( "shift ctrl END", null ), "selectLastColumnExtendSelection"
|
||||
);
|
||||
|
||||
if( !SystemInfo.IS_MAC ) {
|
||||
@@ -501,6 +505,9 @@ class FlatInputMaps
|
||||
"alt KP_LEFT", "selectParent",
|
||||
"alt KP_RIGHT", "selectChild",
|
||||
|
||||
"shift HOME", "selectFirstExtendSelection",
|
||||
"shift END", "selectLastExtendSelection",
|
||||
|
||||
"meta A", "selectAll",
|
||||
"meta C", "copy",
|
||||
"meta V", "paste",
|
||||
@@ -545,8 +552,6 @@ class FlatInputMaps
|
||||
"shift ctrl SPACE", null,
|
||||
"shift ctrl UP", null,
|
||||
"shift DELETE", null,
|
||||
"shift END", null,
|
||||
"shift HOME", null,
|
||||
"shift INSERT", null,
|
||||
"shift PAGE_DOWN", null,
|
||||
"shift PAGE_UP", null,
|
||||
|
||||
@@ -32,11 +32,11 @@ public class FlatIntelliJLaf
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Flat IntelliJ";
|
||||
return "FlatLaf IntelliJ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Flat IntelliJ Look and Feel";
|
||||
return "FlatLaf IntelliJ Look and Feel";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,18 +18,17 @@ package com.formdev.flatlaf;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Font;
|
||||
import java.awt.KeyEventPostProcessor;
|
||||
import java.awt.KeyboardFocusManager;
|
||||
import java.awt.Image;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.image.FilteredImageSource;
|
||||
import java.awt.image.ImageFilter;
|
||||
import java.awt.image.ImageProducer;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -37,12 +36,15 @@ import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.swing.AbstractButton;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JRootPane;
|
||||
import javax.swing.JTabbedPane;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.PopupFactory;
|
||||
import javax.swing.SwingUtilities;
|
||||
@@ -56,6 +58,10 @@ import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicLookAndFeel;
|
||||
import javax.swing.text.StyleContext;
|
||||
import javax.swing.text.html.HTMLEditorKit;
|
||||
import com.formdev.flatlaf.ui.FlatPopupFactory;
|
||||
import com.formdev.flatlaf.ui.JBRCustomDecorations;
|
||||
import com.formdev.flatlaf.util.GrayFilter;
|
||||
import com.formdev.flatlaf.util.MultiResolutionImageSupport;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
@@ -71,17 +77,20 @@ public abstract class FlatLaf
|
||||
private static final String DESKTOPFONTHINTS = "awt.font.desktophints";
|
||||
|
||||
private String desktopPropertyName;
|
||||
private String desktopPropertyName2;
|
||||
private PropertyChangeListener desktopPropertyListener;
|
||||
|
||||
private static boolean aquaLoaded;
|
||||
private static boolean updateUIPending;
|
||||
|
||||
private KeyEventPostProcessor mnemonicListener;
|
||||
private static boolean showMnemonics;
|
||||
private static WeakReference<Window> lastShowMnemonicWindow;
|
||||
private PopupFactory oldPopupFactory;
|
||||
private MnemonicHandler mnemonicHandler;
|
||||
|
||||
private Consumer<UIDefaults> postInitialization;
|
||||
|
||||
private Boolean oldFrameWindowDecorated;
|
||||
private Boolean oldDialogWindowDecorated;
|
||||
|
||||
public static boolean install( LookAndFeel newLookAndFeel ) {
|
||||
try {
|
||||
UIManager.setLookAndFeel( newLookAndFeel );
|
||||
@@ -107,6 +116,45 @@ public abstract class FlatLaf
|
||||
|
||||
public abstract boolean isDark();
|
||||
|
||||
/**
|
||||
* Checks whether the current look and feel is dark.
|
||||
*/
|
||||
public static boolean isLafDark() {
|
||||
LookAndFeel lookAndFeel = UIManager.getLookAndFeel();
|
||||
return lookAndFeel instanceof FlatLaf && ((FlatLaf)lookAndFeel).isDark();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether FlatLaf supports custom window decorations.
|
||||
* This depends on the operating system and on the used Java runtime.
|
||||
* <p>
|
||||
* To use custom window decorations in your application, enable them with
|
||||
* following code (before creating any frames or dialogs). Then custom window
|
||||
* decorations are only enabled if this method returns {@code true}.
|
||||
* <pre>
|
||||
* JFrame.setDefaultLookAndFeelDecorated( true );
|
||||
* JDialog.setDefaultLookAndFeelDecorated( true );
|
||||
* </pre>
|
||||
* <p>
|
||||
* Returns {@code true} on Windows 10, {@code false} otherwise.
|
||||
* <p>
|
||||
* Return also {@code false} if running on Windows 10 in
|
||||
* <a href="https://confluence.jetbrains.com/display/JBR/JetBrains+Runtime">JetBrains Runtime 11 (or later)</a>
|
||||
* (<a href="https://github.com/JetBrains/JetBrainsRuntime">source code on github</a>)
|
||||
* and JBR supports custom window decorations. In this case, JBR custom decorations
|
||||
* are enabled if {@link JFrame#isDefaultLookAndFeelDecorated()} or
|
||||
* {@link JDialog#isDefaultLookAndFeelDecorated()} return {@code true}.
|
||||
*/
|
||||
@Override
|
||||
public boolean getSupportsWindowDecorations() {
|
||||
if( SystemInfo.IS_JETBRAINS_JVM_11_OR_LATER &&
|
||||
SystemInfo.IS_WINDOWS_10_OR_LATER &&
|
||||
JBRCustomDecorations.isSupported() )
|
||||
return false;
|
||||
|
||||
return SystemInfo.IS_WINDOWS_10_OR_LATER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNativeLookAndFeel() {
|
||||
return false;
|
||||
@@ -117,6 +165,26 @@ public abstract class FlatLaf
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getDisabledIcon( JComponent component, Icon icon ) {
|
||||
if( icon instanceof ImageIcon ) {
|
||||
Object grayFilter = UIManager.get( "Component.grayFilter" );
|
||||
ImageFilter filter = (grayFilter instanceof ImageFilter)
|
||||
? (ImageFilter) grayFilter
|
||||
: GrayFilter.createDisabledIconFilter( isDark() ); // fallback
|
||||
|
||||
Function<Image, Image> mapper = img -> {
|
||||
ImageProducer producer = new FilteredImageSource( img.getSource(), filter );
|
||||
return Toolkit.getDefaultToolkit().createImage( producer );
|
||||
};
|
||||
|
||||
Image image = ((ImageIcon)icon).getImage();
|
||||
return new ImageIconUIResource( MultiResolutionImageSupport.map( image, mapper ) );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
if( SystemInfo.IS_MAC )
|
||||
@@ -124,12 +192,13 @@ public abstract class FlatLaf
|
||||
|
||||
super.initialize();
|
||||
|
||||
// add mnemonic listener
|
||||
mnemonicListener = e -> {
|
||||
checkShowMnemonics( e );
|
||||
return false;
|
||||
};
|
||||
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventPostProcessor( mnemonicListener );
|
||||
// install popup factory
|
||||
oldPopupFactory = PopupFactory.getSharedInstance();
|
||||
PopupFactory.setSharedInstance( new FlatPopupFactory() );
|
||||
|
||||
// install mnemonic handler
|
||||
mnemonicHandler = new MnemonicHandler();
|
||||
mnemonicHandler.install();
|
||||
|
||||
// listen to desktop property changes to update UI if system font or scaling changes
|
||||
if( SystemInfo.IS_WINDOWS ) {
|
||||
@@ -137,15 +206,19 @@ public abstract class FlatLaf
|
||||
// Settings > Ease of Access > Display > Make text bigger (100% - 225%)
|
||||
desktopPropertyName = "win.messagebox.font";
|
||||
} else if( SystemInfo.IS_LINUX ) {
|
||||
// Linux/Gnome allows changing font in "Tweaks" app
|
||||
desktopPropertyName = "gnome.Gtk/FontName";
|
||||
|
||||
// Linux/Gnome allows extra scaling and larger text:
|
||||
// Settings > Devices > Displays > Scale (100% or 200%)
|
||||
// Settings > Universal access > Large Text (off or on, 125%)
|
||||
desktopPropertyName = "gnome.Xft/DPI";
|
||||
// "Tweaks" app > Fonts > Scaling Factor (0,5 - 3)
|
||||
desktopPropertyName2 = "gnome.Xft/DPI";
|
||||
}
|
||||
if( desktopPropertyName != null ) {
|
||||
desktopPropertyListener = e -> {
|
||||
String propertyName = e.getPropertyName();
|
||||
if( desktopPropertyName.equals( propertyName ) )
|
||||
if( desktopPropertyName.equals( propertyName ) || propertyName.equals( desktopPropertyName2 ) )
|
||||
reSetLookAndFeel();
|
||||
else if( DESKTOPFONTHINTS.equals( propertyName ) ) {
|
||||
if( UIManager.getLookAndFeel() instanceof FlatLaf ) {
|
||||
@@ -156,6 +229,8 @@ public abstract class FlatLaf
|
||||
};
|
||||
Toolkit toolkit = Toolkit.getDefaultToolkit();
|
||||
toolkit.addPropertyChangeListener( desktopPropertyName, desktopPropertyListener );
|
||||
if( desktopPropertyName2 != null )
|
||||
toolkit.addPropertyChangeListener( desktopPropertyName2, desktopPropertyListener );
|
||||
toolkit.addPropertyChangeListener( DESKTOPFONTHINTS, desktopPropertyListener );
|
||||
}
|
||||
|
||||
@@ -170,6 +245,16 @@ public abstract class FlatLaf
|
||||
String.format( "a { color: #%06x; }", linkColor.getRGB() & 0xffffff ) );
|
||||
}
|
||||
};
|
||||
|
||||
// enable/disable window decorations, but only if system property is either
|
||||
// "true" or "false"; in other cases it is not changed
|
||||
Boolean useWindowDecorations = FlatSystemProperties.getBooleanStrict( FlatSystemProperties.USE_WINDOW_DECORATIONS, null );
|
||||
if( useWindowDecorations != null ) {
|
||||
oldFrameWindowDecorated = JFrame.isDefaultLookAndFeelDecorated();
|
||||
oldDialogWindowDecorated = JDialog.isDefaultLookAndFeelDecorated();
|
||||
JFrame.setDefaultLookAndFeelDecorated( useWindowDecorations );
|
||||
JDialog.setDefaultLookAndFeelDecorated( useWindowDecorations );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -178,21 +263,38 @@ public abstract class FlatLaf
|
||||
if( desktopPropertyListener != null ) {
|
||||
Toolkit toolkit = Toolkit.getDefaultToolkit();
|
||||
toolkit.removePropertyChangeListener( desktopPropertyName, desktopPropertyListener );
|
||||
if( desktopPropertyName2 != null )
|
||||
toolkit.removePropertyChangeListener( desktopPropertyName2, desktopPropertyListener );
|
||||
toolkit.removePropertyChangeListener( DESKTOPFONTHINTS, desktopPropertyListener );
|
||||
desktopPropertyName = null;
|
||||
desktopPropertyName2 = null;
|
||||
desktopPropertyListener = null;
|
||||
}
|
||||
|
||||
// remove mnemonic listener
|
||||
if( mnemonicListener != null ) {
|
||||
KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventPostProcessor( mnemonicListener );
|
||||
mnemonicListener = null;
|
||||
// uninstall popup factory
|
||||
if( oldPopupFactory != null ) {
|
||||
PopupFactory.setSharedInstance( oldPopupFactory );
|
||||
oldPopupFactory = null;
|
||||
}
|
||||
|
||||
// uninstall mnemonic handler
|
||||
if( mnemonicHandler != null ) {
|
||||
mnemonicHandler.uninstall();
|
||||
mnemonicHandler = null;
|
||||
}
|
||||
|
||||
// restore default link color
|
||||
new HTMLEditorKit().getStyleSheet().addRule( "a { color: blue; }" );
|
||||
postInitialization = null;
|
||||
|
||||
// restore enable/disable window decorations
|
||||
if( oldFrameWindowDecorated != null ) {
|
||||
JFrame.setDefaultLookAndFeelDecorated( oldFrameWindowDecorated );
|
||||
JDialog.setDefaultLookAndFeelDecorated( oldDialogWindowDecorated );
|
||||
oldFrameWindowDecorated = null;
|
||||
oldDialogWindowDecorated = null;
|
||||
}
|
||||
|
||||
super.uninitialize();
|
||||
}
|
||||
|
||||
@@ -239,12 +341,13 @@ public abstract class FlatLaf
|
||||
public UIDefaults getDefaults() {
|
||||
UIDefaults defaults = super.getDefaults();
|
||||
|
||||
// add Metal resource bundle, which is required for FlatFileChooserUI
|
||||
defaults.addResourceBundle( "com.sun.swing.internal.plaf.metal.resources.metal" );
|
||||
// add resource bundle for localized texts
|
||||
defaults.addResourceBundle( "com.formdev.flatlaf.resources.Bundle" );
|
||||
|
||||
// initialize some defaults (for overriding) that are used in UI delegates,
|
||||
// but are not set in BasicLookAndFeel
|
||||
putDefaults( defaults, defaults.getColor( "control" ),
|
||||
"Button.disabledBackground",
|
||||
"EditorPane.disabledBackground",
|
||||
"EditorPane.inactiveBackground",
|
||||
"FormattedTextField.disabledBackground",
|
||||
@@ -254,7 +357,8 @@ public abstract class FlatLaf
|
||||
"TextArea.inactiveBackground",
|
||||
"TextField.disabledBackground",
|
||||
"TextPane.disabledBackground",
|
||||
"TextPane.inactiveBackground" );
|
||||
"TextPane.inactiveBackground",
|
||||
"ToggleButton.disabledBackground" );
|
||||
putDefaults( defaults, defaults.getColor( "textInactiveText" ),
|
||||
"Button.disabledText",
|
||||
"CheckBox.disabledText",
|
||||
@@ -282,14 +386,18 @@ public abstract class FlatLaf
|
||||
// load defaults from properties
|
||||
List<Class<?>> lafClassesForDefaultsLoading = getLafClassesForDefaultsLoading();
|
||||
if( lafClassesForDefaultsLoading != null )
|
||||
UIDefaultsLoader.loadDefaultsFromProperties( lafClassesForDefaultsLoading, addons, getAdditionalDefaults(), defaults );
|
||||
UIDefaultsLoader.loadDefaultsFromProperties( lafClassesForDefaultsLoading, addons, getAdditionalDefaults(), isDark(), defaults );
|
||||
else
|
||||
UIDefaultsLoader.loadDefaultsFromProperties( getClass(), addons, getAdditionalDefaults(), defaults );
|
||||
UIDefaultsLoader.loadDefaultsFromProperties( getClass(), addons, getAdditionalDefaults(), isDark(), defaults );
|
||||
|
||||
// use Aqua MenuBarUI if Mac screen menubar is enabled
|
||||
if( SystemInfo.IS_MAC && Boolean.getBoolean( "apple.laf.useScreenMenuBar" ) )
|
||||
if( SystemInfo.IS_MAC && Boolean.getBoolean( "apple.laf.useScreenMenuBar" ) ) {
|
||||
defaults.put( "MenuBarUI", "com.apple.laf.AquaMenuBarUI" );
|
||||
|
||||
// add defaults necessary for AquaMenuBarUI
|
||||
defaults.put( "MenuBar.backgroundPainter", BorderFactory.createEmptyBorder() );
|
||||
}
|
||||
|
||||
// initialize text antialiasing
|
||||
putAATextInfo( defaults );
|
||||
|
||||
@@ -300,6 +408,11 @@ public abstract class FlatLaf
|
||||
for( FlatDefaultsAddon addon : addons )
|
||||
addon.afterDefaultsLoading( this, defaults );
|
||||
|
||||
// add user scale factor to allow layout managers (e.g. MigLayout) to use it
|
||||
defaults.put( "laf.scaleFactor", (ActiveValue) t -> {
|
||||
return UIScale.getUserScaleFactor();
|
||||
} );
|
||||
|
||||
if( postInitialization != null ) {
|
||||
postInitialization.accept( defaults );
|
||||
postInitialization = null;
|
||||
@@ -329,7 +442,10 @@ public abstract class FlatLaf
|
||||
|
||||
} else if( SystemInfo.IS_MAC ) {
|
||||
String fontName;
|
||||
if( SystemInfo.IS_MAC_OS_10_11_EL_CAPITAN_OR_LATER ) {
|
||||
if( SystemInfo.IS_MAC_OS_10_15_CATALINA_OR_LATER ) {
|
||||
// use Helvetica Neue font
|
||||
fontName = "Helvetica Neue";
|
||||
} else if( SystemInfo.IS_MAC_OS_10_11_EL_CAPITAN_OR_LATER ) {
|
||||
// use San Francisco Text font
|
||||
fontName = ".SF NS Text";
|
||||
} else {
|
||||
@@ -371,7 +487,7 @@ public abstract class FlatLaf
|
||||
// using StyleContext.getFont() here because it uses
|
||||
// sun.font.FontUtilities.getCompositeFontUIResource()
|
||||
// and creates a composite font that is able to display all Unicode characters
|
||||
Font font = new StyleContext().getFont( family, style, size );
|
||||
Font font = StyleContext.getDefaultStyleContext().getFont( family, style, size );
|
||||
return (font instanceof FontUIResource) ? (FontUIResource) font : new FontUIResource( font );
|
||||
}
|
||||
|
||||
@@ -388,30 +504,14 @@ public abstract class FlatLaf
|
||||
* <a href="https://jetbrains.design/intellij/principles/icons/#action-icons">Action icons</a>
|
||||
* and
|
||||
* <a href="https://jetbrains.design/intellij/principles/icons/#noun-icons">Noun icons</a>
|
||||
* <p>
|
||||
* These colors may be changed by IntelliJ Platform themes.
|
||||
*/
|
||||
public static void initIconColors( UIDefaults defaults, boolean dark ) {
|
||||
// colors for action icons
|
||||
// see https://jetbrains.design/intellij/principles/icons/#action-icons
|
||||
defaults.put( "Actions.Red", new ColorUIResource( !dark ? 0xDB5860 : 0xC75450 ) );
|
||||
defaults.put( "Actions.Yellow", new ColorUIResource( !dark ? 0xEDA200 : 0xF0A732 ) );
|
||||
defaults.put( "Actions.Green", new ColorUIResource( !dark ? 0x59A869 : 0x499C54 ) );
|
||||
defaults.put( "Actions.Blue", new ColorUIResource( !dark ? 0x389FD6 : 0x3592C4 ) );
|
||||
defaults.put( "Actions.Grey", new ColorUIResource( !dark ? 0x6E6E6E : 0xAFB1B3 ) );
|
||||
defaults.put( "Actions.GreyInline", new ColorUIResource( !dark ? 0x7F8B91 : 0x7F8B91 ) );
|
||||
|
||||
// colors for object icons
|
||||
// see https://jetbrains.design/intellij/principles/icons/#noun-icons
|
||||
defaults.put( "Objects.Grey", new ColorUIResource( 0x9AA7B0 ) );
|
||||
defaults.put( "Objects.Blue", new ColorUIResource( 0x40B6E0 ) );
|
||||
defaults.put( "Objects.Green", new ColorUIResource( 0x62B543 ) );
|
||||
defaults.put( "Objects.Yellow", new ColorUIResource( 0xF4AF3D ) );
|
||||
defaults.put( "Objects.YellowDark", new ColorUIResource( 0xD9A343 ) );
|
||||
defaults.put( "Objects.Purple", new ColorUIResource( 0xB99BF8 ) );
|
||||
defaults.put( "Objects.Pink", new ColorUIResource( 0xF98B9E ) );
|
||||
defaults.put( "Objects.Red", new ColorUIResource( 0xF26522 ) );
|
||||
defaults.put( "Objects.RedStatus", new ColorUIResource( 0xE05555 ) );
|
||||
defaults.put( "Objects.GreenAndroid", new ColorUIResource( 0xA4C639 ) );
|
||||
defaults.put( "Objects.BlackText", new ColorUIResource( 0x231F20 ) );
|
||||
for( FlatIconColors c : FlatIconColors.values() ) {
|
||||
if( c.light == !dark || c.dark == dark )
|
||||
defaults.put( c.key, new ColorUIResource( c.rgb ) );
|
||||
}
|
||||
}
|
||||
|
||||
private void putAATextInfo( UIDefaults defaults ) {
|
||||
@@ -501,86 +601,15 @@ public abstract class FlatLaf
|
||||
}
|
||||
|
||||
public static boolean isShowMnemonics() {
|
||||
return showMnemonics || !UIManager.getBoolean( "Component.hideMnemonics" );
|
||||
return MnemonicHandler.isShowMnemonics();
|
||||
}
|
||||
|
||||
private static void checkShowMnemonics( KeyEvent e ) {
|
||||
int keyCode = e.getKeyCode();
|
||||
if( SystemInfo.IS_MAC ) {
|
||||
// Ctrl+Alt keys must be pressed on Mac
|
||||
if( keyCode == KeyEvent.VK_CONTROL || keyCode == KeyEvent.VK_ALT )
|
||||
showMnemonics( e.getID() == KeyEvent.KEY_PRESSED && e.isControlDown() && e.isAltDown(), e.getComponent() );
|
||||
} else {
|
||||
// Alt key must be pressed on Windows and Linux
|
||||
if( keyCode == KeyEvent.VK_ALT )
|
||||
showMnemonics( e.getID() == KeyEvent.KEY_PRESSED, e.getComponent() );
|
||||
}
|
||||
public static void showMnemonics( Component c ) {
|
||||
MnemonicHandler.showMnemonics( true, c );
|
||||
}
|
||||
|
||||
private static void showMnemonics( boolean show, Component c ) {
|
||||
if( show == showMnemonics )
|
||||
return;
|
||||
|
||||
showMnemonics = show;
|
||||
|
||||
// check whether it is necessary to repaint
|
||||
if( !UIManager.getBoolean( "Component.hideMnemonics" ) )
|
||||
return;
|
||||
|
||||
if( show ) {
|
||||
// get root pane
|
||||
JRootPane rootPane = SwingUtilities.getRootPane( c );
|
||||
if( rootPane == null )
|
||||
return;
|
||||
|
||||
// get window
|
||||
Window window = SwingUtilities.getWindowAncestor( rootPane );
|
||||
if( window == null )
|
||||
return;
|
||||
|
||||
// repaint components with mnemonics in focused window
|
||||
repaintMnemonics( window );
|
||||
|
||||
lastShowMnemonicWindow = new WeakReference<>( window );
|
||||
} else if( lastShowMnemonicWindow != null ) {
|
||||
Window window = lastShowMnemonicWindow.get();
|
||||
if( window != null )
|
||||
repaintMnemonics( window );
|
||||
|
||||
lastShowMnemonicWindow = null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void repaintMnemonics( Container container ) {
|
||||
for( Component c : container.getComponents() ) {
|
||||
if( !c.isVisible() )
|
||||
continue;
|
||||
|
||||
if( hasMnemonic( c ) )
|
||||
c.repaint();
|
||||
|
||||
if( c instanceof Container )
|
||||
repaintMnemonics( (Container) c );
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean hasMnemonic( Component c ) {
|
||||
if( c instanceof JLabel && ((JLabel)c).getDisplayedMnemonicIndex() >= 0 )
|
||||
return true;
|
||||
|
||||
if( c instanceof AbstractButton && ((AbstractButton)c).getDisplayedMnemonicIndex() >= 0 )
|
||||
return true;
|
||||
|
||||
if( c instanceof JTabbedPane ) {
|
||||
JTabbedPane tabPane = (JTabbedPane) c;
|
||||
int tabCount = tabPane.getTabCount();
|
||||
for( int i = 0; i < tabCount; i++ ) {
|
||||
if( tabPane.getDisplayedMnemonicIndexAt( i ) >= 0 )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
public static void hideMnemonics() {
|
||||
MnemonicHandler.showMnemonics( false, null );
|
||||
}
|
||||
|
||||
//---- class ActiveFont ---------------------------------------------------
|
||||
@@ -620,4 +649,15 @@ public abstract class FlatLaf
|
||||
return font;
|
||||
}
|
||||
}
|
||||
|
||||
//---- class ImageIconUIResource ------------------------------------------
|
||||
|
||||
private static class ImageIconUIResource
|
||||
extends ImageIcon
|
||||
implements UIResource
|
||||
{
|
||||
ImageIconUIResource( Image image ) {
|
||||
super( image );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,12 +32,12 @@ public class FlatLightLaf
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Flat Light";
|
||||
return "FlatLaf Light";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Flat Light Look and Feel";
|
||||
return "FlatLaf Light Look and Feel";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* A Flat LaF that is able to load UI defaults from properties passed to the constructor.
|
||||
* <p>
|
||||
* Specify the base theme in the properties with {@code @baseTheme=<baseTheme>}.
|
||||
* Allowed values for {@code <baseTheme>} are {@code light} (the default), {@code dark},
|
||||
* {@code intellij} or {@code darcula}.
|
||||
* <p>
|
||||
* The properties are applied after loading the base theme and may overwrite base properties.
|
||||
* All features of FlatLaf properties files are available.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatPropertiesLaf
|
||||
extends FlatLaf
|
||||
{
|
||||
private final String name;
|
||||
private final String baseTheme;
|
||||
private final boolean dark;
|
||||
private final Properties properties;
|
||||
|
||||
public FlatPropertiesLaf( String name, File propertiesFile )
|
||||
throws IOException
|
||||
{
|
||||
this( name, new FileInputStream( propertiesFile ) );
|
||||
}
|
||||
|
||||
public FlatPropertiesLaf( String name, InputStream in )
|
||||
throws IOException
|
||||
{
|
||||
this( name, loadProperties( in ) );
|
||||
}
|
||||
|
||||
private static Properties loadProperties( InputStream in )
|
||||
throws IOException
|
||||
{
|
||||
Properties properties = new Properties();
|
||||
try( InputStream in2 = in ) {
|
||||
properties.load( in2 );
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
public FlatPropertiesLaf( String name, Properties properties ) {
|
||||
this.name = name;
|
||||
this.properties = properties;
|
||||
|
||||
baseTheme = properties.getProperty( "@baseTheme", "light" );
|
||||
dark = "dark".equalsIgnoreCase( baseTheme ) || "darcula".equalsIgnoreCase( baseTheme );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDark() {
|
||||
return dark;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ArrayList<Class<?>> getLafClassesForDefaultsLoading() {
|
||||
ArrayList<Class<?>> lafClasses = new ArrayList<>();
|
||||
lafClasses.add( FlatLaf.class );
|
||||
switch( baseTheme.toLowerCase() ) {
|
||||
default:
|
||||
case "light":
|
||||
lafClasses.add( FlatLightLaf.class );
|
||||
break;
|
||||
|
||||
case "dark":
|
||||
lafClasses.add( FlatDarkLaf.class );
|
||||
break;
|
||||
|
||||
case "intellij":
|
||||
lafClasses.add( FlatLightLaf.class );
|
||||
lafClasses.add( FlatIntelliJLaf.class );
|
||||
break;
|
||||
|
||||
case "darcula":
|
||||
lafClasses.add( FlatDarkLaf.class );
|
||||
lafClasses.add( FlatDarculaLaf.class );
|
||||
break;
|
||||
}
|
||||
return lafClasses;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Properties getAdditionalDefaults() {
|
||||
return properties;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf;
|
||||
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JFrame;
|
||||
|
||||
/**
|
||||
* Defines/documents own system properties used in FlatLaf.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public interface FlatSystemProperties
|
||||
{
|
||||
/**
|
||||
* Specifies a custom scale factor used to scale the UI.
|
||||
* <p>
|
||||
* If Java runtime scales (Java 9 or later), this scale factor is applied on top
|
||||
* of the Java system scale factor. Java 8 does not scale and this scale factor
|
||||
* replaces the user scale factor that FlatLaf computes based on the font.
|
||||
* To replace the Java 9+ system scale factor, use system property "sun.java2d.uiScale",
|
||||
* which has the same syntax as this one.
|
||||
* <p>
|
||||
* <strong>Allowed Values</strong> e.g. {@code 1.5}, {@code 1.5x}, {@code 150%} or {@code 144dpi} (96dpi is 100%)<br>
|
||||
*/
|
||||
String UI_SCALE = "flatlaf.uiScale";
|
||||
|
||||
/**
|
||||
* Specifies whether Ubuntu font should be used on Ubuntu Linux.
|
||||
* By default, if not running in a JetBrains Runtime, the Liberation Sans font
|
||||
* is used because there are rendering issues (in Java) with Ubuntu fonts.
|
||||
* <p>
|
||||
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
||||
* <strong>Default</strong> {@code false}
|
||||
*/
|
||||
String USE_UBUNTU_FONT = "flatlaf.useUbuntuFont";
|
||||
|
||||
/**
|
||||
* Specifies whether custom look and feel window decorations should be used
|
||||
* when creating {@code JFrame} or {@code JDialog}.
|
||||
* <p>
|
||||
* If this system property is set, FlatLaf invokes {@link JFrame#setDefaultLookAndFeelDecorated(boolean)}
|
||||
* and {@link JDialog#setDefaultLookAndFeelDecorated(boolean)} on LaF initialization.
|
||||
* <p>
|
||||
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
||||
* <strong>Default</strong> none
|
||||
*/
|
||||
String USE_WINDOW_DECORATIONS = "flatlaf.useWindowDecorations";
|
||||
|
||||
/**
|
||||
* Specifies whether JetBrains Runtime custom window decorations should be used
|
||||
* when creating {@code JFrame} or {@code JDialog}.
|
||||
* Requires that the application runs in a
|
||||
* <a href="https://confluence.jetbrains.com/display/JBR/JetBrains+Runtime">JetBrains Runtime</a>
|
||||
* (based on OpenJDK).
|
||||
* <p>
|
||||
* Setting this to {@code true} forces using JetBrains Runtime custom window decorations
|
||||
* even if they are not enabled by the application.
|
||||
* <p>
|
||||
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
||||
* <strong>Default</strong> {@code true}
|
||||
*/
|
||||
String USE_JETBRAINS_CUSTOM_DECORATIONS = "flatlaf.useJetBrainsCustomDecorations";
|
||||
|
||||
/**
|
||||
* Specifies whether menubar is embedded into custom window decorations.
|
||||
* <p>
|
||||
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
||||
* <strong>Default</strong> {@code true}
|
||||
*/
|
||||
String MENUBAR_EMBEDDED = "flatlaf.menuBarEmbedded";
|
||||
|
||||
/**
|
||||
* Specifies whether vertical text position is corrected when UI is scaled on HiDPI screens.
|
||||
* <p>
|
||||
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
||||
* <strong>Default</strong> {@code true}
|
||||
*/
|
||||
String USE_TEXT_Y_CORRECTION = "flatlaf.useTextYCorrection";
|
||||
|
||||
/**
|
||||
* Checks whether a system property is set and returns {@code true} if its value
|
||||
* is {@code "true"} (case-insensitive), otherwise it returns {@code false}.
|
||||
* If the system property is not set, {@code defaultValue} is returned.
|
||||
*/
|
||||
static boolean getBoolean( String key, boolean defaultValue ) {
|
||||
String value = System.getProperty( key );
|
||||
return (value != null) ? Boolean.parseBoolean( value ) : defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a system property is set and returns {@code Boolean.TRUE} if its value
|
||||
* is {@code "true"} (case-insensitive) or returns {@code Boolean.FALSE} if its value
|
||||
* is {@code "false"} (case-insensitive). Otherwise {@code defaultValue} is returned.
|
||||
*/
|
||||
static Boolean getBooleanStrict( String key, Boolean defaultValue ) {
|
||||
String value = System.getProperty( key );
|
||||
if( "true".equalsIgnoreCase( value ) )
|
||||
return Boolean.TRUE;
|
||||
if( "false".equalsIgnoreCase( value ) )
|
||||
return Boolean.FALSE;
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
@@ -86,7 +86,7 @@ public class IntelliJTheme
|
||||
* Using a buffered input stream is not necessary.
|
||||
*/
|
||||
public static FlatLaf createLaf( InputStream in )
|
||||
throws IOException, ParseException
|
||||
throws IOException
|
||||
{
|
||||
return createLaf( new IntelliJTheme( in ) );
|
||||
}
|
||||
@@ -106,11 +106,13 @@ public class IntelliJTheme
|
||||
*/
|
||||
@SuppressWarnings( "unchecked" )
|
||||
public IntelliJTheme( InputStream in )
|
||||
throws IOException, ParseException
|
||||
throws IOException
|
||||
{
|
||||
Map<String, Object> json;
|
||||
try( Reader reader = new InputStreamReader( in, StandardCharsets.UTF_8 ) ) {
|
||||
json = (Map<String, Object>) Json.parse( reader );
|
||||
} catch( ParseException ex ) {
|
||||
throw new IOException( ex.getMessage(), ex );
|
||||
}
|
||||
|
||||
name = (String) json.get( "name" );
|
||||
@@ -132,6 +134,8 @@ public class IntelliJTheme
|
||||
defaults.put( "Button.paintShadow", true );
|
||||
defaults.put( "Button.shadowWidth", dark ? 2 : 1 );
|
||||
|
||||
Map<Object, Object> themeSpecificDefaults = removeThemeSpecificDefaults( defaults );
|
||||
|
||||
loadNamedColors( defaults );
|
||||
|
||||
// convert Json "ui" structure to UI defaults
|
||||
@@ -143,6 +147,11 @@ public class IntelliJTheme
|
||||
applyColorPalette( defaults );
|
||||
applyCheckBoxColors( defaults );
|
||||
|
||||
// IDEA does not paint button background if disabled, but FlatLaf does
|
||||
Object panelBackground = defaults.get( "Panel.background" );
|
||||
defaults.put( "Button.disabledBackground", panelBackground );
|
||||
defaults.put( "ToggleButton.disabledBackground", panelBackground );
|
||||
|
||||
// IDEA uses a SVG icon for the help button, but paints the background with Button.startBackground and Button.endBackground
|
||||
Object helpButtonBackground = defaults.get( "Button.startBackground" );
|
||||
Object helpButtonBorderColor = defaults.get( "Button.startBorderColor" );
|
||||
@@ -152,7 +161,7 @@ public class IntelliJTheme
|
||||
helpButtonBorderColor = defaults.get( "Button.borderColor" );
|
||||
defaults.put( "HelpButton.background", helpButtonBackground );
|
||||
defaults.put( "HelpButton.borderColor", helpButtonBorderColor );
|
||||
defaults.put( "HelpButton.disabledBackground", defaults.get( "Panel.background" ) );
|
||||
defaults.put( "HelpButton.disabledBackground", panelBackground );
|
||||
defaults.put( "HelpButton.disabledBorderColor", defaults.get( "Button.disabledBorderColor" ) );
|
||||
defaults.put( "HelpButton.focusedBorderColor", defaults.get( "Button.focusedBorderColor" ) );
|
||||
defaults.put( "HelpButton.focusedBackground", defaults.get( "Button.focusedBackground" ) );
|
||||
@@ -183,6 +192,42 @@ public class IntelliJTheme
|
||||
if( !uiKeys.contains( "Spinner.background" ) )
|
||||
defaults.put( "Spinner.background", textFieldBackground );
|
||||
}
|
||||
|
||||
// fix ToggleButton
|
||||
if( !uiKeys.contains( "ToggleButton.startBackground" ) && !uiKeys.contains( "*.startBackground" ) )
|
||||
defaults.put( "ToggleButton.startBackground", defaults.get( "Button.startBackground" ) );
|
||||
if( !uiKeys.contains( "ToggleButton.endBackground" ) && !uiKeys.contains( "*.endBackground" ) )
|
||||
defaults.put( "ToggleButton.endBackground", defaults.get( "Button.endBackground" ) );
|
||||
if( !uiKeys.contains( "ToggleButton.foreground" ) && uiKeys.contains( "Button.foreground" ) )
|
||||
defaults.put( "ToggleButton.foreground", defaults.get( "Button.foreground" ) );
|
||||
|
||||
// limit tree row height
|
||||
int rowHeight = defaults.getInt( "Tree.rowHeight" );
|
||||
if( rowHeight > 22 )
|
||||
defaults.put( "Tree.rowHeight", 22 );
|
||||
|
||||
// apply theme specific UI defaults at the end to allow overwriting
|
||||
defaults.putAll( themeSpecificDefaults );
|
||||
}
|
||||
|
||||
private Map<Object, Object> removeThemeSpecificDefaults( UIDefaults defaults ) {
|
||||
// search for theme specific UI defaults keys
|
||||
ArrayList<String> themeSpecificKeys = new ArrayList<>();
|
||||
for( Object key : defaults.keySet() ) {
|
||||
if( key instanceof String && ((String)key).startsWith( "[" ) )
|
||||
themeSpecificKeys.add( (String) key );
|
||||
}
|
||||
|
||||
// remove theme specific UI defaults and remember only those for current theme
|
||||
Map<Object, Object> themeSpecificDefaults = new HashMap<>();
|
||||
String currentThemePrefix = '[' + name.replace( ' ', '_' ) + ']';
|
||||
for( String key : themeSpecificKeys ) {
|
||||
Object value = defaults.remove( key );
|
||||
if( key.startsWith( currentThemePrefix ) )
|
||||
themeSpecificDefaults.put( key.substring( currentThemePrefix.length() ), value );
|
||||
}
|
||||
|
||||
return themeSpecificDefaults;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -200,7 +245,7 @@ public class IntelliJTheme
|
||||
if( color != null ) {
|
||||
String key = e.getKey();
|
||||
namedColors.put( key, color );
|
||||
defaults.put( "ColorPalette." + e.getKey(), color );
|
||||
defaults.put( "ColorPalette." + key, color );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -216,6 +261,11 @@ public class IntelliJTheme
|
||||
} else {
|
||||
uiKeys.add( key );
|
||||
|
||||
// fix ComboBox size and Spinner border in all Material UI Lite themes
|
||||
boolean isMaterialUILite = author.equals( "Mallowigi" );
|
||||
if( isMaterialUILite && (key.equals( "ComboBox.padding" ) || key.equals( "Spinner.border" )) )
|
||||
return; // ignore
|
||||
|
||||
// map keys
|
||||
key = uiKeyMapping.getOrDefault( key, key );
|
||||
if( key.isEmpty() )
|
||||
@@ -270,7 +320,7 @@ public class IntelliJTheme
|
||||
// (e.g. set ComboBox.buttonEditableBackground to *.background
|
||||
// because it is mapped from ComboBox.ArrowButton.background)
|
||||
String km = uiKeyInverseMapping.getOrDefault( k, (String) k );
|
||||
if( km.endsWith( tail ) && !noWildcardReplace.contains( k ) && !((String)k).startsWith( "CheckBox.icon." ) )
|
||||
if( km.endsWith( tail ) && !((String)k).startsWith( "CheckBox.icon." ) )
|
||||
defaults.put( k, uiValue );
|
||||
}
|
||||
}
|
||||
@@ -412,7 +462,6 @@ public class IntelliJTheme
|
||||
private static Map<String, String> uiKeyInverseMapping = new HashMap<>();
|
||||
private static Map<String, String> checkboxKeyMapping = new HashMap<>();
|
||||
private static Map<String, String> checkboxDuplicateColors = new HashMap<>();
|
||||
private static Set<String> noWildcardReplace = new HashSet<>();
|
||||
|
||||
static {
|
||||
// ComboBox
|
||||
@@ -423,9 +472,28 @@ public class IntelliJTheme
|
||||
uiKeyMapping.put( "ComboBox.ArrowButton.iconColor", "ComboBox.buttonArrowColor" );
|
||||
uiKeyMapping.put( "ComboBox.ArrowButton.nonEditableBackground", "ComboBox.buttonBackground" );
|
||||
|
||||
// Component
|
||||
uiKeyMapping.put( "Component.inactiveErrorFocusColor", "Component.error.borderColor" );
|
||||
uiKeyMapping.put( "Component.errorFocusColor", "Component.error.focusedBorderColor" );
|
||||
uiKeyMapping.put( "Component.inactiveWarningFocusColor", "Component.warning.borderColor" );
|
||||
uiKeyMapping.put( "Component.warningFocusColor", "Component.warning.focusedBorderColor" );
|
||||
|
||||
// Link
|
||||
uiKeyMapping.put( "Link.activeForeground", "Component.linkColor" );
|
||||
|
||||
// Menu
|
||||
uiKeyMapping.put( "Menu.border", "Menu.margin" );
|
||||
uiKeyMapping.put( "MenuItem.border", "MenuItem.margin" );
|
||||
uiKeyCopying.put( "CheckBoxMenuItem.margin", "MenuItem.margin" );
|
||||
uiKeyCopying.put( "RadioButtonMenuItem.margin", "MenuItem.margin" );
|
||||
uiKeyMapping.put( "PopupMenu.border", "PopupMenu.borderInsets" );
|
||||
|
||||
// IDEA uses List.selectionBackground also for menu selection
|
||||
uiKeyCopying.put( "Menu.selectionBackground", "List.selectionBackground" );
|
||||
uiKeyCopying.put( "MenuItem.selectionBackground", "List.selectionBackground" );
|
||||
uiKeyCopying.put( "CheckBoxMenuItem.selectionBackground", "List.selectionBackground" );
|
||||
uiKeyCopying.put( "RadioButtonMenuItem.selectionBackground", "List.selectionBackground" );
|
||||
|
||||
// ProgressBar
|
||||
uiKeyMapping.put( "ProgressBar.background", "" ); // ignore
|
||||
uiKeyMapping.put( "ProgressBar.foreground", "" ); // ignore
|
||||
@@ -442,6 +510,10 @@ public class IntelliJTheme
|
||||
// Slider
|
||||
uiKeyMapping.put( "Slider.trackWidth", "" ); // ignore (used in Material Theme UI Lite)
|
||||
|
||||
// TitlePane
|
||||
uiKeyMapping.put( "TitlePane.infoForeground", "TitlePane.foreground" );
|
||||
uiKeyMapping.put( "TitlePane.inactiveInfoForeground", "TitlePane.inactiveForeground" );
|
||||
|
||||
for( Map.Entry<String, String> e : uiKeyMapping.entrySet() )
|
||||
uiKeyInverseMapping.put( e.getValue(), e.getKey() );
|
||||
|
||||
@@ -456,7 +528,7 @@ public class IntelliJTheme
|
||||
checkboxKeyMapping.put( "Checkbox.Border.Default", "CheckBox.icon.borderColor" );
|
||||
checkboxKeyMapping.put( "Checkbox.Border.Disabled", "CheckBox.icon.disabledBorderColor" );
|
||||
checkboxKeyMapping.put( "Checkbox.Focus.Thin.Default", "CheckBox.icon.focusedBorderColor" );
|
||||
checkboxKeyMapping.put( "Checkbox.Focus.Wide", "CheckBox.icon.focusedColor" );
|
||||
checkboxKeyMapping.put( "Checkbox.Focus.Wide", "CheckBox.icon.focusColor" );
|
||||
checkboxKeyMapping.put( "Checkbox.Foreground.Disabled", "CheckBox.icon.disabledCheckmarkColor" );
|
||||
checkboxKeyMapping.put( "Checkbox.Background.Selected", "CheckBox.icon.selectedBackground" );
|
||||
checkboxKeyMapping.put( "Checkbox.Border.Selected", "CheckBox.icon.selectedBorderColor" );
|
||||
@@ -470,16 +542,6 @@ public class IntelliJTheme
|
||||
Map.Entry<String, String>[] entries = checkboxDuplicateColors.entrySet().toArray( new Map.Entry[checkboxDuplicateColors.size()] );
|
||||
for( Map.Entry<String, String> e : entries )
|
||||
checkboxDuplicateColors.put( e.getValue(), e.getKey() );
|
||||
|
||||
// because FlatLaf uses Button.background and Button.borderColor,
|
||||
// but IDEA uses Button.startBackground and Button.startBorderColor,
|
||||
// our default button background and border colors may be replaced by
|
||||
// wildcard *.background and *.borderColor colors
|
||||
noWildcardReplace.add( "Button.background" );
|
||||
noWildcardReplace.add( "Button.borderColor" );
|
||||
noWildcardReplace.add( "Button.default.background" );
|
||||
noWildcardReplace.add( "Button.default.borderColor" );
|
||||
noWildcardReplace.add( "ToggleButton.background" );
|
||||
}
|
||||
|
||||
//---- class ThemeLaf -----------------------------------------------------
|
||||
|
||||
@@ -74,6 +74,13 @@ class LinuxFontPolicy
|
||||
family = family.isEmpty() ? word : (family + ' ' + word);
|
||||
}
|
||||
|
||||
// Ubuntu font is rendered poorly (except if running in JetBrains VM)
|
||||
// --> use Liberation Sans font
|
||||
if( family.startsWith( "Ubuntu" ) &&
|
||||
!SystemInfo.IS_JETBRAINS_JVM &&
|
||||
!FlatSystemProperties.getBoolean( FlatSystemProperties.USE_UBUNTU_FONT, false ) )
|
||||
family = "Liberation Sans";
|
||||
|
||||
// scale font size
|
||||
double dsize = size * getGnomeFontScale();
|
||||
size = (int) (dsize + 0.5);
|
||||
|
||||
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.KeyEventPostProcessor;
|
||||
import java.awt.KeyboardFocusManager;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.awt.event.WindowListener;
|
||||
import java.lang.ref.WeakReference;
|
||||
import javax.swing.AbstractButton;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.JRootPane;
|
||||
import javax.swing.JTabbedPane;
|
||||
import javax.swing.MenuElement;
|
||||
import javax.swing.MenuSelectionManager;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
|
||||
/**
|
||||
* Show/hide mnemonics.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
class MnemonicHandler
|
||||
implements KeyEventPostProcessor, ChangeListener
|
||||
{
|
||||
private static boolean showMnemonics;
|
||||
private static WeakReference<Window> lastShowMnemonicWindow;
|
||||
private static WindowListener windowListener;
|
||||
|
||||
static boolean isShowMnemonics() {
|
||||
return showMnemonics || !UIManager.getBoolean( "Component.hideMnemonics" );
|
||||
}
|
||||
|
||||
void install() {
|
||||
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventPostProcessor( this );
|
||||
MenuSelectionManager.defaultManager().addChangeListener( this );
|
||||
}
|
||||
|
||||
void uninstall() {
|
||||
KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventPostProcessor( this );
|
||||
MenuSelectionManager.defaultManager().removeChangeListener( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean postProcessKeyEvent( KeyEvent e ) {
|
||||
int keyCode = e.getKeyCode();
|
||||
if( SystemInfo.IS_MAC ) {
|
||||
// Ctrl+Alt keys must be pressed on Mac
|
||||
if( keyCode == KeyEvent.VK_CONTROL || keyCode == KeyEvent.VK_ALT )
|
||||
showMnemonics( shouldShowMnemonics( e ) && e.isControlDown() && e.isAltDown(), e.getComponent() );
|
||||
} else {
|
||||
// Alt key must be pressed on Windows and Linux
|
||||
if( SystemInfo.IS_WINDOWS )
|
||||
return processKeyEventOnWindows( e );
|
||||
|
||||
if( keyCode == KeyEvent.VK_ALT )
|
||||
showMnemonics( shouldShowMnemonics( e ), e.getComponent() );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean shouldShowMnemonics( KeyEvent e ) {
|
||||
return e.getID() == KeyEvent.KEY_PRESSED ||
|
||||
MenuSelectionManager.defaultManager().getSelectedPath().length > 0;
|
||||
}
|
||||
|
||||
private static int altPressedEventCount;
|
||||
private static boolean selectMenuOnAltReleased;
|
||||
|
||||
/**
|
||||
* Special Alt key behavior on Windows.
|
||||
*
|
||||
* Press-and-release Alt key selects first menu (if available) and moves focus
|
||||
* temporary to menu bar. If menu bar has focus (some menu is selected),
|
||||
* pressing Alt key unselects menu and moves focus back to permanent focus owner.
|
||||
*/
|
||||
private boolean processKeyEventOnWindows( KeyEvent e ) {
|
||||
if( e.getKeyCode() != KeyEvent.VK_ALT ) {
|
||||
selectMenuOnAltReleased = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
if( e.getID() == KeyEvent.KEY_PRESSED ) {
|
||||
altPressedEventCount++;
|
||||
|
||||
if( altPressedEventCount == 1 && !e.isConsumed() ) {
|
||||
MenuSelectionManager menuSelectionManager = MenuSelectionManager.defaultManager();
|
||||
selectMenuOnAltReleased = (menuSelectionManager.getSelectedPath().length == 0);
|
||||
|
||||
// if menu is selected when Alt key is pressed then clear menu selection
|
||||
if( !selectMenuOnAltReleased )
|
||||
menuSelectionManager.clearSelectedPath();
|
||||
}
|
||||
|
||||
// show mnemonics
|
||||
showMnemonics( shouldShowMnemonics( e ), e.getComponent() );
|
||||
|
||||
// avoid that the system menu of the window gets focus
|
||||
e.consume();
|
||||
return true;
|
||||
|
||||
} else if( e.getID() == KeyEvent.KEY_RELEASED ) {
|
||||
altPressedEventCount = 0;
|
||||
|
||||
boolean mnemonicsShown = false;
|
||||
if( selectMenuOnAltReleased && !e.isConsumed() ) {
|
||||
MenuSelectionManager menuSelectionManager = MenuSelectionManager.defaultManager();
|
||||
if( menuSelectionManager.getSelectedPath().length == 0 ) {
|
||||
// get menu bar and first menu
|
||||
Component c = e.getComponent();
|
||||
JRootPane rootPane = SwingUtilities.getRootPane( c );
|
||||
Window window = (rootPane != null) ? SwingUtilities.getWindowAncestor( rootPane ) : null;
|
||||
JMenuBar menuBar = (rootPane != null) ? rootPane.getJMenuBar() : null;
|
||||
if( menuBar == null && window instanceof JFrame )
|
||||
menuBar = ((JFrame)window).getJMenuBar();
|
||||
JMenu firstMenu = (menuBar != null) ? menuBar.getMenu( 0 ) : null;
|
||||
|
||||
// select first menu and show mnemonics
|
||||
if( firstMenu != null ) {
|
||||
menuSelectionManager.setSelectedPath( new MenuElement[] { menuBar, firstMenu } );
|
||||
showMnemonics( true, c );
|
||||
mnemonicsShown = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
selectMenuOnAltReleased = false;
|
||||
|
||||
// hide mnemonics
|
||||
if( !mnemonicsShown )
|
||||
showMnemonics( shouldShowMnemonics( e ), e.getComponent() );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stateChanged( ChangeEvent e ) {
|
||||
MenuElement[] selectedPath = MenuSelectionManager.defaultManager().getSelectedPath();
|
||||
if( selectedPath.length == 0 && altPressedEventCount == 0 ) {
|
||||
// hide mnemonics when menu selection was canceled
|
||||
showMnemonics( false, null );
|
||||
}
|
||||
}
|
||||
|
||||
static void showMnemonics( boolean show, Component c ) {
|
||||
if( show == showMnemonics )
|
||||
return;
|
||||
|
||||
showMnemonics = show;
|
||||
|
||||
// check whether it is necessary to repaint
|
||||
if( !UIManager.getBoolean( "Component.hideMnemonics" ) )
|
||||
return;
|
||||
|
||||
if( show ) {
|
||||
// get root pane
|
||||
JRootPane rootPane = SwingUtilities.getRootPane( c );
|
||||
if( rootPane == null )
|
||||
return;
|
||||
|
||||
// get window
|
||||
Window window = SwingUtilities.getWindowAncestor( rootPane );
|
||||
if( window == null )
|
||||
return;
|
||||
|
||||
// repaint components with mnemonics in focused window
|
||||
repaintMnemonics( window );
|
||||
|
||||
// hide mnemonics if window is deactivated (e.g. Alt+Tab to another window)
|
||||
windowListener = new WindowAdapter() {
|
||||
@Override
|
||||
public void windowDeactivated( WindowEvent e ) {
|
||||
altPressedEventCount = 0;
|
||||
selectMenuOnAltReleased = false;
|
||||
|
||||
// use invokeLater() to avoid that the listener is removed
|
||||
// while the listener queue is iterated to fire this event
|
||||
EventQueue.invokeLater( () -> {
|
||||
showMnemonics( false, null );
|
||||
} );
|
||||
}
|
||||
};
|
||||
window.addWindowListener( windowListener );
|
||||
|
||||
lastShowMnemonicWindow = new WeakReference<>( window );
|
||||
} else if( lastShowMnemonicWindow != null ) {
|
||||
Window window = lastShowMnemonicWindow.get();
|
||||
if( window != null ) {
|
||||
repaintMnemonics( window );
|
||||
|
||||
if( windowListener != null ) {
|
||||
window.removeWindowListener( windowListener );
|
||||
windowListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
lastShowMnemonicWindow = null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void repaintMnemonics( Container container ) {
|
||||
for( Component c : container.getComponents() ) {
|
||||
if( !c.isVisible() )
|
||||
continue;
|
||||
|
||||
if( hasMnemonic( c ) )
|
||||
c.repaint();
|
||||
|
||||
if( c instanceof Container )
|
||||
repaintMnemonics( (Container) c );
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean hasMnemonic( Component c ) {
|
||||
if( c instanceof JLabel && ((JLabel)c).getDisplayedMnemonicIndex() >= 0 )
|
||||
return true;
|
||||
|
||||
if( c instanceof AbstractButton && ((AbstractButton)c).getDisplayedMnemonicIndex() >= 0 )
|
||||
return true;
|
||||
|
||||
if( c instanceof JTabbedPane ) {
|
||||
JTabbedPane tabPane = (JTabbedPane) c;
|
||||
int tabCount = tabPane.getTabCount();
|
||||
for( int i = 0; i < tabCount; i++ ) {
|
||||
if( tabPane.getDisplayedMnemonicIndexAt( i ) >= 0 )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,9 @@ import javax.swing.plaf.InsetsUIResource;
|
||||
import com.formdev.flatlaf.ui.FlatEmptyBorder;
|
||||
import com.formdev.flatlaf.ui.FlatLineBorder;
|
||||
import com.formdev.flatlaf.util.ColorFunctions;
|
||||
import com.formdev.flatlaf.util.ColorFunctions.ColorFunction;
|
||||
import com.formdev.flatlaf.util.DerivedColor;
|
||||
import com.formdev.flatlaf.util.GrayFilter;
|
||||
import com.formdev.flatlaf.util.HSLColor;
|
||||
import com.formdev.flatlaf.util.StringUtils;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
@@ -62,14 +64,12 @@ class UIDefaultsLoader
|
||||
private static final String TYPE_PREFIX = "{";
|
||||
private static final String TYPE_PREFIX_END = "}";
|
||||
private static final String VARIABLE_PREFIX = "@";
|
||||
@Deprecated
|
||||
private static final String REF_PREFIX = VARIABLE_PREFIX + "@";
|
||||
private static final String PROPERTY_PREFIX = "$";
|
||||
private static final String OPTIONAL_PREFIX = "?";
|
||||
private static final String GLOBAL_PREFIX = "*.";
|
||||
|
||||
static void loadDefaultsFromProperties( Class<?> lookAndFeelClass, List<FlatDefaultsAddon> addons,
|
||||
Properties additionalDefaults, UIDefaults defaults )
|
||||
Properties additionalDefaults, boolean dark, UIDefaults defaults )
|
||||
{
|
||||
// determine classes in class hierarchy in reverse order
|
||||
ArrayList<Class<?>> lafClasses = new ArrayList<>();
|
||||
@@ -80,11 +80,11 @@ class UIDefaultsLoader
|
||||
lafClasses.add( 0, lafClass );
|
||||
}
|
||||
|
||||
loadDefaultsFromProperties( lafClasses, addons, additionalDefaults, defaults );
|
||||
loadDefaultsFromProperties( lafClasses, addons, additionalDefaults, dark, defaults );
|
||||
}
|
||||
|
||||
static void loadDefaultsFromProperties( List<Class<?>> lafClasses, List<FlatDefaultsAddon> addons,
|
||||
Properties additionalDefaults, UIDefaults defaults )
|
||||
Properties additionalDefaults, boolean dark, UIDefaults defaults )
|
||||
{
|
||||
try {
|
||||
// load core properties files
|
||||
@@ -121,14 +121,28 @@ class UIDefaultsLoader
|
||||
|
||||
// collect all platform specific keys (but do not modify properties)
|
||||
ArrayList<String> platformSpecificKeys = new ArrayList<>();
|
||||
for( Object key : properties.keySet() ) {
|
||||
if( ((String)key).startsWith( "[" ) )
|
||||
platformSpecificKeys.add( (String) key );
|
||||
for( Object okey : properties.keySet() ) {
|
||||
String key = (String) okey;
|
||||
if( key.startsWith( "[" ) &&
|
||||
(key.startsWith( "[win]" ) ||
|
||||
key.startsWith( "[mac]" ) ||
|
||||
key.startsWith( "[linux]" ) ||
|
||||
key.startsWith( "[light]" ) ||
|
||||
key.startsWith( "[dark]" )) )
|
||||
platformSpecificKeys.add( key );
|
||||
}
|
||||
|
||||
// remove platform specific properties and re-add only properties
|
||||
// for current platform, but with platform prefix removed
|
||||
if( !platformSpecificKeys.isEmpty() ) {
|
||||
// handle light/dark specific properties
|
||||
String lightOrDarkPrefix = dark ? "[dark]" : "[light]";
|
||||
for( String key : platformSpecificKeys ) {
|
||||
if( key.startsWith( lightOrDarkPrefix ) )
|
||||
properties.put( key.substring( lightOrDarkPrefix.length() ), properties.remove( key ) );
|
||||
}
|
||||
|
||||
// handle platform specific properties
|
||||
String platformPrefix =
|
||||
SystemInfo.IS_WINDOWS ? "[win]" :
|
||||
SystemInfo.IS_MAC ? "[mac]" :
|
||||
@@ -198,12 +212,6 @@ class UIDefaultsLoader
|
||||
else if( !value.startsWith( VARIABLE_PREFIX ) )
|
||||
return value;
|
||||
|
||||
// for compatibility
|
||||
if( value.startsWith( REF_PREFIX ) ) {
|
||||
FlatLaf.LOG.log( Level.WARNING, "FlatLaf: Usage of '@@' in .properties files is deprecated. Use '$' instead." );
|
||||
value = value.substring( REF_PREFIX.length() );
|
||||
}
|
||||
|
||||
boolean optional = false;
|
||||
if( value.startsWith( OPTIONAL_PREFIX ) ) {
|
||||
value = value.substring( OPTIONAL_PREFIX.length() );
|
||||
@@ -222,7 +230,7 @@ class UIDefaultsLoader
|
||||
}
|
||||
|
||||
private enum ValueType { UNKNOWN, STRING, CHARACTER, INTEGER, FLOAT, BORDER, ICON, INSETS, DIMENSION, COLOR,
|
||||
SCALEDINTEGER, SCALEDFLOAT, SCALEDINSETS, SCALEDDIMENSION, INSTANCE, CLASS }
|
||||
SCALEDINTEGER, SCALEDFLOAT, SCALEDINSETS, SCALEDDIMENSION, INSTANCE, CLASS, GRAYFILTER }
|
||||
|
||||
static Object parseValue( String key, String value ) {
|
||||
return parseValue( key, value, v -> v, Collections.emptyList() );
|
||||
@@ -289,6 +297,8 @@ class UIDefaultsLoader
|
||||
valueType = ValueType.CHARACTER;
|
||||
else if( key.endsWith( "UI" ) )
|
||||
valueType = ValueType.STRING;
|
||||
else if( key.endsWith( "grayFilter" ) )
|
||||
valueType = ValueType.GRAYFILTER;
|
||||
}
|
||||
|
||||
// parse value
|
||||
@@ -308,6 +318,7 @@ class UIDefaultsLoader
|
||||
case SCALEDDIMENSION:return parseScaledDimension( value );
|
||||
case INSTANCE: return parseInstance( value, addonClassLoaders );
|
||||
case CLASS: return parseClass( value, addonClassLoaders );
|
||||
case GRAYFILTER: return parseGrayFilter( value );
|
||||
case UNKNOWN:
|
||||
default:
|
||||
// colors
|
||||
@@ -497,29 +508,42 @@ class UIDefaultsLoader
|
||||
throw new IllegalArgumentException( "missing parameters in function '" + value + "'" );
|
||||
|
||||
switch( function ) {
|
||||
case "rgb": return parseColorRgbOrRgba( false, params );
|
||||
case "rgba": return parseColorRgbOrRgba( true, params );
|
||||
case "rgb": return parseColorRgbOrRgba( false, params, resolver, reportError );
|
||||
case "rgba": return parseColorRgbOrRgba( true, params, resolver, reportError );
|
||||
case "hsl": return parseColorHslOrHsla( false, params );
|
||||
case "hsla": return parseColorHslOrHsla( true, params );
|
||||
case "lighten": return parseColorLightenOrDarken( true, params, resolver, reportError );
|
||||
case "darken": return parseColorLightenOrDarken( false, params, resolver, reportError );
|
||||
case "lighten": return parseColorHSLIncreaseDecrease( 2, true, params, resolver, reportError );
|
||||
case "darken": return parseColorHSLIncreaseDecrease( 2, false, params, resolver, reportError );
|
||||
case "saturate": return parseColorHSLIncreaseDecrease( 1, true, params, resolver, reportError );
|
||||
case "desaturate": return parseColorHSLIncreaseDecrease( 1, false, params, resolver, reportError );
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException( "unknown color function '" + value + "'" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Syntax: rgb(red,green,blue) or rgba(red,green,blue,alpha)
|
||||
* - red: an integer 0-255
|
||||
* - green: an integer 0-255
|
||||
* - blue: an integer 0-255
|
||||
* - alpha: an integer 0-255
|
||||
* Syntax: rgb(red,green,blue) or rgba(red,green,blue,alpha) or rgba(color,alpha)
|
||||
* - red: an integer 0-255 or a percentage 0-100%
|
||||
* - green: an integer 0-255 or a percentage 0-100%
|
||||
* - blue: an integer 0-255 or a percentage 0-100%
|
||||
* - alpha: an integer 0-255 or a percentage 0-100%
|
||||
*/
|
||||
private static ColorUIResource parseColorRgbOrRgba( boolean hasAlpha, List<String> params ) {
|
||||
int red = parseInteger( params.get( 0 ), 0, 255 );
|
||||
int green = parseInteger( params.get( 1 ), 0, 255 );
|
||||
int blue = parseInteger( params.get( 2 ), 0, 255 );
|
||||
int alpha = hasAlpha ? parseInteger( params.get( 3 ), 0, 255 ) : 255;
|
||||
private static ColorUIResource parseColorRgbOrRgba( boolean hasAlpha, List<String> params,
|
||||
Function<String, String> resolver, boolean reportError )
|
||||
{
|
||||
if( hasAlpha && params.size() == 2 ) {
|
||||
// syntax rgba(color,alpha), which allows adding alpha to any color
|
||||
String colorStr = params.get( 0 );
|
||||
int alpha = parseInteger( params.get( 1 ), 0, 255, true );
|
||||
|
||||
ColorUIResource color = (ColorUIResource) parseColorOrFunction( resolver.apply( colorStr ), resolver, reportError );
|
||||
return new ColorUIResource( new Color( ((alpha & 0xff) << 24) | (color.getRGB() & 0xffffff), true ) );
|
||||
}
|
||||
|
||||
int red = parseInteger( params.get( 0 ), 0, 255, true );
|
||||
int green = parseInteger( params.get( 1 ), 0, 255, true );
|
||||
int blue = parseInteger( params.get( 2 ), 0, 255, true );
|
||||
int alpha = hasAlpha ? parseInteger( params.get( 3 ), 0, 255, true ) : 255;
|
||||
|
||||
return hasAlpha
|
||||
? new ColorUIResource( new Color( red, green, blue, alpha ) )
|
||||
@@ -534,7 +558,7 @@ class UIDefaultsLoader
|
||||
* - alpha: a percentage 0-100%
|
||||
*/
|
||||
private static ColorUIResource parseColorHslOrHsla( boolean hasAlpha, List<String> params ) {
|
||||
int hue = parseInteger( params.get( 0 ), 0, 360 );
|
||||
int hue = parseInteger( params.get( 0 ), 0, 360, false );
|
||||
int saturation = parsePercentage( params.get( 1 ) );
|
||||
int lightness = parsePercentage( params.get( 2 ) );
|
||||
int alpha = hasAlpha ? parsePercentage( params.get( 3 ) ) : 100;
|
||||
@@ -544,35 +568,37 @@ class UIDefaultsLoader
|
||||
}
|
||||
|
||||
/**
|
||||
* Syntax: lighten([color,]amount[,options]) or darken([color,]amount[,options])
|
||||
* Syntax: lighten(color,amount[,options]) or darken(color,amount[,options]) or
|
||||
* saturate(color,amount[,options]) or desaturate(color,amount[,options])
|
||||
* - color: a color (e.g. #f00) or a color function
|
||||
* - amount: percentage 0-100%
|
||||
* - options: [relative] [autoInverse] [lazy]
|
||||
* - options: [relative] [autoInverse] [noAutoInverse] [lazy] [derived]
|
||||
*/
|
||||
private static Object parseColorLightenOrDarken( boolean lighten, List<String> params,
|
||||
Function<String, String> resolver, boolean reportError )
|
||||
private static Object parseColorHSLIncreaseDecrease( int hslIndex, boolean increase,
|
||||
List<String> params, Function<String, String> resolver, boolean reportError )
|
||||
{
|
||||
boolean isDerived = params.get( 0 ).endsWith( "%" );
|
||||
String colorStr = isDerived ? null : params.get( 0 );
|
||||
int nextParam = isDerived ? 0 : 1;
|
||||
int amount = parsePercentage( params.get( nextParam++ ) );
|
||||
String colorStr = params.get( 0 );
|
||||
int amount = parsePercentage( params.get( 1 ) );
|
||||
boolean relative = false;
|
||||
boolean autoInverse = false;
|
||||
boolean lazy = false;
|
||||
boolean derived = false;
|
||||
|
||||
if( params.size() > nextParam ) {
|
||||
String options = params.get( nextParam++ );
|
||||
if( params.size() > 2 ) {
|
||||
String options = params.get( 2 );
|
||||
relative = options.contains( "relative" );
|
||||
autoInverse = options.contains( "autoInverse" );
|
||||
lazy = options.contains( "lazy" );
|
||||
derived = options.contains( "derived" );
|
||||
|
||||
// use autoInverse by default for derived colors, except if noAutoInverse is set
|
||||
if( derived && !options.contains( "noAutoInverse" ) )
|
||||
autoInverse = true;
|
||||
}
|
||||
|
||||
ColorFunctions.ColorFunction function = lighten
|
||||
? new ColorFunctions.Lighten( amount, relative, autoInverse )
|
||||
: new ColorFunctions.Darken( amount, relative, autoInverse );
|
||||
|
||||
if( isDerived )
|
||||
return new DerivedColor( function );
|
||||
// create function
|
||||
ColorFunction function = new ColorFunctions.HSLIncreaseDecrease(
|
||||
hslIndex, increase, amount, relative, autoInverse );
|
||||
|
||||
if( lazy ) {
|
||||
return (LazyValue) t -> {
|
||||
@@ -583,8 +609,29 @@ class UIDefaultsLoader
|
||||
};
|
||||
}
|
||||
|
||||
ColorUIResource color = (ColorUIResource) parseColorOrFunction( resolver.apply( colorStr ), resolver, reportError );
|
||||
return new ColorUIResource( ColorFunctions.applyFunctions( color, function ) );
|
||||
// parse base color
|
||||
String resolvedColorStr = resolver.apply( colorStr );
|
||||
ColorUIResource baseColor = (ColorUIResource) parseColorOrFunction( resolvedColorStr, resolver, reportError );
|
||||
|
||||
// apply this function to base color
|
||||
Color newColor = ColorFunctions.applyFunctions( baseColor, function );
|
||||
|
||||
if( derived ) {
|
||||
ColorFunction[] functions;
|
||||
if( baseColor instanceof DerivedColor && resolvedColorStr == colorStr ) {
|
||||
// if the base color is also derived, join the color functions
|
||||
// but only if base color function is specified directly in this function
|
||||
ColorFunction[] baseFunctions = ((DerivedColor)baseColor).getFunctions();
|
||||
functions = new ColorFunction[baseFunctions.length + 1];
|
||||
System.arraycopy( baseFunctions, 0, functions, 0, baseFunctions.length );
|
||||
functions[baseFunctions.length] = function;
|
||||
} else
|
||||
functions = new ColorFunction[] { function };
|
||||
|
||||
return new DerivedColor( newColor, functions );
|
||||
}
|
||||
|
||||
return new ColorUIResource( newColor );
|
||||
}
|
||||
|
||||
private static int parsePercentage( String value ) {
|
||||
@@ -609,7 +656,12 @@ class UIDefaultsLoader
|
||||
return value.charAt( 0 );
|
||||
}
|
||||
|
||||
private static Integer parseInteger( String value, int min, int max ) {
|
||||
private static Integer parseInteger( String value, int min, int max, boolean allowPercentage ) {
|
||||
if( allowPercentage && value.endsWith( "%" ) ) {
|
||||
int percent = parsePercentage( value );
|
||||
return (max * percent) / 100;
|
||||
}
|
||||
|
||||
Integer integer = parseInteger( value, true );
|
||||
if( integer.intValue() < min || integer.intValue() > max )
|
||||
throw new NumberFormatException( "integer '" + value + "' out of range (" + min + '-' + max + ')' );
|
||||
@@ -664,6 +716,21 @@ class UIDefaultsLoader
|
||||
};
|
||||
}
|
||||
|
||||
private static Object parseGrayFilter( String value ) {
|
||||
List<String> numbers = split( value, ',' );
|
||||
try {
|
||||
int brightness = Integer.parseInt( numbers.get( 0 ) );
|
||||
int contrast = Integer.parseInt( numbers.get( 1 ) );
|
||||
int alpha = Integer.parseInt( numbers.get( 2 ) );
|
||||
|
||||
return (LazyValue) t -> {
|
||||
return new GrayFilter( brightness, contrast, alpha );
|
||||
};
|
||||
} catch( NumberFormatException ex ) {
|
||||
throw new IllegalArgumentException( "invalid gray filter '" + value + "'" );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Split string and trim parts.
|
||||
*/
|
||||
|
||||
@@ -36,25 +36,28 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
* is painted outside of the icon bounds. Make sure that the checkbox
|
||||
* has margins, which are equal or greater than focusWidth.
|
||||
*
|
||||
* @uiDefault CheckBox.icon.style String optional; "outline"/null (default) or "filled"
|
||||
* @uiDefault Component.focusWidth int
|
||||
* @uiDefault Component.focusColor Color
|
||||
* @uiDefault CheckBox.icon.focusedColor Color optional; defaults to Component.focusColor
|
||||
* @uiDefault CheckBox.icon.focusWidth int optional; defaults to Component.focusWidth
|
||||
* @uiDefault CheckBox.icon.focusColor Color optional; defaults to Component.focusColor
|
||||
* @uiDefault CheckBox.icon.borderColor Color
|
||||
* @uiDefault CheckBox.icon.disabledBorderColor Color
|
||||
* @uiDefault CheckBox.icon.selectedBorderColor Color
|
||||
* @uiDefault CheckBox.icon.focusedBorderColor Color
|
||||
* @uiDefault CheckBox.icon.hoverBorderColor Color optional
|
||||
* @uiDefault CheckBox.icon.selectedFocusedBorderColor Color optional
|
||||
* @uiDefault CheckBox.icon.background Color
|
||||
* @uiDefault CheckBox.icon.disabledBackground Color
|
||||
* @uiDefault CheckBox.icon.focusedBackground Color optional
|
||||
* @uiDefault CheckBox.icon.hoverBackground Color optional
|
||||
* @uiDefault CheckBox.icon.pressedBackground Color optional
|
||||
* @uiDefault CheckBox.icon.selectedBorderColor Color
|
||||
* @uiDefault CheckBox.icon.selectedBackground Color
|
||||
* @uiDefault CheckBox.icon.selectedHoverBackground Color optional
|
||||
* @uiDefault CheckBox.icon.selectedPressedBackground Color optional
|
||||
* @uiDefault CheckBox.icon.checkmarkColor Color
|
||||
* @uiDefault CheckBox.icon.disabledBorderColor Color
|
||||
* @uiDefault CheckBox.icon.disabledBackground Color
|
||||
* @uiDefault CheckBox.icon.disabledCheckmarkColor Color
|
||||
* @uiDefault CheckBox.icon.focusedBorderColor Color
|
||||
* @uiDefault CheckBox.icon.focusedBackground Color optional
|
||||
* @uiDefault CheckBox.icon.selectedFocusedBorderColor Color optional
|
||||
* @uiDefault CheckBox.icon.selectedFocusedBackground Color optional
|
||||
* @uiDefault CheckBox.icon.hoverBorderColor Color optional
|
||||
* @uiDefault CheckBox.icon.hoverBackground Color optional
|
||||
* @uiDefault CheckBox.icon.selectedHoverBackground Color optional
|
||||
* @uiDefault CheckBox.icon.pressedBackground Color optional
|
||||
* @uiDefault CheckBox.icon.selectedPressedBackground Color optional
|
||||
* @uiDefault CheckBox.arc int
|
||||
*
|
||||
* @author Karl Tauber
|
||||
@@ -62,27 +65,62 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
public class FlatCheckBoxIcon
|
||||
extends FlatAbstractIcon
|
||||
{
|
||||
public final int focusWidth = UIManager.getInt( "Component.focusWidth" );
|
||||
protected final Color focusColor = FlatUIUtils.getUIColor( "CheckBox.icon.focusedColor",
|
||||
protected final String style = UIManager.getString( "CheckBox.icon.style" );
|
||||
public final int focusWidth = getUIInt( "CheckBox.icon.focusWidth",
|
||||
UIManager.getInt( "Component.focusWidth" ), style );
|
||||
protected final Color focusColor = FlatUIUtils.getUIColor( "CheckBox.icon.focusColor",
|
||||
UIManager.getColor( "Component.focusColor" ) );
|
||||
protected final int arc = FlatUIUtils.getUIInt( "CheckBox.arc", 2 );
|
||||
|
||||
protected final Color borderColor = UIManager.getColor( "CheckBox.icon.borderColor" );
|
||||
protected final Color disabledBorderColor = UIManager.getColor( "CheckBox.icon.disabledBorderColor" );
|
||||
protected final Color selectedBorderColor = UIManager.getColor( "CheckBox.icon.selectedBorderColor" );
|
||||
protected final Color focusedBorderColor = UIManager.getColor( "CheckBox.icon.focusedBorderColor" );
|
||||
protected final Color hoverBorderColor = UIManager.getColor( "CheckBox.icon.hoverBorderColor" );
|
||||
protected final Color selectedFocusedBorderColor = UIManager.getColor( "CheckBox.icon.selectedFocusedBorderColor" );
|
||||
protected final Color background = UIManager.getColor( "CheckBox.icon.background" );
|
||||
protected final Color disabledBackground = UIManager.getColor( "CheckBox.icon.disabledBackground" );
|
||||
protected final Color focusedBackground = UIManager.getColor( "CheckBox.icon.focusedBackground" );
|
||||
protected final Color hoverBackground = UIManager.getColor( "CheckBox.icon.hoverBackground" );
|
||||
protected final Color pressedBackground = UIManager.getColor( "CheckBox.icon.pressedBackground" );
|
||||
protected final Color selectedBackground = UIManager.getColor( "CheckBox.icon.selectedBackground" );
|
||||
protected final Color selectedHoverBackground = UIManager.getColor( "CheckBox.icon.selectedHoverBackground" );
|
||||
protected final Color selectedPressedBackground = UIManager.getColor( "CheckBox.icon.selectedPressedBackground" );
|
||||
protected final Color checkmarkColor = UIManager.getColor( "CheckBox.icon.checkmarkColor" );
|
||||
protected final Color disabledCheckmarkColor = UIManager.getColor( "CheckBox.icon.disabledCheckmarkColor" );
|
||||
// enabled
|
||||
protected final Color borderColor = getUIColor( "CheckBox.icon.borderColor", style );
|
||||
protected final Color background = getUIColor( "CheckBox.icon.background", style );
|
||||
protected final Color selectedBorderColor = getUIColor( "CheckBox.icon.selectedBorderColor", style );
|
||||
protected final Color selectedBackground = getUIColor( "CheckBox.icon.selectedBackground", style );
|
||||
protected final Color checkmarkColor = getUIColor( "CheckBox.icon.checkmarkColor", style );
|
||||
|
||||
// disabled
|
||||
protected final Color disabledBorderColor = getUIColor( "CheckBox.icon.disabledBorderColor", style );
|
||||
protected final Color disabledBackground = getUIColor( "CheckBox.icon.disabledBackground", style );
|
||||
protected final Color disabledCheckmarkColor = getUIColor( "CheckBox.icon.disabledCheckmarkColor", style );
|
||||
|
||||
// focused
|
||||
protected final Color focusedBorderColor = getUIColor( "CheckBox.icon.focusedBorderColor", style );
|
||||
protected final Color focusedBackground = getUIColor( "CheckBox.icon.focusedBackground", style );
|
||||
protected final Color selectedFocusedBorderColor = getUIColor( "CheckBox.icon.selectedFocusedBorderColor", style );
|
||||
protected final Color selectedFocusedBackground = getUIColor( "CheckBox.icon.selectedFocusedBackground", style );
|
||||
protected final Color selectedFocusedCheckmarkColor = getUIColor( "CheckBox.icon.selectedFocusedCheckmarkColor", style );
|
||||
|
||||
// hover
|
||||
protected final Color hoverBorderColor = getUIColor( "CheckBox.icon.hoverBorderColor", style );
|
||||
protected final Color hoverBackground = getUIColor( "CheckBox.icon.hoverBackground", style );
|
||||
protected final Color selectedHoverBackground = getUIColor( "CheckBox.icon.selectedHoverBackground", style );
|
||||
|
||||
// pressed
|
||||
protected final Color pressedBackground = getUIColor( "CheckBox.icon.pressedBackground", style );
|
||||
protected final Color selectedPressedBackground = getUIColor( "CheckBox.icon.selectedPressedBackground", style );
|
||||
|
||||
protected static Color getUIColor( String key, String style ) {
|
||||
if( style != null ) {
|
||||
Color color = UIManager.getColor( styleKey( key, style ) );
|
||||
if( color != null )
|
||||
return color;
|
||||
}
|
||||
return UIManager.getColor( key );
|
||||
}
|
||||
|
||||
protected static int getUIInt( String key, int defaultValue, String style ) {
|
||||
if( style != null ) {
|
||||
Object value = UIManager.get( styleKey( key, style ) );
|
||||
if( value instanceof Integer )
|
||||
return (Integer) value;
|
||||
}
|
||||
return FlatUIUtils.getUIInt( key, defaultValue );
|
||||
}
|
||||
|
||||
private static String styleKey( String key, String style ) {
|
||||
return key.replace( ".icon.", ".icon[" + style + "]." );
|
||||
}
|
||||
|
||||
static final int ICON_SIZE = 15;
|
||||
|
||||
@@ -94,9 +132,10 @@ public class FlatCheckBoxIcon
|
||||
protected void paintIcon( Component c, Graphics2D g2 ) {
|
||||
boolean indeterminate = c instanceof JComponent && clientPropertyEquals( (JComponent) c, SELECTED_STATE, SELECTED_STATE_INDETERMINATE );
|
||||
boolean selected = indeterminate || (c instanceof AbstractButton && ((AbstractButton)c).isSelected());
|
||||
boolean isFocused = FlatUIUtils.isPermanentFocusOwner( c );
|
||||
|
||||
// paint focused border
|
||||
if( FlatUIUtils.isPermanentFocusOwner( c ) && focusWidth > 0 ) {
|
||||
if( isFocused && focusWidth > 0 && FlatButtonUI.isFocusPainted( c ) ) {
|
||||
g2.setColor( focusColor );
|
||||
paintFocusBorder( g2 );
|
||||
}
|
||||
@@ -111,18 +150,22 @@ public class FlatCheckBoxIcon
|
||||
paintBorder( g2 );
|
||||
|
||||
// paint background
|
||||
FlatUIUtils.setColor( g2, FlatButtonUI.buttonStateColor( c,
|
||||
g2.setColor( FlatUIUtils.deriveColor( FlatButtonUI.buttonStateColor( c,
|
||||
selected ? selectedBackground : background,
|
||||
disabledBackground,
|
||||
focusedBackground,
|
||||
selected && selectedHoverBackground != null ? selectedHoverBackground : hoverBackground,
|
||||
selected && selectedPressedBackground != null ? selectedPressedBackground : pressedBackground ),
|
||||
background );
|
||||
(selected && selectedFocusedBackground != null) ? selectedFocusedBackground : focusedBackground,
|
||||
(selected && selectedHoverBackground != null) ? selectedHoverBackground : hoverBackground,
|
||||
(selected && selectedPressedBackground != null) ? selectedPressedBackground : pressedBackground ),
|
||||
background ) );
|
||||
paintBackground( g2 );
|
||||
|
||||
// paint checkmark
|
||||
if( selected || indeterminate ) {
|
||||
g2.setColor( c.isEnabled() ? checkmarkColor : disabledCheckmarkColor );
|
||||
g2.setColor( c.isEnabled()
|
||||
? ((selected && isFocused && selectedFocusedCheckmarkColor != null)
|
||||
? selectedFocusedCheckmarkColor
|
||||
: checkmarkColor)
|
||||
: disabledCheckmarkColor );
|
||||
if( indeterminate )
|
||||
paintIndeterminate( g2 );
|
||||
else
|
||||
|
||||
@@ -30,7 +30,8 @@ import javax.swing.UIManager;
|
||||
*
|
||||
* @uiDefault MenuItemCheckBox.icon.checkmarkColor Color
|
||||
* @uiDefault MenuItemCheckBox.icon.disabledCheckmarkColor Color
|
||||
* @uiDefault Menu.selectionForeground Color
|
||||
* @uiDefault MenuItem.selectionForeground Color
|
||||
* @uiDefault MenuItem.selectionType String
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
@@ -39,7 +40,7 @@ public class FlatCheckBoxMenuItemIcon
|
||||
{
|
||||
protected final Color checkmarkColor = UIManager.getColor( "MenuItemCheckBox.icon.checkmarkColor" );
|
||||
protected final Color disabledCheckmarkColor = UIManager.getColor( "MenuItemCheckBox.icon.disabledCheckmarkColor" );
|
||||
protected final Color selectionForeground = UIManager.getColor( "Menu.selectionForeground" );
|
||||
protected final Color selectionForeground = UIManager.getColor( "MenuItem.selectionForeground" );
|
||||
|
||||
public FlatCheckBoxMenuItemIcon() {
|
||||
super( 15, 15, null );
|
||||
@@ -66,10 +67,15 @@ public class FlatCheckBoxMenuItemIcon
|
||||
g2.draw( path );
|
||||
}
|
||||
|
||||
private Color getCheckmarkColor( Component c ) {
|
||||
if( c instanceof JMenuItem && ((JMenuItem)c).isArmed() )
|
||||
protected Color getCheckmarkColor( Component c ) {
|
||||
if( c instanceof JMenuItem && ((JMenuItem)c).isArmed() && !isUnderlineSelection() )
|
||||
return selectionForeground;
|
||||
|
||||
return c.isEnabled() ? checkmarkColor : disabledCheckmarkColor;
|
||||
}
|
||||
|
||||
protected boolean isUnderlineSelection() {
|
||||
// not storing value of "MenuItem.selectionType" in class to allow changing at runtime
|
||||
return "underline".equals( UIManager.getString( "MenuItem.selectionType" ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ public class FlatHelpButtonIcon
|
||||
boolean focused = FlatUIUtils.isPermanentFocusOwner( c );
|
||||
|
||||
// paint focused border
|
||||
if( focused ) {
|
||||
if( focused && FlatButtonUI.isFocusPainted( c ) ) {
|
||||
g2.setColor( focusColor );
|
||||
g2.fill( new Ellipse2D.Float( 0.5f, 0.5f, iconSize - 1, iconSize - 1 ) );
|
||||
}
|
||||
@@ -100,12 +100,12 @@ public class FlatHelpButtonIcon
|
||||
g2.fill( new Ellipse2D.Float( focusWidth + 0.5f, focusWidth + 0.5f, 21, 21 ) );
|
||||
|
||||
// paint background
|
||||
FlatUIUtils.setColor( g2, FlatButtonUI.buttonStateColor( c,
|
||||
g2.setColor( FlatUIUtils.deriveColor( FlatButtonUI.buttonStateColor( c,
|
||||
background,
|
||||
disabledBackground,
|
||||
focusedBackground,
|
||||
hoverBackground,
|
||||
pressedBackground ), background );
|
||||
pressedBackground ), background ) );
|
||||
g2.fill( new Ellipse2D.Float( focusWidth + 1.5f, focusWidth + 1.5f, 19, 19 ) );
|
||||
|
||||
// paint question mark
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
/**
|
||||
* Base class for internal frame icons.
|
||||
*
|
||||
* @uiDefault InternalFrame.buttonSize Dimension
|
||||
* @uiDefault InternalFrame.buttonHoverBackground Color
|
||||
* @uiDefault InternalFrame.buttonPressedBackground Color
|
||||
*
|
||||
@@ -53,7 +54,7 @@ public abstract class FlatInternalFrameAbstractIcon
|
||||
protected void paintBackground( Component c, Graphics2D g ) {
|
||||
Color background = FlatButtonUI.buttonStateColor( c, null, null, null, hoverBackground, pressedBackground );
|
||||
if( background != null ) {
|
||||
FlatUIUtils.setColor( g, background, c.getBackground() );
|
||||
g.setColor( FlatUIUtils.deriveColor( background, c.getBackground() ) );
|
||||
g.fillRect( 0, 0, width, height );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,8 +28,11 @@ import com.formdev.flatlaf.ui.FlatButtonUI;
|
||||
/**
|
||||
* "close" icon for {@link javax.swing.JInternalFrame}.
|
||||
*
|
||||
* @uiDefault InternalFrame.buttonHoverBackground Color
|
||||
* @uiDefault InternalFrame.buttonPressedBackground Color
|
||||
* @uiDefault InternalFrame.buttonSize Dimension
|
||||
* @uiDefault InternalFrame.closeHoverBackground Color
|
||||
* @uiDefault InternalFrame.closePressedBackground Color
|
||||
* @uiDefault InternalFrame.closeHoverForeground Color
|
||||
* @uiDefault InternalFrame.closePressedForeground Color
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
|
||||
@@ -24,14 +24,14 @@ import java.awt.geom.Rectangle2D;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
|
||||
/**
|
||||
* "minimize" (actually "restore") icon for {@link javax.swing.JInternalFrame}.
|
||||
* "restore" (or "minimize") icon for {@link javax.swing.JInternalFrame}.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatInternalFrameMinimizeIcon
|
||||
public class FlatInternalFrameRestoreIcon
|
||||
extends FlatInternalFrameAbstractIcon
|
||||
{
|
||||
public FlatInternalFrameMinimizeIcon() {
|
||||
public FlatInternalFrameRestoreIcon() {
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -32,6 +32,7 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
* @uiDefault Menu.icon.arrowColor Color
|
||||
* @uiDefault Menu.icon.disabledArrowColor Color
|
||||
* @uiDefault Menu.selectionForeground Color
|
||||
* @uiDefault MenuItem.selectionType String
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
@@ -64,10 +65,15 @@ public class FlatMenuArrowIcon
|
||||
}
|
||||
}
|
||||
|
||||
private Color getArrowColor( Component c ) {
|
||||
if( c instanceof JMenu && ((JMenu)c).isSelected() )
|
||||
protected Color getArrowColor( Component c ) {
|
||||
if( c instanceof JMenu && ((JMenu)c).isSelected() && !isUnderlineSelection() )
|
||||
return selectionForeground;
|
||||
|
||||
return c.isEnabled() ? arrowColor : disabledArrowColor;
|
||||
}
|
||||
|
||||
protected boolean isUnderlineSelection() {
|
||||
// not storing value of "MenuItem.selectionType" in class to allow changing at runtime
|
||||
return "underline".equals( UIManager.getString( "MenuItem.selectionType" ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ package com.formdev.flatlaf.icons;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
|
||||
/**
|
||||
* Icon for {@link javax.swing.JRadioButton}.
|
||||
@@ -34,7 +33,7 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
public class FlatRadioButtonIcon
|
||||
extends FlatCheckBoxIcon
|
||||
{
|
||||
protected final int centerDiameter = FlatUIUtils.getUIInt( "RadioButton.icon.centerDiameter", 8 );
|
||||
protected final int centerDiameter = getUIInt( "RadioButton.icon.centerDiameter", 8, style );
|
||||
|
||||
@Override
|
||||
protected void paintFocusBorder( Graphics2D g2 ) {
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.icons;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics2D;
|
||||
import javax.swing.UIManager;
|
||||
import com.formdev.flatlaf.ui.FlatButtonUI;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
|
||||
/**
|
||||
* Base class for window icons.
|
||||
*
|
||||
* @uiDefault TitlePane.buttonSize Dimension
|
||||
* @uiDefault TitlePane.buttonHoverBackground Color
|
||||
* @uiDefault TitlePane.buttonPressedBackground Color
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public abstract class FlatWindowAbstractIcon
|
||||
extends FlatAbstractIcon
|
||||
{
|
||||
private final Color hoverBackground;
|
||||
private final Color pressedBackground;
|
||||
|
||||
public FlatWindowAbstractIcon() {
|
||||
this( UIManager.getDimension( "TitlePane.buttonSize" ),
|
||||
UIManager.getColor( "TitlePane.buttonHoverBackground" ),
|
||||
UIManager.getColor( "TitlePane.buttonPressedBackground" ) );
|
||||
}
|
||||
|
||||
public FlatWindowAbstractIcon( Dimension size, Color hoverBackground, Color pressedBackground ) {
|
||||
super( size.width, size.height, null );
|
||||
this.hoverBackground = hoverBackground;
|
||||
this.pressedBackground = pressedBackground;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintIcon( Component c, Graphics2D g ) {
|
||||
paintBackground( c, g );
|
||||
|
||||
g.setColor( getForeground( c ) );
|
||||
HiDPIUtils.paintAtScale1x( g, 0, 0, width, height, this::paintIconAt1x );
|
||||
}
|
||||
|
||||
protected abstract void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor );
|
||||
|
||||
protected void paintBackground( Component c, Graphics2D g ) {
|
||||
Color background = FlatButtonUI.buttonStateColor( c, null, null, null, hoverBackground, pressedBackground );
|
||||
if( background != null ) {
|
||||
g.setColor( FlatUIUtils.deriveColor( background, c.getBackground() ) );
|
||||
g.fillRect( 0, 0, width, height );
|
||||
}
|
||||
}
|
||||
|
||||
protected Color getForeground( Component c ) {
|
||||
return c.getForeground();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.icons;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Line2D;
|
||||
import java.awt.geom.Path2D;
|
||||
import javax.swing.UIManager;
|
||||
import com.formdev.flatlaf.ui.FlatButtonUI;
|
||||
|
||||
/**
|
||||
* "close" icon for windows (frames and dialogs).
|
||||
*
|
||||
* @uiDefault TitlePane.closeHoverBackground Color
|
||||
* @uiDefault TitlePane.closePressedBackground Color
|
||||
* @uiDefault TitlePane.closeHoverForeground Color
|
||||
* @uiDefault TitlePane.closePressedForeground Color
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatWindowCloseIcon
|
||||
extends FlatWindowAbstractIcon
|
||||
{
|
||||
private final Color hoverForeground = UIManager.getColor( "TitlePane.closeHoverForeground" );
|
||||
private final Color pressedForeground = UIManager.getColor( "TitlePane.closePressedForeground" );
|
||||
|
||||
public FlatWindowCloseIcon() {
|
||||
super( UIManager.getDimension( "TitlePane.buttonSize" ),
|
||||
UIManager.getColor( "TitlePane.closeHoverBackground" ),
|
||||
UIManager.getColor( "TitlePane.closePressedBackground" ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
|
||||
int iwh = (int) (10 * scaleFactor);
|
||||
int ix = x + ((width - iwh) / 2);
|
||||
int iy = y + ((height - iwh) / 2);
|
||||
int ix2 = ix + iwh - 1;
|
||||
int iy2 = iy + iwh - 1;
|
||||
int thickness = (int) scaleFactor;
|
||||
|
||||
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
||||
path.append( new Line2D.Float( ix, iy, ix2, iy2 ), false );
|
||||
path.append( new Line2D.Float( ix, iy2, ix2, iy ), false );
|
||||
g.setStroke( new BasicStroke( thickness ) );
|
||||
g.draw( path );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Color getForeground( Component c ) {
|
||||
return FlatButtonUI.buttonStateColor( c, c.getForeground(), null, null, hoverForeground, pressedForeground );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.icons;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
|
||||
/**
|
||||
* "iconify" icon for windows (frames and dialogs).
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatWindowIconifyIcon
|
||||
extends FlatWindowAbstractIcon
|
||||
{
|
||||
public FlatWindowIconifyIcon() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
|
||||
int iw = (int) (10 * scaleFactor);
|
||||
int ih = (int) scaleFactor;
|
||||
int ix = x + ((width - iw) / 2);
|
||||
int iy = y + ((height - ih) / 2);
|
||||
|
||||
g.fillRect( ix, iy, iw, ih );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.icons;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
|
||||
/**
|
||||
* "maximize" icon for windows (frames and dialogs).
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatWindowMaximizeIcon
|
||||
extends FlatWindowAbstractIcon
|
||||
{
|
||||
public FlatWindowMaximizeIcon() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
|
||||
int iwh = (int) (10 * scaleFactor);
|
||||
int ix = x + ((width - iwh) / 2);
|
||||
int iy = y + ((height - iwh) / 2);
|
||||
int thickness = (int) scaleFactor;
|
||||
|
||||
g.fill( FlatUIUtils.createRectangle( ix, iy, iwh, iwh, thickness ) );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.icons;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Area;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
|
||||
/**
|
||||
* "restore" icon for windows (frames and dialogs).
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatWindowRestoreIcon
|
||||
extends FlatWindowAbstractIcon
|
||||
{
|
||||
public FlatWindowRestoreIcon() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
|
||||
int iwh = (int) (10 * scaleFactor);
|
||||
int ix = x + ((width - iwh) / 2);
|
||||
int iy = y + ((height - iwh) / 2);
|
||||
int thickness = (int) scaleFactor;
|
||||
|
||||
int rwh = (int) (8 * scaleFactor);
|
||||
int ro2 = iwh - rwh;
|
||||
|
||||
Path2D r1 = FlatUIUtils.createRectangle( ix + ro2, iy, rwh, rwh, thickness );
|
||||
Path2D r2 = FlatUIUtils.createRectangle( ix, iy + ro2, rwh, rwh, thickness );
|
||||
|
||||
Area area = new Area( r1 );
|
||||
area.subtract( new Area( new Rectangle2D.Float( ix, iy + ro2, rwh, rwh ) ) );
|
||||
g.fill( area );
|
||||
|
||||
g.fill( r2 );
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ package com.formdev.flatlaf.ui;
|
||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
@@ -26,6 +27,7 @@ import java.awt.Shape;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.geom.Path2D;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicArrowButton;
|
||||
|
||||
@@ -45,15 +47,23 @@ public class FlatArrowButton
|
||||
private final Color disabledForeground;
|
||||
private final Color hoverForeground;
|
||||
private final Color hoverBackground;
|
||||
private final Color pressedBackground;
|
||||
|
||||
private int arrowWidth = DEFAULT_ARROW_WIDTH;
|
||||
private int xOffset = 0;
|
||||
private int yOffset = 0;
|
||||
|
||||
private boolean hover;
|
||||
private boolean pressed;
|
||||
|
||||
public FlatArrowButton( int direction, String type, Color foreground, Color disabledForeground,
|
||||
Color hoverForeground, Color hoverBackground )
|
||||
{
|
||||
this( direction, type, foreground, disabledForeground, hoverForeground, hoverBackground, null );
|
||||
}
|
||||
|
||||
public FlatArrowButton( int direction, String type, Color foreground, Color disabledForeground,
|
||||
Color hoverForeground, Color hoverBackground, Color pressedBackground )
|
||||
{
|
||||
super( direction, Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE );
|
||||
|
||||
@@ -62,11 +72,12 @@ public class FlatArrowButton
|
||||
this.disabledForeground = disabledForeground;
|
||||
this.hoverForeground = hoverForeground;
|
||||
this.hoverBackground = hoverBackground;
|
||||
this.pressedBackground = pressedBackground;
|
||||
|
||||
setOpaque( false );
|
||||
setBorder( null );
|
||||
|
||||
if( hoverForeground != null || hoverBackground != null ) {
|
||||
if( hoverForeground != null || hoverBackground != null || pressedBackground != null ) {
|
||||
addMouseListener( new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseEntered( MouseEvent e ) {
|
||||
@@ -79,6 +90,18 @@ public class FlatArrowButton
|
||||
hover = false;
|
||||
repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed( MouseEvent e ) {
|
||||
pressed = true;
|
||||
repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased( MouseEvent e ) {
|
||||
pressed = false;
|
||||
repaint();
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
@@ -95,6 +118,10 @@ public class FlatArrowButton
|
||||
return hover;
|
||||
}
|
||||
|
||||
protected boolean isPressed() {
|
||||
return pressed;
|
||||
}
|
||||
|
||||
public int getXOffset() {
|
||||
return xOffset;
|
||||
}
|
||||
@@ -111,6 +138,10 @@ public class FlatArrowButton
|
||||
this.yOffset = yOffset;
|
||||
}
|
||||
|
||||
protected Color deriveBackground( Color background ) {
|
||||
return background;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
return scale( super.getPreferredSize() );
|
||||
@@ -130,33 +161,54 @@ public class FlatArrowButton
|
||||
int height = getHeight();
|
||||
boolean enabled = isEnabled();
|
||||
|
||||
// paint hover background
|
||||
if( enabled && isHover() && hoverBackground != null ) {
|
||||
g.setColor( hoverBackground );
|
||||
g.fillRect( 0, 0, width, height );
|
||||
// paint hover or pressed background
|
||||
if( enabled ) {
|
||||
Color background = (pressedBackground != null && isPressed())
|
||||
? deriveBackground( pressedBackground )
|
||||
: ((hoverBackground != null && isHover())
|
||||
? deriveBackground( hoverBackground )
|
||||
: null);
|
||||
|
||||
if( background != null ) {
|
||||
g.setColor( background );
|
||||
g.fillRect( 0, 0, width, height );
|
||||
}
|
||||
}
|
||||
|
||||
int direction = getDirection();
|
||||
boolean vert = (direction == NORTH || direction == SOUTH);
|
||||
|
||||
// compute width/height
|
||||
int w = scale( arrowWidth + (chevron ? 0 : 1) );
|
||||
int h = scale( (arrowWidth / 2) + (chevron ? 0 : 1) );
|
||||
|
||||
// rotate width/height
|
||||
int rw = vert ? w : h;
|
||||
int rh = vert ? h : w;
|
||||
|
||||
// chevron lines end 1px outside of width/height
|
||||
if( chevron ) {
|
||||
// add 1px to width/height for position calculation only
|
||||
rw++;
|
||||
rh++;
|
||||
}
|
||||
|
||||
int x = Math.round( (width - rw) / 2f + scale( (float) xOffset ) );
|
||||
int y = Math.round( (height - rh) / 2f + scale( (float) yOffset ) );
|
||||
|
||||
// optimization for small chevron arrows (e.g. OneTouchButtons in SplitPane)
|
||||
if( x + rw >= width && x > 0 )
|
||||
x--;
|
||||
if( y + rh >= height && y > 0 )
|
||||
y--;
|
||||
// move arrow for round borders
|
||||
Container parent = getParent();
|
||||
if( vert && parent instanceof JComponent && FlatUIUtils.hasRoundBorder( (JComponent) parent ) )
|
||||
x -= scale( parent.getComponentOrientation().isLeftToRight() ? 1 : -1 );
|
||||
|
||||
// paint arrow
|
||||
g.setColor( enabled
|
||||
? (isHover() && hoverForeground != null ? hoverForeground : foreground)
|
||||
: disabledForeground );
|
||||
g.translate( x, y );
|
||||
/*debug
|
||||
debugPaint( g2, vert, rw, rh );
|
||||
debug*/
|
||||
Shape arrowShape = createArrowShape( direction, chevron, w, h );
|
||||
if( chevron ) {
|
||||
g2.setStroke( new BasicStroke( scale( 1f ) ) );
|
||||
@@ -177,4 +229,22 @@ public class FlatArrowButton
|
||||
default: return new Path2D.Float();
|
||||
}
|
||||
}
|
||||
|
||||
/*debug
|
||||
private void debugPaint( Graphics g, boolean vert, int w, int h ) {
|
||||
Color oldColor = g.getColor();
|
||||
g.setColor( Color.red );
|
||||
g.drawRect( 0, 0, w - 1, h - 1 );
|
||||
|
||||
int xy1 = -2;
|
||||
int xy2 = h + 1;
|
||||
for( int i = 0; i < 20; i++ ) {
|
||||
g.drawRect( vert ? 0 : xy1, vert ? xy1 : 0, 0, 0 );
|
||||
g.drawRect( vert ? 0 : xy2, vert ? xy2 : 0, 0, 0 );
|
||||
xy1 -= 2;
|
||||
xy2 += 2;
|
||||
}
|
||||
g.setColor( oldColor );
|
||||
}
|
||||
debug*/
|
||||
}
|
||||
|
||||
@@ -36,6 +36,8 @@ import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.basic.BasicBorders;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.util.DerivedColor;
|
||||
|
||||
/**
|
||||
* Border for various components (e.g. {@link javax.swing.JTextField}).
|
||||
@@ -54,6 +56,12 @@ import javax.swing.text.JTextComponent;
|
||||
* @uiDefault Component.disabledBorderColor Color
|
||||
* @uiDefault Component.focusedBorderColor Color
|
||||
*
|
||||
* @uiDefault Component.error.borderColor Color
|
||||
* @uiDefault Component.error.focusedBorderColor Color
|
||||
* @uiDefault Component.warning.borderColor Color
|
||||
* @uiDefault Component.warning.focusedBorderColor Color
|
||||
* @uiDefault Component.custom.borderColor Color
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatBorder
|
||||
@@ -61,11 +69,18 @@ public class FlatBorder
|
||||
{
|
||||
protected final int focusWidth = UIManager.getInt( "Component.focusWidth" );
|
||||
protected final float innerFocusWidth = FlatUIUtils.getUIFloat( "Component.innerFocusWidth", 0 );
|
||||
protected final float innerOutlineWidth = FlatUIUtils.getUIFloat( "Component.innerOutlineWidth", 0 );
|
||||
protected final Color focusColor = UIManager.getColor( "Component.focusColor" );
|
||||
protected final Color borderColor = UIManager.getColor( "Component.borderColor" );
|
||||
protected final Color disabledBorderColor = UIManager.getColor( "Component.disabledBorderColor" );
|
||||
protected final Color focusedBorderColor = UIManager.getColor( "Component.focusedBorderColor" );
|
||||
|
||||
protected final Color errorBorderColor = UIManager.getColor( "Component.error.borderColor" );
|
||||
protected final Color errorFocusedBorderColor = UIManager.getColor( "Component.error.focusedBorderColor" );
|
||||
protected final Color warningBorderColor = UIManager.getColor( "Component.warning.borderColor" );
|
||||
protected final Color warningFocusedBorderColor = UIManager.getColor( "Component.warning.focusedBorderColor" );
|
||||
protected final Color customBorderColor = UIManager.getColor( "Component.custom.borderColor" );
|
||||
|
||||
@Override
|
||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
@@ -73,25 +88,53 @@ public class FlatBorder
|
||||
FlatUIUtils.setRenderingHints( g2 );
|
||||
|
||||
boolean isCellEditor = isTableCellEditor( c );
|
||||
float focusWidth = isCellEditor ? 0 : getFocusWidth( c );
|
||||
float borderWidth = getBorderWidth( c );
|
||||
float arc = isCellEditor ? 0 : getArc( c );
|
||||
float focusWidth = isCellEditor ? 0 : scale( (float) getFocusWidth( c ) );
|
||||
float borderWidth = scale( (float) getBorderWidth( c ) );
|
||||
float arc = isCellEditor ? 0 : scale( (float) getArc( c ) );
|
||||
Color outlineColor = getOutlineColor( c );
|
||||
|
||||
if( isFocused( c ) ) {
|
||||
float innerFocusWidth = !(c instanceof JScrollPane) ? this.innerFocusWidth : 0;
|
||||
if( outlineColor != null || isFocused( c ) ) {
|
||||
float innerFocusWidth = !(c instanceof JScrollPane)
|
||||
? (outlineColor != null ? innerOutlineWidth : this.innerFocusWidth)
|
||||
: 0;
|
||||
|
||||
g2.setColor( getFocusColor( c ) );
|
||||
g2.setColor( (outlineColor != null) ? outlineColor : getFocusColor( c ) );
|
||||
FlatUIUtils.paintComponentOuterBorder( g2, x, y, width, height, focusWidth,
|
||||
getLineWidth( c ) + scale( innerFocusWidth ), arc );
|
||||
scale( (float) getLineWidth( c ) ) + scale( innerFocusWidth ), arc );
|
||||
}
|
||||
|
||||
g2.setPaint( getBorderColor( c ) );
|
||||
g2.setPaint( (outlineColor != null) ? outlineColor : getBorderColor( c ) );
|
||||
FlatUIUtils.paintComponentBorder( g2, x, y, width, height, focusWidth, borderWidth, arc );
|
||||
} finally {
|
||||
g2.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
protected Color getOutlineColor( Component c ) {
|
||||
if( !(c instanceof JComponent) )
|
||||
return null;
|
||||
|
||||
Object outline = ((JComponent)c).getClientProperty( FlatClientProperties.OUTLINE );
|
||||
if( outline instanceof String ) {
|
||||
switch( (String) outline ) {
|
||||
case FlatClientProperties.OUTLINE_ERROR:
|
||||
return isFocused( c ) ? errorFocusedBorderColor : errorBorderColor;
|
||||
|
||||
case FlatClientProperties.OUTLINE_WARNING:
|
||||
return isFocused( c ) ? warningFocusedBorderColor : warningBorderColor;
|
||||
}
|
||||
} else if( outline instanceof Color ) {
|
||||
Color color = (Color) outline;
|
||||
// use color functions to compute color for unfocused state
|
||||
if( !isFocused( c ) && customBorderColor instanceof DerivedColor )
|
||||
color = ((DerivedColor)customBorderColor).derive( color );
|
||||
return color;
|
||||
} else if( outline instanceof Color[] && ((Color[])outline).length >= 2 )
|
||||
return ((Color[])outline)[isFocused( c ) ? 0 : 1];
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected Color getFocusColor( Component c ) {
|
||||
return focusColor;
|
||||
}
|
||||
@@ -135,6 +178,9 @@ public class FlatBorder
|
||||
Component editorComponent = ((JComboBox<?>)c).getEditor().getEditorComponent();
|
||||
return (editorComponent != null) ? FlatUIUtils.isPermanentFocusOwner( editorComponent ) : false;
|
||||
} else if( c instanceof JSpinner ) {
|
||||
if( FlatUIUtils.isPermanentFocusOwner( c ) )
|
||||
return true;
|
||||
|
||||
JComponent editor = ((JSpinner)c).getEditor();
|
||||
if( editor instanceof JSpinner.DefaultEditor ) {
|
||||
JTextField textField = ((JSpinner.DefaultEditor)editor).getTextField();
|
||||
@@ -153,7 +199,8 @@ public class FlatBorder
|
||||
@Override
|
||||
public Insets getBorderInsets( Component c, Insets insets ) {
|
||||
boolean isCellEditor = isTableCellEditor( c );
|
||||
float ow = (isCellEditor ? 0 : getFocusWidth( c )) + getLineWidth( c );
|
||||
float focusWidth = isCellEditor ? 0 : scale( (float) getFocusWidth( c ) );
|
||||
float ow = focusWidth + scale( (float) getLineWidth( c ) );
|
||||
|
||||
insets = super.getBorderInsets( c, insets );
|
||||
insets.top = Math.round( scale( (float) insets.top ) + ow );
|
||||
@@ -163,19 +210,33 @@ public class FlatBorder
|
||||
return insets;
|
||||
}
|
||||
|
||||
protected float getFocusWidth( Component c ) {
|
||||
return scale( (float) focusWidth );
|
||||
/**
|
||||
* Returns the (unscaled) thickness of the outer focus border.
|
||||
*/
|
||||
protected int getFocusWidth( Component c ) {
|
||||
return focusWidth;
|
||||
}
|
||||
|
||||
protected float getLineWidth( Component c ) {
|
||||
return scale( 1f );
|
||||
/**
|
||||
* Returns the (unscaled) line thickness used to compute the border insets.
|
||||
* This may be different to {@link #getBorderWidth}.
|
||||
*/
|
||||
protected int getLineWidth( Component c ) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
protected float getBorderWidth( Component c ) {
|
||||
/**
|
||||
* Returns the (unscaled) line thickness used to paint the border.
|
||||
* This may be different to {@link #getLineWidth}.
|
||||
*/
|
||||
protected int getBorderWidth( Component c ) {
|
||||
return getLineWidth( c );
|
||||
}
|
||||
|
||||
protected float getArc( Component c ) {
|
||||
/**
|
||||
* Returns the (unscaled) arc diameter of the border.
|
||||
*/
|
||||
protected int getArc( Component c ) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.GradientPaint;
|
||||
@@ -82,6 +81,11 @@ public class FlatButtonBorder
|
||||
return FlatButtonUI.isDefaultButton( c ) ? defaultFocusColor : super.getFocusColor( c );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isFocused( Component c ) {
|
||||
return FlatButtonUI.isFocusPainted( c ) && super.isFocused( c );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Paint getBorderColor( Component c ) {
|
||||
boolean def = FlatButtonUI.isDefaultButton( c );
|
||||
@@ -115,8 +119,8 @@ public class FlatButtonBorder
|
||||
} else {
|
||||
insets = super.getBorderInsets( c, insets );
|
||||
|
||||
// use smaller left and right insets for icon-only buttons (so that they are square)
|
||||
if( FlatButtonUI.isIconOnlyButton( c ) && ((AbstractButton)c).getMargin() instanceof UIResource )
|
||||
// use smaller left and right insets for icon-only or single-character buttons (so that they are square)
|
||||
if( FlatButtonUI.isIconOnlyOrSingleCharacterButton( c ) && ((AbstractButton)c).getMargin() instanceof UIResource )
|
||||
insets.left = insets.right = Math.min( insets.top, insets.bottom );
|
||||
}
|
||||
|
||||
@@ -124,17 +128,21 @@ public class FlatButtonBorder
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getFocusWidth( Component c ) {
|
||||
return FlatToggleButtonUI.isTabButton( c ) ? 0 : super.getFocusWidth(c );
|
||||
protected int getFocusWidth( Component c ) {
|
||||
return FlatToggleButtonUI.isTabButton( c ) ? 0 : super.getFocusWidth( c );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getBorderWidth( Component c ) {
|
||||
return FlatButtonUI.isDefaultButton( c ) ? scale( (float) defaultBorderWidth ) : super.getBorderWidth( c );
|
||||
protected int getBorderWidth( Component c ) {
|
||||
return FlatButtonUI.isDefaultButton( c ) ? defaultBorderWidth : super.getBorderWidth( c );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getArc( Component c ) {
|
||||
return FlatButtonUI.isSquareButton( c ) ? 0 : scale( (float) arc );
|
||||
protected int getArc( Component c ) {
|
||||
switch( FlatButtonUI.getButtonType( c ) ) {
|
||||
case FlatButtonUI.TYPE_SQUARE: return 0;
|
||||
case FlatButtonUI.TYPE_ROUND_RECT: return Short.MAX_VALUE;
|
||||
default: return arc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,6 @@ import javax.swing.JToggleButton;
|
||||
import javax.swing.JToolBar;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicButtonListener;
|
||||
@@ -61,8 +60,6 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
*
|
||||
* <!-- FlatButtonUI -->
|
||||
*
|
||||
* @uiDefault Component.focusWidth int
|
||||
* @uiDefault Button.arc int
|
||||
* @uiDefault Button.minimumWidth int
|
||||
* @uiDefault Button.iconTextGap int
|
||||
* @uiDefault Button.startBackground Color optional; if set, a gradient paint is used and Button.background is ignored
|
||||
@@ -70,6 +67,7 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault Button.focusedBackground Color optional
|
||||
* @uiDefault Button.hoverBackground Color optional
|
||||
* @uiDefault Button.pressedBackground Color optional
|
||||
* @uiDefault Button.disabledBackground Color optional
|
||||
* @uiDefault Button.disabledText Color
|
||||
* @uiDefault Button.default.background Color
|
||||
* @uiDefault Button.default.startBackground Color optional; if set, a gradient paint is used and Button.default.background is ignored
|
||||
@@ -92,16 +90,18 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
public class FlatButtonUI
|
||||
extends BasicButtonUI
|
||||
{
|
||||
protected int focusWidth;
|
||||
protected int arc;
|
||||
protected int minimumWidth;
|
||||
protected int iconTextGap;
|
||||
|
||||
protected Color background;
|
||||
protected Color foreground;
|
||||
|
||||
protected Color startBackground;
|
||||
protected Color endBackground;
|
||||
protected Color focusedBackground;
|
||||
protected Color hoverBackground;
|
||||
protected Color pressedBackground;
|
||||
protected Color disabledBackground;
|
||||
protected Color disabledText;
|
||||
|
||||
protected Color defaultBackground;
|
||||
@@ -139,16 +139,18 @@ public class FlatButtonUI
|
||||
if( !defaults_initialized ) {
|
||||
String prefix = getPropertyPrefix();
|
||||
|
||||
focusWidth = UIManager.getInt( "Component.focusWidth" );
|
||||
arc = UIManager.getInt( "Button.arc" );
|
||||
minimumWidth = UIManager.getInt( prefix + "minimumWidth" );
|
||||
iconTextGap = FlatUIUtils.getUIInt( prefix + "iconTextGap", 4 );
|
||||
|
||||
background = UIManager.getColor( prefix + "background" );
|
||||
foreground = UIManager.getColor( prefix + "foreground" );
|
||||
|
||||
startBackground = UIManager.getColor( prefix + "startBackground" );
|
||||
endBackground = UIManager.getColor( prefix + "endBackground" );
|
||||
focusedBackground = UIManager.getColor( prefix + "focusedBackground" );
|
||||
hoverBackground = UIManager.getColor( prefix + "hoverBackground" );
|
||||
pressedBackground = UIManager.getColor( prefix + "pressedBackground" );
|
||||
disabledBackground = UIManager.getColor( prefix + "disabledBackground" );
|
||||
disabledText = UIManager.getColor( prefix + "disabledText" );
|
||||
|
||||
if( UIManager.getBoolean( "Button.paintShadow" ) ) {
|
||||
@@ -187,7 +189,7 @@ public class FlatButtonUI
|
||||
LookAndFeel.installProperty( b, "opaque", false );
|
||||
LookAndFeel.installProperty( b, "iconTextGap", scale( iconTextGap ) );
|
||||
|
||||
MigLayoutVisualPadding.install( b, getFocusWidth( b ) );
|
||||
MigLayoutVisualPadding.install( b );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -211,10 +213,16 @@ public class FlatButtonUI
|
||||
|
||||
protected void propertyChange( AbstractButton b, PropertyChangeEvent e ) {
|
||||
switch( e.getPropertyName() ) {
|
||||
case SQUARE_SIZE:
|
||||
case MINIMUM_WIDTH:
|
||||
case MINIMUM_HEIGHT:
|
||||
b.revalidate();
|
||||
break;
|
||||
|
||||
case BUTTON_TYPE:
|
||||
b.revalidate();
|
||||
b.repaint();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,11 +230,19 @@ public class FlatButtonUI
|
||||
return !(c instanceof AbstractButton) || ((AbstractButton)c).isContentAreaFilled();
|
||||
}
|
||||
|
||||
public static boolean isFocusPainted( Component c ) {
|
||||
return !(c instanceof AbstractButton) || ((AbstractButton)c).isFocusPainted();
|
||||
}
|
||||
|
||||
static boolean isDefaultButton( Component c ) {
|
||||
return c instanceof JButton && ((JButton)c).isDefaultButton();
|
||||
}
|
||||
|
||||
static boolean isIconOnlyButton( Component c ) {
|
||||
/**
|
||||
* Returns true if the button has an icon but no text,
|
||||
* or it it does not have an icon and the text is either "..." or one character.
|
||||
*/
|
||||
static boolean isIconOnlyOrSingleCharacterButton( Component c ) {
|
||||
if( !(c instanceof JButton) && !(c instanceof JToggleButton) )
|
||||
return false;
|
||||
|
||||
@@ -236,8 +252,15 @@ public class FlatButtonUI
|
||||
(icon == null && text != null && ("...".equals( text ) || text.length() == 1));
|
||||
}
|
||||
|
||||
static boolean isSquareButton( Component c ) {
|
||||
return c instanceof AbstractButton && clientPropertyEquals( (AbstractButton) c, BUTTON_TYPE, BUTTON_TYPE_SQUARE );
|
||||
// same indices as in parameters to clientPropertyChoice()
|
||||
static final int TYPE_OTHER = -1;
|
||||
static final int TYPE_SQUARE = 0;
|
||||
static final int TYPE_ROUND_RECT = 1;
|
||||
|
||||
static int getButtonType( Component c ) {
|
||||
return (c instanceof AbstractButton)
|
||||
? clientPropertyChoice( (AbstractButton) c, BUTTON_TYPE, BUTTON_TYPE_SQUARE, BUTTON_TYPE_ROUND_RECT )
|
||||
: TYPE_OTHER;
|
||||
}
|
||||
|
||||
static boolean isHelpButton( Component c ) {
|
||||
@@ -245,7 +268,8 @@ public class FlatButtonUI
|
||||
}
|
||||
|
||||
static boolean isToolBarButton( Component c ) {
|
||||
return c.getParent() instanceof JToolBar;
|
||||
return c.getParent() instanceof JToolBar ||
|
||||
(c instanceof AbstractButton && clientPropertyEquals( (AbstractButton) c, BUTTON_TYPE, BUTTON_TYPE_TOOLBAR_BUTTON ));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -267,56 +291,61 @@ public class FlatButtonUI
|
||||
|
||||
protected void paintBackground( Graphics g, JComponent c ) {
|
||||
Color background = getBackground( c );
|
||||
if( background != null ) {
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
try {
|
||||
FlatUIUtils.setRenderingHints( g2 );
|
||||
if( background == null )
|
||||
return;
|
||||
|
||||
Border border = c.getBorder();
|
||||
boolean isToolBarButton = isToolBarButton( c );
|
||||
float focusWidth = (border instanceof FlatBorder && !isToolBarButton) ? scale( (float) getFocusWidth( c ) ) : 0;
|
||||
float arc = ((border instanceof FlatButtonBorder && !isSquareButton( c )) || isToolBarButton)
|
||||
? scale( (float) this.arc ) : 0;
|
||||
boolean def = isDefaultButton( c );
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
try {
|
||||
FlatUIUtils.setRenderingHints( g2 );
|
||||
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int width = c.getWidth();
|
||||
int height = c.getHeight();
|
||||
boolean isToolBarButton = isToolBarButton( c );
|
||||
float focusWidth = isToolBarButton ? 0 : FlatUIUtils.getBorderFocusWidth( c );
|
||||
float arc = FlatUIUtils.getBorderArc( c );
|
||||
|
||||
if( isToolBarButton ) {
|
||||
Insets spacing = UIScale.scale( toolbarSpacingInsets );
|
||||
x += spacing.left;
|
||||
y += spacing.top;
|
||||
width -= spacing.left + spacing.right;
|
||||
height -= spacing.top + spacing.bottom;
|
||||
}
|
||||
boolean def = isDefaultButton( c );
|
||||
|
||||
// paint shadow
|
||||
Color shadowColor = def ? defaultShadowColor : this.shadowColor;
|
||||
if( !isToolBarButton && shadowColor != null && shadowWidth > 0 && focusWidth > 0 &&
|
||||
!FlatUIUtils.isPermanentFocusOwner( c ) && c.isEnabled() )
|
||||
{
|
||||
g2.setColor( shadowColor );
|
||||
g2.fill( new RoundRectangle2D.Float( focusWidth, focusWidth + UIScale.scale( (float) shadowWidth ),
|
||||
width - focusWidth * 2, height - focusWidth * 2, arc, arc ) );
|
||||
}
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int width = c.getWidth();
|
||||
int height = c.getHeight();
|
||||
|
||||
// paint background
|
||||
Color startBg = def ? defaultBackground : startBackground;
|
||||
Color endBg = def ? defaultEndBackground : endBackground;
|
||||
if( background == startBg && endBg != null && !startBg.equals( endBg ) )
|
||||
g2.setPaint( new GradientPaint( 0, 0, startBg, 0, height, endBg ) );
|
||||
else
|
||||
FlatUIUtils.setColor( g2, background, def ? defaultBackground : c.getBackground() );
|
||||
|
||||
FlatUIUtils.paintComponentBackground( g2, x, y, width, height, focusWidth, arc );
|
||||
} finally {
|
||||
g2.dispose();
|
||||
if( isToolBarButton ) {
|
||||
Insets spacing = UIScale.scale( toolbarSpacingInsets );
|
||||
x += spacing.left;
|
||||
y += spacing.top;
|
||||
width -= spacing.left + spacing.right;
|
||||
height -= spacing.top + spacing.bottom;
|
||||
}
|
||||
|
||||
// paint shadow
|
||||
Color shadowColor = def ? defaultShadowColor : this.shadowColor;
|
||||
if( !isToolBarButton && shadowColor != null && shadowWidth > 0 && focusWidth > 0 &&
|
||||
!(isFocusPainted( c ) && FlatUIUtils.isPermanentFocusOwner( c )) && c.isEnabled() )
|
||||
{
|
||||
g2.setColor( shadowColor );
|
||||
g2.fill( new RoundRectangle2D.Float( focusWidth, focusWidth + UIScale.scale( (float) shadowWidth ),
|
||||
width - focusWidth * 2, height - focusWidth * 2, arc, arc ) );
|
||||
}
|
||||
|
||||
// paint background
|
||||
Color startBg = def ? defaultBackground : startBackground;
|
||||
Color endBg = def ? defaultEndBackground : endBackground;
|
||||
if( background == startBg && endBg != null && !startBg.equals( endBg ) )
|
||||
g2.setPaint( new GradientPaint( 0, 0, startBg, 0, height, endBg ) );
|
||||
else
|
||||
g2.setColor( FlatUIUtils.deriveColor( background, getBackgroundBase( c, def ) ) );
|
||||
|
||||
FlatUIUtils.paintComponentBackground( g2, x, y, width, height, focusWidth, arc );
|
||||
} finally {
|
||||
g2.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint( Graphics g, JComponent c ) {
|
||||
super.paint( FlatLabelUI.createGraphicsHTMLTextYCorrection( g, c ), c );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintText( Graphics g, AbstractButton b, Rectangle textRect, String text ) {
|
||||
if( isHelpButton( b ) )
|
||||
@@ -333,7 +362,7 @@ public class FlatButtonUI
|
||||
}
|
||||
}
|
||||
|
||||
paintText( g, b, textRect, text, b.isEnabled() ? getForeground( b ) : disabledText );
|
||||
paintText( g, b, textRect, text, getForeground( b ) );
|
||||
}
|
||||
|
||||
public static void paintText( Graphics g, AbstractButton b, Rectangle textRect, String text, Color foreground ) {
|
||||
@@ -347,7 +376,7 @@ public class FlatButtonUI
|
||||
|
||||
protected Color getBackground( JComponent c ) {
|
||||
if( !c.isEnabled() )
|
||||
return null;
|
||||
return disabledBackground;
|
||||
|
||||
// toolbar button
|
||||
if( isToolBarButton( c ) ) {
|
||||
@@ -363,13 +392,26 @@ public class FlatButtonUI
|
||||
|
||||
boolean def = isDefaultButton( c );
|
||||
return buttonStateColor( c,
|
||||
def ? defaultBackground : c.getBackground(),
|
||||
getBackgroundBase( c, def ),
|
||||
null,
|
||||
def ? defaultFocusedBackground : focusedBackground,
|
||||
isCustomBackground( c.getBackground() ) ? null : (def ? defaultFocusedBackground : focusedBackground),
|
||||
def ? defaultHoverBackground : hoverBackground,
|
||||
def ? defaultPressedBackground : pressedBackground );
|
||||
}
|
||||
|
||||
protected Color getBackgroundBase( JComponent c, boolean def ) {
|
||||
// use component background if explicitly set
|
||||
Color bg = c.getBackground();
|
||||
if( isCustomBackground( bg ) )
|
||||
return bg;
|
||||
|
||||
return def ? defaultBackground : bg;
|
||||
}
|
||||
|
||||
protected boolean isCustomBackground( Color bg ) {
|
||||
return bg != background && (startBackground == null || bg != startBackground);
|
||||
}
|
||||
|
||||
public static Color buttonStateColor( Component c, Color enabledColor, Color disabledColor,
|
||||
Color focusedColor, Color hoverColor, Color pressedColor )
|
||||
{
|
||||
@@ -384,15 +426,27 @@ public class FlatButtonUI
|
||||
if( hoverColor != null && b != null && b.getModel().isRollover() )
|
||||
return hoverColor;
|
||||
|
||||
if( focusedColor != null && FlatUIUtils.isPermanentFocusOwner( c ) )
|
||||
if( focusedColor != null && isFocusPainted( c ) && FlatUIUtils.isPermanentFocusOwner( c ) )
|
||||
return focusedColor;
|
||||
|
||||
return enabledColor;
|
||||
}
|
||||
|
||||
protected Color getForeground( JComponent c ) {
|
||||
if( !c.isEnabled() )
|
||||
return disabledText;
|
||||
|
||||
// use component foreground if explicitly set
|
||||
Color fg = c.getForeground();
|
||||
if( isCustomForeground( fg ) )
|
||||
return fg;
|
||||
|
||||
boolean def = isDefaultButton( c );
|
||||
return def ? defaultForeground : c.getForeground();
|
||||
return def ? defaultForeground : fg;
|
||||
}
|
||||
|
||||
protected boolean isCustomForeground( Color fg ) {
|
||||
return fg != foreground;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -401,23 +455,24 @@ public class FlatButtonUI
|
||||
return new Dimension( helpButtonIcon.getIconWidth(), helpButtonIcon.getIconHeight() );
|
||||
|
||||
Dimension prefSize = super.getPreferredSize( c );
|
||||
if ( prefSize == null )
|
||||
if( prefSize == null )
|
||||
return null;
|
||||
|
||||
// make button square if it is a icon-only button
|
||||
// or apply minimum width, if not in toolbar and not a icon-only button
|
||||
if( isIconOnlyButton( c ) )
|
||||
// make square or apply minimum width/height
|
||||
boolean isIconOnlyOrSingleCharacter = isIconOnlyOrSingleCharacterButton( c );
|
||||
if( clientPropertyBoolean( c, SQUARE_SIZE, false ) ) {
|
||||
// make button square (increase width or height so that they are equal)
|
||||
prefSize.width = prefSize.height = Math.max( prefSize.width, prefSize.height );
|
||||
} else if( isIconOnlyOrSingleCharacter && ((AbstractButton)c).getIcon() == null ) {
|
||||
// make single-character-no-icon button square (increase width)
|
||||
prefSize.width = Math.max( prefSize.width, prefSize.height );
|
||||
else if( !isToolBarButton( c ) && c.getBorder() instanceof FlatButtonBorder ) {
|
||||
int focusWidth = getFocusWidth( c );
|
||||
prefSize.width = Math.max( prefSize.width, scale( FlatUIUtils.minimumWidth( c, minimumWidth ) + (focusWidth * 2) ) );
|
||||
prefSize.height = Math.max( prefSize.height, scale( FlatUIUtils.minimumHeight( c, 0 ) + (focusWidth * 2) ) );
|
||||
} else if( !isIconOnlyOrSingleCharacter && !isToolBarButton( c ) && c.getBorder() instanceof FlatButtonBorder ) {
|
||||
// apply minimum width/height
|
||||
float focusWidth = FlatUIUtils.getBorderFocusWidth( c );
|
||||
prefSize.width = Math.max( prefSize.width, scale( FlatUIUtils.minimumWidth( c, minimumWidth ) ) + Math.round( focusWidth * 2 ) );
|
||||
prefSize.height = Math.max( prefSize.height, scale( FlatUIUtils.minimumHeight( c, 0 ) ) + Math.round( focusWidth * 2 ) );
|
||||
}
|
||||
|
||||
return prefSize;
|
||||
}
|
||||
|
||||
protected int getFocusWidth( JComponent c ) {
|
||||
return focusWidth;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ import javax.swing.text.JTextComponent;
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
class FlatCaret
|
||||
public class FlatCaret
|
||||
extends DefaultCaret
|
||||
implements UIResource
|
||||
{
|
||||
@@ -41,7 +41,7 @@ class FlatCaret
|
||||
private boolean wasTemporaryLost;
|
||||
private boolean isMousePressed;
|
||||
|
||||
FlatCaret( String selectAllOnFocusPolicy ) {
|
||||
public FlatCaret( String selectAllOnFocusPolicy ) {
|
||||
this.selectAllOnFocusPolicy = selectAllOnFocusPolicy;
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ class FlatCaret
|
||||
super.mouseReleased( e );
|
||||
}
|
||||
|
||||
private void selectAllOnFocusGained() {
|
||||
protected void selectAllOnFocusGained() {
|
||||
JTextComponent c = getComponent();
|
||||
Document doc = c.getDocument();
|
||||
if( doc == null || !c.isEnabled() || !c.isEditable() )
|
||||
|
||||
@@ -16,12 +16,11 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Rectangle;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicCheckBoxMenuItemUI;
|
||||
|
||||
@@ -30,29 +29,34 @@ import javax.swing.plaf.basic.BasicCheckBoxMenuItemUI;
|
||||
*
|
||||
* <!-- BasicCheckBoxMenuItemUI -->
|
||||
*
|
||||
* @uiDefault CheckBoxMenuItem.font Font
|
||||
* @uiDefault CheckBoxMenuItem.background Color
|
||||
* @uiDefault CheckBoxMenuItem.foreground Color
|
||||
* @uiDefault CheckBoxMenuItem.disabledForeground Color
|
||||
* @uiDefault CheckBoxMenuItem.selectionBackground Color
|
||||
* @uiDefault CheckBoxMenuItem.selectionForeground Color
|
||||
* @uiDefault CheckBoxMenuItem.acceleratorForeground Color
|
||||
* @uiDefault CheckBoxMenuItem.acceleratorSelectionForeground Color
|
||||
* @uiDefault MenuItem.acceleratorFont Font defaults to MenuItem.font
|
||||
* @uiDefault MenuItem.acceleratorDelimiter String
|
||||
* @uiDefault CheckBoxMenuItem.border Border
|
||||
* @uiDefault CheckBoxMenuItem.borderPainted boolean
|
||||
* @uiDefault CheckBoxMenuItem.margin Insets
|
||||
* @uiDefault CheckBoxMenuItem.arrowIcon Icon
|
||||
* @uiDefault CheckBoxMenuItem.checkIcon Icon
|
||||
* @uiDefault CheckBoxMenuItem.opaque boolean
|
||||
* @uiDefault CheckBoxMenuItem.evenHeight boolean
|
||||
* @uiDefault CheckBoxMenuItem.font Font
|
||||
* @uiDefault CheckBoxMenuItem.background Color
|
||||
* @uiDefault CheckBoxMenuItem.foreground Color
|
||||
* @uiDefault CheckBoxMenuItem.disabledForeground Color
|
||||
* @uiDefault CheckBoxMenuItem.selectionBackground Color
|
||||
* @uiDefault CheckBoxMenuItem.selectionForeground Color
|
||||
* @uiDefault CheckBoxMenuItem.acceleratorForeground Color
|
||||
* @uiDefault CheckBoxMenuItem.acceleratorSelectionForeground Color
|
||||
* @uiDefault MenuItem.acceleratorFont Font defaults to MenuItem.font
|
||||
* @uiDefault MenuItem.acceleratorDelimiter String
|
||||
* @uiDefault CheckBoxMenuItem.border Border
|
||||
* @uiDefault CheckBoxMenuItem.borderPainted boolean
|
||||
* @uiDefault CheckBoxMenuItem.margin Insets
|
||||
* @uiDefault CheckBoxMenuItem.arrowIcon Icon
|
||||
* @uiDefault CheckBoxMenuItem.checkIcon Icon
|
||||
* @uiDefault CheckBoxMenuItem.opaque boolean
|
||||
*
|
||||
* <!-- FlatCheckBoxMenuItemUI -->
|
||||
*
|
||||
* @uiDefault MenuItem.iconTextGap int
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatCheckBoxMenuItemUI
|
||||
extends BasicCheckBoxMenuItemUI
|
||||
{
|
||||
private FlatMenuItemRenderer renderer;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatCheckBoxMenuItemUI();
|
||||
}
|
||||
@@ -61,25 +65,30 @@ public class FlatCheckBoxMenuItemUI
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
|
||||
// scale
|
||||
defaultTextIconGap = scale( defaultTextIconGap );
|
||||
}
|
||||
LookAndFeel.installProperty( menuItem, "iconTextGap", FlatUIUtils.getUIInt( "MenuItem.iconTextGap", 4 ) );
|
||||
|
||||
/**
|
||||
* Scale defaultTextIconGap again if iconTextGap property has changed.
|
||||
*/
|
||||
@Override
|
||||
protected PropertyChangeListener createPropertyChangeListener( JComponent c ) {
|
||||
PropertyChangeListener superListener = super.createPropertyChangeListener( c );
|
||||
return e -> {
|
||||
superListener.propertyChange( e );
|
||||
if( e.getPropertyName() == "iconTextGap" )
|
||||
defaultTextIconGap = scale( defaultTextIconGap );
|
||||
};
|
||||
renderer = createRenderer();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintText( Graphics g, JMenuItem menuItem, Rectangle textRect, String text ) {
|
||||
FlatMenuItemUI.paintText( g, menuItem, textRect, text, disabledForeground, selectionForeground );
|
||||
protected void uninstallDefaults() {
|
||||
super.uninstallDefaults();
|
||||
|
||||
renderer = null;
|
||||
}
|
||||
|
||||
protected FlatMenuItemRenderer createRenderer() {
|
||||
return new FlatMenuItemRenderer( menuItem, checkIcon, arrowIcon, acceleratorFont, acceleratorDelimiter );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dimension getPreferredMenuItemSize( JComponent c, Icon checkIcon, Icon arrowIcon, int defaultTextIconGap ) {
|
||||
return renderer.getPreferredMenuItemSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint( Graphics g, JComponent c ) {
|
||||
renderer.paintMenuItem( g, selectionBackground, selectionForeground, disabledForeground,
|
||||
acceleratorForeground, acceleratorSelectionForeground );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ import java.beans.PropertyChangeListener;
|
||||
import java.lang.ref.WeakReference;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.ComboBoxEditor;
|
||||
import javax.swing.DefaultListCellRenderer;
|
||||
import javax.swing.InputMap;
|
||||
import javax.swing.JButton;
|
||||
@@ -46,6 +47,7 @@ import javax.swing.JComboBox;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.ListCellRenderer;
|
||||
import javax.swing.LookAndFeel;
|
||||
@@ -76,8 +78,10 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
*
|
||||
* <!-- FlatComboBoxUI -->
|
||||
*
|
||||
* @uiDefault Component.focusWidth int
|
||||
* @uiDefault Component.arc int
|
||||
* @uiDefault ComboBox.minimumWidth int
|
||||
* @uiDefault ComboBox.editorColumns int
|
||||
* @uiDefault ComboBox.maximumRowCount int
|
||||
* @uiDefault ComboBox.buttonStyle String auto (default), button or none
|
||||
* @uiDefault Component.arrowType String triangle (default) or chevron
|
||||
* @uiDefault Component.isIntelliJTheme boolean
|
||||
* @uiDefault Component.borderColor Color
|
||||
@@ -96,8 +100,9 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
public class FlatComboBoxUI
|
||||
extends BasicComboBoxUI
|
||||
{
|
||||
protected int focusWidth;
|
||||
protected int arc;
|
||||
protected int minimumWidth;
|
||||
protected int editorColumns;
|
||||
protected String buttonStyle;
|
||||
protected String arrowType;
|
||||
protected boolean isIntelliJTheme;
|
||||
protected Color borderColor;
|
||||
@@ -150,8 +155,9 @@ public class FlatComboBoxUI
|
||||
|
||||
LookAndFeel.installProperty( comboBox, "opaque", false );
|
||||
|
||||
focusWidth = UIManager.getInt( "Component.focusWidth" );
|
||||
arc = UIManager.getInt( "Component.arc" );
|
||||
minimumWidth = UIManager.getInt( "ComboBox.minimumWidth" );
|
||||
editorColumns = UIManager.getInt( "ComboBox.editorColumns" );
|
||||
buttonStyle = UIManager.getString( "ComboBox.buttonStyle" );
|
||||
arrowType = UIManager.getString( "Component.arrowType" );
|
||||
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
||||
borderColor = UIManager.getColor( "Component.borderColor" );
|
||||
@@ -167,10 +173,15 @@ public class FlatComboBoxUI
|
||||
buttonDisabledArrowColor = UIManager.getColor( "ComboBox.buttonDisabledArrowColor" );
|
||||
buttonHoverArrowColor = UIManager.getColor( "ComboBox.buttonHoverArrowColor" );
|
||||
|
||||
// set maximumRowCount
|
||||
int maximumRowCount = UIManager.getInt( "ComboBox.maximumRowCount" );
|
||||
if( maximumRowCount > 0 && maximumRowCount != 8 && comboBox.getMaximumRowCount() == 8 )
|
||||
comboBox.setMaximumRowCount( maximumRowCount );
|
||||
|
||||
// scale
|
||||
padding = UIScale.scale( padding );
|
||||
|
||||
MigLayoutVisualPadding.install( comboBox, focusWidth );
|
||||
MigLayoutVisualPadding.install( comboBox );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -249,6 +260,10 @@ public class FlatComboBoxUI
|
||||
editor.applyComponentOrientation( o );
|
||||
} else if( editor != null && FlatClientProperties.PLACEHOLDER_TEXT.equals( propertyName ) )
|
||||
editor.repaint();
|
||||
else if( FlatClientProperties.COMPONENT_ROUND_RECT.equals( propertyName ) )
|
||||
comboBox.repaint();
|
||||
else if( FlatClientProperties.MINIMUM_WIDTH.equals( propertyName ) )
|
||||
comboBox.revalidate();
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -258,18 +273,30 @@ public class FlatComboBoxUI
|
||||
return new FlatComboPopup( comboBox );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ComboBoxEditor createEditor() {
|
||||
ComboBoxEditor comboBoxEditor = super.createEditor();
|
||||
|
||||
Component editor = comboBoxEditor.getEditorComponent();
|
||||
if( editor instanceof JTextField ) {
|
||||
JTextField textField = (JTextField) editor;
|
||||
textField.setColumns( editorColumns );
|
||||
|
||||
// assign a non-null and non-javax.swing.plaf.UIResource border to the text field,
|
||||
// otherwise it is replaced with default text field border when switching LaF
|
||||
// because javax.swing.plaf.basic.BasicComboBoxEditor.BorderlessTextField.setBorder()
|
||||
// uses "border instanceof javax.swing.plaf.basic.BasicComboBoxEditor.UIResource"
|
||||
// instead of "border instanceof javax.swing.plaf.UIResource"
|
||||
textField.setBorder( BorderFactory.createEmptyBorder() );
|
||||
}
|
||||
|
||||
return comboBoxEditor;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureEditor() {
|
||||
super.configureEditor();
|
||||
|
||||
// assign a non-javax.swing.plaf.UIResource border to the text field,
|
||||
// otherwise it is replaced with default text field border when switching LaF
|
||||
// because javax.swing.plaf.basic.BasicComboBoxEditor.BorderlessTextField.setBorder()
|
||||
// uses "border instanceof javax.swing.plaf.basic.BasicComboBoxEditor.UIResource"
|
||||
// instead of "border instanceof javax.swing.plaf.UIResource"
|
||||
if( editor instanceof JTextComponent )
|
||||
((JTextComponent)editor).setBorder( BorderFactory.createEmptyBorder() );
|
||||
|
||||
// explicitly make non-opaque
|
||||
if( editor instanceof JComponent )
|
||||
((JComponent)editor).setOpaque( false );
|
||||
@@ -296,12 +323,11 @@ public class FlatComboBoxUI
|
||||
// use non-UIResource colors because when SwingUtilities.updateComponentTreeUI()
|
||||
// is used, then the editor is updated after the combobox and the
|
||||
// colors are again replaced with default colors
|
||||
boolean enabled = editor.isEnabled();
|
||||
editor.setForeground( FlatUIUtils.nonUIResource( (enabled || editor instanceof JTextComponent)
|
||||
? comboBox.getForeground()
|
||||
: disabledForeground ) );
|
||||
if( editor instanceof JTextComponent )
|
||||
((JTextComponent)editor).setDisabledTextColor( FlatUIUtils.nonUIResource( disabledForeground ) );
|
||||
boolean isTextComponent = editor instanceof JTextComponent;
|
||||
editor.setForeground( FlatUIUtils.nonUIResource( getForeground( isTextComponent || editor.isEnabled() ) ) );
|
||||
|
||||
if( isTextComponent )
|
||||
((JTextComponent)editor).setDisabledTextColor( FlatUIUtils.nonUIResource( getForeground( false ) ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -318,8 +344,11 @@ public class FlatComboBoxUI
|
||||
|
||||
@Override
|
||||
public void update( Graphics g, JComponent c ) {
|
||||
float focusWidth = FlatUIUtils.getBorderFocusWidth( c );
|
||||
float arc = FlatUIUtils.getBorderArc( c );
|
||||
|
||||
// fill background if opaque to avoid garbage if user sets opaque to true
|
||||
if( c.isOpaque() && (focusWidth > 0 || arc != 0) )
|
||||
if( c.isOpaque() && (focusWidth > 0 || arc > 0) )
|
||||
FlatUIUtils.paintParentBackground( g, c );
|
||||
|
||||
Graphics2D g2 = (Graphics2D) g;
|
||||
@@ -327,22 +356,19 @@ public class FlatComboBoxUI
|
||||
|
||||
int width = c.getWidth();
|
||||
int height = c.getHeight();
|
||||
float focusWidth = (c.getBorder() instanceof FlatBorder) ? scale( (float) this.focusWidth ) : 0;
|
||||
float arc = (c.getBorder() instanceof FlatRoundBorder) ? scale( (float) this.arc ) : 0;
|
||||
int arrowX = arrowButton.getX();
|
||||
int arrowWidth = arrowButton.getWidth();
|
||||
boolean paintButton = (comboBox.isEditable() || "button".equals( buttonStyle )) && !"none".equals( buttonStyle );
|
||||
boolean enabled = comboBox.isEnabled();
|
||||
boolean isLeftToRight = comboBox.getComponentOrientation().isLeftToRight();
|
||||
|
||||
// paint background
|
||||
g2.setColor( enabled
|
||||
? (editableBackground != null && comboBox.isEditable() ? editableBackground : c.getBackground())
|
||||
: getDisabledBackground( comboBox ) );
|
||||
g2.setColor( getBackground( enabled ) );
|
||||
FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc );
|
||||
|
||||
// paint arrow button background
|
||||
if( enabled ) {
|
||||
g2.setColor( comboBox.isEditable() ? buttonEditableBackground : buttonBackground );
|
||||
g2.setColor( paintButton ? buttonEditableBackground : buttonBackground );
|
||||
Shape oldClip = g2.getClip();
|
||||
if( isLeftToRight )
|
||||
g2.clipRect( arrowX, 0, width - arrowX, height );
|
||||
@@ -353,7 +379,7 @@ public class FlatComboBoxUI
|
||||
}
|
||||
|
||||
// paint vertical line between value and arrow button
|
||||
if( comboBox.isEditable() ) {
|
||||
if( paintButton ) {
|
||||
g2.setColor( enabled ? borderColor : disabledBorderColor );
|
||||
float lw = scale( 1f );
|
||||
float lx = isLeftToRight ? arrowX : arrowX + arrowWidth - lw;
|
||||
@@ -376,8 +402,8 @@ public class FlatComboBoxUI
|
||||
uninstallCellPaddingBorder( c );
|
||||
|
||||
boolean enabled = comboBox.isEnabled();
|
||||
c.setForeground( enabled ? comboBox.getForeground() : disabledForeground );
|
||||
c.setBackground( enabled ? comboBox.getBackground() : getDisabledBackground( comboBox ) );
|
||||
c.setBackground( getBackground( enabled ) );
|
||||
c.setForeground( getForeground( enabled ) );
|
||||
|
||||
boolean shouldValidate = (c instanceof JPanel);
|
||||
if( padding != null )
|
||||
@@ -394,12 +420,24 @@ public class FlatComboBoxUI
|
||||
|
||||
@Override
|
||||
public void paintCurrentValueBackground( Graphics g, Rectangle bounds, boolean hasFocus ) {
|
||||
g.setColor( comboBox.isEnabled() ? comboBox.getBackground() : getDisabledBackground( comboBox ) );
|
||||
g.fillRect( bounds.x, bounds.y, bounds.width, bounds.height );
|
||||
// not necessary because already painted in update()
|
||||
}
|
||||
|
||||
private Color getDisabledBackground( JComponent c ) {
|
||||
return isIntelliJTheme ? FlatUIUtils.getParentBackground( c ) : disabledBackground;
|
||||
protected Color getBackground( boolean enabled ) {
|
||||
return enabled
|
||||
? (editableBackground != null && comboBox.isEditable() ? editableBackground : comboBox.getBackground())
|
||||
: (isIntelliJTheme ? FlatUIUtils.getParentBackground( comboBox ) : disabledBackground);
|
||||
}
|
||||
|
||||
protected Color getForeground( boolean enabled ) {
|
||||
return enabled ? comboBox.getForeground() : disabledForeground;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize( JComponent c ) {
|
||||
Dimension minimumSize = super.getMinimumSize( c );
|
||||
minimumSize.width = Math.max( minimumSize.width, scale( FlatUIUtils.minimumWidth( c, minimumWidth ) ) );
|
||||
return minimumSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -422,6 +460,18 @@ public class FlatComboBoxUI
|
||||
|
||||
Dimension displaySize = super.getDisplaySize();
|
||||
|
||||
// recalculate width without hardcoded 100 under special conditions
|
||||
if( displaySize.width == 100 + padding.left + padding.right &&
|
||||
comboBox.isEditable() &&
|
||||
comboBox.getItemCount() == 0 &&
|
||||
comboBox.getPrototypeDisplayValue() == null )
|
||||
{
|
||||
int width = getDefaultSize().width;
|
||||
width = Math.max( width, editor.getPreferredSize().width );
|
||||
width += padding.left + padding.right;
|
||||
displaySize = new Dimension( width, displaySize.height );
|
||||
}
|
||||
|
||||
uninstallCellPaddingBorder( renderer );
|
||||
return displaySize;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Copyright 2020 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.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Image;
|
||||
import java.awt.Insets;
|
||||
import java.awt.RadialGradientPaint;
|
||||
import java.awt.image.BufferedImage;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
* Paints a drop shadow border around the component.
|
||||
* Supports 1-sided, 2-side, 3-sided or 4-sided drop shadows.
|
||||
* <p>
|
||||
* The shadow insets allow specifying drop shadow thickness for each side.
|
||||
* A zero or negative value hides the drop shadow on that side.
|
||||
* A negative value can be used to indent the drop shadow on corners.
|
||||
* E.g. -4 on left indents drop shadow at top-left and bottom-left corners by 4 pixels.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatDropShadowBorder
|
||||
extends FlatEmptyBorder
|
||||
{
|
||||
private final Color shadowColor;
|
||||
private final Insets shadowInsets;
|
||||
private final float shadowOpacity;
|
||||
|
||||
private final int shadowSize;
|
||||
private Image shadowImage;
|
||||
private Color lastShadowColor;
|
||||
private double lastSystemScaleFactor;
|
||||
private float lastUserScaleFactor;
|
||||
|
||||
public FlatDropShadowBorder() {
|
||||
this( null );
|
||||
}
|
||||
|
||||
public FlatDropShadowBorder( Color shadowColor ) {
|
||||
this( shadowColor, 4, 0.5f );
|
||||
}
|
||||
|
||||
public FlatDropShadowBorder( Color shadowColor, int shadowSize, float shadowOpacity ) {
|
||||
this( shadowColor, new Insets( -shadowSize, -shadowSize, shadowSize, shadowSize ), shadowOpacity );
|
||||
}
|
||||
|
||||
public FlatDropShadowBorder( Color shadowColor, Insets shadowInsets, float shadowOpacity ) {
|
||||
super( Math.max( shadowInsets.top, 0 ), Math.max( shadowInsets.left, 0 ),
|
||||
Math.max( shadowInsets.bottom, 0 ), Math.max( shadowInsets.right, 0 ) );
|
||||
this.shadowColor = shadowColor;
|
||||
this.shadowInsets = shadowInsets;
|
||||
this.shadowOpacity = shadowOpacity;
|
||||
|
||||
shadowSize = Math.max(
|
||||
Math.max( shadowInsets.left, shadowInsets.right ),
|
||||
Math.max( shadowInsets.top, shadowInsets.bottom ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||
if( shadowSize <= 0 )
|
||||
return;
|
||||
|
||||
HiDPIUtils.paintAtScale1x( (Graphics2D) g, x, y, width, height, this::paintImpl );
|
||||
}
|
||||
|
||||
private void paintImpl( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
|
||||
Color shadowColor = (this.shadowColor != null) ? this.shadowColor : g.getColor();
|
||||
int shadowSize = scale( this.shadowSize, scaleFactor );
|
||||
|
||||
// create and cache shadow image
|
||||
float userScaleFactor = UIScale.getUserScaleFactor();
|
||||
if( shadowImage == null ||
|
||||
!shadowColor.equals( lastShadowColor ) ||
|
||||
lastSystemScaleFactor != scaleFactor ||
|
||||
lastUserScaleFactor != userScaleFactor )
|
||||
{
|
||||
shadowImage = createShadowImage( shadowColor, shadowSize, shadowOpacity,
|
||||
(float) (scaleFactor * userScaleFactor) );
|
||||
lastShadowColor = shadowColor;
|
||||
lastSystemScaleFactor = scaleFactor;
|
||||
lastUserScaleFactor = userScaleFactor;
|
||||
}
|
||||
|
||||
/*debug
|
||||
int m = shadowImage.getWidth( null );
|
||||
Color oldColor = g.getColor();
|
||||
g.setColor( Color.lightGray );
|
||||
g.drawRect( x - m - 1, y - m - 1, m + 1, m + 1 );
|
||||
g.setColor( Color.white );
|
||||
g.fillRect( x - m, y - m, m, m );
|
||||
g.drawImage( shadowImage, x - m, y - m, null );
|
||||
g.setColor( oldColor );
|
||||
debug*/
|
||||
|
||||
int left = scale( shadowInsets.left, scaleFactor );
|
||||
int right = scale( shadowInsets.right, scaleFactor );
|
||||
int top = scale( shadowInsets.top, scaleFactor );
|
||||
int bottom = scale( shadowInsets.bottom, scaleFactor );
|
||||
|
||||
// shadow outer coordinates
|
||||
int x1o = x - Math.min( left, 0 );
|
||||
int y1o = y - Math.min( top, 0 );
|
||||
int x2o = x + width + Math.min( right, 0 );
|
||||
int y2o = y + height + Math.min( bottom, 0 );
|
||||
|
||||
// shadow inner coordinates
|
||||
int x1i = x1o + shadowSize;
|
||||
int y1i = y1o + shadowSize;
|
||||
int x2i = x2o - shadowSize;
|
||||
int y2i = y2o - shadowSize;
|
||||
|
||||
int wh = (shadowSize * 2) - 1;
|
||||
int center = shadowSize - 1;
|
||||
|
||||
// left-top edge
|
||||
if( left > 0 || top > 0 ) {
|
||||
g.drawImage( shadowImage, x1o, y1o, x1i, y1i,
|
||||
0, 0, center, center, null );
|
||||
}
|
||||
|
||||
// top shadow
|
||||
if( top > 0 ) {
|
||||
g.drawImage( shadowImage, x1i, y1o, x2i, y1i,
|
||||
center, 0, center + 1, center, null );
|
||||
}
|
||||
|
||||
// right-top edge
|
||||
if( right > 0 || top > 0 ) {
|
||||
g.drawImage( shadowImage, x2i, y1o, x2o, y1i,
|
||||
center, 0, wh, center, null );
|
||||
}
|
||||
|
||||
// left shadow
|
||||
if( left > 0 ) {
|
||||
g.drawImage( shadowImage, x1o, y1i, x1i, y2i,
|
||||
0, center, center, center + 1, null );
|
||||
}
|
||||
|
||||
// right shadow
|
||||
if( right > 0 ) {
|
||||
g.drawImage( shadowImage, x2i, y1i, x2o, y2i,
|
||||
center, center, wh, center + 1, null );
|
||||
}
|
||||
|
||||
// left-bottom edge
|
||||
if( left > 0 || bottom > 0 ) {
|
||||
g.drawImage( shadowImage, x1o, y2i, x1i, y2o,
|
||||
0, center, center, wh, null );
|
||||
}
|
||||
|
||||
// bottom shadow
|
||||
if( bottom > 0 ) {
|
||||
g.drawImage( shadowImage, x1i, y2i, x2i, y2o,
|
||||
center, center, center + 1, wh, null );
|
||||
}
|
||||
|
||||
// right-bottom edge
|
||||
if( right > 0 || bottom > 0 ) {
|
||||
g.drawImage( shadowImage, x2i, y2i, x2o, y2o,
|
||||
center, center, wh, wh, null );
|
||||
}
|
||||
}
|
||||
|
||||
private int scale( int value, double scaleFactor ) {
|
||||
return (int) Math.ceil( UIScale.scale( value ) * scaleFactor );
|
||||
}
|
||||
|
||||
private static BufferedImage createShadowImage( Color shadowColor, int shadowSize,
|
||||
float shadowOpacity, float scaleFactor )
|
||||
{
|
||||
int shadowRGB = shadowColor.getRGB() & 0xffffff;
|
||||
int shadowAlpha = (int) (255 * shadowOpacity);
|
||||
Color startColor = new Color( shadowRGB | ((shadowAlpha & 0xff) << 24), true );
|
||||
Color midColor = new Color( shadowRGB | (((shadowAlpha / 2) & 0xff) << 24), true );
|
||||
Color endColor = new Color( shadowRGB, true );
|
||||
|
||||
/*debug
|
||||
startColor = Color.red;
|
||||
midColor = Color.green;
|
||||
endColor = Color.blue;
|
||||
debug*/
|
||||
|
||||
int wh = (shadowSize * 2) - 1;
|
||||
int center = shadowSize - 1;
|
||||
|
||||
RadialGradientPaint p = new RadialGradientPaint( center, center,
|
||||
shadowSize - (0.75f * scaleFactor),
|
||||
new float[] { 0, 0.35f, 1 },
|
||||
new Color[] { startColor, midColor, endColor } );
|
||||
|
||||
BufferedImage image = new BufferedImage( wh, wh, BufferedImage.TYPE_INT_ARGB );
|
||||
|
||||
Graphics2D g = image.createGraphics();
|
||||
try {
|
||||
g.setPaint( p );
|
||||
g.fillRect( 0, 0, wh, wh );
|
||||
} finally {
|
||||
g.dispose();
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,8 @@ package com.formdev.flatlaf.ui;
|
||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JEditorPane;
|
||||
import javax.swing.UIManager;
|
||||
@@ -26,6 +28,8 @@ import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicEditorPaneUI;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JEditorPane}.
|
||||
@@ -83,26 +87,45 @@ public class FlatEditorPaneUI
|
||||
getComponent().putClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES, oldHonorDisplayProperties );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void propertyChange( PropertyChangeEvent e ) {
|
||||
super.propertyChange( e );
|
||||
propertyChange( getComponent(), e );
|
||||
}
|
||||
|
||||
static void propertyChange( JTextComponent c, PropertyChangeEvent e ) {
|
||||
switch( e.getPropertyName() ) {
|
||||
case FlatClientProperties.MINIMUM_WIDTH:
|
||||
c.revalidate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize( JComponent c ) {
|
||||
return applyMinimumWidth( super.getPreferredSize( c ) );
|
||||
return applyMinimumWidth( c, super.getPreferredSize( c ), minimumWidth );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize( JComponent c ) {
|
||||
return applyMinimumWidth( super.getMinimumSize( c ) );
|
||||
return applyMinimumWidth( c, super.getMinimumSize( c ), minimumWidth );
|
||||
}
|
||||
|
||||
private Dimension applyMinimumWidth( Dimension size ) {
|
||||
static Dimension applyMinimumWidth( JComponent c, Dimension size, int minimumWidth ) {
|
||||
// Assume that text area is in a scroll pane (that displays the border)
|
||||
// and subtract 1px border line width.
|
||||
// Using "(scale( 1 ) * 2)" instead of "scale( 2 )" to deal with rounding
|
||||
// issues. E.g. at scale factor 1.5 the first returns 4, but the second 3.
|
||||
int minimumWidth = FlatUIUtils.minimumWidth( getComponent(), this.minimumWidth );
|
||||
minimumWidth = FlatUIUtils.minimumWidth( c, minimumWidth );
|
||||
size.width = Math.max( size.width, scale( minimumWidth ) - (scale( 1 ) * 2) );
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintSafely( Graphics g ) {
|
||||
super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintBackground( Graphics g ) {
|
||||
JTextComponent c = getComponent();
|
||||
|
||||
@@ -16,11 +16,28 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Insets;
|
||||
import java.io.File;
|
||||
import javax.swing.AbstractButton;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JToggleButton;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.filechooser.FileView;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.metal.MetalFileChooserUI;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.util.ScaledImageIcon;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
@@ -86,6 +103,7 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault FileChooser.folderNameLabelText String
|
||||
* @uiDefault FileChooser.filesOfTypeLabelMnemonic String
|
||||
* @uiDefault FileChooser.filesOfTypeLabelText String
|
||||
*
|
||||
* @uiDefault FileChooser.upFolderToolTipText String
|
||||
* @uiDefault FileChooser.upFolderAccessibleName String
|
||||
* @uiDefault FileChooser.homeFolderToolTipText String
|
||||
@@ -97,11 +115,27 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault FileChooser.detailsViewButtonToolTipText String
|
||||
* @uiDefault FileChooser.detailsViewButtonAccessibleName String
|
||||
*
|
||||
* <!-- FilePane -->
|
||||
*
|
||||
* @uiDefault FileChooser.fileNameHeaderText String
|
||||
* @uiDefault FileChooser.fileSizeHeaderText String
|
||||
* @uiDefault FileChooser.fileTypeHeaderText String
|
||||
* @uiDefault FileChooser.fileDateHeaderText String
|
||||
* @uiDefault FileChooser.fileAttrHeaderText String
|
||||
*
|
||||
* @uiDefault FileChooser.viewMenuLabelText String
|
||||
* @uiDefault FileChooser.refreshActionLabelText String
|
||||
* @uiDefault FileChooser.newFolderActionLabelText String
|
||||
* @uiDefault FileChooser.listViewActionLabelText String
|
||||
* @uiDefault FileChooser.detailsViewActionLabelText String
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatFileChooserUI
|
||||
extends MetalFileChooserUI
|
||||
{
|
||||
private final FlatFileView fileView = new FlatFileView();
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatFileChooserUI( (JFileChooser) c );
|
||||
}
|
||||
@@ -110,6 +144,52 @@ public class FlatFileChooserUI
|
||||
super( filechooser );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installComponents( JFileChooser fc ) {
|
||||
super.installComponents( fc );
|
||||
|
||||
patchUI( fc );
|
||||
}
|
||||
|
||||
private void patchUI( JFileChooser fc ) {
|
||||
// turn top-right buttons into toolbar buttons
|
||||
Component topPanel = fc.getComponent( 0 );
|
||||
if( (topPanel instanceof JPanel) &&
|
||||
(((JPanel)topPanel).getLayout() instanceof BorderLayout) )
|
||||
{
|
||||
Component topButtonPanel = ((JPanel)topPanel).getComponent( 0 );
|
||||
if( (topButtonPanel instanceof JPanel) &&
|
||||
(((JPanel)topButtonPanel).getLayout() instanceof BoxLayout) )
|
||||
{
|
||||
Insets margin = UIManager.getInsets( "Button.margin" );
|
||||
Component[] comps = ((JPanel)topButtonPanel).getComponents();
|
||||
for( int i = comps.length - 1; i >= 0; i-- ) {
|
||||
Component c = comps[i];
|
||||
if( c instanceof JButton || c instanceof JToggleButton ) {
|
||||
AbstractButton b = (AbstractButton)c;
|
||||
b.putClientProperty( FlatClientProperties.BUTTON_TYPE,
|
||||
FlatClientProperties.BUTTON_TYPE_TOOLBAR_BUTTON );
|
||||
b.setMargin( margin );
|
||||
b.setFocusable( false );
|
||||
} else if( c instanceof Box.Filler )
|
||||
((JPanel)topButtonPanel).remove( i );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// increase maximum row count of directory combo box popup list
|
||||
try {
|
||||
Component directoryComboBox = ((JPanel)topPanel).getComponent( 2 );
|
||||
if( directoryComboBox instanceof JComboBox ) {
|
||||
int maximumRowCount = UIManager.getInt( "ComboBox.maximumRowCount" );
|
||||
if( maximumRowCount > 0 )
|
||||
((JComboBox<?>)directoryComboBox).setMaximumRowCount( maximumRowCount );
|
||||
}
|
||||
} catch( ArrayIndexOutOfBoundsException ex ) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize( JComponent c ) {
|
||||
return UIScale.scale( super.getPreferredSize( c ) );
|
||||
@@ -119,4 +199,50 @@ public class FlatFileChooserUI
|
||||
public Dimension getMinimumSize( JComponent c ) {
|
||||
return UIScale.scale( super.getMinimumSize( c ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileView getFileView( JFileChooser fc ) {
|
||||
return fileView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearIconCache() {
|
||||
fileView.clearIconCache();
|
||||
}
|
||||
|
||||
//---- class FlatFileView -------------------------------------------------
|
||||
|
||||
private class FlatFileView
|
||||
extends BasicFileView
|
||||
{
|
||||
@Override
|
||||
public Icon getIcon( File f ) {
|
||||
// get cached icon
|
||||
Icon icon = getCachedIcon( f );
|
||||
if( icon != null )
|
||||
return icon;
|
||||
|
||||
// get system icon
|
||||
if( f != null ) {
|
||||
icon = getFileChooser().getFileSystemView().getSystemIcon( f );
|
||||
|
||||
if( icon != null ) {
|
||||
if( icon instanceof ImageIcon )
|
||||
icon = new ScaledImageIcon( (ImageIcon) icon );
|
||||
cacheIcon( f, icon );
|
||||
return icon;
|
||||
}
|
||||
}
|
||||
|
||||
// get default icon
|
||||
icon = super.getIcon( f );
|
||||
|
||||
if( icon instanceof ImageIcon ) {
|
||||
icon = new ScaledImageIcon( (ImageIcon) icon );
|
||||
cacheIcon( f, icon );
|
||||
}
|
||||
|
||||
return icon;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,6 +112,16 @@ public class FlatInternalFrameUI
|
||||
private final Color activeBorderColor = UIManager.getColor( "InternalFrame.activeBorderColor" );
|
||||
private final Color inactiveBorderColor = UIManager.getColor( "InternalFrame.inactiveBorderColor" );
|
||||
private final int borderLineWidth = FlatUIUtils.getUIInt( "InternalFrame.borderLineWidth", 1 );
|
||||
private final boolean dropShadowPainted = UIManager.getBoolean( "InternalFrame.dropShadowPainted" );
|
||||
|
||||
private final FlatDropShadowBorder activeDropShadowBorder = new FlatDropShadowBorder(
|
||||
UIManager.getColor( "InternalFrame.activeDropShadowColor" ),
|
||||
UIManager.getInsets( "InternalFrame.activeDropShadowInsets" ),
|
||||
FlatUIUtils.getUIFloat( "InternalFrame.activeDropShadowOpacity", 0.5f ) );
|
||||
private final FlatDropShadowBorder inactiveDropShadowBorder = new FlatDropShadowBorder(
|
||||
UIManager.getColor( "InternalFrame.inactiveDropShadowColor" ),
|
||||
UIManager.getInsets( "InternalFrame.inactiveDropShadowInsets" ),
|
||||
FlatUIUtils.getUIFloat( "InternalFrame.inactiveDropShadowOpacity", 0.5f ) );
|
||||
|
||||
public FlatInternalFrameBorder() {
|
||||
super( UIManager.getInsets( "InternalFrame.borderMargins" ) );
|
||||
@@ -137,16 +147,31 @@ public class FlatInternalFrameUI
|
||||
Insets insets = getBorderInsets( c );
|
||||
float lineWidth = scale( (float) borderLineWidth );
|
||||
|
||||
float rx = x + insets.left - lineWidth;
|
||||
float ry = y + insets.top - lineWidth;
|
||||
float rwidth = width - insets.left - insets.right + (lineWidth * 2);
|
||||
float rheight = height - insets.top - insets.bottom + (lineWidth * 2);
|
||||
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
try {
|
||||
FlatUIUtils.setRenderingHints( g2 );
|
||||
g2.setColor( f.isSelected() ? activeBorderColor : inactiveBorderColor );
|
||||
g2.fill( FlatUIUtils.createRectangle(
|
||||
x + insets.left - lineWidth,
|
||||
y + insets.top - lineWidth,
|
||||
width - insets.left - insets.right + (lineWidth * 2),
|
||||
height - insets.top - insets.bottom + (lineWidth * 2),
|
||||
lineWidth ) );
|
||||
|
||||
// paint drop shadow
|
||||
if( dropShadowPainted ) {
|
||||
FlatDropShadowBorder dropShadowBorder = f.isSelected()
|
||||
? activeDropShadowBorder : inactiveDropShadowBorder;
|
||||
|
||||
Insets dropShadowInsets = dropShadowBorder.getBorderInsets();
|
||||
dropShadowBorder.paintBorder( c, g2,
|
||||
(int) rx - dropShadowInsets.left,
|
||||
(int) ry - dropShadowInsets.top,
|
||||
(int) rwidth + dropShadowInsets.left + dropShadowInsets.right,
|
||||
(int) rheight + dropShadowInsets.top + dropShadowInsets.bottom );
|
||||
}
|
||||
|
||||
// paint border
|
||||
g2.fill( FlatUIUtils.createRectangle( rx, ry, rwidth, rheight, lineWidth ) );
|
||||
} finally {
|
||||
g2.dispose();
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.formdev.flatlaf.ui;
|
||||
import java.awt.Color;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import javax.swing.Icon;
|
||||
@@ -30,6 +31,7 @@ import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicHTML;
|
||||
import javax.swing.plaf.basic.BasicLabelUI;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
@@ -124,6 +126,17 @@ public class FlatLabelUI
|
||||
BasicHTML.updateRenderer( c, text );
|
||||
}
|
||||
|
||||
static Graphics createGraphicsHTMLTextYCorrection( Graphics g, JComponent c ) {
|
||||
return (c.getClientProperty( BasicHTML.propertyKey ) != null)
|
||||
? HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g )
|
||||
: g;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint( Graphics g, JComponent c ) {
|
||||
super.paint( createGraphicsHTMLTextYCorrection( g, c ), c );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintEnabledText( JLabel l, Graphics g, String s, int textX, int textY ) {
|
||||
int mnemIndex = FlatLaf.isShowMnemonics() ? l.getDisplayedMnemonicIndex() : -1;
|
||||
|
||||
@@ -48,6 +48,14 @@ public class FlatLineBorder
|
||||
this.lineThickness = lineThickness;
|
||||
}
|
||||
|
||||
public Color getLineColor() {
|
||||
return lineColor;
|
||||
}
|
||||
|
||||
public float getLineThickness() {
|
||||
return lineThickness;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
|
||||
@@ -16,9 +16,20 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.ActionMap;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.MenuElement;
|
||||
import javax.swing.MenuSelectionManager;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.plaf.ActionMapUIResource;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicMenuBarUI;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JMenuBar}.
|
||||
@@ -38,4 +49,45 @@ public class FlatMenuBarUI
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatMenuBarUI();
|
||||
}
|
||||
|
||||
/*
|
||||
* WARNING: This class is not used on macOS if screen menu bar is enabled.
|
||||
* Do not add any functionality here.
|
||||
*/
|
||||
|
||||
@Override
|
||||
protected void installKeyboardActions() {
|
||||
super.installKeyboardActions();
|
||||
|
||||
ActionMap map = SwingUtilities.getUIActionMap( menuBar );
|
||||
if( map == null ) {
|
||||
map = new ActionMapUIResource();
|
||||
SwingUtilities.replaceUIActionMap( menuBar, map );
|
||||
}
|
||||
map.put( "takeFocus", new TakeFocus() );
|
||||
}
|
||||
|
||||
//---- class TakeFocus ----------------------------------------------------
|
||||
|
||||
/**
|
||||
* Activates the menu bar and shows mnemonics.
|
||||
* On Windows, the popup of the first menu is not shown.
|
||||
* On other platforms, the popup of the first menu is shown.
|
||||
*/
|
||||
private static class TakeFocus
|
||||
extends AbstractAction
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e ) {
|
||||
JMenuBar menuBar = (JMenuBar) e.getSource();
|
||||
JMenu menu = menuBar.getMenu( 0 );
|
||||
if( menu != null ) {
|
||||
MenuSelectionManager.defaultManager().setSelectedPath( SystemInfo.IS_WINDOWS
|
||||
? new MenuElement[] { menuBar, menu }
|
||||
: new MenuElement[] { menuBar, menu, menu.getPopupMenu() } );
|
||||
|
||||
FlatLaf.showMnemonics( menuBar );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ public class FlatMenuItemBorder
|
||||
if( c.getParent() instanceof JMenuBar ) {
|
||||
insets.top = scale( menuBarItemMargins.top );
|
||||
insets.left = scale( menuBarItemMargins.left );
|
||||
insets.bottom = scale( menuBarItemMargins.bottom + 1 );
|
||||
insets.bottom = scale( menuBarItemMargins.bottom );
|
||||
insets.right = scale( menuBarItemMargins.right );
|
||||
return insets;
|
||||
} else
|
||||
|
||||
@@ -0,0 +1,531 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Paint;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.text.AttributedCharacterIterator;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.basic.BasicHTML;
|
||||
import javax.swing.text.View;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.util.Graphics2DProxy;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
|
||||
/**
|
||||
* Renderer for menu items.
|
||||
*
|
||||
* @uiDefault MenuItem.minimumWidth int
|
||||
* @uiDefault MenuItem.minimumIconSize Dimension
|
||||
* @uiDefault MenuItem.textAcceleratorGap int
|
||||
* @uiDefault MenuItem.textNoAcceleratorGap int
|
||||
* @uiDefault MenuItem.acceleratorArrowGap int
|
||||
* @uiDefault MenuItem.checkBackground Color
|
||||
* @uiDefault MenuItem.underlineSelectionBackground Color
|
||||
* @uiDefault MenuItem.underlineSelectionCheckBackground Color
|
||||
* @uiDefault MenuItem.underlineSelectionColor Color
|
||||
* @uiDefault MenuItem.underlineSelectionHeight Color
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatMenuItemRenderer
|
||||
{
|
||||
protected final JMenuItem menuItem;
|
||||
protected final Icon checkIcon;
|
||||
protected final Icon arrowIcon;
|
||||
protected final Font acceleratorFont;
|
||||
protected final String acceleratorDelimiter;
|
||||
|
||||
protected final int minimumWidth = UIManager.getInt( "MenuItem.minimumWidth" );
|
||||
protected final Dimension minimumIconSize;
|
||||
protected final int textAcceleratorGap = FlatUIUtils.getUIInt( "MenuItem.textAcceleratorGap", 28 );
|
||||
protected final int textNoAcceleratorGap = FlatUIUtils.getUIInt( "MenuItem.textNoAcceleratorGap", 6 );
|
||||
protected final int acceleratorArrowGap = FlatUIUtils.getUIInt( "MenuItem.acceleratorArrowGap", 2 );
|
||||
|
||||
protected final Color checkBackground = UIManager.getColor( "MenuItem.checkBackground" );
|
||||
protected final Insets checkMargins = UIManager.getInsets( "MenuItem.checkMargins" );
|
||||
|
||||
protected final Color underlineSelectionBackground = UIManager.getColor( "MenuItem.underlineSelectionBackground" );
|
||||
protected final Color underlineSelectionCheckBackground = UIManager.getColor( "MenuItem.underlineSelectionCheckBackground" );
|
||||
protected final Color underlineSelectionColor = UIManager.getColor( "MenuItem.underlineSelectionColor" );
|
||||
protected final int underlineSelectionHeight = UIManager.getInt( "MenuItem.underlineSelectionHeight" );
|
||||
|
||||
protected FlatMenuItemRenderer( JMenuItem menuItem, Icon checkIcon, Icon arrowIcon,
|
||||
Font acceleratorFont, String acceleratorDelimiter )
|
||||
{
|
||||
this.menuItem = menuItem;
|
||||
this.checkIcon = checkIcon;
|
||||
this.arrowIcon = arrowIcon;
|
||||
this.acceleratorFont = acceleratorFont;
|
||||
this.acceleratorDelimiter = acceleratorDelimiter;
|
||||
|
||||
Dimension minimumIconSize = UIManager.getDimension( "MenuItem.minimumIconSize" );
|
||||
this.minimumIconSize = (minimumIconSize != null) ? minimumIconSize : new Dimension( 16, 16 );
|
||||
}
|
||||
|
||||
protected Dimension getPreferredMenuItemSize() {
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
boolean isTopLevelMenu = isTopLevelMenu( menuItem );
|
||||
|
||||
Rectangle viewRect = new Rectangle( 0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE );
|
||||
Rectangle iconRect = new Rectangle();
|
||||
Rectangle textRect = new Rectangle();
|
||||
|
||||
// layout icon and text
|
||||
SwingUtilities.layoutCompoundLabel( menuItem,
|
||||
menuItem.getFontMetrics( menuItem.getFont() ), menuItem.getText(), getIconForLayout(),
|
||||
menuItem.getVerticalAlignment(), menuItem.getHorizontalAlignment(),
|
||||
menuItem.getVerticalTextPosition(), menuItem.getHorizontalTextPosition(),
|
||||
viewRect, iconRect, textRect, scale( menuItem.getIconTextGap() ) );
|
||||
|
||||
// union icon and text rectangles
|
||||
Rectangle labelRect = iconRect.union( textRect );
|
||||
width += labelRect.width;
|
||||
height = Math.max( labelRect.height, height );
|
||||
|
||||
// accelerator size
|
||||
String accelText = getAcceleratorText();
|
||||
if( accelText != null ) {
|
||||
// gap between text and accelerator
|
||||
width += scale( !isTopLevelMenu ? textAcceleratorGap : menuItem.getIconTextGap() );
|
||||
|
||||
FontMetrics accelFm = menuItem.getFontMetrics( acceleratorFont );
|
||||
width += SwingUtilities.computeStringWidth( accelFm, accelText );
|
||||
height = Math.max( accelFm.getHeight(), height );
|
||||
}
|
||||
|
||||
// arrow size
|
||||
if( !isTopLevelMenu && arrowIcon != null ) {
|
||||
// gap between text and arrow
|
||||
if( accelText == null )
|
||||
width += scale( textNoAcceleratorGap );
|
||||
|
||||
// gap between accelerator and arrow
|
||||
width += scale( acceleratorArrowGap );
|
||||
|
||||
width += arrowIcon.getIconWidth();
|
||||
height = Math.max( arrowIcon.getIconHeight(), height );
|
||||
}
|
||||
|
||||
// add insets
|
||||
Insets insets = menuItem.getInsets();
|
||||
width += insets.left + insets.right;
|
||||
height += insets.top + insets.bottom;
|
||||
|
||||
// minimum width
|
||||
if( !isTopLevelMenu ) {
|
||||
int minimumWidth = FlatUIUtils.minimumWidth( menuItem, this.minimumWidth );
|
||||
width = Math.max( width, scale( minimumWidth ) );
|
||||
}
|
||||
|
||||
return new Dimension( width, height );
|
||||
}
|
||||
|
||||
private void layout( Rectangle viewRect, Rectangle iconRect, Rectangle textRect,
|
||||
Rectangle accelRect, Rectangle arrowRect, Rectangle labelRect )
|
||||
{
|
||||
boolean isTopLevelMenu = isTopLevelMenu( menuItem );
|
||||
|
||||
// layout arrow
|
||||
if( !isTopLevelMenu && arrowIcon != null ) {
|
||||
arrowRect.width = arrowIcon.getIconWidth();
|
||||
arrowRect.height = arrowIcon.getIconHeight();
|
||||
} else
|
||||
arrowRect.setSize( 0, 0 );
|
||||
arrowRect.y = viewRect.y + centerOffset( viewRect.height, arrowRect.height );
|
||||
|
||||
// layout accelerator
|
||||
String accelText = getAcceleratorText();
|
||||
if( accelText != null ) {
|
||||
FontMetrics accelFm = menuItem.getFontMetrics( acceleratorFont );
|
||||
accelRect.width = SwingUtilities.computeStringWidth( accelFm, accelText );
|
||||
accelRect.height = accelFm.getHeight();
|
||||
|
||||
accelRect.y = viewRect.y + centerOffset( viewRect.height, accelRect.height );
|
||||
} else
|
||||
accelRect.setBounds( 0, 0, 0, 0 );
|
||||
|
||||
// compute horizontal positions of accelerator and arrow
|
||||
int accelArrowGap = !isTopLevelMenu ? scale( acceleratorArrowGap ) : 0;
|
||||
if( menuItem.getComponentOrientation().isLeftToRight() ) {
|
||||
// left-to-right
|
||||
arrowRect.x = viewRect.x + viewRect.width - arrowRect.width;
|
||||
accelRect.x = arrowRect.x - accelArrowGap - accelRect.width;
|
||||
} else {
|
||||
// right-to-left
|
||||
arrowRect.x = viewRect.x;
|
||||
accelRect.x = arrowRect.x + accelArrowGap + arrowRect.width;
|
||||
}
|
||||
|
||||
// width of accelerator, arrow and gap
|
||||
int accelArrowWidth = accelRect.width + arrowRect.width;
|
||||
if( accelText != null )
|
||||
accelArrowWidth += scale( !isTopLevelMenu ? textAcceleratorGap : menuItem.getIconTextGap() );
|
||||
if( !isTopLevelMenu && arrowIcon != null ) {
|
||||
if( accelText == null )
|
||||
accelArrowWidth += scale( textNoAcceleratorGap );
|
||||
accelArrowWidth += scale( acceleratorArrowGap );
|
||||
}
|
||||
|
||||
// label rectangle is view rectangle subtracted by accelerator, arrow and gap
|
||||
labelRect.setBounds( viewRect );
|
||||
labelRect.width -= accelArrowWidth;
|
||||
if( !menuItem.getComponentOrientation().isLeftToRight() )
|
||||
labelRect.x += accelArrowWidth;
|
||||
|
||||
// layout icon and text
|
||||
SwingUtilities.layoutCompoundLabel( menuItem,
|
||||
menuItem.getFontMetrics( menuItem.getFont() ), menuItem.getText(), getIconForLayout(),
|
||||
menuItem.getVerticalAlignment(), menuItem.getHorizontalAlignment(),
|
||||
menuItem.getVerticalTextPosition(), menuItem.getHorizontalTextPosition(),
|
||||
labelRect, iconRect, textRect, scale( menuItem.getIconTextGap() ) );
|
||||
}
|
||||
|
||||
private static int centerOffset( int wh1, int wh2 ) {
|
||||
return (wh1 / 2) - (wh2 / 2);
|
||||
}
|
||||
|
||||
protected void paintMenuItem( Graphics g, Color selectionBackground, Color selectionForeground,
|
||||
Color disabledForeground, Color acceleratorForeground, Color acceleratorSelectionForeground )
|
||||
{
|
||||
Rectangle viewRect = new Rectangle( menuItem.getWidth(), menuItem.getHeight() );
|
||||
|
||||
// subtract insets
|
||||
Insets insets = menuItem.getInsets();
|
||||
viewRect.x += insets.left;
|
||||
viewRect.y += insets.top;
|
||||
viewRect.width -= (insets.left + insets.right);
|
||||
viewRect.height -= (insets.top + insets.bottom);
|
||||
|
||||
Rectangle iconRect = new Rectangle();
|
||||
Rectangle textRect = new Rectangle();
|
||||
Rectangle accelRect = new Rectangle();
|
||||
Rectangle arrowRect = new Rectangle();
|
||||
Rectangle labelRect = new Rectangle();
|
||||
|
||||
layout( viewRect, iconRect, textRect, accelRect, arrowRect, labelRect );
|
||||
|
||||
/*debug
|
||||
g.setColor( Color.green ); g.drawRect( viewRect.x, viewRect.y, viewRect.width - 1, viewRect.height - 1 );
|
||||
g.setColor( Color.red ); g.drawRect( labelRect.x, labelRect.y, labelRect.width - 1, labelRect.height - 1 );
|
||||
g.setColor( Color.blue ); g.drawRect( iconRect.x, iconRect.y, iconRect.width - 1, iconRect.height - 1 );
|
||||
g.setColor( Color.cyan ); g.drawRect( textRect.x, textRect.y, textRect.width - 1, textRect.height - 1 );
|
||||
g.setColor( Color.magenta ); g.drawRect( accelRect.x, accelRect.y, accelRect.width - 1, accelRect.height - 1 );
|
||||
g.setColor( Color.orange ); g.drawRect( arrowRect.x, arrowRect.y, arrowRect.width - 1, arrowRect.height - 1 );
|
||||
debug*/
|
||||
|
||||
paintBackground( g, selectionBackground );
|
||||
paintIcon( g, iconRect, getIconForPainting() );
|
||||
paintText( g, textRect, menuItem.getText(), selectionForeground, disabledForeground );
|
||||
paintAccelerator( g, accelRect, getAcceleratorText(), acceleratorForeground, acceleratorSelectionForeground, disabledForeground );
|
||||
if( !isTopLevelMenu( menuItem ) )
|
||||
paintArrowIcon( g, arrowRect, arrowIcon );
|
||||
}
|
||||
|
||||
protected void paintBackground( Graphics g, Color selectionBackground ) {
|
||||
boolean armedOrSelected = isArmedOrSelected( menuItem );
|
||||
if( menuItem.isOpaque() || armedOrSelected ) {
|
||||
int width = menuItem.getWidth();
|
||||
int height = menuItem.getHeight();
|
||||
|
||||
// paint background
|
||||
g.setColor( armedOrSelected
|
||||
? (isUnderlineSelection()
|
||||
? deriveBackground( underlineSelectionBackground )
|
||||
: selectionBackground)
|
||||
: menuItem.getBackground() );
|
||||
g.fillRect( 0, 0, width, height );
|
||||
|
||||
// paint underline
|
||||
if( armedOrSelected && isUnderlineSelection() ) {
|
||||
int underlineHeight = scale( underlineSelectionHeight );
|
||||
g.setColor( underlineSelectionColor );
|
||||
if( isTopLevelMenu( menuItem ) ) {
|
||||
// paint underline at bottom
|
||||
g.fillRect( 0, height - underlineHeight, width, underlineHeight );
|
||||
} else if( menuItem.getComponentOrientation().isLeftToRight() ) {
|
||||
// paint underline at left side
|
||||
g.fillRect( 0, 0, underlineHeight, height );
|
||||
} else {
|
||||
// paint underline at right side
|
||||
g.fillRect( width - underlineHeight, 0, underlineHeight, height );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected Color deriveBackground( Color background ) {
|
||||
Color baseColor = menuItem.isOpaque()
|
||||
? menuItem.getBackground()
|
||||
: FlatUIUtils.getParentBackground( menuItem );
|
||||
|
||||
return FlatUIUtils.deriveColor( background, baseColor );
|
||||
}
|
||||
|
||||
protected void paintIcon( Graphics g, Rectangle iconRect, Icon icon ) {
|
||||
// if checkbox/radiobutton menu item is selected and also has a custom icon,
|
||||
// then use filled icon background to indicate selection (instead of using checkIcon)
|
||||
if( menuItem.isSelected() && checkIcon != null && icon != checkIcon ) {
|
||||
Rectangle r = FlatUIUtils.addInsets( iconRect, scale( checkMargins ) );
|
||||
g.setColor( deriveBackground( isUnderlineSelection() ? underlineSelectionCheckBackground : checkBackground ) );
|
||||
g.fillRect( r.x, r.y, r.width, r.height );
|
||||
}
|
||||
|
||||
paintIcon( g, menuItem, icon, iconRect );
|
||||
}
|
||||
|
||||
protected void paintText( Graphics g, Rectangle textRect, String text, Color selectionForeground, Color disabledForeground ) {
|
||||
View htmlView = (View) menuItem.getClientProperty( BasicHTML.propertyKey );
|
||||
if( htmlView != null ) {
|
||||
paintHTMLText( g, menuItem, textRect, htmlView, isUnderlineSelection() ? null : selectionForeground );
|
||||
return;
|
||||
}
|
||||
|
||||
int mnemonicIndex = FlatLaf.isShowMnemonics() ? menuItem.getDisplayedMnemonicIndex() : -1;
|
||||
Color foreground = (isTopLevelMenu( menuItem ) ? menuItem.getParent() : menuItem).getForeground();
|
||||
|
||||
paintText( g, menuItem, textRect, text, mnemonicIndex, menuItem.getFont(),
|
||||
foreground, isUnderlineSelection() ? foreground : selectionForeground, disabledForeground );
|
||||
}
|
||||
|
||||
protected void paintAccelerator( Graphics g, Rectangle accelRect, String accelText,
|
||||
Color foreground, Color selectionForeground, Color disabledForeground )
|
||||
{
|
||||
paintText( g, menuItem, accelRect, accelText, -1, acceleratorFont,
|
||||
foreground, isUnderlineSelection() ? foreground : selectionForeground, disabledForeground );
|
||||
}
|
||||
|
||||
protected void paintArrowIcon( Graphics g, Rectangle arrowRect, Icon arrowIcon ) {
|
||||
paintIcon( g, menuItem, arrowIcon, arrowRect );
|
||||
}
|
||||
|
||||
protected static void paintIcon( Graphics g, JMenuItem menuItem, Icon icon, Rectangle iconRect ) {
|
||||
if( icon == null )
|
||||
return;
|
||||
|
||||
// center because the real icon may be smaller than dimension in iconRect
|
||||
int x = iconRect.x + centerOffset( iconRect.width, icon.getIconWidth() );
|
||||
int y = iconRect.y + centerOffset( iconRect.height, icon.getIconHeight() );
|
||||
|
||||
// paint
|
||||
icon.paintIcon( menuItem, g, x, y );
|
||||
}
|
||||
|
||||
protected static void paintText( Graphics g, JMenuItem menuItem,
|
||||
Rectangle textRect, String text, int mnemonicIndex, Font font,
|
||||
Color foreground, Color selectionForeground, Color disabledForeground )
|
||||
{
|
||||
if( text == null || text.isEmpty() )
|
||||
return;
|
||||
|
||||
FontMetrics fm = menuItem.getFontMetrics( font );
|
||||
|
||||
Font oldFont = g.getFont();
|
||||
g.setFont( font );
|
||||
g.setColor( !menuItem.isEnabled()
|
||||
? disabledForeground
|
||||
: (isArmedOrSelected( menuItem )
|
||||
? selectionForeground
|
||||
: foreground) );
|
||||
|
||||
FlatUIUtils.drawStringUnderlineCharAt( menuItem, g, text, mnemonicIndex,
|
||||
textRect.x, textRect.y + fm.getAscent() );
|
||||
|
||||
g.setFont( oldFont );
|
||||
}
|
||||
|
||||
protected static void paintHTMLText( Graphics g, JMenuItem menuItem,
|
||||
Rectangle textRect, View htmlView, Color selectionForeground )
|
||||
{
|
||||
if( isArmedOrSelected( menuItem ) && selectionForeground != null )
|
||||
g = new GraphicsProxyWithTextColor( (Graphics2D) g, selectionForeground );
|
||||
|
||||
htmlView.paint( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ), textRect );
|
||||
}
|
||||
|
||||
protected static boolean isArmedOrSelected( JMenuItem menuItem ) {
|
||||
return menuItem.isArmed() || (menuItem instanceof JMenu && menuItem.isSelected());
|
||||
}
|
||||
|
||||
protected static boolean isTopLevelMenu( JMenuItem menuItem ) {
|
||||
return menuItem instanceof JMenu && ((JMenu)menuItem).isTopLevelMenu();
|
||||
}
|
||||
|
||||
protected boolean isUnderlineSelection() {
|
||||
return "underline".equals( UIManager.getString( "MenuItem.selectionType" ) );
|
||||
}
|
||||
|
||||
private Icon getIconForPainting() {
|
||||
Icon icon = menuItem.getIcon();
|
||||
|
||||
if( icon == null && checkIcon != null && !isTopLevelMenu( menuItem ) )
|
||||
return checkIcon;
|
||||
|
||||
if( icon == null )
|
||||
return null;
|
||||
|
||||
if( !menuItem.isEnabled() )
|
||||
return menuItem.getDisabledIcon();
|
||||
|
||||
if( menuItem.getModel().isPressed() && menuItem.isArmed() ) {
|
||||
Icon pressedIcon = menuItem.getPressedIcon();
|
||||
if( pressedIcon != null )
|
||||
return pressedIcon;
|
||||
}
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
private Icon getIconForLayout() {
|
||||
Icon icon = menuItem.getIcon();
|
||||
|
||||
if( isTopLevelMenu( menuItem ) )
|
||||
return (icon != null) ? new MinSizeIcon( icon ) : null;
|
||||
|
||||
return new MinSizeIcon( (icon != null) ? icon : checkIcon );
|
||||
}
|
||||
|
||||
private KeyStroke cachedAccelerator;
|
||||
private String cachedAcceleratorText;
|
||||
|
||||
private String getAcceleratorText() {
|
||||
KeyStroke accelerator = menuItem.getAccelerator();
|
||||
if( accelerator == null )
|
||||
return null;
|
||||
|
||||
if( accelerator == cachedAccelerator )
|
||||
return cachedAcceleratorText;
|
||||
|
||||
cachedAccelerator = accelerator;
|
||||
cachedAcceleratorText = getTextForAccelerator( accelerator );
|
||||
|
||||
return cachedAcceleratorText;
|
||||
}
|
||||
|
||||
protected String getTextForAccelerator( KeyStroke accelerator ) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
int modifiers = accelerator.getModifiers();
|
||||
if( modifiers != 0 )
|
||||
buf.append( InputEvent.getModifiersExText( modifiers ) ).append( acceleratorDelimiter );
|
||||
|
||||
int keyCode = accelerator.getKeyCode();
|
||||
if( keyCode != 0 )
|
||||
buf.append( KeyEvent.getKeyText( keyCode ) );
|
||||
else
|
||||
buf.append( accelerator.getKeyChar() );
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
//---- class MinSizeIcon --------------------------------------------------
|
||||
|
||||
private class MinSizeIcon
|
||||
implements Icon
|
||||
{
|
||||
private final Icon delegate;
|
||||
|
||||
MinSizeIcon( Icon delegate ) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconWidth() {
|
||||
int iconWidth = (delegate != null) ? delegate.getIconWidth() : 0;
|
||||
return Math.max( iconWidth, scale( minimumIconSize.width ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconHeight() {
|
||||
int iconHeight = (delegate != null) ? delegate.getIconHeight() : 0;
|
||||
return Math.max( iconHeight, scale( minimumIconSize.height ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintIcon( Component c, Graphics g, int x, int y ) {
|
||||
}
|
||||
}
|
||||
|
||||
//---- class GraphicsProxyWithTextColor -----------------------------------
|
||||
|
||||
private static class GraphicsProxyWithTextColor
|
||||
extends Graphics2DProxy
|
||||
{
|
||||
private final Color textColor;
|
||||
|
||||
GraphicsProxyWithTextColor( Graphics2D delegate, Color textColor ) {
|
||||
super( delegate );
|
||||
this.textColor = textColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawString( String str, int x, int y ) {
|
||||
Paint oldPaint = getPaint();
|
||||
setPaint( textColor );
|
||||
super.drawString( str, x, y );
|
||||
setPaint( oldPaint );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawString( String str, float x, float y ) {
|
||||
Paint oldPaint = getPaint();
|
||||
setPaint( textColor );
|
||||
super.drawString( str, x, y );
|
||||
setPaint( oldPaint );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawString( AttributedCharacterIterator iterator, int x, int y ) {
|
||||
Paint oldPaint = getPaint();
|
||||
setPaint( textColor );
|
||||
super.drawString( iterator, x, y );
|
||||
setPaint( oldPaint );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawString( AttributedCharacterIterator iterator, float x, float y ) {
|
||||
Paint oldPaint = getPaint();
|
||||
setPaint( textColor );
|
||||
super.drawString( iterator, x, y );
|
||||
setPaint( oldPaint );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawChars( char[] data, int offset, int length, int x, int y ) {
|
||||
Paint oldPaint = getPaint();
|
||||
setPaint( textColor );
|
||||
super.drawChars( data, offset, length, x, y );
|
||||
setPaint( oldPaint );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,48 +16,47 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import java.awt.Color;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Rectangle;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import javax.swing.ButtonModel;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicMenuItemUI;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JMenuItem}.
|
||||
*
|
||||
* <!-- BasicMenuItemUI -->
|
||||
*
|
||||
* @uiDefault MenuItem.font Font
|
||||
* @uiDefault MenuItem.background Color
|
||||
* @uiDefault MenuItem.foreground Color
|
||||
* @uiDefault MenuItem.disabledForeground Color
|
||||
* @uiDefault MenuItem.selectionBackground Color
|
||||
* @uiDefault MenuItem.selectionForeground Color
|
||||
* @uiDefault MenuItem.acceleratorForeground Color
|
||||
* @uiDefault MenuItem.acceleratorSelectionForeground Color
|
||||
* @uiDefault MenuItem.acceleratorFont Font defaults to MenuItem.font
|
||||
* @uiDefault MenuItem.acceleratorDelimiter String
|
||||
* @uiDefault MenuItem.border Border
|
||||
* @uiDefault MenuItem.borderPainted boolean
|
||||
* @uiDefault MenuItem.margin Insets
|
||||
* @uiDefault MenuItem.arrowIcon Icon
|
||||
* @uiDefault MenuItem.checkIcon Icon
|
||||
* @uiDefault MenuItem.opaque boolean
|
||||
* @uiDefault MenuItem.evenHeight boolean
|
||||
* @uiDefault MenuItem.font Font
|
||||
* @uiDefault MenuItem.background Color
|
||||
* @uiDefault MenuItem.foreground Color
|
||||
* @uiDefault MenuItem.disabledForeground Color
|
||||
* @uiDefault MenuItem.selectionBackground Color
|
||||
* @uiDefault MenuItem.selectionForeground Color
|
||||
* @uiDefault MenuItem.acceleratorForeground Color
|
||||
* @uiDefault MenuItem.acceleratorSelectionForeground Color
|
||||
* @uiDefault MenuItem.acceleratorFont Font defaults to MenuItem.font
|
||||
* @uiDefault MenuItem.acceleratorDelimiter String
|
||||
* @uiDefault MenuItem.border Border
|
||||
* @uiDefault MenuItem.borderPainted boolean
|
||||
* @uiDefault MenuItem.margin Insets
|
||||
* @uiDefault MenuItem.arrowIcon Icon
|
||||
* @uiDefault MenuItem.checkIcon Icon
|
||||
* @uiDefault MenuItem.opaque boolean
|
||||
*
|
||||
* <!-- FlatMenuItemUI -->
|
||||
*
|
||||
* @uiDefault MenuItem.iconTextGap int
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatMenuItemUI
|
||||
extends BasicMenuItemUI
|
||||
{
|
||||
private FlatMenuItemRenderer renderer;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatMenuItemUI();
|
||||
}
|
||||
@@ -66,42 +65,30 @@ public class FlatMenuItemUI
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
|
||||
// scale
|
||||
defaultTextIconGap = scale( defaultTextIconGap );
|
||||
}
|
||||
LookAndFeel.installProperty( menuItem, "iconTextGap", FlatUIUtils.getUIInt( "MenuItem.iconTextGap", 4 ) );
|
||||
|
||||
/**
|
||||
* Scale defaultTextIconGap again if iconTextGap property has changed.
|
||||
*/
|
||||
@Override
|
||||
protected PropertyChangeListener createPropertyChangeListener( JComponent c ) {
|
||||
PropertyChangeListener superListener = super.createPropertyChangeListener( c );
|
||||
return e -> {
|
||||
superListener.propertyChange( e );
|
||||
if( e.getPropertyName() == "iconTextGap" )
|
||||
defaultTextIconGap = scale( defaultTextIconGap );
|
||||
};
|
||||
renderer = createRenderer();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintText( Graphics g, JMenuItem menuItem, Rectangle textRect, String text ) {
|
||||
paintText( g, menuItem, textRect, text, disabledForeground, selectionForeground );
|
||||
protected void uninstallDefaults() {
|
||||
super.uninstallDefaults();
|
||||
|
||||
renderer = null;
|
||||
}
|
||||
|
||||
public static void paintText( Graphics g, JMenuItem menuItem, Rectangle textRect,
|
||||
String text, Color disabledForeground, Color selectionForeground )
|
||||
{
|
||||
FontMetrics fm = menuItem.getFontMetrics( menuItem.getFont() );
|
||||
int mnemonicIndex = FlatLaf.isShowMnemonics() ? menuItem.getDisplayedMnemonicIndex() : -1;
|
||||
protected FlatMenuItemRenderer createRenderer() {
|
||||
return new FlatMenuItemRenderer( menuItem, checkIcon, arrowIcon, acceleratorFont, acceleratorDelimiter );
|
||||
}
|
||||
|
||||
ButtonModel model = menuItem.getModel();
|
||||
g.setColor( !model.isEnabled()
|
||||
? disabledForeground
|
||||
: (model.isArmed() || (menuItem instanceof JMenu && model.isSelected())
|
||||
? selectionForeground
|
||||
: menuItem.getForeground()) );
|
||||
@Override
|
||||
protected Dimension getPreferredMenuItemSize( JComponent c, Icon checkIcon, Icon arrowIcon, int defaultTextIconGap ) {
|
||||
return renderer.getPreferredMenuItemSize();
|
||||
}
|
||||
|
||||
FlatUIUtils.drawStringUnderlineCharAt( menuItem, g, text, mnemonicIndex,
|
||||
textRect.x, textRect.y + fm.getAscent() );
|
||||
@Override
|
||||
public void paint( Graphics g, JComponent c ) {
|
||||
renderer.paintMenuItem( g, selectionBackground, selectionForeground, disabledForeground,
|
||||
acceleratorForeground, acceleratorSelectionForeground );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,16 +16,17 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import javax.swing.ButtonModel;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.event.MouseInputListener;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
@@ -36,30 +37,30 @@ import javax.swing.plaf.basic.BasicMenuUI;
|
||||
*
|
||||
* <!-- BasicMenuUI -->
|
||||
*
|
||||
* @uiDefault Menu.font Font
|
||||
* @uiDefault Menu.background Color
|
||||
* @uiDefault Menu.foreground Color
|
||||
* @uiDefault Menu.disabledForeground Color
|
||||
* @uiDefault Menu.selectionBackground Color
|
||||
* @uiDefault Menu.selectionForeground Color
|
||||
* @uiDefault Menu.acceleratorForeground Color
|
||||
* @uiDefault Menu.acceleratorSelectionForeground Color
|
||||
* @uiDefault MenuItem.acceleratorFont Font defaults to MenuItem.font
|
||||
* @uiDefault MenuItem.acceleratorDelimiter String
|
||||
* @uiDefault Menu.border Border
|
||||
* @uiDefault Menu.borderPainted boolean
|
||||
* @uiDefault Menu.margin Insets
|
||||
* @uiDefault Menu.arrowIcon Icon
|
||||
* @uiDefault Menu.checkIcon Icon
|
||||
* @uiDefault Menu.opaque boolean
|
||||
* @uiDefault Menu.evenHeight boolean
|
||||
* @uiDefault Menu.crossMenuMnemonic boolean default is false
|
||||
* @uiDefault Menu.useMenuBarBackgroundForTopLevel boolean default is false
|
||||
* @uiDefault MenuBar.background Color used if Menu.useMenuBarBackgroundForTopLevel is true
|
||||
* @uiDefault Menu.font Font
|
||||
* @uiDefault Menu.background Color
|
||||
* @uiDefault Menu.foreground Color
|
||||
* @uiDefault Menu.disabledForeground Color
|
||||
* @uiDefault Menu.selectionBackground Color
|
||||
* @uiDefault Menu.selectionForeground Color
|
||||
* @uiDefault Menu.acceleratorForeground Color
|
||||
* @uiDefault Menu.acceleratorSelectionForeground Color
|
||||
* @uiDefault MenuItem.acceleratorFont Font defaults to MenuItem.font
|
||||
* @uiDefault MenuItem.acceleratorDelimiter String
|
||||
* @uiDefault Menu.border Border
|
||||
* @uiDefault Menu.borderPainted boolean
|
||||
* @uiDefault Menu.margin Insets
|
||||
* @uiDefault Menu.arrowIcon Icon
|
||||
* @uiDefault Menu.checkIcon Icon
|
||||
* @uiDefault Menu.opaque boolean
|
||||
* @uiDefault Menu.crossMenuMnemonic boolean default is false
|
||||
* @uiDefault Menu.useMenuBarBackgroundForTopLevel boolean default is false
|
||||
* @uiDefault MenuBar.background Color used if Menu.useMenuBarBackgroundForTopLevel is true
|
||||
*
|
||||
* <!-- FlatMenuUI -->
|
||||
*
|
||||
* @uiDefault MenuBar.hoverBackground Color
|
||||
* @uiDefault MenuItem.iconTextGap int
|
||||
* @uiDefault MenuBar.hoverBackground Color
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
@@ -67,6 +68,7 @@ public class FlatMenuUI
|
||||
extends BasicMenuUI
|
||||
{
|
||||
private Color hoverBackground;
|
||||
private FlatMenuItemRenderer renderer;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatMenuUI();
|
||||
@@ -76,12 +78,12 @@ public class FlatMenuUI
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
|
||||
LookAndFeel.installProperty( menuItem, "iconTextGap", FlatUIUtils.getUIInt( "MenuItem.iconTextGap", 4 ) );
|
||||
|
||||
menuItem.setRolloverEnabled( true );
|
||||
|
||||
hoverBackground = UIManager.getColor( "MenuBar.hoverBackground" );
|
||||
|
||||
// scale
|
||||
defaultTextIconGap = scale( defaultTextIconGap );
|
||||
renderer = createRenderer();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -89,19 +91,11 @@ public class FlatMenuUI
|
||||
super.uninstallDefaults();
|
||||
|
||||
hoverBackground = null;
|
||||
renderer = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scale defaultTextIconGap again if iconTextGap property has changed.
|
||||
*/
|
||||
@Override
|
||||
protected PropertyChangeListener createPropertyChangeListener( JComponent c ) {
|
||||
PropertyChangeListener superListener = super.createPropertyChangeListener( c );
|
||||
return e -> {
|
||||
superListener.propertyChange( e );
|
||||
if( e.getPropertyName() == "iconTextGap" )
|
||||
defaultTextIconGap = scale( defaultTextIconGap );
|
||||
};
|
||||
protected FlatMenuItemRenderer createRenderer() {
|
||||
return new FlatMenuRenderer( menuItem, checkIcon, arrowIcon, acceleratorFont, acceleratorDelimiter );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -130,19 +124,37 @@ public class FlatMenuUI
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintBackground( Graphics g, JMenuItem menuItem, Color bgColor ) {
|
||||
ButtonModel model = menuItem.getModel();
|
||||
if( model.isArmed() || model.isSelected() ) {
|
||||
super.paintBackground( g, menuItem, bgColor );
|
||||
} else if( model.isRollover() && model.isEnabled() && ((JMenu)menuItem).isTopLevelMenu() ) {
|
||||
FlatUIUtils.setColor( g, hoverBackground, menuItem.getBackground() );
|
||||
g.fillRect( 0, 0, menuItem.getWidth(), menuItem.getHeight() );
|
||||
} else
|
||||
super.paintBackground( g, menuItem, bgColor );
|
||||
protected Dimension getPreferredMenuItemSize( JComponent c, Icon checkIcon, Icon arrowIcon, int defaultTextIconGap ) {
|
||||
return renderer.getPreferredMenuItemSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintText( Graphics g, JMenuItem menuItem, Rectangle textRect, String text ) {
|
||||
FlatMenuItemUI.paintText( g, menuItem, textRect, text, disabledForeground, selectionForeground );
|
||||
public void paint( Graphics g, JComponent c ) {
|
||||
renderer.paintMenuItem( g, selectionBackground, selectionForeground, disabledForeground,
|
||||
acceleratorForeground, acceleratorSelectionForeground );
|
||||
}
|
||||
|
||||
//---- class FlatMenuRenderer ---------------------------------------------
|
||||
|
||||
protected class FlatMenuRenderer
|
||||
extends FlatMenuItemRenderer
|
||||
{
|
||||
protected FlatMenuRenderer( JMenuItem menuItem, Icon checkIcon, Icon arrowIcon,
|
||||
Font acceleratorFont, String acceleratorDelimiter )
|
||||
{
|
||||
super( menuItem, checkIcon, arrowIcon, acceleratorFont, acceleratorDelimiter );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintBackground( Graphics g, Color selectionBackground ) {
|
||||
ButtonModel model = menuItem.getModel();
|
||||
if( model.isRollover() && !model.isArmed() && !model.isSelected() &&
|
||||
model.isEnabled() && ((JMenu)menuItem).isTopLevelMenu() )
|
||||
{
|
||||
g.setColor( deriveBackground( hoverBackground ) );
|
||||
g.fillRect( 0, 0, menuItem.getWidth(), menuItem.getHeight() );
|
||||
} else
|
||||
super.paintBackground( g, selectionBackground );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.awt.event.KeyAdapter;
|
||||
@@ -34,7 +34,7 @@ import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicPasswordFieldUI;
|
||||
import javax.swing.text.Caret;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JPasswordField}.
|
||||
@@ -57,8 +57,6 @@ import com.formdev.flatlaf.FlatClientProperties;
|
||||
*
|
||||
* <!-- FlatPasswordFieldUI -->
|
||||
*
|
||||
* @uiDefault TextComponent.arc int
|
||||
* @uiDefault Component.focusWidth int
|
||||
* @uiDefault Component.minimumWidth int
|
||||
* @uiDefault Component.isIntelliJTheme boolean
|
||||
* @uiDefault PasswordField.placeholderForeground Color
|
||||
@@ -70,8 +68,6 @@ import com.formdev.flatlaf.FlatClientProperties;
|
||||
public class FlatPasswordFieldUI
|
||||
extends BasicPasswordFieldUI
|
||||
{
|
||||
protected int arc;
|
||||
protected int focusWidth;
|
||||
protected int minimumWidth;
|
||||
protected boolean isIntelliJTheme;
|
||||
protected Color placeholderForeground;
|
||||
@@ -89,16 +85,14 @@ public class FlatPasswordFieldUI
|
||||
super.installDefaults();
|
||||
|
||||
String prefix = getPropertyPrefix();
|
||||
arc = UIManager.getInt( "TextComponent.arc" );
|
||||
focusWidth = UIManager.getInt( "Component.focusWidth" );
|
||||
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
||||
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
||||
placeholderForeground = UIManager.getColor( prefix + ".placeholderForeground" );
|
||||
capsLockIcon = UIManager.getIcon( "PasswordField.capsLockIcon" );
|
||||
|
||||
LookAndFeel.installProperty( getComponent(), "opaque", focusWidth == 0 );
|
||||
LookAndFeel.installProperty( getComponent(), "opaque", false );
|
||||
|
||||
MigLayoutVisualPadding.install( getComponent(), focusWidth );
|
||||
MigLayoutVisualPadding.install( getComponent() );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -153,17 +147,16 @@ public class FlatPasswordFieldUI
|
||||
@Override
|
||||
protected void propertyChange( PropertyChangeEvent e ) {
|
||||
super.propertyChange( e );
|
||||
|
||||
if( FlatClientProperties.PLACEHOLDER_TEXT.equals( e.getPropertyName() ) )
|
||||
getComponent().repaint();
|
||||
FlatTextFieldUI.propertyChange( getComponent(), e );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintSafely( Graphics g ) {
|
||||
FlatTextFieldUI.paintBackground( g, getComponent(), focusWidth, arc, isIntelliJTheme );
|
||||
FlatTextFieldUI.paintBackground( g, getComponent(), isIntelliJTheme );
|
||||
FlatTextFieldUI.paintPlaceholder( g, getComponent(), placeholderForeground );
|
||||
paintCapsLock( g );
|
||||
super.paintSafely( g );
|
||||
|
||||
super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) );
|
||||
}
|
||||
|
||||
protected void paintCapsLock( Graphics g ) {
|
||||
@@ -184,18 +177,11 @@ public class FlatPasswordFieldUI
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize( JComponent c ) {
|
||||
return applyMinimumWidth( super.getPreferredSize( c ), c );
|
||||
return FlatTextFieldUI.applyMinimumWidth( c, super.getPreferredSize( c ), minimumWidth );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize( JComponent c ) {
|
||||
return applyMinimumWidth( super.getMinimumSize( c ), c );
|
||||
}
|
||||
|
||||
private Dimension applyMinimumWidth( Dimension size, JComponent c ) {
|
||||
int minimumWidth = FlatUIUtils.minimumWidth( getComponent(), this.minimumWidth );
|
||||
int focusWidth = (c.getBorder() instanceof FlatBorder) ? this.focusWidth : 0;
|
||||
size.width = Math.max( size.width, scale( minimumWidth + (focusWidth * 2) ) );
|
||||
return size;
|
||||
return FlatTextFieldUI.applyMinimumWidth( c, super.getMinimumSize( c ), minimumWidth );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,375 @@
|
||||
/*
|
||||
* Copyright 2020 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.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Panel;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.event.ComponentListener;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLayeredPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.Popup;
|
||||
import javax.swing.PopupFactory;
|
||||
import javax.swing.RootPaneContainer;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.Border;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
|
||||
/**
|
||||
* A popup factory that adds drop shadows to popups on Windows.
|
||||
* On macOS and Linux, heavy weight popups (without drop shadow) are produced and the
|
||||
* operating system automatically adds drop shadows.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatPopupFactory
|
||||
extends PopupFactory
|
||||
{
|
||||
private Method java8getPopupMethod;
|
||||
private Method java9getPopupMethod;
|
||||
|
||||
@Override
|
||||
public Popup getPopup( Component owner, Component contents, int x, int y )
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
if( !isDropShadowPainted( owner, contents ) )
|
||||
return new NonFlashingPopup( super.getPopup( owner, contents, x, y ), contents );
|
||||
|
||||
// macOS and Linux adds drop shadow to heavy weight popups
|
||||
if( SystemInfo.IS_MAC || SystemInfo.IS_LINUX ) {
|
||||
Popup popup = getHeavyWeightPopup( owner, contents, x, y );
|
||||
if( popup == null )
|
||||
popup = super.getPopup( owner, contents, x, y );
|
||||
return new NonFlashingPopup( popup, contents );
|
||||
}
|
||||
|
||||
// create drop shadow popup
|
||||
return new DropShadowPopup( super.getPopup( owner, contents, x, y ), owner, contents );
|
||||
}
|
||||
|
||||
private boolean isDropShadowPainted( Component owner, Component contents ) {
|
||||
Boolean b = isDropShadowPainted( owner );
|
||||
if( b != null )
|
||||
return b;
|
||||
|
||||
b = isDropShadowPainted( contents );
|
||||
if( b != null )
|
||||
return b;
|
||||
|
||||
return UIManager.getBoolean( "Popup.dropShadowPainted" );
|
||||
}
|
||||
|
||||
private Boolean isDropShadowPainted( Component c ) {
|
||||
if( !(c instanceof JComponent) )
|
||||
return null;
|
||||
|
||||
Object value = ((JComponent)c).getClientProperty( FlatClientProperties.POPUP_DROP_SHADOW_PAINTED );
|
||||
return (value instanceof Boolean ) ? (Boolean) value : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* There is no API in Java 8 to force creation of heavy weight popups,
|
||||
* but it is possible with reflection. Java 9 provides a new method.
|
||||
*
|
||||
* When changing FlatLaf system requirements to Java 9+,
|
||||
* then this method can be replaced with:
|
||||
* return getPopup( owner, contents, x, y, true );
|
||||
*/
|
||||
private Popup getHeavyWeightPopup( Component owner, Component contents, int x, int y )
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
try {
|
||||
if( SystemInfo.IS_JAVA_9_OR_LATER ) {
|
||||
if( java9getPopupMethod == null ) {
|
||||
java9getPopupMethod = PopupFactory.class.getDeclaredMethod(
|
||||
"getPopup", Component.class, Component.class, int.class, int.class, boolean.class );
|
||||
}
|
||||
return (Popup) java9getPopupMethod.invoke( this, owner, contents, x, y, true );
|
||||
} else {
|
||||
// Java 8
|
||||
if( java8getPopupMethod == null ) {
|
||||
java8getPopupMethod = PopupFactory.class.getDeclaredMethod(
|
||||
"getPopup", Component.class, Component.class, int.class, int.class, int.class );
|
||||
java8getPopupMethod.setAccessible( true );
|
||||
}
|
||||
return (Popup) java8getPopupMethod.invoke( this, owner, contents, x, y, /*HEAVY_WEIGHT_POPUP*/ 2 );
|
||||
}
|
||||
} catch( NoSuchMethodException | SecurityException | IllegalAccessException | InvocationTargetException ex ) {
|
||||
// ignore
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//---- class NonFlashingPopup ---------------------------------------------
|
||||
|
||||
private class NonFlashingPopup
|
||||
extends Popup
|
||||
{
|
||||
private Popup delegate;
|
||||
|
||||
// heavy weight
|
||||
protected Window popupWindow;
|
||||
private Color oldPopupWindowBackground;
|
||||
|
||||
NonFlashingPopup( Popup delegate, Component contents ) {
|
||||
this.delegate = delegate;
|
||||
|
||||
popupWindow = SwingUtilities.windowForComponent( contents );
|
||||
if( popupWindow != null ) {
|
||||
// heavy weight popup
|
||||
|
||||
// fix background flashing which may occur on some platforms
|
||||
// (e.g. macOS and Linux) when using dark theme
|
||||
oldPopupWindowBackground = popupWindow.getBackground();
|
||||
popupWindow.setBackground( contents.getBackground() );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
if( delegate != null )
|
||||
delegate.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hide() {
|
||||
if( delegate != null ) {
|
||||
delegate.hide();
|
||||
delegate = null;
|
||||
}
|
||||
|
||||
if( popupWindow != null ) {
|
||||
// restore background so that it can not affect other LaFs (when switching)
|
||||
// because popup windows are cached and reused
|
||||
popupWindow.setBackground( oldPopupWindowBackground );
|
||||
popupWindow = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---- class DropShadowPopup ----------------------------------------------
|
||||
|
||||
private class DropShadowPopup
|
||||
extends NonFlashingPopup
|
||||
{
|
||||
private final Component owner;
|
||||
|
||||
// light weight
|
||||
private JComponent lightComp;
|
||||
private Border oldBorder;
|
||||
private boolean oldOpaque;
|
||||
|
||||
// medium weight
|
||||
private boolean mediumWeightShown;
|
||||
private Panel mediumWeightPanel;
|
||||
private JPanel dropShadowPanel;
|
||||
private ComponentListener mediumPanelListener;
|
||||
|
||||
// heavy weight
|
||||
private Popup dropShadowDelegate;
|
||||
private Window dropShadowWindow;
|
||||
private Color oldDropShadowWindowBackground;
|
||||
|
||||
DropShadowPopup( Popup delegate, Component owner, Component contents ) {
|
||||
super( delegate, contents );
|
||||
this.owner = owner;
|
||||
|
||||
Dimension size = contents.getPreferredSize();
|
||||
if( size.width <= 0 || size.height <= 0 )
|
||||
return;
|
||||
|
||||
if( popupWindow != null ) {
|
||||
// heavy weight popup
|
||||
|
||||
// Since Java has a problem with sub-pixel text rendering on translucent
|
||||
// windows, we can not make the popup window translucent for the drop shadow.
|
||||
// (see https://bugs.openjdk.java.net/browse/JDK-8215980)
|
||||
// The solution is to create a second translucent window that paints
|
||||
// the drop shadow and is positioned behind the popup window.
|
||||
|
||||
// create panel that paints the drop shadow
|
||||
JPanel dropShadowPanel = new JPanel();
|
||||
dropShadowPanel.setBorder( createDropShadowBorder() );
|
||||
dropShadowPanel.setOpaque( false );
|
||||
|
||||
// set preferred size of drop shadow panel
|
||||
Dimension prefSize = popupWindow.getPreferredSize();
|
||||
Insets insets = dropShadowPanel.getInsets();
|
||||
dropShadowPanel.setPreferredSize( new Dimension(
|
||||
prefSize.width + insets.left + insets.right,
|
||||
prefSize.height + insets.top + insets.bottom ) );
|
||||
|
||||
// create heavy weight popup for drop shadow
|
||||
int x = popupWindow.getX() - insets.left;
|
||||
int y = popupWindow.getY() - insets.top;
|
||||
dropShadowDelegate = getHeavyWeightPopup( owner, dropShadowPanel, x, y );
|
||||
|
||||
// make drop shadow popup window translucent
|
||||
dropShadowWindow = SwingUtilities.windowForComponent( dropShadowPanel );
|
||||
if( dropShadowWindow != null ) {
|
||||
oldDropShadowWindowBackground = dropShadowWindow.getBackground();
|
||||
dropShadowWindow.setBackground( new Color( 0, true ) );
|
||||
}
|
||||
} else {
|
||||
mediumWeightPanel = (Panel) SwingUtilities.getAncestorOfClass( Panel.class, contents );
|
||||
if( mediumWeightPanel != null ) {
|
||||
// medium weight popup
|
||||
dropShadowPanel = new JPanel();
|
||||
dropShadowPanel.setBorder( createDropShadowBorder() );
|
||||
dropShadowPanel.setOpaque( false );
|
||||
dropShadowPanel.setSize( FlatUIUtils.addInsets( mediumWeightPanel.getSize(), dropShadowPanel.getInsets() ) );
|
||||
} else {
|
||||
// light weight popup
|
||||
Container p = contents.getParent();
|
||||
if( !(p instanceof JComponent) )
|
||||
return;
|
||||
|
||||
lightComp = (JComponent) p;
|
||||
oldBorder = lightComp.getBorder();
|
||||
oldOpaque = lightComp.isOpaque();
|
||||
lightComp.setBorder( createDropShadowBorder() );
|
||||
lightComp.setOpaque( false );
|
||||
lightComp.setSize( lightComp.getPreferredSize() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Border createDropShadowBorder() {
|
||||
return new FlatDropShadowBorder(
|
||||
UIManager.getColor( "Popup.dropShadowColor" ),
|
||||
UIManager.getInsets( "Popup.dropShadowInsets" ),
|
||||
FlatUIUtils.getUIFloat( "Popup.dropShadowOpacity", 0.5f ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
if( dropShadowDelegate != null )
|
||||
dropShadowDelegate.show();
|
||||
|
||||
if( mediumWeightPanel != null )
|
||||
showMediumWeightDropShadow();
|
||||
|
||||
super.show();
|
||||
|
||||
// fix location of light weight popup in case it has left or top drop shadow
|
||||
if( lightComp != null ) {
|
||||
Insets insets = lightComp.getInsets();
|
||||
if( insets.left != 0 || insets.top != 0 )
|
||||
lightComp.setLocation( lightComp.getX() - insets.left, lightComp.getY() - insets.top );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hide() {
|
||||
if( dropShadowDelegate != null ) {
|
||||
dropShadowDelegate.hide();
|
||||
dropShadowDelegate = null;
|
||||
}
|
||||
|
||||
if( mediumWeightPanel != null ) {
|
||||
hideMediumWeightDropShadow();
|
||||
dropShadowPanel = null;
|
||||
mediumWeightPanel = null;
|
||||
}
|
||||
|
||||
super.hide();
|
||||
|
||||
if( dropShadowWindow != null ) {
|
||||
dropShadowWindow.setBackground( oldDropShadowWindowBackground );
|
||||
dropShadowWindow = null;
|
||||
}
|
||||
|
||||
if( lightComp != null ) {
|
||||
lightComp.setBorder( oldBorder );
|
||||
lightComp.setOpaque( oldOpaque );
|
||||
lightComp = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void showMediumWeightDropShadow() {
|
||||
if( mediumWeightShown )
|
||||
return;
|
||||
|
||||
mediumWeightShown = true;
|
||||
|
||||
Window window = SwingUtilities.windowForComponent( owner );
|
||||
if( window == null )
|
||||
return;
|
||||
|
||||
if( !(window instanceof RootPaneContainer) )
|
||||
return;
|
||||
|
||||
dropShadowPanel.setVisible( false );
|
||||
|
||||
JLayeredPane layeredPane = ((RootPaneContainer)window).getLayeredPane();
|
||||
layeredPane.add( dropShadowPanel, JLayeredPane.POPUP_LAYER, 0 );
|
||||
|
||||
mediumPanelListener = new ComponentListener() {
|
||||
@Override
|
||||
public void componentShown( ComponentEvent e ) {
|
||||
if( dropShadowPanel != null )
|
||||
dropShadowPanel.setVisible( true );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentHidden( ComponentEvent e ) {
|
||||
if( dropShadowPanel != null )
|
||||
dropShadowPanel.setVisible( false );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentMoved( ComponentEvent e ) {
|
||||
if( dropShadowPanel != null && mediumWeightPanel != null ) {
|
||||
Point location = mediumWeightPanel.getLocation();
|
||||
Insets insets = dropShadowPanel.getInsets();
|
||||
dropShadowPanel.setLocation( location.x - insets.left, location.y - insets.top );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentResized( ComponentEvent e ) {
|
||||
if( dropShadowPanel != null )
|
||||
dropShadowPanel.setSize( FlatUIUtils.addInsets( mediumWeightPanel.getSize(), dropShadowPanel.getInsets() ) );
|
||||
}
|
||||
};
|
||||
mediumWeightPanel.addComponentListener( mediumPanelListener );
|
||||
}
|
||||
|
||||
private void hideMediumWeightDropShadow() {
|
||||
mediumWeightPanel.removeComponentListener( mediumPanelListener );
|
||||
|
||||
Container parent = dropShadowPanel.getParent();
|
||||
if( parent != null ) {
|
||||
Rectangle bounds = dropShadowPanel.getBounds();
|
||||
parent.remove( dropShadowPanel );
|
||||
parent.repaint( bounds.x, bounds.y, bounds.width, bounds.height );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@ import javax.swing.LookAndFeel;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicProgressBarUI;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
@@ -194,6 +195,11 @@ public class FlatProgressBarUI
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintString( Graphics g, int x, int y, int width, int height, int amountFull, Insets b ) {
|
||||
super.paintString( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ), x, y, width, height, amountFull, b );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setAnimationIndex( int newValue ) {
|
||||
super.setAnimationIndex( newValue );
|
||||
|
||||
@@ -16,12 +16,11 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Rectangle;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicRadioButtonMenuItemUI;
|
||||
|
||||
@@ -46,13 +45,18 @@ import javax.swing.plaf.basic.BasicRadioButtonMenuItemUI;
|
||||
* @uiDefault RadioButtonMenuItem.arrowIcon Icon
|
||||
* @uiDefault RadioButtonMenuItem.checkIcon Icon
|
||||
* @uiDefault RadioButtonMenuItem.opaque boolean
|
||||
* @uiDefault RadioButtonMenuItem.evenHeight boolean
|
||||
*
|
||||
* <!-- FlatRadioButtonMenuItemUI -->
|
||||
*
|
||||
* @uiDefault MenuItem.iconTextGap int
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatRadioButtonMenuItemUI
|
||||
extends BasicRadioButtonMenuItemUI
|
||||
{
|
||||
private FlatMenuItemRenderer renderer;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatRadioButtonMenuItemUI();
|
||||
}
|
||||
@@ -61,25 +65,30 @@ public class FlatRadioButtonMenuItemUI
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
|
||||
// scale
|
||||
defaultTextIconGap = scale( defaultTextIconGap );
|
||||
}
|
||||
LookAndFeel.installProperty( menuItem, "iconTextGap", FlatUIUtils.getUIInt( "MenuItem.iconTextGap", 4 ) );
|
||||
|
||||
/**
|
||||
* Scale defaultTextIconGap again if iconTextGap property has changed.
|
||||
*/
|
||||
@Override
|
||||
protected PropertyChangeListener createPropertyChangeListener( JComponent c ) {
|
||||
PropertyChangeListener superListener = super.createPropertyChangeListener( c );
|
||||
return e -> {
|
||||
superListener.propertyChange( e );
|
||||
if( e.getPropertyName() == "iconTextGap" )
|
||||
defaultTextIconGap = scale( defaultTextIconGap );
|
||||
};
|
||||
renderer = createRenderer();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintText( Graphics g, JMenuItem menuItem, Rectangle textRect, String text ) {
|
||||
FlatMenuItemUI.paintText( g, menuItem, textRect, text, disabledForeground, selectionForeground );
|
||||
protected void uninstallDefaults() {
|
||||
super.uninstallDefaults();
|
||||
|
||||
renderer = null;
|
||||
}
|
||||
|
||||
protected FlatMenuItemRenderer createRenderer() {
|
||||
return new FlatMenuItemRenderer( menuItem, checkIcon, arrowIcon, acceleratorFont, acceleratorDelimiter );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dimension getPreferredMenuItemSize( JComponent c, Icon checkIcon, Icon arrowIcon, int defaultTextIconGap ) {
|
||||
return renderer.getPreferredMenuItemSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint( Graphics g, JComponent c ) {
|
||||
renderer.paintMenuItem( g, selectionBackground, selectionForeground, disabledForeground,
|
||||
acceleratorForeground, acceleratorSelectionForeground );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import java.awt.Graphics;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import javax.swing.AbstractButton;
|
||||
import javax.swing.CellRendererPane;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.UIManager;
|
||||
@@ -122,11 +121,10 @@ public class FlatRadioButtonUI
|
||||
public void paint( Graphics g, JComponent c ) {
|
||||
// fill background even if not opaque if
|
||||
// - contentAreaFilled is true and
|
||||
// - used as cell renderer (because of selection background)
|
||||
// - or if background was explicitly set to a non-UIResource color
|
||||
// - if background was explicitly set to a non-UIResource color
|
||||
if( !c.isOpaque() &&
|
||||
((AbstractButton)c).isContentAreaFilled() &&
|
||||
(c.getParent() instanceof CellRendererPane || !(c.getBackground() instanceof UIResource)))
|
||||
!(c.getBackground() instanceof UIResource) )
|
||||
{
|
||||
g.setColor( c.getBackground() );
|
||||
g.fillRect( 0, 0, c.getWidth(), c.getHeight() );
|
||||
@@ -155,7 +153,7 @@ public class FlatRadioButtonUI
|
||||
}
|
||||
}
|
||||
|
||||
super.paint( g, c );
|
||||
super.paint( FlatLabelUI.createGraphicsHTMLTextYCorrection( g, c ), c );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,23 +16,331 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.LayoutManager;
|
||||
import java.awt.LayoutManager2;
|
||||
import java.awt.Toolkit;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.util.function.Function;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLayeredPane;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.JRootPane;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.BorderUIResource;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicRootPaneUI;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JRootPane}.
|
||||
*
|
||||
* <!-- FlatRootPaneUI -->
|
||||
*
|
||||
* @uiDefault RootPane.border Border
|
||||
*
|
||||
* <!-- FlatWindowResizer -->
|
||||
*
|
||||
* @uiDefault RootPane.borderDragThickness int
|
||||
* @uiDefault RootPane.cornerDragWidth int
|
||||
* @uiDefault RootPane.honorMinimumSizeOnResize boolean
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatRootPaneUI
|
||||
extends BasicRootPaneUI
|
||||
{
|
||||
private static ComponentUI instance;
|
||||
// check this field before using class JBRCustomDecorations to avoid unnecessary loading of that class
|
||||
static final boolean canUseJBRCustomDecorations
|
||||
= SystemInfo.IS_JETBRAINS_JVM_11_OR_LATER && SystemInfo.IS_WINDOWS_10_OR_LATER;
|
||||
|
||||
private JRootPane rootPane;
|
||||
private FlatTitlePane titlePane;
|
||||
private LayoutManager oldLayout;
|
||||
private FlatWindowResizer windowResizer;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
if( instance == null )
|
||||
instance = new FlatRootPaneUI();
|
||||
return instance;
|
||||
return new FlatRootPaneUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
rootPane = (JRootPane) c;
|
||||
|
||||
if( rootPane.getWindowDecorationStyle() != JRootPane.NONE )
|
||||
installClientDecorations();
|
||||
|
||||
if( canUseJBRCustomDecorations )
|
||||
JBRCustomDecorations.install( rootPane );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uninstallUI( JComponent c ) {
|
||||
super.uninstallUI( c );
|
||||
|
||||
uninstallClientDecorations();
|
||||
rootPane = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installDefaults( JRootPane c ) {
|
||||
super.installDefaults( c );
|
||||
|
||||
// Update background color of JFrame or JDialog parent to avoid bad border
|
||||
// on HiDPI screens when switching from light to dark Laf.
|
||||
// The background of JFrame is initialized in JFrame.frameInit() and
|
||||
// the background of JDialog in JDialog.dialogInit(),
|
||||
// but it was not updated when switching Laf.
|
||||
Container parent = c.getParent();
|
||||
if( parent instanceof JFrame || parent instanceof JDialog ) {
|
||||
Color background = parent.getBackground();
|
||||
if( background == null || background instanceof UIResource )
|
||||
parent.setBackground( UIManager.getColor( "control" ) );
|
||||
}
|
||||
|
||||
// enable dark window appearance on macOS when running in JetBrains Runtime
|
||||
if( SystemInfo.IS_JETBRAINS_JVM && SystemInfo.IS_MAC_OS_10_14_MOJAVE ) {
|
||||
LookAndFeel laf = UIManager.getLookAndFeel();
|
||||
boolean isDark = laf instanceof FlatLaf && ((FlatLaf)laf).isDark();
|
||||
c.putClientProperty( "jetbrains.awt.windowDarkAppearance", isDark );
|
||||
}
|
||||
}
|
||||
|
||||
protected void installClientDecorations() {
|
||||
boolean isJBRSupported = canUseJBRCustomDecorations && JBRCustomDecorations.isSupported();
|
||||
|
||||
// install border
|
||||
if( rootPane.getWindowDecorationStyle() != JRootPane.NONE && !isJBRSupported )
|
||||
LookAndFeel.installBorder( rootPane, "RootPane.border" );
|
||||
else
|
||||
LookAndFeel.uninstallBorder( rootPane );
|
||||
|
||||
// install title pane
|
||||
setTitlePane( createTitlePane() );
|
||||
|
||||
// install layout
|
||||
oldLayout = rootPane.getLayout();
|
||||
rootPane.setLayout( createRootLayout() );
|
||||
|
||||
// install window resizer
|
||||
if( !isJBRSupported )
|
||||
windowResizer = createWindowResizer();
|
||||
}
|
||||
|
||||
protected void uninstallClientDecorations() {
|
||||
LookAndFeel.uninstallBorder( rootPane );
|
||||
setTitlePane( null );
|
||||
|
||||
if( windowResizer != null ) {
|
||||
windowResizer.uninstall();
|
||||
windowResizer = null;
|
||||
}
|
||||
|
||||
if( oldLayout != null ) {
|
||||
rootPane.setLayout( oldLayout );
|
||||
oldLayout = null;
|
||||
}
|
||||
|
||||
if( rootPane.getWindowDecorationStyle() == JRootPane.NONE ) {
|
||||
rootPane.revalidate();
|
||||
rootPane.repaint();
|
||||
}
|
||||
}
|
||||
|
||||
protected FlatRootLayout createRootLayout() {
|
||||
return new FlatRootLayout();
|
||||
}
|
||||
|
||||
protected FlatWindowResizer createWindowResizer() {
|
||||
return new FlatWindowResizer( rootPane );
|
||||
}
|
||||
|
||||
protected FlatTitlePane createTitlePane() {
|
||||
return new FlatTitlePane( rootPane );
|
||||
}
|
||||
|
||||
// layer title pane under frame content layer to allow placing menu bar over title pane
|
||||
protected final static Integer TITLE_PANE_LAYER = JLayeredPane.FRAME_CONTENT_LAYER - 1;
|
||||
|
||||
protected void setTitlePane( FlatTitlePane newTitlePane ) {
|
||||
JLayeredPane layeredPane = rootPane.getLayeredPane();
|
||||
|
||||
if( titlePane != null )
|
||||
layeredPane.remove( titlePane );
|
||||
|
||||
if( newTitlePane != null )
|
||||
layeredPane.add( newTitlePane, TITLE_PANE_LAYER );
|
||||
|
||||
titlePane = newTitlePane;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void propertyChange( PropertyChangeEvent e ) {
|
||||
super.propertyChange( e );
|
||||
|
||||
switch( e.getPropertyName() ) {
|
||||
case "windowDecorationStyle":
|
||||
uninstallClientDecorations();
|
||||
if( rootPane.getWindowDecorationStyle() != JRootPane.NONE )
|
||||
installClientDecorations();
|
||||
break;
|
||||
|
||||
case FlatClientProperties.MENU_BAR_EMBEDDED:
|
||||
if( titlePane != null ) {
|
||||
titlePane.menuBarChanged();
|
||||
rootPane.revalidate();
|
||||
rootPane.repaint();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//---- class FlatRootLayout -----------------------------------------------
|
||||
|
||||
protected class FlatRootLayout
|
||||
implements LayoutManager2
|
||||
{
|
||||
@Override public void addLayoutComponent( String name, Component comp ) {}
|
||||
@Override public void addLayoutComponent( Component comp, Object constraints ) {}
|
||||
@Override public void removeLayoutComponent( Component comp ) {}
|
||||
|
||||
@Override
|
||||
public Dimension preferredLayoutSize( Container parent ) {
|
||||
return computeLayoutSize( parent, c -> c.getPreferredSize() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension minimumLayoutSize( Container parent ) {
|
||||
return computeLayoutSize( parent, c -> c.getMinimumSize() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension maximumLayoutSize( Container parent ) {
|
||||
return new Dimension( Integer.MAX_VALUE, Integer.MAX_VALUE );
|
||||
}
|
||||
|
||||
private Dimension computeLayoutSize( Container parent, Function<Component, Dimension> getSizeFunc ) {
|
||||
JRootPane rootPane = (JRootPane) parent;
|
||||
|
||||
Dimension titlePaneSize = (titlePane != null)
|
||||
? getSizeFunc.apply( titlePane )
|
||||
: new Dimension();
|
||||
Dimension contentSize = (rootPane.getContentPane() != null)
|
||||
? getSizeFunc.apply( rootPane.getContentPane() )
|
||||
: rootPane.getSize();
|
||||
|
||||
int width = Math.max( titlePaneSize.width, contentSize.width );
|
||||
int height = titlePaneSize.height + contentSize.height;
|
||||
if( titlePane == null || !titlePane.isMenuBarEmbedded() ) {
|
||||
Dimension menuBarSize = (rootPane.getJMenuBar() != null)
|
||||
? getSizeFunc.apply( rootPane.getJMenuBar() )
|
||||
: new Dimension();
|
||||
|
||||
width = Math.max( width, menuBarSize.width );
|
||||
height += menuBarSize.height;
|
||||
}
|
||||
|
||||
Insets insets = rootPane.getInsets();
|
||||
|
||||
return new Dimension(
|
||||
width + insets.left + insets.right,
|
||||
height + insets.top + insets.bottom );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void layoutContainer( Container parent ) {
|
||||
JRootPane rootPane = (JRootPane) parent;
|
||||
|
||||
Insets insets = rootPane.getInsets();
|
||||
int x = insets.left;
|
||||
int y = insets.top;
|
||||
int width = rootPane.getWidth() - insets.left - insets.right;
|
||||
int height = rootPane.getHeight() - insets.top - insets.bottom;
|
||||
|
||||
if( rootPane.getLayeredPane() != null )
|
||||
rootPane.getLayeredPane().setBounds( x, y, width, height );
|
||||
if( rootPane.getGlassPane() != null )
|
||||
rootPane.getGlassPane().setBounds( x, y, width, height );
|
||||
|
||||
int nextY = 0;
|
||||
if( titlePane != null ) {
|
||||
Dimension prefSize = titlePane.getPreferredSize();
|
||||
titlePane.setBounds( 0, 0, width, prefSize.height );
|
||||
nextY += prefSize.height;
|
||||
}
|
||||
|
||||
JMenuBar menuBar = rootPane.getJMenuBar();
|
||||
if( menuBar != null ) {
|
||||
if( titlePane != null && titlePane.isMenuBarEmbedded() ) {
|
||||
titlePane.validate();
|
||||
menuBar.setBounds( titlePane.getMenuBarBounds() );
|
||||
} else {
|
||||
Dimension prefSize = menuBar.getPreferredSize();
|
||||
menuBar.setBounds( 0, nextY, width, prefSize.height );
|
||||
nextY += prefSize.height;
|
||||
}
|
||||
}
|
||||
|
||||
Container contentPane = rootPane.getContentPane();
|
||||
if( contentPane != null )
|
||||
contentPane.setBounds( 0, nextY, width, Math.max( height - nextY, 0 ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateLayout( Container parent ) {
|
||||
if( titlePane != null )
|
||||
titlePane.menuBarChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getLayoutAlignmentX( Container target ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getLayoutAlignmentY( Container target ) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//---- class FlatWindowBorder ---------------------------------------------
|
||||
|
||||
public static class FlatWindowBorder
|
||||
extends BorderUIResource.EmptyBorderUIResource
|
||||
{
|
||||
public FlatWindowBorder() {
|
||||
super( 1, 1, 1, 1 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||
Object borderColorObj = Toolkit.getDefaultToolkit().getDesktopProperty(
|
||||
"win.frame.activeBorderColor" );
|
||||
Color borderColor = (borderColorObj instanceof Color)
|
||||
? (Color) borderColorObj
|
||||
: UIManager.getColor( "windowBorder" );
|
||||
|
||||
g.setColor( borderColor );
|
||||
HiDPIUtils.paintAtScale1x( (Graphics2D) g, x, y, width, height, this::paintImpl );
|
||||
}
|
||||
|
||||
private void paintImpl( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
|
||||
g.drawRect( x, y, width - 1, height - 1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import java.awt.Component;
|
||||
import javax.swing.UIManager;
|
||||
|
||||
@@ -33,7 +32,7 @@ public class FlatRoundBorder
|
||||
protected final int arc = UIManager.getInt( "Component.arc" );
|
||||
|
||||
@Override
|
||||
protected float getArc( Component c ) {
|
||||
return scale( (float) arc );
|
||||
protected int getArc( Component c ) {
|
||||
return FlatUIUtils.isRoundRect( c ) ? Short.MAX_VALUE : arc;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ package com.formdev.flatlaf.ui;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
@@ -28,6 +30,7 @@ import java.util.Objects;
|
||||
import javax.swing.InputMap;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JScrollBar;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
@@ -52,29 +55,49 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
*
|
||||
* <!-- FlatScrollBarUI -->
|
||||
*
|
||||
* @uiDefault ScrollBar.hoverTrackColor Color
|
||||
* @uiDefault ScrollBar.hoverThumbColor Color
|
||||
* @uiDefault ScrollBar.trackInsets Insets
|
||||
* @uiDefault ScrollBar.thumbInsets Insets
|
||||
* @uiDefault ScrollBar.trackArc int
|
||||
* @uiDefault ScrollBar.thumbArc int
|
||||
* @uiDefault ScrollBar.hoverTrackColor Color optional
|
||||
* @uiDefault ScrollBar.hoverThumbColor Color optional
|
||||
* @uiDefault ScrollBar.hoverThumbWithTrack boolean
|
||||
* @uiDefault ScrollBar.pressedTrackColor Color optional
|
||||
* @uiDefault ScrollBar.pressedThumbColor Color optional
|
||||
* @uiDefault ScrollBar.pressedThumbWithTrack boolean
|
||||
* @uiDefault Component.arrowType String triangle (default) or chevron
|
||||
* @uiDefault ScrollBar.showButtons boolean
|
||||
* @uiDefault ScrollBar.buttonArrowColor Color
|
||||
* @uiDefault ScrollBar.buttonDisabledArrowColor Color
|
||||
* @uiDefault ScrollBar.hoverButtonBackground Color optional
|
||||
* @uiDefault ScrollBar.pressedButtonBackground Color optional
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatScrollBarUI
|
||||
extends BasicScrollBarUI
|
||||
{
|
||||
protected Insets trackInsets;
|
||||
protected Insets thumbInsets;
|
||||
protected int trackArc;
|
||||
protected int thumbArc;
|
||||
protected Color hoverTrackColor;
|
||||
protected Color hoverThumbColor;
|
||||
protected boolean hoverThumbWithTrack;
|
||||
protected Color pressedTrackColor;
|
||||
protected Color pressedThumbColor;
|
||||
protected boolean pressedThumbWithTrack;
|
||||
|
||||
protected boolean showButtons;
|
||||
protected String arrowType;
|
||||
protected Color buttonArrowColor;
|
||||
protected Color buttonDisabledArrowColor;
|
||||
protected Color hoverButtonBackground;
|
||||
protected Color pressedButtonBackground;
|
||||
|
||||
private MouseAdapter hoverListener;
|
||||
private boolean hoverTrack;
|
||||
private boolean hoverThumb;
|
||||
protected boolean hoverTrack;
|
||||
protected boolean hoverThumb;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatScrollBarUI();
|
||||
@@ -102,24 +125,40 @@ public class FlatScrollBarUI
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
|
||||
trackInsets = UIManager.getInsets( "ScrollBar.trackInsets" );
|
||||
thumbInsets = UIManager.getInsets( "ScrollBar.thumbInsets" );
|
||||
trackArc = UIManager.getInt( "ScrollBar.trackArc" );
|
||||
thumbArc = UIManager.getInt( "ScrollBar.thumbArc" );
|
||||
hoverTrackColor = UIManager.getColor( "ScrollBar.hoverTrackColor" );
|
||||
hoverThumbColor = UIManager.getColor( "ScrollBar.hoverThumbColor" );
|
||||
hoverThumbWithTrack = UIManager.getBoolean( "ScrollBar.hoverThumbWithTrack" );
|
||||
pressedTrackColor = UIManager.getColor( "ScrollBar.pressedTrackColor" );
|
||||
pressedThumbColor = UIManager.getColor( "ScrollBar.pressedThumbColor" );
|
||||
pressedThumbWithTrack = UIManager.getBoolean( "ScrollBar.pressedThumbWithTrack" );
|
||||
|
||||
showButtons = UIManager.getBoolean( "ScrollBar.showButtons" );
|
||||
arrowType = UIManager.getString( "Component.arrowType" );
|
||||
buttonArrowColor = UIManager.getColor( "ScrollBar.buttonArrowColor" );
|
||||
buttonDisabledArrowColor = UIManager.getColor( "ScrollBar.buttonDisabledArrowColor" );
|
||||
hoverButtonBackground = UIManager.getColor( "ScrollBar.hoverButtonBackground" );
|
||||
pressedButtonBackground = UIManager.getColor( "ScrollBar.pressedButtonBackground" );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void uninstallDefaults() {
|
||||
super.uninstallDefaults();
|
||||
|
||||
trackInsets = null;
|
||||
thumbInsets = null;
|
||||
hoverTrackColor = null;
|
||||
hoverThumbColor = null;
|
||||
pressedTrackColor = null;
|
||||
pressedThumbColor = null;
|
||||
|
||||
buttonArrowColor = null;
|
||||
buttonDisabledArrowColor = null;
|
||||
hoverButtonBackground = null;
|
||||
pressedButtonBackground = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -168,9 +207,14 @@ public class FlatScrollBarUI
|
||||
}
|
||||
|
||||
private JButton createArrowButton( int orientation ) {
|
||||
FlatArrowButton button = new FlatArrowButton( orientation,
|
||||
arrowType, buttonArrowColor, buttonDisabledArrowColor, null, hoverTrackColor )
|
||||
FlatArrowButton button = new FlatArrowButton( orientation, arrowType, buttonArrowColor,
|
||||
buttonDisabledArrowColor, null, hoverButtonBackground, pressedButtonBackground )
|
||||
{
|
||||
@Override
|
||||
protected Color deriveBackground( Color background ) {
|
||||
return FlatUIUtils.deriveColor( background, scrollbar.getBackground() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
if( isShowButtons() ) {
|
||||
@@ -196,13 +240,53 @@ public class FlatScrollBarUI
|
||||
return button;
|
||||
}
|
||||
|
||||
private boolean isShowButtons() {
|
||||
protected boolean isShowButtons() {
|
||||
Object showButtons = scrollbar.getClientProperty( FlatClientProperties.SCROLL_BAR_SHOW_BUTTONS );
|
||||
if( showButtons == null && scrollbar.getParent() instanceof JScrollPane )
|
||||
showButtons = ((JScrollPane)scrollbar.getParent()).getClientProperty( FlatClientProperties.SCROLL_BAR_SHOW_BUTTONS );
|
||||
return (showButtons != null) ? Objects.equals( showButtons, true ) : this.showButtons;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint( Graphics g, JComponent c ) {
|
||||
FlatUIUtils.setRenderingHints( (Graphics2D) g );
|
||||
super.paint( g, c );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintTrack( Graphics g, JComponent c, Rectangle trackBounds ) {
|
||||
g.setColor( getTrackColor( c, hoverTrack, isPressed && hoverTrack && !hoverThumb ) );
|
||||
paintTrackOrThumb( g, c, trackBounds, trackInsets, trackArc );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintThumb( Graphics g, JComponent c, Rectangle thumbBounds ) {
|
||||
if( thumbBounds.isEmpty() || !scrollbar.isEnabled() )
|
||||
return;
|
||||
|
||||
g.setColor( getThumbColor( c, hoverThumb || (hoverThumbWithTrack && hoverTrack),
|
||||
isPressed && (hoverThumb || (pressedThumbWithTrack && hoverTrack)) ) );
|
||||
paintTrackOrThumb( g, c, thumbBounds, thumbInsets, thumbArc );
|
||||
}
|
||||
|
||||
protected void paintTrackOrThumb( Graphics g, JComponent c, Rectangle bounds, Insets insets, int arc ) {
|
||||
// rotate insets for horizontal orientation because they are given for vertical orientation
|
||||
if( scrollbar.getOrientation() == JScrollBar.HORIZONTAL )
|
||||
insets = new Insets( insets.right, insets.top, insets.left, insets.bottom );
|
||||
|
||||
// subtract insets from bounds
|
||||
bounds = FlatUIUtils.subtractInsets( bounds, UIScale.scale( insets ) );
|
||||
|
||||
if( arc <= 0 ) {
|
||||
// paint rectangle
|
||||
g.fillRect( bounds.x, bounds.y, bounds.width, bounds.height );
|
||||
} else {
|
||||
// paint round rectangle
|
||||
arc = Math.min( UIScale.scale( arc ), Math.min( bounds.width, bounds.height ) );
|
||||
g.fillRoundRect( bounds.x, bounds.y, bounds.width, bounds.height, arc, arc );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintDecreaseHighlight( Graphics g ) {
|
||||
// do not paint
|
||||
@@ -213,19 +297,23 @@ public class FlatScrollBarUI
|
||||
// do not paint
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintTrack( Graphics g, JComponent c, Rectangle trackBounds ) {
|
||||
g.setColor( hoverTrack ? hoverTrackColor : trackColor );
|
||||
g.fillRect( trackBounds.x, trackBounds.y, trackBounds.width, trackBounds.height );
|
||||
protected Color getTrackColor( JComponent c, boolean hover, boolean pressed ) {
|
||||
Color trackColor = FlatUIUtils.deriveColor( this.trackColor, c.getBackground() );
|
||||
return (pressed && pressedTrackColor != null)
|
||||
? FlatUIUtils.deriveColor( pressedTrackColor, trackColor )
|
||||
: ((hover && hoverTrackColor != null)
|
||||
? FlatUIUtils.deriveColor( hoverTrackColor, trackColor )
|
||||
: trackColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintThumb( Graphics g, JComponent c, Rectangle thumbBounds ) {
|
||||
if( thumbBounds.isEmpty() || !scrollbar.isEnabled() )
|
||||
return;
|
||||
|
||||
g.setColor( hoverThumb ? hoverThumbColor : thumbColor );
|
||||
g.fillRect( thumbBounds.x, thumbBounds.y, thumbBounds.width, thumbBounds.height );
|
||||
protected Color getThumbColor( JComponent c, boolean hover, boolean pressed ) {
|
||||
Color trackColor = FlatUIUtils.deriveColor( this.trackColor, c.getBackground() );
|
||||
Color thumbColor = FlatUIUtils.deriveColor( this.thumbColor, trackColor );
|
||||
return (pressed && pressedThumbColor != null)
|
||||
? FlatUIUtils.deriveColor( pressedThumbColor, thumbColor )
|
||||
: ((hover && hoverThumbColor != null)
|
||||
? FlatUIUtils.deriveColor( hoverThumbColor, thumbColor )
|
||||
: thumbColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -263,11 +351,14 @@ public class FlatScrollBarUI
|
||||
@Override
|
||||
public void mousePressed( MouseEvent e ) {
|
||||
isPressed = true;
|
||||
repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased( MouseEvent e ) {
|
||||
isPressed = false;
|
||||
repaint();
|
||||
|
||||
update( e.getX(), e.getY() );
|
||||
}
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ public class FlatScrollPaneUI
|
||||
int focusWidth = UIManager.getInt( "Component.focusWidth" );
|
||||
LookAndFeel.installProperty( c, "opaque", focusWidth == 0 );
|
||||
|
||||
MigLayoutVisualPadding.install( scrollpane, focusWidth );
|
||||
MigLayoutVisualPadding.install( scrollpane );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -201,7 +201,7 @@ public class FlatSliderUI
|
||||
}
|
||||
|
||||
if( coloredTrack != null ) {
|
||||
FlatUIUtils.setColor( g, FlatUIUtils.isPermanentFocusOwner( slider ) ? focusColor : (hover ? hoverColor : thumbColor), thumbColor );
|
||||
g.setColor( FlatUIUtils.deriveColor( FlatUIUtils.isPermanentFocusOwner( slider ) ? focusColor : (hover ? hoverColor : thumbColor), thumbColor ) );
|
||||
((Graphics2D)g).fill( coloredTrack );
|
||||
}
|
||||
|
||||
@@ -211,10 +211,10 @@ public class FlatSliderUI
|
||||
|
||||
@Override
|
||||
public void paintThumb( Graphics g ) {
|
||||
FlatUIUtils.setColor( g, slider.isEnabled()
|
||||
g.setColor( FlatUIUtils.deriveColor( slider.isEnabled()
|
||||
? (FlatUIUtils.isPermanentFocusOwner( slider ) ? focusColor : (hover ? hoverColor : thumbColor))
|
||||
: disabledForeground,
|
||||
thumbColor );
|
||||
thumbColor ) );
|
||||
|
||||
if( isRoundThumb() )
|
||||
g.fillOval( thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height );
|
||||
|
||||
@@ -40,6 +40,7 @@ import javax.swing.SwingConstants;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicSpinnerUI;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JSpinner}.
|
||||
@@ -56,9 +57,8 @@ import javax.swing.plaf.basic.BasicSpinnerUI;
|
||||
*
|
||||
* <!-- FlatSpinnerUI -->
|
||||
*
|
||||
* @uiDefault Component.focusWidth int
|
||||
* @uiDefault Component.arc int
|
||||
* @uiDefault Component.minimumWidth int
|
||||
* @uiDefault Spinner.buttonStyle String button (default) or none
|
||||
* @uiDefault Component.arrowType String triangle (default) or chevron
|
||||
* @uiDefault Component.isIntelliJTheme boolean
|
||||
* @uiDefault Component.borderColor Color
|
||||
@@ -78,9 +78,8 @@ public class FlatSpinnerUI
|
||||
{
|
||||
private Handler handler;
|
||||
|
||||
protected int focusWidth;
|
||||
protected int arc;
|
||||
protected int minimumWidth;
|
||||
protected String buttonStyle;
|
||||
protected String arrowType;
|
||||
protected boolean isIntelliJTheme;
|
||||
protected Color borderColor;
|
||||
@@ -103,9 +102,8 @@ public class FlatSpinnerUI
|
||||
|
||||
LookAndFeel.installProperty( spinner, "opaque", false );
|
||||
|
||||
focusWidth = UIManager.getInt( "Component.focusWidth" );
|
||||
arc = UIManager.getInt( "Component.arc" );
|
||||
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
||||
buttonStyle = UIManager.getString( "Spinner.buttonStyle" );
|
||||
arrowType = UIManager.getString( "Component.arrowType" );
|
||||
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
||||
borderColor = UIManager.getColor( "Component.borderColor" );
|
||||
@@ -121,7 +119,7 @@ public class FlatSpinnerUI
|
||||
// scale
|
||||
padding = scale( padding );
|
||||
|
||||
MigLayoutVisualPadding.install( spinner, focusWidth );
|
||||
MigLayoutVisualPadding.install( spinner );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -146,6 +144,7 @@ public class FlatSpinnerUI
|
||||
super.installListeners();
|
||||
|
||||
addEditorFocusListener( spinner.getEditor() );
|
||||
spinner.addFocusListener( getHandler() );
|
||||
spinner.addPropertyChangeListener( getHandler() );
|
||||
}
|
||||
|
||||
@@ -154,6 +153,7 @@ public class FlatSpinnerUI
|
||||
super.uninstallListeners();
|
||||
|
||||
removeEditorFocusListener( spinner.getEditor() );
|
||||
spinner.removeFocusListener( getHandler() );
|
||||
spinner.removePropertyChangeListener( getHandler() );
|
||||
|
||||
handler = null;
|
||||
@@ -206,17 +206,27 @@ public class FlatSpinnerUI
|
||||
// use non-UIResource colors because when SwingUtilities.updateComponentTreeUI()
|
||||
// is used, then the text field is updated after the spinner and the
|
||||
// colors are again replaced with default colors
|
||||
textField.setForeground( FlatUIUtils.nonUIResource( spinner.getForeground() ) );
|
||||
textField.setDisabledTextColor( FlatUIUtils.nonUIResource( disabledForeground ) );
|
||||
textField.setForeground( FlatUIUtils.nonUIResource( getForeground( true ) ) );
|
||||
textField.setDisabledTextColor( FlatUIUtils.nonUIResource( getForeground( false ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
private JTextField getEditorTextField( JComponent editor ) {
|
||||
private static JTextField getEditorTextField( JComponent editor ) {
|
||||
return editor instanceof JSpinner.DefaultEditor
|
||||
? ((JSpinner.DefaultEditor)editor).getTextField()
|
||||
: null;
|
||||
}
|
||||
|
||||
protected Color getBackground( boolean enabled ) {
|
||||
return enabled
|
||||
? spinner.getBackground()
|
||||
: (isIntelliJTheme ? FlatUIUtils.getParentBackground( spinner ) : disabledBackground);
|
||||
}
|
||||
|
||||
protected Color getForeground( boolean enabled ) {
|
||||
return enabled ? spinner.getForeground() : disabledForeground;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LayoutManager createLayout() {
|
||||
return getHandler();
|
||||
@@ -246,8 +256,11 @@ public class FlatSpinnerUI
|
||||
|
||||
@Override
|
||||
public void update( Graphics g, JComponent c ) {
|
||||
float focusWidth = FlatUIUtils.getBorderFocusWidth( c );
|
||||
float arc = FlatUIUtils.getBorderArc( c );
|
||||
|
||||
// fill background if opaque to avoid garbage if user sets opaque to true
|
||||
if( c.isOpaque() && (focusWidth > 0 || arc != 0) )
|
||||
if( c.isOpaque() && (focusWidth > 0 || arc > 0) )
|
||||
FlatUIUtils.paintParentBackground( g, c );
|
||||
|
||||
Graphics2D g2 = (Graphics2D) g;
|
||||
@@ -255,22 +268,19 @@ public class FlatSpinnerUI
|
||||
|
||||
int width = c.getWidth();
|
||||
int height = c.getHeight();
|
||||
float focusWidth = (c.getBorder() instanceof FlatBorder) ? scale( (float) this.focusWidth ) : 0;
|
||||
float arc = (c.getBorder() instanceof FlatRoundBorder) ? scale( (float) this.arc ) : 0;
|
||||
Component nextButton = getHandler().nextButton;
|
||||
int arrowX = nextButton.getX();
|
||||
int arrowWidth = nextButton.getWidth();
|
||||
boolean paintButton = !"none".equals( buttonStyle );
|
||||
boolean enabled = spinner.isEnabled();
|
||||
boolean isLeftToRight = spinner.getComponentOrientation().isLeftToRight();
|
||||
|
||||
// paint background
|
||||
g2.setColor( enabled
|
||||
? c.getBackground()
|
||||
: (isIntelliJTheme ? FlatUIUtils.getParentBackground( c ) : disabledBackground) );
|
||||
g2.setColor( getBackground( enabled ) );
|
||||
FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc );
|
||||
|
||||
// paint arrow buttons background
|
||||
if( enabled ) {
|
||||
if( paintButton && enabled ) {
|
||||
g2.setColor( buttonBackground );
|
||||
Shape oldClip = g2.getClip();
|
||||
if( isLeftToRight )
|
||||
@@ -282,10 +292,12 @@ public class FlatSpinnerUI
|
||||
}
|
||||
|
||||
// paint vertical line between value and arrow buttons
|
||||
g2.setColor( enabled ? borderColor : disabledBorderColor );
|
||||
float lw = scale( 1f );
|
||||
float lx = isLeftToRight ? arrowX : arrowX + arrowWidth - lw;
|
||||
g2.fill( new Rectangle2D.Float( lx, focusWidth, lw, height - 1 - (focusWidth * 2) ) );
|
||||
if( paintButton ) {
|
||||
g2.setColor( enabled ? borderColor : disabledBorderColor );
|
||||
float lw = scale( 1f );
|
||||
float lx = isLeftToRight ? arrowX : arrowX + arrowWidth - lw;
|
||||
g2.fill( new Rectangle2D.Float( lx, focusWidth, lw, height - 1 - (focusWidth * 2) ) );
|
||||
}
|
||||
|
||||
paint( g, c );
|
||||
}
|
||||
@@ -328,8 +340,9 @@ public class FlatSpinnerUI
|
||||
// the arrows width is the same as the inner height so that the arrows area is square
|
||||
int minimumWidth = FlatUIUtils.minimumWidth( spinner, FlatSpinnerUI.this.minimumWidth );
|
||||
int innerHeight = editorSize.height + padding.top + padding.bottom;
|
||||
float focusWidth = FlatUIUtils.getBorderFocusWidth( spinner );
|
||||
return new Dimension(
|
||||
Math.max( insets.left + insets.right + editorSize.width + padding.left + padding.right + innerHeight, scale( minimumWidth + (focusWidth * 2) ) ),
|
||||
Math.max( insets.left + insets.right + editorSize.width + padding.left + padding.right + innerHeight, scale( minimumWidth ) + Math.round( focusWidth * 2 ) ),
|
||||
insets.top + insets.bottom + innerHeight );
|
||||
}
|
||||
|
||||
@@ -368,12 +381,14 @@ public class FlatSpinnerUI
|
||||
if( editor != null )
|
||||
editor.setBounds( FlatUIUtils.subtractInsets( editorRect, padding ) );
|
||||
|
||||
int nextHeight = Math.round( buttonsRect.height / 2f );
|
||||
int nextHeight = (buttonsRect.height / 2) + (buttonsRect.height % 2); // round up
|
||||
if( nextButton != null )
|
||||
nextButton.setBounds( buttonsRect.x, buttonsRect.y, buttonsRect.width, nextHeight );
|
||||
if( previousButton != null ) {
|
||||
previousButton.setBounds( buttonsRect.x, buttonsRect.y + nextHeight,
|
||||
buttonsRect.width, buttonsRect.height - nextHeight );
|
||||
// for precise layout of arrows, the "previous" button has the same height
|
||||
// as the "next" button and may overlap on uneven buttonsRect.height
|
||||
int previousY = buttonsRect.y + buttonsRect.height - nextHeight;
|
||||
previousButton.setBounds( buttonsRect.x, previousY, buttonsRect.width, nextHeight );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -382,6 +397,13 @@ public class FlatSpinnerUI
|
||||
@Override
|
||||
public void focusGained( FocusEvent e ) {
|
||||
spinner.repaint();
|
||||
|
||||
// if spinner gained focus, transfer it to the editor text field
|
||||
if( e.getComponent() == spinner ) {
|
||||
JTextField textField = getEditorTextField( spinner.getEditor() );
|
||||
if( textField != null )
|
||||
textField.requestFocusInWindow();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -398,6 +420,14 @@ public class FlatSpinnerUI
|
||||
case "enabled":
|
||||
updateEditorColors();
|
||||
break;
|
||||
|
||||
case FlatClientProperties.COMPONENT_ROUND_RECT:
|
||||
spinner.repaint();
|
||||
break;
|
||||
|
||||
case FlatClientProperties.MINIMUM_WIDTH:
|
||||
spinner.revalidate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -333,28 +333,30 @@ public class FlatTabbedPaneUI
|
||||
// paint tab separators
|
||||
if( clientPropertyBoolean( tabPane, TABBED_PANE_SHOW_TAB_SEPARATORS, showTabSeparators ) &&
|
||||
!isLastInRun( tabIndex ) )
|
||||
{
|
||||
float sepWidth = UIScale.scale( 1f );
|
||||
float offset = tabSeparatorsFullHeight ? 0 : UIScale.scale( 5f );
|
||||
|
||||
g.setColor( (tabSeparatorColor != null) ? tabSeparatorColor : contentAreaColor );
|
||||
if( tabPlacement == LEFT || tabPlacement == RIGHT ) {
|
||||
// paint tab separator at bottom side
|
||||
((Graphics2D)g).fill( new Rectangle2D.Float( x + offset, y + h - sepWidth, w - (offset * 2), sepWidth ) );
|
||||
} else if( tabPane.getComponentOrientation().isLeftToRight() ) {
|
||||
// paint tab separator at right side
|
||||
((Graphics2D)g).fill( new Rectangle2D.Float( x + w - sepWidth, y + offset, sepWidth, h - (offset * 2) ) );
|
||||
} else {
|
||||
// paint tab separator at left side
|
||||
((Graphics2D)g).fill( new Rectangle2D.Float( x, y + offset, sepWidth, h - (offset * 2) ) );
|
||||
}
|
||||
}
|
||||
paintTabSeparator( g, tabPlacement, x, y, w, h );
|
||||
|
||||
if( isSelected )
|
||||
paintTabSelection( g, tabPlacement, x, y, w, h );
|
||||
}
|
||||
|
||||
protected void paintTabSelection( Graphics g, int tabPlacement, int x, int y, int w, int h ) {
|
||||
protected void paintTabSeparator( Graphics g, int tabPlacement, int x, int y, int w, int h ) {
|
||||
float sepWidth = UIScale.scale( 1f );
|
||||
float offset = tabSeparatorsFullHeight ? 0 : UIScale.scale( 5f );
|
||||
|
||||
g.setColor( (tabSeparatorColor != null) ? tabSeparatorColor : contentAreaColor );
|
||||
if( tabPlacement == LEFT || tabPlacement == RIGHT ) {
|
||||
// paint tab separator at bottom side
|
||||
((Graphics2D)g).fill( new Rectangle2D.Float( x + offset, y + h - sepWidth, w - (offset * 2), sepWidth ) );
|
||||
} else if( tabPane.getComponentOrientation().isLeftToRight() ) {
|
||||
// paint tab separator at right side
|
||||
((Graphics2D)g).fill( new Rectangle2D.Float( x + w - sepWidth, y + offset, sepWidth, h - (offset * 2) ) );
|
||||
} else {
|
||||
// paint tab separator at left side
|
||||
((Graphics2D)g).fill( new Rectangle2D.Float( x, y + offset, sepWidth, h - (offset * 2) ) );
|
||||
}
|
||||
}
|
||||
|
||||
protected void paintTabSelection( Graphics g, int tabPlacement, int x, int y, int w, int h ) {
|
||||
// increase clip bounds in scroll-tab-layout to paint over the separator line
|
||||
Rectangle clipBounds = isScrollTabLayout() ? g.getClipBounds() : null;
|
||||
if( clipBounds != null ) {
|
||||
|
||||
@@ -86,7 +86,7 @@ public class FlatTableCellBorder
|
||||
/**
|
||||
* Checks whether at least one selected cell is editable.
|
||||
*/
|
||||
private boolean isSelectionEditable( JTable table ) {
|
||||
protected boolean isSelectionEditable( JTable table ) {
|
||||
if( table.getRowSelectionAllowed() ) {
|
||||
int columnCount = table.getColumnCount();
|
||||
int[] selectedRows = table.getSelectedRows();
|
||||
|
||||
@@ -86,26 +86,12 @@ public class FlatTableHeaderUI
|
||||
case "top": sortIconPosition = SwingConstants.TOP; break;
|
||||
case "bottom": sortIconPosition = SwingConstants.BOTTOM; break;
|
||||
}
|
||||
|
||||
// use own renderer if necessary
|
||||
if( sortIconPosition != SwingConstants.RIGHT ) {
|
||||
TableCellRenderer defaultRenderer = header.getDefaultRenderer();
|
||||
if( defaultRenderer instanceof UIResource )
|
||||
header.setDefaultRenderer( new FlatTableCellHeaderRenderer( defaultRenderer ) );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void uninstallDefaults() {
|
||||
super.uninstallDefaults();
|
||||
|
||||
// restore default renderer
|
||||
TableCellRenderer defaultRenderer = header.getDefaultRenderer();
|
||||
if( defaultRenderer instanceof FlatTableCellHeaderRenderer ) {
|
||||
((FlatTableCellHeaderRenderer)defaultRenderer).reset();
|
||||
header.setDefaultRenderer( ((FlatTableCellHeaderRenderer)defaultRenderer).delegate );
|
||||
}
|
||||
|
||||
separatorColor = null;
|
||||
bottomSeparatorColor = null;
|
||||
}
|
||||
@@ -125,8 +111,22 @@ public class FlatTableHeaderUI
|
||||
if( paintBorders )
|
||||
paintColumnBorders( g, c );
|
||||
|
||||
// temporary use own default renderer if necessary
|
||||
FlatTableCellHeaderRenderer sortIconRenderer = null;
|
||||
if( sortIconPosition != SwingConstants.RIGHT ) {
|
||||
sortIconRenderer = new FlatTableCellHeaderRenderer( header.getDefaultRenderer() );
|
||||
header.setDefaultRenderer( sortIconRenderer );
|
||||
}
|
||||
|
||||
// paint header
|
||||
super.paint( g, c );
|
||||
|
||||
// restore default renderer
|
||||
if( sortIconRenderer != null ) {
|
||||
sortIconRenderer.reset();
|
||||
header.setDefaultRenderer( sortIconRenderer.delegate );
|
||||
}
|
||||
|
||||
if( paintBorders )
|
||||
paintDraggedColumnBorders( g, c );
|
||||
}
|
||||
@@ -257,6 +257,7 @@ public class FlatTableHeaderUI
|
||||
{
|
||||
private final TableCellRenderer delegate;
|
||||
|
||||
private JLabel l;
|
||||
private int oldHorizontalTextPosition = -1;
|
||||
private Border origBorder;
|
||||
private Icon sortIcon;
|
||||
@@ -273,7 +274,7 @@ public class FlatTableHeaderUI
|
||||
if( !(c instanceof JLabel) )
|
||||
return c;
|
||||
|
||||
JLabel l = (JLabel) c;
|
||||
l = (JLabel) c;
|
||||
|
||||
if( sortIconPosition == SwingConstants.LEFT ) {
|
||||
if( oldHorizontalTextPosition < 0 )
|
||||
@@ -291,11 +292,8 @@ public class FlatTableHeaderUI
|
||||
}
|
||||
|
||||
void reset() {
|
||||
if( sortIconPosition == SwingConstants.LEFT && oldHorizontalTextPosition >= 0 ) {
|
||||
Component c = getTableCellRendererComponent( header.getTable(), "", false, false, -1, 0 );
|
||||
if( c instanceof JLabel && ((JLabel)c).getHorizontalTextPosition() == SwingConstants.RIGHT )
|
||||
((JLabel)c).setHorizontalTextPosition( oldHorizontalTextPosition );
|
||||
}
|
||||
if( l != null && sortIconPosition == SwingConstants.LEFT && oldHorizontalTextPosition >= 0 )
|
||||
l.setHorizontalTextPosition( oldHorizontalTextPosition );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -20,11 +20,13 @@ import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.FocusListener;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicTableUI;
|
||||
import javax.swing.table.TableCellRenderer;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
@@ -132,6 +134,12 @@ public class FlatTableUI
|
||||
oldIntercellSpacing = table.getIntercellSpacing();
|
||||
table.setIntercellSpacing( intercellSpacing );
|
||||
}
|
||||
|
||||
// checkbox is non-opaque in FlatLaf and therefore would not paint selection
|
||||
// --> make checkbox renderer opaque (but opaque in Metal or Windows LaF)
|
||||
TableCellRenderer booleanRenderer = table.getDefaultRenderer( Boolean.class );
|
||||
if( booleanRenderer instanceof JCheckBox )
|
||||
((JCheckBox)booleanRenderer).setOpaque( true );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,10 +16,11 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.UIManager;
|
||||
@@ -27,6 +28,7 @@ import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicTextAreaUI;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JTextArea}.
|
||||
@@ -83,6 +85,17 @@ public class FlatTextAreaUI
|
||||
inactiveBackground = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void propertyChange( PropertyChangeEvent e ) {
|
||||
super.propertyChange( e );
|
||||
FlatEditorPaneUI.propertyChange( getComponent(), e );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintSafely( Graphics g ) {
|
||||
super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintBackground( Graphics g ) {
|
||||
JTextComponent c = getComponent();
|
||||
@@ -100,25 +113,19 @@ public class FlatTextAreaUI
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize( JComponent c ) {
|
||||
return applyMinimumWidth( super.getPreferredSize( c ), c );
|
||||
return applyMinimumWidth( c, super.getPreferredSize( c ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize( JComponent c ) {
|
||||
return applyMinimumWidth( super.getMinimumSize( c ), c );
|
||||
return applyMinimumWidth( c, super.getMinimumSize( c ) );
|
||||
}
|
||||
|
||||
private Dimension applyMinimumWidth( Dimension size, JComponent c ) {
|
||||
private Dimension applyMinimumWidth( JComponent c, Dimension size ) {
|
||||
// do not apply minimum width if JTextArea.columns is set
|
||||
if( c instanceof JTextArea && ((JTextArea)c).getColumns() > 0 )
|
||||
return size;
|
||||
|
||||
// Assume that text area is in a scroll pane (that displays the border)
|
||||
// and subtract 1px border line width.
|
||||
// Using "(scale( 1 ) * 2)" instead of "scale( 2 )" to deal with rounding
|
||||
// issues. E.g. at scale factor 1.5 the first returns 4, but the second 3.
|
||||
int minimumWidth = FlatUIUtils.minimumWidth( getComponent(), this.minimumWidth );
|
||||
size.width = Math.max( size.width, scale( minimumWidth ) - (scale( 1 ) * 2) );
|
||||
return size;
|
||||
return FlatEditorPaneUI.applyMinimumWidth( c, size, minimumWidth );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,14 +16,13 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import java.awt.Component;
|
||||
import javax.swing.UIManager;
|
||||
|
||||
/**
|
||||
* Border for various text components (e.g. {@link javax.swing.JTextField}).
|
||||
*
|
||||
* @uiDefault Component.arc int
|
||||
* @uiDefault TextComponent.arc int
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
@@ -33,7 +32,7 @@ public class FlatTextBorder
|
||||
protected final int arc = UIManager.getInt( "TextComponent.arc" );
|
||||
|
||||
@Override
|
||||
protected float getArc( Component c ) {
|
||||
return scale( (float) arc );
|
||||
protected int getArc( Component c ) {
|
||||
return FlatUIUtils.isRoundRect( c ) ? Short.MAX_VALUE : arc;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,13 +32,13 @@ import javax.swing.JSpinner;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicTextFieldUI;
|
||||
import javax.swing.text.Caret;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JTextField}.
|
||||
@@ -60,8 +60,6 @@ import com.formdev.flatlaf.FlatClientProperties;
|
||||
*
|
||||
* <!-- FlatTextFieldUI -->
|
||||
*
|
||||
* @uiDefault TextComponent.arc int
|
||||
* @uiDefault Component.focusWidth int
|
||||
* @uiDefault Component.minimumWidth int
|
||||
* @uiDefault Component.isIntelliJTheme boolean
|
||||
* @uiDefault TextField.placeholderForeground Color
|
||||
@@ -72,8 +70,6 @@ import com.formdev.flatlaf.FlatClientProperties;
|
||||
public class FlatTextFieldUI
|
||||
extends BasicTextFieldUI
|
||||
{
|
||||
protected int arc;
|
||||
protected int focusWidth;
|
||||
protected int minimumWidth;
|
||||
protected boolean isIntelliJTheme;
|
||||
protected Color placeholderForeground;
|
||||
@@ -89,15 +85,13 @@ public class FlatTextFieldUI
|
||||
super.installDefaults();
|
||||
|
||||
String prefix = getPropertyPrefix();
|
||||
arc = UIManager.getInt( "TextComponent.arc" );
|
||||
focusWidth = UIManager.getInt( "Component.focusWidth" );
|
||||
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
||||
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
||||
placeholderForeground = UIManager.getColor( prefix + ".placeholderForeground" );
|
||||
|
||||
LookAndFeel.installProperty( getComponent(), "opaque", focusWidth == 0 );
|
||||
LookAndFeel.installProperty( getComponent(), "opaque", false );
|
||||
|
||||
MigLayoutVisualPadding.install( getComponent(), focusWidth );
|
||||
MigLayoutVisualPadding.install( getComponent() );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -133,16 +127,28 @@ public class FlatTextFieldUI
|
||||
@Override
|
||||
protected void propertyChange( PropertyChangeEvent e ) {
|
||||
super.propertyChange( e );
|
||||
propertyChange( getComponent(), e );
|
||||
}
|
||||
|
||||
if( FlatClientProperties.PLACEHOLDER_TEXT.equals( e.getPropertyName() ) )
|
||||
getComponent().repaint();
|
||||
static void propertyChange( JTextComponent c, PropertyChangeEvent e ) {
|
||||
switch( e.getPropertyName() ) {
|
||||
case FlatClientProperties.PLACEHOLDER_TEXT:
|
||||
case FlatClientProperties.COMPONENT_ROUND_RECT:
|
||||
c.repaint();
|
||||
break;
|
||||
|
||||
case FlatClientProperties.MINIMUM_WIDTH:
|
||||
c.revalidate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintSafely( Graphics g ) {
|
||||
paintBackground( g, getComponent(), focusWidth, arc, isIntelliJTheme );
|
||||
paintBackground( g, getComponent(), isIntelliJTheme );
|
||||
paintPlaceholder( g, getComponent(), placeholderForeground );
|
||||
super.paintSafely( g );
|
||||
|
||||
super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -150,19 +156,20 @@ public class FlatTextFieldUI
|
||||
// background is painted elsewhere
|
||||
}
|
||||
|
||||
static void paintBackground( Graphics g, JTextComponent c, int focusWidth, int arc, boolean isIntelliJTheme ) {
|
||||
Border border = c.getBorder();
|
||||
|
||||
static void paintBackground( Graphics g, JTextComponent c, boolean isIntelliJTheme ) {
|
||||
// do not paint background if:
|
||||
// - not opaque and
|
||||
// - border is not a flat border and
|
||||
// - opaque was explicitly set (to false)
|
||||
// (same behaviour as in AquaTextFieldUI)
|
||||
if( !c.isOpaque() && !(border instanceof FlatBorder) && FlatUIUtils.hasOpaqueBeenExplicitlySet( c ) )
|
||||
if( !c.isOpaque() && FlatUIUtils.getOutsideFlatBorder( c ) == null && FlatUIUtils.hasOpaqueBeenExplicitlySet( c ) )
|
||||
return;
|
||||
|
||||
float focusWidth = FlatUIUtils.getBorderFocusWidth( c );
|
||||
float arc = FlatUIUtils.getBorderArc( c );
|
||||
|
||||
// fill background if opaque to avoid garbage if user sets opaque to true
|
||||
if( c.isOpaque() && focusWidth > 0 )
|
||||
if( c.isOpaque() && (focusWidth > 0 || arc > 0) )
|
||||
FlatUIUtils.paintParentBackground( g, c );
|
||||
|
||||
// paint background
|
||||
@@ -170,16 +177,13 @@ public class FlatTextFieldUI
|
||||
try {
|
||||
FlatUIUtils.setRenderingHints( g2 );
|
||||
|
||||
float fFocusWidth = (border instanceof FlatBorder) ? scale( (float) focusWidth ) : 0;
|
||||
float fArc = (border instanceof FlatTextBorder) ? scale( (float) arc ) : 0;
|
||||
|
||||
Color background = c.getBackground();
|
||||
g2.setColor( !(background instanceof UIResource)
|
||||
? background
|
||||
: (isIntelliJTheme && (!c.isEnabled() || !c.isEditable())
|
||||
? FlatUIUtils.getParentBackground( c )
|
||||
: background) );
|
||||
FlatUIUtils.paintComponentBackground( g2, 0, 0, c.getWidth(), c.getHeight(), fFocusWidth, fArc );
|
||||
FlatUIUtils.paintComponentBackground( g2, 0, 0, c.getWidth(), c.getHeight(), focusWidth, arc );
|
||||
} finally {
|
||||
g2.dispose();
|
||||
}
|
||||
@@ -212,28 +216,29 @@ public class FlatTextFieldUI
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize( JComponent c ) {
|
||||
return applyMinimumWidth( super.getPreferredSize( c ), c );
|
||||
return applyMinimumWidth( c, super.getPreferredSize( c ), minimumWidth );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize( JComponent c ) {
|
||||
return applyMinimumWidth( super.getMinimumSize( c ), c );
|
||||
return applyMinimumWidth( c, super.getMinimumSize( c ), minimumWidth );
|
||||
}
|
||||
|
||||
private Dimension applyMinimumWidth( Dimension size, JComponent c ) {
|
||||
static Dimension applyMinimumWidth( JComponent c, Dimension size, int minimumWidth ) {
|
||||
// do not apply minimum width if JTextField.columns is set
|
||||
if( c instanceof JTextField && ((JTextField)c).getColumns() > 0 )
|
||||
return size;
|
||||
|
||||
// do not apply minimum width if used in combobox or spinner
|
||||
Container parent = c.getParent();
|
||||
if( parent instanceof JComboBox ||
|
||||
parent instanceof JSpinner ||
|
||||
(parent != null && parent.getParent() instanceof JSpinner) )
|
||||
return size;
|
||||
|
||||
int minimumWidth = FlatUIUtils.minimumWidth( getComponent(), this.minimumWidth );
|
||||
int focusWidth = (c.getBorder() instanceof FlatBorder) ? this.focusWidth : 0;
|
||||
size.width = Math.max( size.width, scale( minimumWidth + (focusWidth * 2) ) );
|
||||
minimumWidth = FlatUIUtils.minimumWidth( c, minimumWidth );
|
||||
float focusWidth = FlatUIUtils.getBorderFocusWidth( c );
|
||||
size.width = Math.max( size.width, scale( minimumWidth ) + Math.round( focusWidth * 2 ) );
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,10 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JEditorPane;
|
||||
import javax.swing.UIManager;
|
||||
@@ -26,6 +27,7 @@ import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicTextPaneUI;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JTextPane}.
|
||||
@@ -83,24 +85,25 @@ public class FlatTextPaneUI
|
||||
getComponent().putClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES, oldHonorDisplayProperties );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void propertyChange( PropertyChangeEvent e ) {
|
||||
super.propertyChange( e );
|
||||
FlatEditorPaneUI.propertyChange( getComponent(), e );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize( JComponent c ) {
|
||||
return applyMinimumWidth( super.getPreferredSize( c ) );
|
||||
return FlatEditorPaneUI.applyMinimumWidth( c, super.getPreferredSize( c ), minimumWidth );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize( JComponent c ) {
|
||||
return applyMinimumWidth( super.getMinimumSize( c ) );
|
||||
return FlatEditorPaneUI.applyMinimumWidth( c, super.getMinimumSize( c ), minimumWidth );
|
||||
}
|
||||
|
||||
private Dimension applyMinimumWidth( Dimension size ) {
|
||||
// Assume that text area is in a scroll pane (that displays the border)
|
||||
// and subtract 1px border line width.
|
||||
// Using "(scale( 1 ) * 2)" instead of "scale( 2 )" to deal with rounding
|
||||
// issues. E.g. at scale factor 1.5 the first returns 4, but the second 3.
|
||||
int minimumWidth = FlatUIUtils.minimumWidth( getComponent(), this.minimumWidth );
|
||||
size.width = Math.max( size.width, scale( minimumWidth ) - (scale( 1 ) * 2) );
|
||||
return size;
|
||||
@Override
|
||||
protected void paintSafely( Graphics g ) {
|
||||
super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,727 @@
|
||||
/*
|
||||
* Copyright 2020 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.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dialog;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Frame;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.Image;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.event.ComponentListener;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.awt.event.MouseMotionListener;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import javax.accessibility.AccessibleContext;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JRootPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.AbstractBorder;
|
||||
import javax.swing.border.Border;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.FlatSystemProperties;
|
||||
import com.formdev.flatlaf.ui.JBRCustomDecorations.JBRWindowTopBorder;
|
||||
import com.formdev.flatlaf.util.ScaledImageIcon;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF title bar.
|
||||
*
|
||||
* @uiDefault TitlePane.background Color
|
||||
* @uiDefault TitlePane.inactiveBackground Color
|
||||
* @uiDefault TitlePane.foreground Color
|
||||
* @uiDefault TitlePane.inactiveForeground Color
|
||||
* @uiDefault TitlePane.embeddedForeground Color
|
||||
* @uiDefault TitlePane.iconSize Dimension
|
||||
* @uiDefault TitlePane.iconMargins Insets
|
||||
* @uiDefault TitlePane.titleMargins Insets
|
||||
* @uiDefault TitlePane.menuBarMargins Insets
|
||||
* @uiDefault TitlePane.menuBarEmbedded boolean
|
||||
* @uiDefault TitlePane.buttonMaximizedHeight int
|
||||
* @uiDefault TitlePane.closeIcon Icon
|
||||
* @uiDefault TitlePane.iconifyIcon Icon
|
||||
* @uiDefault TitlePane.maximizeIcon Icon
|
||||
* @uiDefault TitlePane.restoreIcon Icon
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatTitlePane
|
||||
extends JComponent
|
||||
{
|
||||
private final Color activeBackground = UIManager.getColor( "TitlePane.background" );
|
||||
private final Color inactiveBackground = UIManager.getColor( "TitlePane.inactiveBackground" );
|
||||
private final Color activeForeground = UIManager.getColor( "TitlePane.foreground" );
|
||||
private final Color inactiveForeground = UIManager.getColor( "TitlePane.inactiveForeground" );
|
||||
private final Color embeddedForeground = UIManager.getColor( "TitlePane.embeddedForeground" );
|
||||
|
||||
private final Insets menuBarMargins = UIManager.getInsets( "TitlePane.menuBarMargins" );
|
||||
private final Dimension iconSize = UIManager.getDimension( "TitlePane.iconSize" );
|
||||
private final int buttonMaximizedHeight = UIManager.getInt( "TitlePane.buttonMaximizedHeight" );
|
||||
|
||||
private final JRootPane rootPane;
|
||||
|
||||
private JPanel leftPanel;
|
||||
private JLabel iconLabel;
|
||||
private JComponent menuBarPlaceholder;
|
||||
private JLabel titleLabel;
|
||||
private JPanel buttonPanel;
|
||||
private JButton iconifyButton;
|
||||
private JButton maximizeButton;
|
||||
private JButton restoreButton;
|
||||
private JButton closeButton;
|
||||
|
||||
private final Handler handler;
|
||||
private Window window;
|
||||
|
||||
public FlatTitlePane( JRootPane rootPane ) {
|
||||
this.rootPane = rootPane;
|
||||
|
||||
handler = createHandler();
|
||||
setBorder( createTitlePaneBorder() );
|
||||
|
||||
addSubComponents();
|
||||
activeChanged( true );
|
||||
|
||||
addMouseListener( handler );
|
||||
addMouseMotionListener( handler );
|
||||
|
||||
// necessary for closing window with double-click on icon
|
||||
iconLabel.addMouseListener( handler );
|
||||
}
|
||||
|
||||
protected FlatTitlePaneBorder createTitlePaneBorder() {
|
||||
return new FlatTitlePaneBorder();
|
||||
}
|
||||
|
||||
protected Handler createHandler() {
|
||||
return new Handler();
|
||||
}
|
||||
|
||||
protected void addSubComponents() {
|
||||
leftPanel = new JPanel();
|
||||
iconLabel = new JLabel();
|
||||
titleLabel = new JLabel();
|
||||
iconLabel.setBorder( new FlatEmptyBorder( UIManager.getInsets( "TitlePane.iconMargins" ) ) );
|
||||
titleLabel.setBorder( new FlatEmptyBorder( UIManager.getInsets( "TitlePane.titleMargins" ) ) );
|
||||
|
||||
leftPanel.setLayout( new BoxLayout( leftPanel, BoxLayout.LINE_AXIS ) );
|
||||
leftPanel.setOpaque( false );
|
||||
leftPanel.add( iconLabel );
|
||||
|
||||
menuBarPlaceholder = new JComponent() {
|
||||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
JMenuBar menuBar = rootPane.getJMenuBar();
|
||||
return (menuBar != null && isMenuBarEmbedded())
|
||||
? FlatUIUtils.addInsets( menuBar.getPreferredSize(), UIScale.scale( menuBarMargins ) )
|
||||
: new Dimension();
|
||||
}
|
||||
};
|
||||
leftPanel.add( menuBarPlaceholder );
|
||||
|
||||
createButtons();
|
||||
|
||||
setLayout( new BorderLayout() );
|
||||
add( leftPanel, BorderLayout.LINE_START );
|
||||
add( titleLabel, BorderLayout.CENTER );
|
||||
add( buttonPanel, BorderLayout.LINE_END );
|
||||
}
|
||||
|
||||
protected void createButtons() {
|
||||
iconifyButton = createButton( "TitlePane.iconifyIcon", "Iconify", e -> iconify() );
|
||||
maximizeButton = createButton( "TitlePane.maximizeIcon", "Maximize", e -> maximize() );
|
||||
restoreButton = createButton( "TitlePane.restoreIcon", "Restore", e -> restore() );
|
||||
closeButton = createButton( "TitlePane.closeIcon", "Close", e -> close() );
|
||||
|
||||
buttonPanel = new JPanel() {
|
||||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
Dimension size = super.getPreferredSize();
|
||||
if( buttonMaximizedHeight > 0 &&
|
||||
window instanceof Frame &&
|
||||
(((Frame)window).getExtendedState() & Frame.MAXIMIZED_BOTH) != 0 )
|
||||
{
|
||||
// make title pane height smaller when frame is maximized
|
||||
size = new Dimension( size.width, Math.min( size.height, UIScale.scale( buttonMaximizedHeight ) ) );
|
||||
}
|
||||
return size;
|
||||
}
|
||||
};
|
||||
buttonPanel.setOpaque( false );
|
||||
buttonPanel.setLayout( new BoxLayout( buttonPanel, BoxLayout.LINE_AXIS ) );
|
||||
if( rootPane.getWindowDecorationStyle() == JRootPane.FRAME ) {
|
||||
// JRootPane.FRAME works only for frames (and not for dialogs)
|
||||
// but at this time the owner window type is unknown (not yet added)
|
||||
// so we add the iconify/maximize/restore buttons and they are hidden
|
||||
// later in frameStateChanged(), which is invoked from addNotify()
|
||||
|
||||
restoreButton.setVisible( false );
|
||||
|
||||
buttonPanel.add( iconifyButton );
|
||||
buttonPanel.add( maximizeButton );
|
||||
buttonPanel.add( restoreButton );
|
||||
}
|
||||
buttonPanel.add( closeButton );
|
||||
}
|
||||
|
||||
protected JButton createButton( String iconKey, String accessibleName, ActionListener action ) {
|
||||
JButton button = new JButton( UIManager.getIcon( iconKey ) );
|
||||
button.setFocusable( false );
|
||||
button.setContentAreaFilled( false );
|
||||
button.setBorder( BorderFactory.createEmptyBorder() );
|
||||
button.putClientProperty( AccessibleContext.ACCESSIBLE_NAME_PROPERTY, accessibleName );
|
||||
button.addActionListener( action );
|
||||
return button;
|
||||
}
|
||||
|
||||
protected void activeChanged( boolean active ) {
|
||||
Color background = FlatUIUtils.nonUIResource( active ? activeBackground : inactiveBackground );
|
||||
Color foreground = FlatUIUtils.nonUIResource( active
|
||||
? (rootPane.getJMenuBar() != null && isMenuBarEmbedded() ? embeddedForeground : activeForeground)
|
||||
: inactiveForeground );
|
||||
|
||||
setBackground( background );
|
||||
titleLabel.setForeground( foreground );
|
||||
|
||||
// this is necessary because hover/pressed colors are derived from background color
|
||||
iconifyButton.setBackground( background );
|
||||
maximizeButton.setBackground( background );
|
||||
restoreButton.setBackground( background );
|
||||
closeButton.setBackground( background );
|
||||
}
|
||||
|
||||
protected void frameStateChanged() {
|
||||
if( window == null || rootPane.getWindowDecorationStyle() != JRootPane.FRAME )
|
||||
return;
|
||||
|
||||
if( window instanceof Frame ) {
|
||||
Frame frame = (Frame) window;
|
||||
boolean resizable = frame.isResizable();
|
||||
boolean maximized = ((frame.getExtendedState() & Frame.MAXIMIZED_BOTH) != 0);
|
||||
|
||||
iconifyButton.setVisible( true );
|
||||
maximizeButton.setVisible( resizable && !maximized );
|
||||
restoreButton.setVisible( resizable && maximized );
|
||||
} else {
|
||||
// hide buttons because they are only supported in frames
|
||||
iconifyButton.setVisible( false );
|
||||
maximizeButton.setVisible( false );
|
||||
restoreButton.setVisible( false );
|
||||
|
||||
revalidate();
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateIcon() {
|
||||
// get window images
|
||||
List<Image> images = window.getIconImages();
|
||||
if( images.isEmpty() ) {
|
||||
// search in owners
|
||||
for( Window owner = window.getOwner(); owner != null; owner = owner.getOwner() ) {
|
||||
images = owner.getIconImages();
|
||||
if( !images.isEmpty() )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
boolean hasIcon = true;
|
||||
|
||||
// set icon
|
||||
if( !images.isEmpty() )
|
||||
iconLabel.setIcon( FlatTitlePaneIcon.create( images, iconSize ) );
|
||||
else {
|
||||
// no icon set on window --> use default icon
|
||||
Icon defaultIcon = UIManager.getIcon( "InternalFrame.icon" );
|
||||
if( defaultIcon != null ) {
|
||||
if( defaultIcon instanceof ImageIcon )
|
||||
defaultIcon = new ScaledImageIcon( (ImageIcon) defaultIcon, iconSize.width, iconSize.height );
|
||||
iconLabel.setIcon( defaultIcon );
|
||||
} else
|
||||
hasIcon = false;
|
||||
}
|
||||
|
||||
// show/hide icon
|
||||
iconLabel.setVisible( hasIcon );
|
||||
|
||||
updateJBRHitTestSpotsAndTitleBarHeightLater();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNotify() {
|
||||
super.addNotify();
|
||||
|
||||
uninstallWindowListeners();
|
||||
|
||||
window = SwingUtilities.getWindowAncestor( this );
|
||||
if( window != null ) {
|
||||
frameStateChanged();
|
||||
activeChanged( window.isActive() );
|
||||
updateIcon();
|
||||
titleLabel.setText( getWindowTitle() );
|
||||
installWindowListeners();
|
||||
}
|
||||
|
||||
updateJBRHitTestSpotsAndTitleBarHeightLater();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNotify() {
|
||||
super.removeNotify();
|
||||
|
||||
uninstallWindowListeners();
|
||||
window = null;
|
||||
}
|
||||
|
||||
protected String getWindowTitle() {
|
||||
if( window instanceof Frame )
|
||||
return ((Frame)window).getTitle();
|
||||
if( window instanceof Dialog )
|
||||
return ((Dialog)window).getTitle();
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void installWindowListeners() {
|
||||
if( window == null )
|
||||
return;
|
||||
|
||||
window.addPropertyChangeListener( handler );
|
||||
window.addWindowListener( handler );
|
||||
window.addWindowStateListener( handler );
|
||||
window.addComponentListener( handler );
|
||||
}
|
||||
|
||||
protected void uninstallWindowListeners() {
|
||||
if( window == null )
|
||||
return;
|
||||
|
||||
window.removePropertyChangeListener( handler );
|
||||
window.removeWindowListener( handler );
|
||||
window.removeWindowStateListener( handler );
|
||||
window.removeComponentListener( handler );
|
||||
}
|
||||
|
||||
protected boolean isMenuBarEmbedded() {
|
||||
// not storing value of "TitlePane.menuBarEmbedded" in class to allow changing at runtime
|
||||
return UIManager.getBoolean( "TitlePane.menuBarEmbedded" ) &&
|
||||
FlatClientProperties.clientPropertyBoolean( rootPane, FlatClientProperties.MENU_BAR_EMBEDDED, true ) &&
|
||||
FlatSystemProperties.getBoolean( FlatSystemProperties.MENUBAR_EMBEDDED, true );
|
||||
}
|
||||
|
||||
protected Rectangle getMenuBarBounds() {
|
||||
Insets insets = rootPane.getInsets();
|
||||
Rectangle bounds = new Rectangle(
|
||||
SwingUtilities.convertPoint( menuBarPlaceholder, -insets.left, -insets.top, rootPane ),
|
||||
menuBarPlaceholder.getSize() );
|
||||
|
||||
// add menu bar bottom border insets to bounds so that menu bar overlaps
|
||||
// title pane border (menu bar border is painted over title pane border)
|
||||
Insets borderInsets = getBorder().getBorderInsets( this );
|
||||
bounds.height += borderInsets.bottom;
|
||||
|
||||
return FlatUIUtils.subtractInsets( bounds, UIScale.scale( getMenuBarMargins() ) );
|
||||
}
|
||||
|
||||
protected void menuBarChanged() {
|
||||
menuBarPlaceholder.invalidate();
|
||||
|
||||
// update title foreground color
|
||||
EventQueue.invokeLater( () -> {
|
||||
activeChanged( window == null || window.isActive() );
|
||||
} );
|
||||
}
|
||||
|
||||
protected Insets getMenuBarMargins() {
|
||||
return getComponentOrientation().isLeftToRight()
|
||||
? menuBarMargins
|
||||
: new Insets( menuBarMargins.top, menuBarMargins.right, menuBarMargins.bottom, menuBarMargins.left );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintComponent( Graphics g ) {
|
||||
g.setColor( getBackground() );
|
||||
g.fillRect( 0, 0, getWidth(), getHeight() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Iconifies the window.
|
||||
*/
|
||||
protected void iconify() {
|
||||
if( window instanceof Frame ) {
|
||||
Frame frame = (Frame) window;
|
||||
frame.setExtendedState( frame.getExtendedState() | Frame.ICONIFIED );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maximizes the window.
|
||||
*/
|
||||
protected void maximize() {
|
||||
if( !(window instanceof Frame) )
|
||||
return;
|
||||
|
||||
Frame frame = (Frame) window;
|
||||
|
||||
// set maximized bounds to avoid that maximized window overlaps Windows task bar
|
||||
// (if not running in JBR and if not modified from the application)
|
||||
if( !hasJBRCustomDecoration() &&
|
||||
(frame.getMaximizedBounds() == null ||
|
||||
Objects.equals( frame.getMaximizedBounds(), rootPane.getClientProperty( "_flatlaf.maximizedBounds" ) )) )
|
||||
{
|
||||
GraphicsConfiguration gc = window.getGraphicsConfiguration();
|
||||
|
||||
// Screen bounds, which may be smaller than physical size on Java 9+.
|
||||
// E.g. if running a 3840x2160 screen at 200%, screenBounds.size is 1920x1080.
|
||||
// In Java 9+, each screen can have its own scale factor.
|
||||
//
|
||||
// On Java 8, which does not scale, screenBounds.size of the primary screen
|
||||
// is identical to its physical size. But when the primary screen is scaled,
|
||||
// then screenBounds.size of secondary screens is scaled with the scale factor
|
||||
// of the primary screen.
|
||||
// E.g. primary 3840x2160 screen at 150%, secondary 1920x1080 screen at 100%,
|
||||
// then screenBounds.size is 3840x2160 on primary and 2880x1560 on secondary.
|
||||
Rectangle screenBounds = gc.getBounds();
|
||||
|
||||
int maximizedX = screenBounds.x;
|
||||
int maximizedY = screenBounds.y;
|
||||
int maximizedWidth = screenBounds.width;
|
||||
int maximizedHeight = screenBounds.height;
|
||||
|
||||
if( !SystemInfo.IS_JAVA_15_OR_LATER ) {
|
||||
// on Java 8 to 14, maximized x,y are 0,0 based on all screens in a multi-screen environment
|
||||
maximizedX = 0;
|
||||
maximizedY = 0;
|
||||
|
||||
// scale maximized screen size to get physical screen size for Java 9 to 14
|
||||
AffineTransform defaultTransform = gc.getDefaultTransform();
|
||||
maximizedWidth = (int) (maximizedWidth * defaultTransform.getScaleX());
|
||||
maximizedHeight = (int) (maximizedHeight * defaultTransform.getScaleY());
|
||||
}
|
||||
|
||||
// screen insets are in physical size, except for Java 15+
|
||||
// (see https://bugs.openjdk.java.net/browse/JDK-8243925)
|
||||
// and except for Java 8 on secondary screens where primary screen is scaled
|
||||
Insets screenInsets = window.getToolkit().getScreenInsets( gc );
|
||||
|
||||
// maximized bounds are required in physical size, except for Java 15+
|
||||
// (see https://bugs.openjdk.java.net/browse/JDK-8231564 and
|
||||
// https://bugs.openjdk.java.net/browse/JDK-8176359)
|
||||
// and except for Java 8 on secondary screens where primary screen is scaled
|
||||
Rectangle maximizedBounds = new Rectangle(
|
||||
maximizedX + screenInsets.left,
|
||||
maximizedY + screenInsets.top,
|
||||
maximizedWidth - screenInsets.left - screenInsets.right,
|
||||
maximizedHeight - screenInsets.top - screenInsets.bottom );
|
||||
|
||||
// change maximized bounds
|
||||
frame.setMaximizedBounds( maximizedBounds );
|
||||
|
||||
// remember maximized bounds in client property to be able to detect
|
||||
// whether maximized bounds are modified from the application
|
||||
rootPane.putClientProperty( "_flatlaf.maximizedBounds", maximizedBounds );
|
||||
}
|
||||
|
||||
// maximize window
|
||||
frame.setExtendedState( frame.getExtendedState() | Frame.MAXIMIZED_BOTH );
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the window size.
|
||||
*/
|
||||
protected void restore() {
|
||||
if( window instanceof Frame ) {
|
||||
Frame frame = (Frame) window;
|
||||
int state = frame.getExtendedState();
|
||||
frame.setExtendedState( ((state & Frame.ICONIFIED) != 0)
|
||||
? (state & ~Frame.ICONIFIED)
|
||||
: (state & ~Frame.MAXIMIZED_BOTH) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the window.
|
||||
*/
|
||||
protected void close() {
|
||||
if( window != null )
|
||||
window.dispatchEvent( new WindowEvent( window, WindowEvent.WINDOW_CLOSING ) );
|
||||
}
|
||||
|
||||
protected boolean hasJBRCustomDecoration() {
|
||||
return FlatRootPaneUI.canUseJBRCustomDecorations &&
|
||||
window != null &&
|
||||
JBRCustomDecorations.hasCustomDecoration( window );
|
||||
}
|
||||
|
||||
protected void updateJBRHitTestSpotsAndTitleBarHeightLater() {
|
||||
EventQueue.invokeLater( () -> {
|
||||
updateJBRHitTestSpotsAndTitleBarHeight();
|
||||
} );
|
||||
}
|
||||
|
||||
protected void updateJBRHitTestSpotsAndTitleBarHeight() {
|
||||
if( !isDisplayable() )
|
||||
return;
|
||||
|
||||
if( !hasJBRCustomDecoration() )
|
||||
return;
|
||||
|
||||
List<Rectangle> hitTestSpots = new ArrayList<>();
|
||||
if( iconLabel.isVisible() )
|
||||
addJBRHitTestSpot( iconLabel, false, hitTestSpots );
|
||||
addJBRHitTestSpot( buttonPanel, false, hitTestSpots );
|
||||
addJBRHitTestSpot( menuBarPlaceholder, true, hitTestSpots );
|
||||
|
||||
int titleBarHeight = getHeight();
|
||||
// slightly reduce height so that component receives mouseExit events
|
||||
if( titleBarHeight > 0 )
|
||||
titleBarHeight--;
|
||||
|
||||
JBRCustomDecorations.setHitTestSpotsAndTitleBarHeight( window, hitTestSpots, titleBarHeight );
|
||||
}
|
||||
|
||||
protected void addJBRHitTestSpot( JComponent c, boolean subtractMenuBarMargins, List<Rectangle> hitTestSpots ) {
|
||||
Dimension size = c.getSize();
|
||||
if( size.width <= 0 || size.height <= 0 )
|
||||
return;
|
||||
|
||||
Point location = SwingUtilities.convertPoint( c, 0, 0, window );
|
||||
Rectangle r = new Rectangle( location, size );
|
||||
if( subtractMenuBarMargins )
|
||||
r = FlatUIUtils.subtractInsets( r, UIScale.scale( getMenuBarMargins() ) );
|
||||
// slightly increase rectangle so that component receives mouseExit events
|
||||
r.grow( 2, 2 );
|
||||
hitTestSpots.add( r );
|
||||
}
|
||||
|
||||
//---- class TitlePaneBorder ----------------------------------------------
|
||||
|
||||
protected class FlatTitlePaneBorder
|
||||
extends AbstractBorder
|
||||
{
|
||||
@Override
|
||||
public Insets getBorderInsets( Component c, Insets insets ) {
|
||||
super.getBorderInsets( c, insets );
|
||||
|
||||
// if menu bar is embedded, add bottom insets of menu bar border
|
||||
Border menuBarBorder = getMenuBarBorder();
|
||||
if( menuBarBorder != null ) {
|
||||
Insets menuBarInsets = menuBarBorder.getBorderInsets( c );
|
||||
insets.bottom += menuBarInsets.bottom;
|
||||
}
|
||||
|
||||
if( hasJBRCustomDecoration() )
|
||||
insets = FlatUIUtils.addInsets( insets, JBRWindowTopBorder.getInstance().getBorderInsets() );
|
||||
|
||||
return insets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||
// if menu bar is embedded, paint menu bar border
|
||||
Border menuBarBorder = getMenuBarBorder();
|
||||
if( menuBarBorder != null )
|
||||
menuBarBorder.paintBorder( c, g, x, y, width, height );
|
||||
|
||||
if( hasJBRCustomDecoration() )
|
||||
JBRWindowTopBorder.getInstance().paintBorder( c, g, x, y, width, height );
|
||||
}
|
||||
|
||||
protected Border getMenuBarBorder() {
|
||||
JMenuBar menuBar = rootPane.getJMenuBar();
|
||||
return (menuBar != null && isMenuBarEmbedded()) ? menuBar.getBorder() : null;
|
||||
}
|
||||
}
|
||||
|
||||
//---- class Handler ------------------------------------------------------
|
||||
|
||||
protected class Handler
|
||||
extends WindowAdapter
|
||||
implements PropertyChangeListener, MouseListener, MouseMotionListener, ComponentListener
|
||||
{
|
||||
//---- interface PropertyChangeListener ----
|
||||
|
||||
@Override
|
||||
public void propertyChange( PropertyChangeEvent e ) {
|
||||
switch( e.getPropertyName() ) {
|
||||
case "title":
|
||||
titleLabel.setText( getWindowTitle() );
|
||||
break;
|
||||
|
||||
case "resizable":
|
||||
if( window instanceof Frame )
|
||||
frameStateChanged();
|
||||
break;
|
||||
|
||||
case "iconImage":
|
||||
updateIcon();
|
||||
break;
|
||||
|
||||
case "componentOrientation":
|
||||
updateJBRHitTestSpotsAndTitleBarHeightLater();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//---- interface WindowListener ----
|
||||
|
||||
@Override
|
||||
public void windowActivated( WindowEvent e ) {
|
||||
activeChanged( true );
|
||||
updateJBRHitTestSpotsAndTitleBarHeight();
|
||||
|
||||
if( hasJBRCustomDecoration() )
|
||||
JBRWindowTopBorder.getInstance().repaintBorder( FlatTitlePane.this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowDeactivated( WindowEvent e ) {
|
||||
activeChanged( false );
|
||||
updateJBRHitTestSpotsAndTitleBarHeight();
|
||||
|
||||
if( hasJBRCustomDecoration() )
|
||||
JBRWindowTopBorder.getInstance().repaintBorder( FlatTitlePane.this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowStateChanged( WindowEvent e ) {
|
||||
frameStateChanged();
|
||||
updateJBRHitTestSpotsAndTitleBarHeight();
|
||||
}
|
||||
|
||||
//---- interface MouseListener ----
|
||||
|
||||
private int lastXOnScreen;
|
||||
private int lastYOnScreen;
|
||||
|
||||
@Override
|
||||
public void mouseClicked( MouseEvent e ) {
|
||||
if( e.getClickCount() == 2 && SwingUtilities.isLeftMouseButton( e ) ) {
|
||||
if( e.getSource() == iconLabel ) {
|
||||
// double-click on icon closes window
|
||||
close();
|
||||
} else if( !hasJBRCustomDecoration() &&
|
||||
window instanceof Frame &&
|
||||
((Frame)window).isResizable() )
|
||||
{
|
||||
// maximize/restore on double-click
|
||||
Frame frame = (Frame) window;
|
||||
if( (frame.getExtendedState() & Frame.MAXIMIZED_BOTH) != 0 )
|
||||
restore();
|
||||
else
|
||||
maximize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed( MouseEvent e ) {
|
||||
lastXOnScreen = e.getXOnScreen();
|
||||
lastYOnScreen = e.getYOnScreen();
|
||||
}
|
||||
|
||||
@Override public void mouseReleased( MouseEvent e ) {}
|
||||
@Override public void mouseEntered( MouseEvent e ) {}
|
||||
@Override public void mouseExited( MouseEvent e ) {}
|
||||
|
||||
//---- interface MouseMotionListener ----
|
||||
|
||||
@Override
|
||||
public void mouseDragged( MouseEvent e ) {
|
||||
if( hasJBRCustomDecoration() )
|
||||
return; // do nothing if running in JBR
|
||||
|
||||
int xOnScreen = e.getXOnScreen();
|
||||
int yOnScreen = e.getYOnScreen();
|
||||
if( lastXOnScreen == xOnScreen && lastYOnScreen == yOnScreen )
|
||||
return;
|
||||
|
||||
// restore window if it is maximized
|
||||
if( window instanceof Frame ) {
|
||||
Frame frame = (Frame) window;
|
||||
int state = frame.getExtendedState();
|
||||
if( (state & Frame.MAXIMIZED_BOTH) != 0 ) {
|
||||
int maximizedX = window.getX();
|
||||
int maximizedY = window.getY();
|
||||
|
||||
// restore window size, which also moves window to pre-maximized location
|
||||
frame.setExtendedState( state & ~Frame.MAXIMIZED_BOTH );
|
||||
|
||||
int restoredWidth = window.getWidth();
|
||||
int newX = maximizedX;
|
||||
JComponent rightComp = getComponentOrientation().isLeftToRight() ? buttonPanel : leftPanel;
|
||||
if( xOnScreen >= maximizedX + restoredWidth - rightComp.getWidth() - 10 )
|
||||
newX = xOnScreen + rightComp.getWidth() + 10 - restoredWidth;
|
||||
|
||||
// move window near mouse
|
||||
window.setLocation( newX, maximizedY );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// compute new window location
|
||||
int newX = window.getX() + (xOnScreen - lastXOnScreen);
|
||||
int newY = window.getY() + (yOnScreen - lastYOnScreen);
|
||||
|
||||
// move window
|
||||
window.setLocation( newX, newY );
|
||||
|
||||
lastXOnScreen = xOnScreen;
|
||||
lastYOnScreen = yOnScreen;
|
||||
}
|
||||
|
||||
@Override public void mouseMoved( MouseEvent e ) {}
|
||||
|
||||
//---- interface ComponentListener ----
|
||||
|
||||
@Override
|
||||
public void componentResized( ComponentEvent e ) {
|
||||
updateJBRHitTestSpotsAndTitleBarHeightLater();
|
||||
}
|
||||
|
||||
@Override public void componentMoved( ComponentEvent e ) {}
|
||||
@Override public void componentShown( ComponentEvent e ) {}
|
||||
@Override public void componentHidden( ComponentEvent e ) {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2020 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.Dimension;
|
||||
import java.awt.Image;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
import com.formdev.flatlaf.util.MultiResolutionImageSupport;
|
||||
import com.formdev.flatlaf.util.ScaledImageIcon;
|
||||
|
||||
/**
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatTitlePaneIcon
|
||||
extends ScaledImageIcon
|
||||
{
|
||||
public static Icon create( List<Image> images, Dimension size ) {
|
||||
// collect all images including multi-resolution variants
|
||||
List<Image> allImages = new ArrayList<>();
|
||||
for( Image image : images ) {
|
||||
if( MultiResolutionImageSupport.isMultiResolutionImage( image ) )
|
||||
allImages.addAll( MultiResolutionImageSupport.getResolutionVariants( image ) );
|
||||
else
|
||||
allImages.add( image );
|
||||
}
|
||||
|
||||
// sort images by size
|
||||
allImages.sort( (image1, image2) -> {
|
||||
return image1.getWidth( null ) - image2.getWidth( null );
|
||||
} );
|
||||
|
||||
// create icon
|
||||
return new FlatTitlePaneIcon( allImages, size );
|
||||
}
|
||||
|
||||
private final List<Image> images;
|
||||
|
||||
private FlatTitlePaneIcon( List<Image> images, Dimension size ) {
|
||||
super( new ImageIcon( images.get( 0 ) ), size.width, size.height );
|
||||
this.images = images;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Image getResolutionVariant( int destImageWidth, int destImageHeight ) {
|
||||
for( Image image : images ) {
|
||||
if( destImageWidth <= image.getWidth( null ) &&
|
||||
destImageHeight <= image.getHeight( null ) )
|
||||
return image;
|
||||
}
|
||||
|
||||
return images.get( images.size() - 1 );
|
||||
}
|
||||
}
|
||||
@@ -50,6 +50,7 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault ToggleButton.startBackground Color optional; if set, a gradient paint is used and ToggleButton.background is ignored
|
||||
* @uiDefault ToggleButton.endBackground Color optional; if set, a gradient paint is used
|
||||
* @uiDefault ToggleButton.pressedBackground Color
|
||||
* @uiDefault ToggleButton.disabledBackground Color optional
|
||||
* @uiDefault ToggleButton.disabledText Color
|
||||
* @uiDefault ToggleButton.toolbar.hoverBackground Color
|
||||
* @uiDefault ToggleButton.toolbar.pressedBackground Color
|
||||
@@ -138,7 +139,7 @@ public class FlatToggleButtonUI
|
||||
case BUTTON_TYPE:
|
||||
if( BUTTON_TYPE_TAB.equals( e.getOldValue() ) || BUTTON_TYPE_TAB.equals( e.getNewValue() ) ) {
|
||||
MigLayoutVisualPadding.uninstall( b );
|
||||
MigLayoutVisualPadding.install( b, getFocusWidth( b ) );
|
||||
MigLayoutVisualPadding.install( b );
|
||||
b.revalidate();
|
||||
}
|
||||
|
||||
@@ -205,16 +206,9 @@ public class FlatToggleButtonUI
|
||||
|
||||
@Override
|
||||
protected Color getForeground( JComponent c ) {
|
||||
ButtonModel model = ((AbstractButton)c).getModel();
|
||||
|
||||
if( model.isSelected() && !isToolBarButton( c ) )
|
||||
if( c.isEnabled() && ((AbstractButton)c).isSelected() && !isToolBarButton( c ) )
|
||||
return selectedForeground;
|
||||
|
||||
return super.getForeground( c );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getFocusWidth( JComponent c ) {
|
||||
return isTabButton( c ) ? 0 : super.getFocusWidth( c );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,9 @@ import javax.swing.JComponent;
|
||||
import javax.swing.JToolTip;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicHTML;
|
||||
import javax.swing.plaf.basic.BasicToolTipUI;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -102,7 +104,7 @@ public class FlatToolTipUI
|
||||
for( String line : lines )
|
||||
width = Math.max( width, SwingUtilities.computeStringWidth( fm, line ) );
|
||||
|
||||
return new Dimension( insets.left + width + insets.right, insets.top + height + insets.bottom );
|
||||
return new Dimension( insets.left + width + insets.right + 6, insets.top + height + insets.bottom );
|
||||
} else
|
||||
return super.getPreferredSize( c );
|
||||
}
|
||||
@@ -118,8 +120,8 @@ public class FlatToolTipUI
|
||||
|
||||
List<String> lines = StringUtils.split( ((JToolTip)c).getTipText(), '\n' );
|
||||
|
||||
int x = insets.left;
|
||||
int x2 = c.getWidth() - insets.right;
|
||||
int x = insets.left + 3;
|
||||
int x2 = c.getWidth() - insets.right - 3;
|
||||
int y = insets.top - fm.getDescent();
|
||||
int lineHeight = fm.getHeight();
|
||||
JComponent comp = ((JToolTip)c).getComponent();
|
||||
@@ -129,11 +131,11 @@ public class FlatToolTipUI
|
||||
FlatUIUtils.drawString( c, g, line, leftToRight ? x : x2 - SwingUtilities.computeStringWidth( fm, line ), y );
|
||||
}
|
||||
} else
|
||||
super.paint( g, c );
|
||||
super.paint( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ), c );
|
||||
}
|
||||
|
||||
private boolean isMultiLine( JComponent c ) {
|
||||
String text = ((JToolTip)c).getTipText();
|
||||
return c.getClientProperty( "html" ) == null && text != null && text.indexOf( '\n' ) >= 0;
|
||||
return c.getClientProperty( BasicHTML.propertyKey ) == null && text != null && text.indexOf( '\n' ) >= 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,11 +39,13 @@ import java.util.function.Consumer;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.border.CompoundBorder;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.util.DerivedColor;
|
||||
import com.formdev.flatlaf.util.Graphics2DProxy;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.JavaCompatibility;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
@@ -141,6 +143,47 @@ public class FlatUIUtils
|
||||
return (KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner() == c);
|
||||
}
|
||||
|
||||
public static boolean isRoundRect( Component c ) {
|
||||
return c instanceof JComponent && FlatClientProperties.clientPropertyBoolean(
|
||||
(JComponent) c, FlatClientProperties.COMPONENT_ROUND_RECT, false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the scaled thickness of the outer focus border for the given component.
|
||||
*/
|
||||
public static float getBorderFocusWidth( JComponent c ) {
|
||||
FlatBorder border = getOutsideFlatBorder( c );
|
||||
return (border != null)
|
||||
? UIScale.scale( (float) border.getFocusWidth( c ) )
|
||||
: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the scaled arc diameter of the border for the given component.
|
||||
*/
|
||||
public static float getBorderArc( JComponent c ) {
|
||||
FlatBorder border = getOutsideFlatBorder( c );
|
||||
return (border != null)
|
||||
? UIScale.scale( (float) border.getArc( c ) )
|
||||
: 0;
|
||||
}
|
||||
|
||||
public static boolean hasRoundBorder( JComponent c ) {
|
||||
return getBorderArc( c ) >= c.getHeight();
|
||||
}
|
||||
|
||||
public static FlatBorder getOutsideFlatBorder( JComponent c ) {
|
||||
Border border = c.getBorder();
|
||||
for(;;) {
|
||||
if( border instanceof FlatBorder )
|
||||
return (FlatBorder) border;
|
||||
else if( border instanceof CompoundBorder )
|
||||
border = ((CompoundBorder)border).getOutsideBorder();
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets rendering hints used for painting.
|
||||
*/
|
||||
@@ -150,10 +193,10 @@ public class FlatUIUtils
|
||||
MAC_USE_QUARTZ ? RenderingHints.VALUE_STROKE_PURE : RenderingHints.VALUE_STROKE_NORMALIZE );
|
||||
}
|
||||
|
||||
public static void setColor( Graphics g, Color color, Color baseColor ) {
|
||||
if( color instanceof DerivedColor )
|
||||
color = ((DerivedColor)color).derive( baseColor );
|
||||
g.setColor( color );
|
||||
public static Color deriveColor( Color color, Color baseColor ) {
|
||||
return (color instanceof DerivedColor)
|
||||
? ((DerivedColor)color).derive( baseColor )
|
||||
: color;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -194,14 +237,9 @@ public class FlatUIUtils
|
||||
if( arc > 0 && arc < UIScale.scale( 10 ) )
|
||||
outerArc -= UIScale.scale( 2f );
|
||||
|
||||
if( outerArc < 0 )
|
||||
outerArc = 0;
|
||||
if( innerArc < 0 )
|
||||
innerArc = 0;
|
||||
|
||||
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
||||
path.append( new RoundRectangle2D.Float( x, y, width, height, outerArc, outerArc ), false );
|
||||
path.append( new RoundRectangle2D.Float( x + ow, y + ow, width - (ow * 2), height - (ow * 2), innerArc, innerArc ), false );
|
||||
path.append( createComponentRectangle( x, y, width, height, outerArc ), false );
|
||||
path.append( createComponentRectangle( x + ow, y + ow, width - (ow * 2), height - (ow * 2), innerArc ), false );
|
||||
g.fill( path );
|
||||
}
|
||||
|
||||
@@ -235,19 +273,16 @@ public class FlatUIUtils
|
||||
private static void paintComponentBorderImpl( Graphics2D g, int x, int y, int width, int height,
|
||||
float focusWidth, float lineWidth, float arc )
|
||||
{
|
||||
float x1 = x + focusWidth;
|
||||
float y1 = y + focusWidth;
|
||||
float width1 = width - focusWidth * 2;
|
||||
float height1 = height - focusWidth * 2;
|
||||
float arc2 = arc - (lineWidth * 2);
|
||||
|
||||
if( arc < 0 )
|
||||
arc = 0;
|
||||
if( arc2 < 0 )
|
||||
arc2 = 0;
|
||||
|
||||
RoundRectangle2D.Float r1 = new RoundRectangle2D.Float(
|
||||
x + focusWidth, y + focusWidth,
|
||||
width - focusWidth * 2, height - focusWidth * 2, arc, arc );
|
||||
RoundRectangle2D.Float r2 = new RoundRectangle2D.Float(
|
||||
r1.x + lineWidth, r1.y + lineWidth,
|
||||
r1.width - lineWidth * 2, r1.height - lineWidth * 2, arc2, arc2 );
|
||||
Shape r1 = createComponentRectangle( x1, y1, width1, height1, arc );
|
||||
Shape r2 = createComponentRectangle(
|
||||
x1 + lineWidth, y1 + lineWidth,
|
||||
width1 - lineWidth * 2, height1 - lineWidth * 2, arc2 );
|
||||
|
||||
Path2D border = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
||||
border.append( r1, false );
|
||||
@@ -285,12 +320,21 @@ public class FlatUIUtils
|
||||
private static void paintComponentBackgroundImpl( Graphics2D g, int x, int y, int width, int height,
|
||||
float focusWidth, float arc )
|
||||
{
|
||||
if( arc < 0 )
|
||||
arc = 0;
|
||||
|
||||
g.fill( new RoundRectangle2D.Float(
|
||||
g.fill( createComponentRectangle(
|
||||
x + focusWidth, y + focusWidth,
|
||||
width - focusWidth * 2, height - focusWidth * 2, arc, arc ) );
|
||||
width - focusWidth * 2, height - focusWidth * 2, arc ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a (rounded) rectangle used to paint components (border, background, etc).
|
||||
* The given arc diameter is limited to min(width,height).
|
||||
*/
|
||||
public static Shape createComponentRectangle( float x, float y, float w, float h, float arc ) {
|
||||
if( arc <= 0 )
|
||||
return new Rectangle2D.Float( x, y, w, h );
|
||||
|
||||
arc = Math.min( arc, Math.min( w, h ) );
|
||||
return new RoundRectangle2D.Float( x, y, w, h, arc, arc );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -359,14 +403,12 @@ public class FlatUIUtils
|
||||
if( arcTopLeft <= 0 && arcTopRight <= 0 && arcBottomLeft <= 0 && arcBottomRight <= 0 )
|
||||
return new Rectangle2D.Float( x, y, width, height );
|
||||
|
||||
if( arcTopLeft < 0 )
|
||||
arcTopLeft = 0;
|
||||
if( arcTopRight < 0 )
|
||||
arcTopRight = 0;
|
||||
if( arcBottomLeft < 0 )
|
||||
arcBottomLeft = 0;
|
||||
if( arcBottomRight < 0 )
|
||||
arcBottomRight = 0;
|
||||
// limit arcs to min(width,height)
|
||||
float maxArc = Math.min( width, height ) / 2;
|
||||
arcTopLeft = (arcTopLeft > 0) ? Math.min( arcTopLeft, maxArc ) : 0;
|
||||
arcTopRight = (arcTopRight > 0) ? Math.min( arcTopRight, maxArc ) : 0;
|
||||
arcBottomLeft = (arcBottomLeft > 0) ? Math.min( arcBottomLeft, maxArc ) : 0;
|
||||
arcBottomRight = (arcBottomRight > 0) ? Math.min( arcBottomRight, maxArc ) : 0;
|
||||
|
||||
float x2 = x + width;
|
||||
float y2 = y + height;
|
||||
@@ -406,28 +448,46 @@ public class FlatUIUtils
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the given string at the specified location using text properties
|
||||
* and anti-aliasing hints from the provided component.
|
||||
*
|
||||
* Use this method instead of Graphics.drawString() for correct anti-aliasing.
|
||||
*
|
||||
* Replacement for SwingUtilities2.drawString()
|
||||
* Draws the given string at the specified location.
|
||||
* The provided component is used to query text properties and anti-aliasing hints.
|
||||
* <p>
|
||||
* Use this method instead of {@link Graphics#drawString(String, int, int)} for correct anti-aliasing.
|
||||
* <p>
|
||||
* Replacement for {@code SwingUtilities2.drawString()}.
|
||||
* Uses {@link HiDPIUtils#drawStringWithYCorrection(JComponent, Graphics2D, String, int, int)}.
|
||||
*/
|
||||
public static void drawString( JComponent c, Graphics g, String text, int x, int y ) {
|
||||
JavaCompatibility.drawStringUnderlineCharAt( c, g, text, -1, x, y );
|
||||
HiDPIUtils.drawStringWithYCorrection( c, (Graphics2D) g, text, x, y );
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the given string at the specified location underlining the specified
|
||||
* character. The provided component is used to query text properties and
|
||||
* anti-aliasing hints.
|
||||
*
|
||||
* Replacement for SwingUtilities2.drawStringUnderlineCharAt()
|
||||
* Draws the given string at the specified location underlining the specified character.
|
||||
* The provided component is used to query text properties and anti-aliasing hints.
|
||||
* <p>
|
||||
* Replacement for {@code SwingUtilities2.drawStringUnderlineCharAt()}.
|
||||
* Uses {@link HiDPIUtils#drawStringUnderlineCharAtWithYCorrection(JComponent, Graphics2D, String, int, int, int)}.
|
||||
*/
|
||||
public static void drawStringUnderlineCharAt( JComponent c, Graphics g,
|
||||
String text, int underlinedIndex, int x, int y )
|
||||
{
|
||||
JavaCompatibility.drawStringUnderlineCharAt( c, g, text, underlinedIndex, x, y );
|
||||
// scale underline height if necessary
|
||||
if( underlinedIndex >= 0 && UIScale.getUserScaleFactor() > 1 ) {
|
||||
g = new Graphics2DProxy( (Graphics2D) g ) {
|
||||
@Override
|
||||
public void fillRect( int x, int y, int width, int height ) {
|
||||
if( height == 1 ) {
|
||||
// scale height and correct y position
|
||||
// (using 0.9f so that underline height is 1 at scale factor 1.5x)
|
||||
height = Math.round( UIScale.scale( 0.9f ) );
|
||||
y += height - 1;
|
||||
}
|
||||
|
||||
super.fillRect( x, y, width, height );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
HiDPIUtils.drawStringUnderlineCharAtWithYCorrection( c, (Graphics2D) g, text, underlinedIndex, x, y );
|
||||
}
|
||||
|
||||
public static boolean hasOpaqueBeenExplicitlySet( JComponent c ) {
|
||||
|
||||
@@ -0,0 +1,325 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import static java.awt.Cursor.*;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dialog;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Frame;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.event.ComponentListener;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.awt.event.MouseMotionListener;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.awt.event.WindowStateListener;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLayeredPane;
|
||||
import javax.swing.JRootPane;
|
||||
import javax.swing.UIManager;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
* Resizes frames and dialogs.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatWindowResizer
|
||||
extends JComponent
|
||||
implements PropertyChangeListener, WindowStateListener, ComponentListener
|
||||
{
|
||||
private final static Integer WINDOW_RESIZER_LAYER = JLayeredPane.DRAG_LAYER + 1;
|
||||
|
||||
private final JRootPane rootPane;
|
||||
|
||||
private final int borderDragThickness = FlatUIUtils.getUIInt( "RootPane.borderDragThickness", 5 );
|
||||
private final int cornerDragWidth = FlatUIUtils.getUIInt( "RootPane.cornerDragWidth", 16 );
|
||||
private final boolean honorMinimumSizeOnResize = UIManager.getBoolean( "RootPane.honorMinimumSizeOnResize" );
|
||||
|
||||
private Window window;
|
||||
|
||||
public FlatWindowResizer( JRootPane rootPane ) {
|
||||
this.rootPane = rootPane;
|
||||
|
||||
setLayout( new BorderLayout() );
|
||||
add( createDragBorderComponent( NW_RESIZE_CURSOR, N_RESIZE_CURSOR, NE_RESIZE_CURSOR ), BorderLayout.NORTH );
|
||||
add( createDragBorderComponent( SW_RESIZE_CURSOR, S_RESIZE_CURSOR, SE_RESIZE_CURSOR ), BorderLayout.SOUTH );
|
||||
add( createDragBorderComponent( NW_RESIZE_CURSOR, W_RESIZE_CURSOR, SW_RESIZE_CURSOR ), BorderLayout.WEST );
|
||||
add( createDragBorderComponent( NE_RESIZE_CURSOR, E_RESIZE_CURSOR, SE_RESIZE_CURSOR ), BorderLayout.EAST );
|
||||
|
||||
rootPane.addComponentListener( this );
|
||||
rootPane.getLayeredPane().add( this, WINDOW_RESIZER_LAYER );
|
||||
|
||||
if( rootPane.isDisplayable() )
|
||||
setBounds( 0, 0, rootPane.getWidth(), rootPane.getHeight() );
|
||||
}
|
||||
|
||||
protected DragBorderComponent createDragBorderComponent( int leadingResizeDir, int centerResizeDir, int trailingResizeDir ) {
|
||||
return new DragBorderComponent( leadingResizeDir, centerResizeDir, trailingResizeDir );
|
||||
}
|
||||
|
||||
public void uninstall() {
|
||||
rootPane.removeComponentListener( this );
|
||||
rootPane.getLayeredPane().remove( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNotify() {
|
||||
super.addNotify();
|
||||
|
||||
Container parent = rootPane.getParent();
|
||||
window = (parent instanceof Window) ? (Window) parent : null;
|
||||
if( window instanceof Frame ) {
|
||||
window.addPropertyChangeListener( "resizable", this );
|
||||
window.addWindowStateListener( this );
|
||||
}
|
||||
|
||||
updateVisibility();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNotify() {
|
||||
super.removeNotify();
|
||||
|
||||
if( window instanceof Frame ) {
|
||||
window.removePropertyChangeListener( "resizable", this );
|
||||
window.removeWindowStateListener( this );
|
||||
}
|
||||
window = null;
|
||||
|
||||
updateVisibility();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintChildren( Graphics g ) {
|
||||
super.paintChildren( g );
|
||||
|
||||
// this is necessary because Dialog.setResizable() does not fire events
|
||||
if( window instanceof Dialog )
|
||||
updateVisibility();
|
||||
}
|
||||
|
||||
private void updateVisibility() {
|
||||
boolean visible = isWindowResizable();
|
||||
if( visible == getComponent( 0 ).isVisible() )
|
||||
return;
|
||||
|
||||
for( Component c : getComponents() )
|
||||
c.setVisible( visible );
|
||||
}
|
||||
|
||||
private boolean isWindowResizable() {
|
||||
if( window instanceof Frame )
|
||||
return ((Frame)window).isResizable() && (((Frame)window).getExtendedState() & Frame.MAXIMIZED_BOTH) == 0;
|
||||
if( window instanceof Dialog )
|
||||
return ((Dialog)window).isResizable();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void propertyChange( PropertyChangeEvent e ) {
|
||||
updateVisibility();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowStateChanged( WindowEvent e ) {
|
||||
updateVisibility();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentResized( ComponentEvent e ) {
|
||||
setBounds( 0, 0, rootPane.getWidth(), rootPane.getHeight() );
|
||||
validate();
|
||||
}
|
||||
|
||||
@Override public void componentMoved( ComponentEvent e ) {}
|
||||
@Override public void componentShown( ComponentEvent e ) {}
|
||||
@Override public void componentHidden( ComponentEvent e ) {}
|
||||
|
||||
//---- class DragBorderComponent ------------------------------------------
|
||||
|
||||
protected class DragBorderComponent
|
||||
extends JComponent
|
||||
implements MouseListener, MouseMotionListener
|
||||
{
|
||||
private final int leadingResizeDir;
|
||||
private final int centerResizeDir;
|
||||
private final int trailingResizeDir;
|
||||
|
||||
private int resizeDir = -1;
|
||||
private int dragStartMouseX;
|
||||
private int dragStartMouseY;
|
||||
private Rectangle dragStartWindowBounds;
|
||||
|
||||
protected DragBorderComponent( int leadingResizeDir, int centerResizeDir, int trailingResizeDir ) {
|
||||
this.leadingResizeDir = leadingResizeDir;
|
||||
this.centerResizeDir = centerResizeDir;
|
||||
this.trailingResizeDir = trailingResizeDir;
|
||||
|
||||
setResizeDir( centerResizeDir );
|
||||
setVisible( false );
|
||||
|
||||
addMouseListener( this );
|
||||
addMouseMotionListener( this );
|
||||
}
|
||||
|
||||
protected void setResizeDir( int resizeDir ) {
|
||||
if( this.resizeDir == resizeDir )
|
||||
return;
|
||||
this.resizeDir = resizeDir;
|
||||
|
||||
setCursor( getPredefinedCursor( resizeDir ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
int thickness = UIScale.scale( borderDragThickness );
|
||||
return new Dimension( thickness, thickness );
|
||||
}
|
||||
|
||||
/*debug
|
||||
@Override
|
||||
protected void paintComponent( Graphics g ) {
|
||||
g.setColor( java.awt.Color.red );
|
||||
g.drawRect( 0, 0, getWidth() - 1, getHeight() - 1 );
|
||||
}
|
||||
debug*/
|
||||
|
||||
@Override
|
||||
public void mouseClicked( MouseEvent e ) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed( MouseEvent e ) {
|
||||
if( window == null )
|
||||
return;
|
||||
|
||||
dragStartMouseX = e.getXOnScreen();
|
||||
dragStartMouseY = e.getYOnScreen();
|
||||
dragStartWindowBounds = window.getBounds();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased( MouseEvent e ) {
|
||||
dragStartWindowBounds = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseEntered( MouseEvent e ) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited( MouseEvent e ) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseMoved( MouseEvent e ) {
|
||||
boolean topBottom = (centerResizeDir == N_RESIZE_CURSOR || centerResizeDir == S_RESIZE_CURSOR);
|
||||
int xy = topBottom ? e.getX() : e.getY();
|
||||
int wh = topBottom ? getWidth() : getHeight();
|
||||
int cornerWH = UIScale.scale( cornerDragWidth - (topBottom ? 0 : borderDragThickness) );
|
||||
|
||||
setResizeDir( xy <= cornerWH
|
||||
? leadingResizeDir
|
||||
: (xy >= wh - cornerWH
|
||||
? trailingResizeDir
|
||||
: centerResizeDir) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDragged( MouseEvent e ) {
|
||||
if( dragStartWindowBounds == null )
|
||||
return;
|
||||
|
||||
if( !isWindowResizable() )
|
||||
return;
|
||||
|
||||
int mouseDeltaX = e.getXOnScreen() - dragStartMouseX;
|
||||
int mouseDeltaY = e.getYOnScreen() - dragStartMouseY;
|
||||
|
||||
int deltaX = 0;
|
||||
int deltaY = 0;
|
||||
int deltaWidth = 0;
|
||||
int deltaHeight = 0;
|
||||
|
||||
// north
|
||||
if( resizeDir == N_RESIZE_CURSOR || resizeDir == NW_RESIZE_CURSOR || resizeDir == NE_RESIZE_CURSOR ) {
|
||||
deltaY = mouseDeltaY;
|
||||
deltaHeight = -mouseDeltaY;
|
||||
}
|
||||
|
||||
// south
|
||||
if( resizeDir == S_RESIZE_CURSOR || resizeDir == SW_RESIZE_CURSOR || resizeDir == SE_RESIZE_CURSOR )
|
||||
deltaHeight = mouseDeltaY;
|
||||
|
||||
// west
|
||||
if( resizeDir == W_RESIZE_CURSOR || resizeDir == NW_RESIZE_CURSOR || resizeDir == SW_RESIZE_CURSOR ) {
|
||||
deltaX = mouseDeltaX;
|
||||
deltaWidth = -mouseDeltaX;
|
||||
}
|
||||
|
||||
// east
|
||||
if( resizeDir == E_RESIZE_CURSOR || resizeDir == NE_RESIZE_CURSOR || resizeDir == SE_RESIZE_CURSOR )
|
||||
deltaWidth = mouseDeltaX;
|
||||
|
||||
// compute new window bounds
|
||||
Rectangle newBounds = new Rectangle( dragStartWindowBounds );
|
||||
newBounds.x += deltaX;
|
||||
newBounds.y += deltaY;
|
||||
newBounds.width += deltaWidth;
|
||||
newBounds.height += deltaHeight;
|
||||
|
||||
// apply minimum window size
|
||||
Dimension minimumSize = honorMinimumSizeOnResize ? window.getMinimumSize() : null;
|
||||
if( minimumSize == null )
|
||||
minimumSize = UIScale.scale( new Dimension( 150, 50 ) );
|
||||
if( newBounds.width < minimumSize.width ) {
|
||||
if( deltaX != 0 )
|
||||
newBounds.x -= (minimumSize.width - newBounds.width);
|
||||
newBounds.width = minimumSize.width;
|
||||
}
|
||||
if( newBounds.height < minimumSize.height ) {
|
||||
if( deltaY != 0 )
|
||||
newBounds.y -= (minimumSize.height - newBounds.height);
|
||||
newBounds.height = minimumSize.height;
|
||||
}
|
||||
|
||||
// set window bounds
|
||||
if( !newBounds.equals( dragStartWindowBounds ) ) {
|
||||
window.setBounds( newBounds );
|
||||
|
||||
// immediately layout drag border components
|
||||
FlatWindowResizer.this.setBounds( 0, 0, newBounds.width, newBounds.height );
|
||||
FlatWindowResizer.this.validate();
|
||||
|
||||
if( Toolkit.getDefaultToolkit().isDynamicLayoutActive() ) {
|
||||
window.validate();
|
||||
rootPane.repaint();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
* Copyright 2020 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.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.HierarchyEvent;
|
||||
import java.awt.event.HierarchyListener;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JRootPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.BorderUIResource;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.FlatSystemProperties;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
|
||||
/**
|
||||
* Support for custom window decorations provided by JetBrains Runtime (based on OpenJDK).
|
||||
* Requires that the application runs on Windows 10 in a JetBrains Runtime 11 or later.
|
||||
* <ul>
|
||||
* <li><a href="https://confluence.jetbrains.com/display/JBR/JetBrains+Runtime">https://confluence.jetbrains.com/display/JBR/JetBrains+Runtime</a></li>
|
||||
* <li><a href="https://github.com/JetBrains/JetBrainsRuntime">https://github.com/JetBrains/JetBrainsRuntime</a></li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class JBRCustomDecorations
|
||||
{
|
||||
private static boolean initialized;
|
||||
private static Method Window_hasCustomDecoration;
|
||||
private static Method Window_setHasCustomDecoration;
|
||||
private static Method WWindowPeer_setCustomDecorationHitTestSpots;
|
||||
private static Method WWindowPeer_setCustomDecorationTitleBarHeight;
|
||||
private static Method AWTAccessor_getComponentAccessor;
|
||||
private static Method AWTAccessor_ComponentAccessor_getPeer;
|
||||
|
||||
public static boolean isSupported() {
|
||||
initialize();
|
||||
return Window_setHasCustomDecoration != null;
|
||||
}
|
||||
|
||||
static void install( JRootPane rootPane ) {
|
||||
if( !isSupported() )
|
||||
return;
|
||||
|
||||
// check whether root pane already has a parent, which is the case when switching LaF
|
||||
if( rootPane.getParent() != null )
|
||||
return;
|
||||
|
||||
// Use hierarchy listener to wait until the root pane is added to a window.
|
||||
// Enabling JBR decorations must be done very early, probably before
|
||||
// window becomes displayable (window.isDisplayable()). Tried also using
|
||||
// "ancestor" property change event on root pane, but this is invoked too late.
|
||||
HierarchyListener addListener = new HierarchyListener() {
|
||||
@Override
|
||||
public void hierarchyChanged( HierarchyEvent e ) {
|
||||
if( e.getChanged() != rootPane || (e.getChangeFlags() & HierarchyEvent.PARENT_CHANGED) == 0 )
|
||||
return;
|
||||
|
||||
Container parent = e.getChangedParent();
|
||||
if( parent instanceof Window )
|
||||
install( (Window) parent );
|
||||
|
||||
// use invokeLater to remove listener to avoid that listener
|
||||
// is removed while listener queue is processed
|
||||
EventQueue.invokeLater( () -> {
|
||||
rootPane.removeHierarchyListener( this );
|
||||
} );
|
||||
}
|
||||
};
|
||||
rootPane.addHierarchyListener( addListener );
|
||||
}
|
||||
|
||||
static void install( Window window ) {
|
||||
if( !isSupported() )
|
||||
return;
|
||||
|
||||
// do not enable JBR decorations if LaF provides decorations
|
||||
if( UIManager.getLookAndFeel().getSupportsWindowDecorations() )
|
||||
return;
|
||||
|
||||
if( window instanceof JFrame ) {
|
||||
JFrame frame = (JFrame) window;
|
||||
|
||||
// do not enable JBR decorations if JFrame should use system window decorations
|
||||
// and if not forced to use JBR decorations
|
||||
if( !JFrame.isDefaultLookAndFeelDecorated() &&
|
||||
!FlatSystemProperties.getBoolean( FlatSystemProperties.USE_JETBRAINS_CUSTOM_DECORATIONS, false ))
|
||||
return;
|
||||
|
||||
// do not enable JBR decorations if frame is undecorated
|
||||
if( frame.isUndecorated() )
|
||||
return;
|
||||
|
||||
// enable JBR custom window decoration for window
|
||||
setHasCustomDecoration( frame );
|
||||
|
||||
// enable Swing window decoration
|
||||
frame.getRootPane().setWindowDecorationStyle( JRootPane.FRAME );
|
||||
|
||||
} else if( window instanceof JDialog ) {
|
||||
JDialog dialog = (JDialog) window;
|
||||
|
||||
// do not enable JBR decorations if JDialog should use system window decorations
|
||||
// and if not forced to use JBR decorations
|
||||
if( !JDialog.isDefaultLookAndFeelDecorated() &&
|
||||
!FlatSystemProperties.getBoolean( FlatSystemProperties.USE_JETBRAINS_CUSTOM_DECORATIONS, false ))
|
||||
return;
|
||||
|
||||
// do not enable JBR decorations if dialog is undecorated
|
||||
if( dialog.isUndecorated() )
|
||||
return;
|
||||
|
||||
// enable JBR custom window decoration for window
|
||||
setHasCustomDecoration( dialog );
|
||||
|
||||
// enable Swing window decoration
|
||||
dialog.getRootPane().setWindowDecorationStyle( JRootPane.PLAIN_DIALOG );
|
||||
}
|
||||
}
|
||||
|
||||
static boolean hasCustomDecoration( Window window ) {
|
||||
if( !isSupported() )
|
||||
return false;
|
||||
|
||||
try {
|
||||
return (Boolean) Window_hasCustomDecoration.invoke( window );
|
||||
} catch( Exception ex ) {
|
||||
Logger.getLogger( FlatLaf.class.getName() ).log( Level.SEVERE, null, ex );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void setHasCustomDecoration( Window window ) {
|
||||
if( !isSupported() )
|
||||
return;
|
||||
|
||||
try {
|
||||
Window_setHasCustomDecoration.invoke( window );
|
||||
} catch( Exception ex ) {
|
||||
Logger.getLogger( FlatLaf.class.getName() ).log( Level.SEVERE, null, ex );
|
||||
}
|
||||
}
|
||||
|
||||
static void setHitTestSpotsAndTitleBarHeight( Window window, List<Rectangle> hitTestSpots, int titleBarHeight ) {
|
||||
if( !isSupported() )
|
||||
return;
|
||||
|
||||
try {
|
||||
Object compAccessor = AWTAccessor_getComponentAccessor.invoke( null );
|
||||
Object peer = AWTAccessor_ComponentAccessor_getPeer.invoke( compAccessor, window );
|
||||
WWindowPeer_setCustomDecorationHitTestSpots.invoke( peer, hitTestSpots );
|
||||
WWindowPeer_setCustomDecorationTitleBarHeight.invoke( peer, titleBarHeight );
|
||||
} catch( Exception ex ) {
|
||||
Logger.getLogger( FlatLaf.class.getName() ).log( Level.SEVERE, null, ex );
|
||||
}
|
||||
}
|
||||
|
||||
private static void initialize() {
|
||||
if( initialized )
|
||||
return;
|
||||
initialized = true;
|
||||
|
||||
// requires JetBrains Runtime 11 and Windows 10
|
||||
if( !SystemInfo.IS_JETBRAINS_JVM_11_OR_LATER || !SystemInfo.IS_WINDOWS_10_OR_LATER )
|
||||
return;
|
||||
|
||||
if( !FlatSystemProperties.getBoolean( FlatSystemProperties.USE_JETBRAINS_CUSTOM_DECORATIONS, true ) )
|
||||
return;
|
||||
|
||||
try {
|
||||
Class<?> awtAcessorClass = Class.forName( "sun.awt.AWTAccessor" );
|
||||
Class<?> compAccessorClass = Class.forName( "sun.awt.AWTAccessor$ComponentAccessor" );
|
||||
AWTAccessor_getComponentAccessor = awtAcessorClass.getDeclaredMethod( "getComponentAccessor" );
|
||||
AWTAccessor_ComponentAccessor_getPeer = compAccessorClass.getDeclaredMethod( "getPeer", Component.class );
|
||||
|
||||
Class<?> peerClass = Class.forName( "sun.awt.windows.WWindowPeer" );
|
||||
WWindowPeer_setCustomDecorationHitTestSpots = peerClass.getDeclaredMethod( "setCustomDecorationHitTestSpots", List.class );
|
||||
WWindowPeer_setCustomDecorationTitleBarHeight = peerClass.getDeclaredMethod( "setCustomDecorationTitleBarHeight", int.class );
|
||||
WWindowPeer_setCustomDecorationHitTestSpots.setAccessible( true );
|
||||
WWindowPeer_setCustomDecorationTitleBarHeight.setAccessible( true );
|
||||
|
||||
Window_hasCustomDecoration = Window.class.getDeclaredMethod( "hasCustomDecoration" );
|
||||
Window_setHasCustomDecoration = Window.class.getDeclaredMethod( "setHasCustomDecoration" );
|
||||
Window_hasCustomDecoration.setAccessible( true );
|
||||
Window_setHasCustomDecoration.setAccessible( true );
|
||||
} catch( Exception ex ) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
//---- class JBRWindowTopBorder -------------------------------------------
|
||||
|
||||
static class JBRWindowTopBorder
|
||||
extends BorderUIResource.EmptyBorderUIResource
|
||||
{
|
||||
private static JBRWindowTopBorder instance;
|
||||
|
||||
private final Color defaultActiveBorder = new Color( 0x707070 );
|
||||
private final Color inactiveLightColor = new Color( 0xaaaaaa );
|
||||
private final Color inactiveDarkColor = new Color( 0x3f3f3f );
|
||||
|
||||
private boolean colorizationAffectsBorders;
|
||||
private Color activeColor = defaultActiveBorder;
|
||||
|
||||
static JBRWindowTopBorder getInstance() {
|
||||
if( instance == null )
|
||||
instance = new JBRWindowTopBorder();
|
||||
return instance;
|
||||
}
|
||||
|
||||
private JBRWindowTopBorder() {
|
||||
super( 1, 0, 0, 0 );
|
||||
|
||||
colorizationAffectsBorders = calculateAffectsBorders();
|
||||
activeColor = calculateActiveBorderColor();
|
||||
|
||||
Toolkit toolkit = Toolkit.getDefaultToolkit();
|
||||
toolkit.addPropertyChangeListener( "win.dwm.colorizationColor.affects.borders", e -> {
|
||||
colorizationAffectsBorders = calculateAffectsBorders();
|
||||
activeColor = calculateActiveBorderColor();
|
||||
} );
|
||||
|
||||
PropertyChangeListener l = e -> {
|
||||
activeColor = calculateActiveBorderColor();
|
||||
};
|
||||
toolkit.addPropertyChangeListener( "win.dwm.colorizationColor", l );
|
||||
toolkit.addPropertyChangeListener( "win.dwm.colorizationColorBalance", l );
|
||||
toolkit.addPropertyChangeListener( "win.frame.activeBorderColor", l );
|
||||
}
|
||||
|
||||
private boolean calculateAffectsBorders() {
|
||||
Object value = Toolkit.getDefaultToolkit().getDesktopProperty( "win.dwm.colorizationColor.affects.borders" );
|
||||
return (value instanceof Boolean) ? (Boolean) value : true;
|
||||
}
|
||||
|
||||
private Color calculateActiveBorderColor() {
|
||||
if( !colorizationAffectsBorders )
|
||||
return defaultActiveBorder;
|
||||
|
||||
Toolkit toolkit = Toolkit.getDefaultToolkit();
|
||||
Color colorizationColor = (Color) toolkit.getDesktopProperty( "win.dwm.colorizationColor" );
|
||||
if( colorizationColor != null ) {
|
||||
Object colorizationColorBalanceObj = toolkit.getDesktopProperty( "win.dwm.colorizationColorBalance" );
|
||||
if( colorizationColorBalanceObj instanceof Integer ) {
|
||||
int colorizationColorBalance = (Integer) colorizationColorBalanceObj;
|
||||
if( colorizationColorBalance < 0 )
|
||||
colorizationColorBalance = 100;
|
||||
|
||||
if( colorizationColorBalance == 0 )
|
||||
return new Color( 0xD9D9D9 );
|
||||
if( colorizationColorBalance == 100 )
|
||||
return colorizationColor;
|
||||
|
||||
float alpha = colorizationColorBalance / 100.0f;
|
||||
float remainder = 1 - alpha;
|
||||
int r = Math.round( (colorizationColor.getRed() * alpha + 0xD9 * remainder) );
|
||||
int g = Math.round( (colorizationColor.getGreen() * alpha + 0xD9 * remainder) );
|
||||
int b = Math.round( (colorizationColor.getBlue() * alpha + 0xD9 * remainder) );
|
||||
return new Color( r, g, b );
|
||||
}
|
||||
return colorizationColor;
|
||||
}
|
||||
|
||||
Color activeBorderColor = (Color) toolkit.getDesktopProperty( "win.frame.activeBorderColor" );
|
||||
return (activeBorderColor != null) ? activeBorderColor : UIManager.getColor( "MenuBar.borderColor" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||
Window window = SwingUtilities.windowForComponent( c );
|
||||
boolean active = (window != null) ? window.isActive() : false;
|
||||
|
||||
g.setColor( active ? activeColor : (FlatLaf.isLafDark() ? inactiveDarkColor : inactiveLightColor) );
|
||||
HiDPIUtils.paintAtScale1x( (Graphics2D) g, x, y, width, height, this::paintImpl );
|
||||
}
|
||||
|
||||
private void paintImpl( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
|
||||
g.drawRect( x, y, width - 1, 0 );
|
||||
}
|
||||
|
||||
void repaintBorder( Component c ) {
|
||||
c.repaint( 0, 0, c.getWidth(), 1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,14 +69,17 @@ public class MigLayoutVisualPadding
|
||||
/**
|
||||
* Convenience method that checks whether component border is a FlatBorder.
|
||||
*/
|
||||
public static void install( JComponent c, int focusWidth ) {
|
||||
public static void install( JComponent c ) {
|
||||
if( !migLayoutAvailable )
|
||||
return;
|
||||
|
||||
install( c, c2 -> {
|
||||
return (c2.getBorder() instanceof FlatBorder)
|
||||
? new Insets( focusWidth, focusWidth, focusWidth, focusWidth )
|
||||
: null;
|
||||
FlatBorder border = FlatUIUtils.getOutsideFlatBorder( c2 );
|
||||
if( border != null ) {
|
||||
int focusWidth = border.getFocusWidth( c2 );
|
||||
return new Insets( focusWidth, focusWidth, focusWidth, focusWidth );
|
||||
} else
|
||||
return null;
|
||||
}, "border" );
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ public class ColorFunctions
|
||||
return HSLColor.toRGB( hsl, alpha );
|
||||
}
|
||||
|
||||
private static float clamp( float value ) {
|
||||
public static float clamp( float value ) {
|
||||
return (value < 0)
|
||||
? 0
|
||||
: ((value > 100)
|
||||
@@ -49,20 +49,26 @@ public class ColorFunctions
|
||||
void apply( float[] hsl );
|
||||
}
|
||||
|
||||
//---- class Lighten ------------------------------------------------------
|
||||
//---- class HSLIncreaseDecrease ------------------------------------------
|
||||
|
||||
/**
|
||||
* Increase the lightness of a color in the HSL color space by an absolute
|
||||
* or relative amount.
|
||||
* Increase or decrease hue, saturation or luminance of a color in the HSL color space
|
||||
* by an absolute or relative amount.
|
||||
*/
|
||||
public static class Lighten
|
||||
public static class HSLIncreaseDecrease
|
||||
implements ColorFunction
|
||||
{
|
||||
private final float amount;
|
||||
private final boolean relative;
|
||||
private final boolean autoInverse;
|
||||
public final int hslIndex;
|
||||
public final boolean increase;
|
||||
public final float amount;
|
||||
public final boolean relative;
|
||||
public final boolean autoInverse;
|
||||
|
||||
public Lighten( float amount, boolean relative, boolean autoInverse ) {
|
||||
public HSLIncreaseDecrease( int hslIndex, boolean increase,
|
||||
float amount, boolean relative, boolean autoInverse )
|
||||
{
|
||||
this.hslIndex = hslIndex;
|
||||
this.increase = increase;
|
||||
this.amount = amount;
|
||||
this.relative = relative;
|
||||
this.autoInverse = autoInverse;
|
||||
@@ -70,33 +76,17 @@ public class ColorFunctions
|
||||
|
||||
@Override
|
||||
public void apply( float[] hsl ) {
|
||||
float amount2 = autoInverse && shouldInverse( hsl ) ? -amount : amount;
|
||||
hsl[2] = clamp( relative
|
||||
? (hsl[2] * ((100 + amount2) / 100))
|
||||
: (hsl[2] + amount2) );
|
||||
float amount2 = increase ? amount : -amount;
|
||||
amount2 = autoInverse && shouldInverse( hsl ) ? -amount2 : amount2;
|
||||
hsl[hslIndex] = clamp( relative
|
||||
? (hsl[hslIndex] * ((100 + amount2) / 100))
|
||||
: (hsl[hslIndex] + amount2) );
|
||||
}
|
||||
|
||||
protected boolean shouldInverse( float[] hsl ) {
|
||||
return hsl[2] >= 50;
|
||||
}
|
||||
}
|
||||
|
||||
//---- class Darken -------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Decrease the lightness of a color in the HSL color space by an absolute
|
||||
* or relative amount.
|
||||
*/
|
||||
public static class Darken
|
||||
extends Lighten
|
||||
{
|
||||
public Darken( float amount, boolean relative, boolean autoInverse ) {
|
||||
super( -amount, relative, autoInverse );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldInverse( float[] hsl ) {
|
||||
return hsl[2] < 50;
|
||||
return increase
|
||||
? hsl[hslIndex] >= 50
|
||||
: hsl[hslIndex] < 50;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,12 +32,31 @@ public class DerivedColor
|
||||
{
|
||||
private final ColorFunction[] functions;
|
||||
|
||||
public DerivedColor( ColorFunction... functions ) {
|
||||
super( Color.red );
|
||||
private boolean hasBaseOfDefaultColor;
|
||||
private int baseOfDefaultColorRGB;
|
||||
|
||||
public DerivedColor( Color defaultColor, ColorFunction... functions ) {
|
||||
super( (defaultColor != null) ? defaultColor : Color.red );
|
||||
this.functions = functions;
|
||||
}
|
||||
|
||||
public Color derive( Color baseColor ) {
|
||||
return ColorFunctions.applyFunctions( baseColor, functions );
|
||||
if( (hasBaseOfDefaultColor && baseOfDefaultColorRGB == baseColor.getRGB()) || baseColor == this )
|
||||
return this; // return default color
|
||||
|
||||
Color result = ColorFunctions.applyFunctions( baseColor, functions );
|
||||
|
||||
// if the result is equal to the default color, then the original base color
|
||||
// was passed and we can cache this to avoid color calculations
|
||||
if( !hasBaseOfDefaultColor && result.getRGB() == this.getRGB() ) {
|
||||
hasBaseOfDefaultColor = true;
|
||||
baseOfDefaultColorRGB = baseColor.getRGB();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public ColorFunction[] getFunctions() {
|
||||
return functions;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,479 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.util;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Composite;
|
||||
import java.awt.Font;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.Image;
|
||||
import java.awt.Paint;
|
||||
import java.awt.Polygon;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.RenderingHints.Key;
|
||||
import java.awt.Shape;
|
||||
import java.awt.Stroke;
|
||||
import java.awt.font.FontRenderContext;
|
||||
import java.awt.font.GlyphVector;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.BufferedImageOp;
|
||||
import java.awt.image.ImageObserver;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.awt.image.renderable.RenderableImage;
|
||||
import java.text.AttributedCharacterIterator;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A proxy for {@link Graphics2D}.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class Graphics2DProxy
|
||||
extends Graphics2D
|
||||
{
|
||||
private final Graphics2D delegate;
|
||||
|
||||
public Graphics2DProxy( Graphics2D delegate ) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Graphics create() {
|
||||
return delegate.create();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Graphics create( int x, int y, int width, int height ) {
|
||||
return delegate.create( x, y, width, height );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getColor() {
|
||||
return delegate.getColor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColor( Color c ) {
|
||||
delegate.setColor( c );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPaintMode() {
|
||||
delegate.setPaintMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setXORMode( Color c1 ) {
|
||||
delegate.setXORMode( c1 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Font getFont() {
|
||||
return delegate.getFont();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFont( Font font ) {
|
||||
delegate.setFont( font );
|
||||
}
|
||||
|
||||
@Override
|
||||
public FontMetrics getFontMetrics() {
|
||||
return delegate.getFontMetrics();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FontMetrics getFontMetrics( Font f ) {
|
||||
return delegate.getFontMetrics( f );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle getClipBounds() {
|
||||
return delegate.getClipBounds();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clipRect( int x, int y, int width, int height ) {
|
||||
delegate.clipRect( x, y, width, height );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClip( int x, int y, int width, int height ) {
|
||||
delegate.setClip( x, y, width, height );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Shape getClip() {
|
||||
return delegate.getClip();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClip( Shape clip ) {
|
||||
delegate.setClip( clip );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyArea( int x, int y, int width, int height, int dx, int dy ) {
|
||||
delegate.copyArea( x, y, width, height, dx, dy );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawLine( int x1, int y1, int x2, int y2 ) {
|
||||
delegate.drawLine( x1, y1, x2, y2 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillRect( int x, int y, int width, int height ) {
|
||||
delegate.fillRect( x, y, width, height );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawRect( int x, int y, int width, int height ) {
|
||||
delegate.drawRect( x, y, width, height );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearRect( int x, int y, int width, int height ) {
|
||||
delegate.clearRect( x, y, width, height );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawRoundRect( int x, int y, int width, int height, int arcWidth, int arcHeight ) {
|
||||
delegate.drawRoundRect( x, y, width, height, arcWidth, arcHeight );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillRoundRect( int x, int y, int width, int height, int arcWidth, int arcHeight ) {
|
||||
delegate.fillRoundRect( x, y, width, height, arcWidth, arcHeight );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawOval( int x, int y, int width, int height ) {
|
||||
delegate.drawOval( x, y, width, height );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillOval( int x, int y, int width, int height ) {
|
||||
delegate.fillOval( x, y, width, height );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawArc( int x, int y, int width, int height, int startAngle, int arcAngle ) {
|
||||
delegate.drawArc( x, y, width, height, startAngle, arcAngle );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillArc( int x, int y, int width, int height, int startAngle, int arcAngle ) {
|
||||
delegate.fillArc( x, y, width, height, startAngle, arcAngle );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawPolyline( int[] xPoints, int[] yPoints, int nPoints ) {
|
||||
delegate.drawPolyline( xPoints, yPoints, nPoints );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawPolygon( int[] xPoints, int[] yPoints, int nPoints ) {
|
||||
delegate.drawPolygon( xPoints, yPoints, nPoints );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawPolygon( Polygon p ) {
|
||||
delegate.drawPolygon( p );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillPolygon( int[] xPoints, int[] yPoints, int nPoints ) {
|
||||
delegate.fillPolygon( xPoints, yPoints, nPoints );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillPolygon( Polygon p ) {
|
||||
delegate.fillPolygon( p );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawChars( char[] data, int offset, int length, int x, int y ) {
|
||||
delegate.drawChars( data, offset, length, x, y );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawBytes( byte[] data, int offset, int length, int x, int y ) {
|
||||
delegate.drawBytes( data, offset, length, x, y );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean drawImage( Image img, int x, int y, ImageObserver observer ) {
|
||||
return delegate.drawImage( img, x, y, observer );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean drawImage( Image img, int x, int y, int width, int height, ImageObserver observer ) {
|
||||
return delegate.drawImage( img, x, y, width, height, observer );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean drawImage( Image img, int x, int y, Color bgcolor, ImageObserver observer ) {
|
||||
return delegate.drawImage( img, x, y, bgcolor, observer );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean drawImage( Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer ) {
|
||||
return delegate.drawImage( img, x, y, width, height, bgcolor, observer );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean drawImage( Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer ) {
|
||||
return delegate.drawImage( img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean drawImage( Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor, ImageObserver observer ) {
|
||||
return delegate.drawImage( img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bgcolor, observer );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
delegate.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finalize() {
|
||||
delegate.finalize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return delegate.toString();
|
||||
}
|
||||
|
||||
@SuppressWarnings( "deprecation" )
|
||||
@Override
|
||||
public Rectangle getClipRect() {
|
||||
return delegate.getClipRect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hitClip( int x, int y, int width, int height ) {
|
||||
return delegate.hitClip( x, y, width, height );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle getClipBounds( Rectangle r ) {
|
||||
return delegate.getClipBounds( r );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw3DRect( int x, int y, int width, int height, boolean raised ) {
|
||||
delegate.draw3DRect( x, y, width, height, raised );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fill3DRect( int x, int y, int width, int height, boolean raised ) {
|
||||
delegate.fill3DRect( x, y, width, height, raised );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw( Shape s ) {
|
||||
delegate.draw( s );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean drawImage( Image img, AffineTransform xform, ImageObserver obs ) {
|
||||
return delegate.drawImage( img, xform, obs );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawImage( BufferedImage img, BufferedImageOp op, int x, int y ) {
|
||||
delegate.drawImage( img, op, x, y );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawRenderedImage( RenderedImage img, AffineTransform xform ) {
|
||||
delegate.drawRenderedImage( img, xform );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawRenderableImage( RenderableImage img, AffineTransform xform ) {
|
||||
delegate.drawRenderableImage( img, xform );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawString( String str, int x, int y ) {
|
||||
delegate.drawString( str, x, y );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawString( String str, float x, float y ) {
|
||||
delegate.drawString( str, x, y );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawString( AttributedCharacterIterator iterator, int x, int y ) {
|
||||
delegate.drawString( iterator, x, y );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawString( AttributedCharacterIterator iterator, float x, float y ) {
|
||||
delegate.drawString( iterator, x, y );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawGlyphVector( GlyphVector g, float x, float y ) {
|
||||
delegate.drawGlyphVector( g, x, y );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fill( Shape s ) {
|
||||
delegate.fill( s );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hit( Rectangle rect, Shape s, boolean onStroke ) {
|
||||
return delegate.hit( rect, s, onStroke );
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphicsConfiguration getDeviceConfiguration() {
|
||||
return delegate.getDeviceConfiguration();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setComposite( Composite comp ) {
|
||||
delegate.setComposite( comp );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPaint( Paint paint ) {
|
||||
delegate.setPaint( paint );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStroke( Stroke s ) {
|
||||
delegate.setStroke( s );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRenderingHint( Key hintKey, Object hintValue ) {
|
||||
delegate.setRenderingHint( hintKey, hintValue );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getRenderingHint( Key hintKey ) {
|
||||
return delegate.getRenderingHint( hintKey );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRenderingHints( Map<?, ?> hints ) {
|
||||
delegate.setRenderingHints( hints );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRenderingHints( Map<?, ?> hints ) {
|
||||
delegate.addRenderingHints( hints );
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderingHints getRenderingHints() {
|
||||
return delegate.getRenderingHints();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate( int x, int y ) {
|
||||
delegate.translate( x, y );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate( double tx, double ty ) {
|
||||
delegate.translate( tx, ty );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rotate( double theta ) {
|
||||
delegate.rotate( theta );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rotate( double theta, double x, double y ) {
|
||||
delegate.rotate( theta, x, y );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scale( double sx, double sy ) {
|
||||
delegate.scale( sx, sy );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shear( double shx, double shy ) {
|
||||
delegate.shear( shx, shy );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transform( AffineTransform Tx ) {
|
||||
delegate.transform( Tx );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTransform( AffineTransform Tx ) {
|
||||
delegate.setTransform( Tx );
|
||||
}
|
||||
|
||||
@Override
|
||||
public AffineTransform getTransform() {
|
||||
return delegate.getTransform();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Paint getPaint() {
|
||||
return delegate.getPaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Composite getComposite() {
|
||||
return delegate.getComposite();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBackground( Color color ) {
|
||||
delegate.setBackground( color );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getBackground() {
|
||||
return delegate.getBackground();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stroke getStroke() {
|
||||
return delegate.getStroke();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clip( Shape s ) {
|
||||
delegate.clip( s );
|
||||
}
|
||||
|
||||
@Override
|
||||
public FontRenderContext getFontRenderContext() {
|
||||
return delegate.getFontRenderContext();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.formdev.flatlaf.util;
|
||||
|
||||
import java.awt.image.RGBImageFilter;
|
||||
|
||||
// based on https://github.com/JetBrains/intellij-community/blob/3840eab54746f5c4f301bb3ac78f00a980b5fd6e/platform/util/ui/src/com/intellij/util/ui/UIUtil.java#L253-L347
|
||||
|
||||
/**
|
||||
* An image filter that turns an image into a grayscale image.
|
||||
* Used for icons in disabled buttons and labels.
|
||||
*/
|
||||
public class GrayFilter
|
||||
extends RGBImageFilter
|
||||
{
|
||||
private final float brightness;
|
||||
private final float contrast;
|
||||
private final int alpha;
|
||||
|
||||
private final int origContrast;
|
||||
private final int origBrightness;
|
||||
|
||||
public static GrayFilter createDisabledIconFilter( boolean dark ) {
|
||||
return dark
|
||||
? new GrayFilter( -20, -70, 100 )
|
||||
: new GrayFilter( 25, -25, 100 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param brightness in range [-100..100] where 0 has no effect
|
||||
* @param contrast in range [-100..100] where 0 has no effect
|
||||
* @param alpha in range [0..100] where 0 is transparent, 100 has no effect
|
||||
*/
|
||||
public GrayFilter( int brightness, int contrast, int alpha ) {
|
||||
this.origBrightness = Math.max( -100, Math.min( 100, brightness ) );
|
||||
this.origContrast = Math.max( -100, Math.min( 100, contrast ) );
|
||||
this.alpha = Math.max( 0, Math.min( 100, alpha ) );
|
||||
|
||||
this.brightness = (float) (Math.pow( origBrightness, 3 ) / (100f * 100f)); // cubic in [0..100]
|
||||
this.contrast = origContrast / 100f;
|
||||
|
||||
canFilterIndexColorModel = true;
|
||||
}
|
||||
|
||||
public GrayFilter() {
|
||||
this( 0, 0, 100 );
|
||||
}
|
||||
|
||||
public int getBrightness() {
|
||||
return origBrightness;
|
||||
}
|
||||
|
||||
public int getContrast() {
|
||||
return origContrast;
|
||||
}
|
||||
|
||||
public int getAlpha() {
|
||||
return alpha;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int filterRGB( int x, int y, int rgb ) {
|
||||
// use NTSC conversion formula
|
||||
int gray = (int)(
|
||||
0.30 * (rgb >> 16 & 0xff) +
|
||||
0.59 * (rgb >> 8 & 0xff) +
|
||||
0.11 * (rgb & 0xff));
|
||||
|
||||
if( brightness >= 0 )
|
||||
gray = (int) ((gray + brightness * 255) / (1 + brightness));
|
||||
else
|
||||
gray = (int) (gray / (1 - brightness));
|
||||
|
||||
if( contrast >= 0 ) {
|
||||
if( gray >= 127 )
|
||||
gray = (int) (gray + (255 - gray) * contrast);
|
||||
else
|
||||
gray = (int) (gray - gray * contrast);
|
||||
} else
|
||||
gray = (int) (127 + (gray - 127) * (contrast + 1));
|
||||
|
||||
int a = (alpha != 100)
|
||||
? (((rgb >> 24) & 0xff) * alpha / 100) << 24
|
||||
: (rgb & 0xff000000);
|
||||
|
||||
return a | (gray << 16) | (gray << 8) | gray;
|
||||
}
|
||||
}
|
||||
@@ -16,10 +16,14 @@
|
||||
|
||||
package com.formdev.flatlaf.util;
|
||||
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.font.GlyphVector;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.text.AttributedCharacterIterator;
|
||||
import javax.swing.JComponent;
|
||||
import com.formdev.flatlaf.FlatSystemProperties;
|
||||
|
||||
/**
|
||||
* @author Karl Tauber
|
||||
@@ -95,4 +99,134 @@ public class HiDPIUtils
|
||||
private static double normalize( double value ) {
|
||||
return Math.floor( value + 0.25 ) + 0.25;
|
||||
}
|
||||
|
||||
|
||||
private static Boolean useTextYCorrection;
|
||||
|
||||
private static boolean useTextYCorrection() {
|
||||
if( useTextYCorrection == null )
|
||||
useTextYCorrection = FlatSystemProperties.getBoolean( FlatSystemProperties.USE_TEXT_Y_CORRECTION, true );
|
||||
return useTextYCorrection;
|
||||
}
|
||||
|
||||
/**
|
||||
* When painting text on HiDPI screens and the JRE scales, then the text is
|
||||
* painted too far down on some operating systems.
|
||||
* The higher the system scale factor is, the more.
|
||||
* <p>
|
||||
* This methods computes a correction value for the Y position.
|
||||
*/
|
||||
public static float computeTextYCorrection( Graphics2D g ) {
|
||||
if( !useTextYCorrection() || !SystemInfo.IS_WINDOWS )
|
||||
return 0;
|
||||
|
||||
if( !SystemInfo.IS_JAVA_9_OR_LATER )
|
||||
return UIScale.getUserScaleFactor() > 1 ? -UIScale.scale( 0.625f ) : 0;
|
||||
|
||||
AffineTransform t = g.getTransform();
|
||||
double scaleY = t.getScaleY();
|
||||
if( scaleY < 1.25 )
|
||||
return 0;
|
||||
|
||||
// Text is painted at slightly different Y positions depending on scale factor
|
||||
// and Y position of component.
|
||||
// The exact reason is not yet known (to me), but there are several factors:
|
||||
// - fractional scale factors result in fractional component Y device coordinates
|
||||
// - fractional text Y device coordinates are rounded for horizontal lines of characters
|
||||
// - maybe different rounding methods for drawing primitives (e.g. rectangle) and text
|
||||
// - Java adds 0.5 to X/Y positions in before drawing string in BufferedTextPipe.enqueueGlyphList()
|
||||
|
||||
// this is not the optimal solution, but works very good in most cases
|
||||
// (tested with class FlatPaintingStringTest on Windows 10 with font "Segoe UI")
|
||||
if( scaleY <= 1.25 )
|
||||
return -0.875f;
|
||||
if( scaleY <= 1.5 )
|
||||
return -0.625f;
|
||||
if( scaleY <= 1.75 )
|
||||
return -0.875f;
|
||||
if( scaleY <= 2.0 )
|
||||
return -0.75f;
|
||||
if( scaleY <= 2.25 )
|
||||
return -0.875f;
|
||||
if( scaleY <= 3.5 )
|
||||
return -0.75f;
|
||||
return -0.875f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies Y correction and draws the given string at the specified location.
|
||||
* The provided component is used to query text properties and anti-aliasing hints.
|
||||
* <p>
|
||||
* Use this method instead of {@link Graphics#drawString(String, int, int)} for correct anti-aliasing.
|
||||
* <p>
|
||||
* Replacement for {@code SwingUtilities2.drawString()}.
|
||||
*/
|
||||
public static void drawStringWithYCorrection( JComponent c, Graphics2D g, String text, int x, int y ) {
|
||||
drawStringUnderlineCharAtWithYCorrection( c, g, text, -1, x, y );
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies Y correction and draws the given string at the specified location underlining the specified character.
|
||||
* The provided component is used to query text properties and anti-aliasing hints.
|
||||
* <p>
|
||||
* Replacement for {@code SwingUtilities2.drawStringUnderlineCharAt()}.
|
||||
*/
|
||||
public static void drawStringUnderlineCharAtWithYCorrection( JComponent c,
|
||||
Graphics2D g, String text, int underlinedIndex, int x, int y )
|
||||
{
|
||||
float yCorrection = computeTextYCorrection( g );
|
||||
if( yCorrection != 0 ) {
|
||||
g.translate( 0, yCorrection );
|
||||
JavaCompatibility.drawStringUnderlineCharAt( c, g, text, underlinedIndex, x, y );
|
||||
g.translate( 0, -yCorrection );
|
||||
} else
|
||||
JavaCompatibility.drawStringUnderlineCharAt( c, g, text, underlinedIndex, x, y );
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a graphics object and applies Y correction to string drawing methods.
|
||||
* If no Y correction is necessary, the passed in graphics object is returned.
|
||||
*/
|
||||
public static Graphics2D createGraphicsTextYCorrection( Graphics2D g ) {
|
||||
float yCorrection = computeTextYCorrection( g );
|
||||
if( yCorrection == 0 )
|
||||
return g;
|
||||
|
||||
return new Graphics2DProxy( g ) {
|
||||
@Override
|
||||
public void drawString( String str, int x, int y ) {
|
||||
super.drawString( str, x, y + yCorrection );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawString( String str, float x, float y ) {
|
||||
super.drawString( str, x, y + yCorrection );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawString( AttributedCharacterIterator iterator, int x, int y ) {
|
||||
super.drawString( iterator, x, y + yCorrection );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawString( AttributedCharacterIterator iterator, float x, float y ) {
|
||||
super.drawString( iterator, x, y + yCorrection );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawChars( char[] data, int offset, int length, int x, int y ) {
|
||||
super.drawChars( data, offset, length, x, Math.round( y + yCorrection ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawBytes( byte[] data, int offset, int length, int x, int y ) {
|
||||
super.drawBytes( data, offset, length, x, Math.round( y + yCorrection ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawGlyphVector( GlyphVector g, float x, float y ) {
|
||||
super.drawGlyphVector( g, x, y + yCorrection );
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.util;
|
||||
|
||||
import java.awt.Image;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Support for multi-resolution images available since Java 9.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class MultiResolutionImageSupport
|
||||
{
|
||||
public static boolean isAvailable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isMultiResolutionImage( Image image ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Image create( int baseImageIndex, Image... resolutionVariants ) {
|
||||
return resolutionVariants[baseImageIndex];
|
||||
}
|
||||
|
||||
public static Image map( Image image, Function<Image, Image> mapper ) {
|
||||
return mapper.apply( image );
|
||||
}
|
||||
|
||||
public static Image getResolutionVariant( Image image, int destImageWidth, int destImageHeight ) {
|
||||
return image;
|
||||
}
|
||||
|
||||
public static List<Image> getResolutionVariants( Image image ) {
|
||||
return Collections.singletonList( image );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.util;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Image;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.image.BufferedImage;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
|
||||
/**
|
||||
* Scales the given image icon using the system and user scale factors and
|
||||
* paints the icon at system scale factor 1x. This gives best scaling quality.
|
||||
* If the given image icon supports multiple resolutions, the best resolution
|
||||
* variant is used. The last scaled image is cached for faster repainting.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class ScaledImageIcon
|
||||
implements Icon
|
||||
{
|
||||
private final ImageIcon imageIcon;
|
||||
private final int iconWidth;
|
||||
private final int iconHeight;
|
||||
|
||||
private double lastSystemScaleFactor;
|
||||
private float lastUserScaleFactor;
|
||||
private Image lastImage;
|
||||
|
||||
public ScaledImageIcon( ImageIcon imageIcon ) {
|
||||
this( imageIcon, imageIcon.getIconWidth(), imageIcon.getIconHeight() );
|
||||
}
|
||||
|
||||
public ScaledImageIcon( ImageIcon imageIcon, int iconWidth, int iconHeight ) {
|
||||
this.imageIcon = imageIcon;
|
||||
this.iconWidth = iconWidth;
|
||||
this.iconHeight = iconHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconWidth() {
|
||||
return UIScale.scale( iconWidth );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconHeight() {
|
||||
return UIScale.scale( iconHeight );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintIcon( Component c, Graphics g, int x, int y ) {
|
||||
/*debug
|
||||
g.setColor( Color.red );
|
||||
g.drawRect( x, y, getIconWidth() - 1, getIconHeight() - 1 );
|
||||
debug*/
|
||||
|
||||
// scale factor
|
||||
double systemScaleFactor = UIScale.getSystemScaleFactor( (Graphics2D) g );
|
||||
float userScaleFactor = UIScale.getUserScaleFactor();
|
||||
double scaleFactor = systemScaleFactor * userScaleFactor;
|
||||
|
||||
// paint input image icon if not necessary to scale
|
||||
if( scaleFactor == 1 && iconWidth == imageIcon.getIconWidth() && iconHeight == imageIcon.getIconHeight() ) {
|
||||
imageIcon.paintIcon( c, g, x, y );
|
||||
return;
|
||||
}
|
||||
|
||||
// paint cached scaled icon
|
||||
if( systemScaleFactor == lastSystemScaleFactor &&
|
||||
userScaleFactor == lastUserScaleFactor &&
|
||||
lastImage != null )
|
||||
{
|
||||
paintLastImage( g, x, y );
|
||||
return;
|
||||
}
|
||||
|
||||
// destination image size
|
||||
int destImageWidth = (int) Math.round( iconWidth * scaleFactor );
|
||||
int destImageHeight = (int) Math.round( iconHeight * scaleFactor );
|
||||
|
||||
// get resolution variant of image if it is a multi-resolution image
|
||||
Image image = getResolutionVariant( destImageWidth, destImageHeight );
|
||||
|
||||
// size of image
|
||||
int imageWidth = image.getWidth( null );
|
||||
int imageHeight = image.getHeight( null );
|
||||
|
||||
// scale image if necessary to destination size
|
||||
if( imageWidth != destImageWidth || imageHeight != destImageHeight ) {
|
||||
// determine scaling method; default is "quality"
|
||||
Object scalingInterpolation = RenderingHints.VALUE_INTERPOLATION_BICUBIC;
|
||||
float imageScaleFactor = (float) destImageWidth / (float) imageWidth;
|
||||
if( ((int) imageScaleFactor) == imageScaleFactor &&
|
||||
imageScaleFactor > 1f &&
|
||||
imageWidth <= 16 &&
|
||||
imageHeight <= 16 )
|
||||
{
|
||||
// use "speed" scaling for small icons if the scale factor is an integer
|
||||
// to avoid blurred icons
|
||||
scalingInterpolation = RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR;
|
||||
}
|
||||
|
||||
// scale image
|
||||
BufferedImage bufferedImage = image2bufferedImage( image );
|
||||
image = scaleImage( bufferedImage, destImageWidth, destImageHeight, scalingInterpolation );
|
||||
}
|
||||
|
||||
// cache image
|
||||
lastSystemScaleFactor = systemScaleFactor;
|
||||
lastUserScaleFactor = userScaleFactor;
|
||||
lastImage = image;
|
||||
|
||||
// paint image
|
||||
paintLastImage( g, x, y );
|
||||
}
|
||||
|
||||
protected Image getResolutionVariant( int destImageWidth, int destImageHeight ) {
|
||||
return MultiResolutionImageSupport.getResolutionVariant(
|
||||
imageIcon.getImage(), destImageWidth, destImageHeight );
|
||||
}
|
||||
|
||||
private void paintLastImage( Graphics g, int x, int y ) {
|
||||
if( lastSystemScaleFactor > 1 ) {
|
||||
HiDPIUtils.paintAtScale1x( (Graphics2D) g, x, y, 100, 100, // width and height are not used
|
||||
(g2, x2, y2, width2, height2, scaleFactor2) -> {
|
||||
g2.drawImage( lastImage, x2, y2, null );
|
||||
} );
|
||||
} else
|
||||
g.drawImage( lastImage, x, y, null );
|
||||
}
|
||||
|
||||
/**
|
||||
* Scales the given image to the target dimensions.
|
||||
*
|
||||
* This is the same what imgscalr library (https://github.com/rkalla/imgscalr)
|
||||
* would do when invoking Scalr.resize().
|
||||
*/
|
||||
private BufferedImage scaleImage( BufferedImage image, int targetWidth, int targetHeight,
|
||||
Object scalingInterpolation )
|
||||
{
|
||||
BufferedImage bufferedImage = new BufferedImage( targetWidth, targetHeight, BufferedImage.TYPE_INT_ARGB );
|
||||
Graphics2D g = bufferedImage.createGraphics();
|
||||
try {
|
||||
g.setRenderingHint( RenderingHints.KEY_INTERPOLATION, scalingInterpolation );
|
||||
g.drawImage( image, 0, 0, targetWidth, targetHeight, null );
|
||||
} finally {
|
||||
g.dispose();
|
||||
}
|
||||
return bufferedImage;
|
||||
|
||||
}
|
||||
|
||||
private BufferedImage image2bufferedImage( Image image ) {
|
||||
if( image instanceof BufferedImage )
|
||||
return (BufferedImage) image;
|
||||
|
||||
BufferedImage bufferedImage = new BufferedImage( image.getWidth( null ),
|
||||
image.getHeight( null ), BufferedImage.TYPE_INT_ARGB );
|
||||
Graphics2D g = bufferedImage.createGraphics();
|
||||
try {
|
||||
g.drawImage( image, 0, 0, null );
|
||||
} finally {
|
||||
g.dispose();
|
||||
}
|
||||
return bufferedImage;
|
||||
}
|
||||
}
|
||||
@@ -32,13 +32,19 @@ public class SystemInfo
|
||||
public static final boolean IS_LINUX;
|
||||
|
||||
// OS versions
|
||||
public static final boolean IS_WINDOWS_10_OR_LATER;
|
||||
public static final boolean IS_MAC_OS_10_11_EL_CAPITAN_OR_LATER;
|
||||
public static final boolean IS_MAC_OS_10_14_MOJAVE;
|
||||
public static final boolean IS_MAC_OS_10_15_CATALINA_OR_LATER;
|
||||
|
||||
// Java versions
|
||||
public static final boolean IS_JAVA_9_OR_LATER;
|
||||
public static final boolean IS_JAVA_11_OR_LATER;
|
||||
public static final boolean IS_JAVA_15_OR_LATER;
|
||||
|
||||
// Java VMs
|
||||
public static final boolean IS_JETBRAINS_JVM;
|
||||
public static final boolean IS_JETBRAINS_JVM_11_OR_LATER;
|
||||
|
||||
// UI toolkits
|
||||
public static final boolean IS_KDE;
|
||||
@@ -52,21 +58,27 @@ public class SystemInfo
|
||||
|
||||
// OS versions
|
||||
long osVersion = scanVersion( System.getProperty( "os.version" ) );
|
||||
IS_WINDOWS_10_OR_LATER = (IS_WINDOWS && osVersion >= toVersion( 10, 0, 0, 0 ));
|
||||
IS_MAC_OS_10_11_EL_CAPITAN_OR_LATER = (IS_MAC && osVersion >= toVersion( 10, 11, 0, 0 ));
|
||||
IS_MAC_OS_10_14_MOJAVE = (IS_MAC && osVersion >= toVersion( 10, 14, 0, 0 ));
|
||||
IS_MAC_OS_10_15_CATALINA_OR_LATER = (IS_MAC && osVersion >= toVersion( 10, 15, 0, 0 ));
|
||||
|
||||
// Java versions
|
||||
long javaVersion = scanVersion( System.getProperty( "java.version" ) );
|
||||
IS_JAVA_9_OR_LATER = (javaVersion >= toVersion( 9, 0, 0, 0 ));
|
||||
IS_JAVA_11_OR_LATER = (javaVersion >= toVersion( 11, 0, 0, 0 ));
|
||||
IS_JAVA_15_OR_LATER = (javaVersion >= toVersion( 15, 0, 0, 0 ));
|
||||
|
||||
// Java VMs
|
||||
IS_JETBRAINS_JVM = System.getProperty( "java.vm.vendor", "Unknown" )
|
||||
.toLowerCase( Locale.ENGLISH ).contains( "jetbrains" );
|
||||
IS_JETBRAINS_JVM_11_OR_LATER = IS_JETBRAINS_JVM && IS_JAVA_11_OR_LATER;
|
||||
|
||||
// UI toolkits
|
||||
IS_KDE = (IS_LINUX && System.getenv( "KDE_FULL_SESSION" ) != null);
|
||||
}
|
||||
|
||||
private static long scanVersion( String version ) {
|
||||
public static long scanVersion( String version ) {
|
||||
int major = 1;
|
||||
int minor = 0;
|
||||
int micro = 0;
|
||||
@@ -84,7 +96,7 @@ public class SystemInfo
|
||||
return toVersion( major, minor, micro, patch );
|
||||
}
|
||||
|
||||
private static long toVersion( int major, int minor, int micro, int patch ) {
|
||||
public static long toVersion( int major, int minor, int micro, int patch ) {
|
||||
return ((long) major << 48) + ((long) minor << 32) + ((long) micro << 16) + patch;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import javax.swing.plaf.DimensionUIResource;
|
||||
import javax.swing.plaf.FontUIResource;
|
||||
import javax.swing.plaf.InsetsUIResource;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import com.formdev.flatlaf.FlatSystemProperties;
|
||||
|
||||
/**
|
||||
* Two scaling modes are supported for HiDPI displays:
|
||||
@@ -195,8 +196,7 @@ public class UIScale
|
||||
|
||||
private static boolean isUserScalingEnabled() {
|
||||
// same as in IntelliJ IDEA
|
||||
String hidpi = System.getProperty( "hidpi" );
|
||||
return (hidpi != null) ? Boolean.parseBoolean( hidpi ) : true;
|
||||
return FlatSystemProperties.getBoolean( "hidpi", true );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -204,7 +204,7 @@ public class UIScale
|
||||
* to the given font.
|
||||
*/
|
||||
public static FontUIResource applyCustomScaleFactor( FontUIResource font ) {
|
||||
String uiScale = System.getProperty( "flatlaf.uiScale" );
|
||||
String uiScale = System.getProperty( FlatSystemProperties.UI_SCALE );
|
||||
float scaleFactor = parseScaleFactor( uiScale );
|
||||
if( scaleFactor <= 0 )
|
||||
return font;
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.util;
|
||||
|
||||
import java.awt.Image;
|
||||
import java.awt.image.AbstractMultiResolutionImage;
|
||||
import java.awt.image.BaseMultiResolutionImage;
|
||||
import java.awt.image.MultiResolutionImage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import javax.swing.ImageIcon;
|
||||
|
||||
/**
|
||||
* Support for multi-resolution images available since Java 9.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class MultiResolutionImageSupport
|
||||
{
|
||||
public static boolean isAvailable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean isMultiResolutionImage( Image image ) {
|
||||
return image instanceof MultiResolutionImage;
|
||||
}
|
||||
|
||||
public static Image create( int baseImageIndex, Image... resolutionVariants ) {
|
||||
return new BaseMultiResolutionImage( baseImageIndex, resolutionVariants );
|
||||
}
|
||||
|
||||
public static Image map( Image image, Function<Image, Image> mapper ) {
|
||||
return image instanceof MultiResolutionImage
|
||||
? new MappedMultiResolutionImage( image, mapper )
|
||||
: mapper.apply( image );
|
||||
}
|
||||
|
||||
public static Image getResolutionVariant( Image image, int destImageWidth, int destImageHeight ) {
|
||||
return (image instanceof MultiResolutionImage)
|
||||
? ((MultiResolutionImage)image).getResolutionVariant( destImageWidth, destImageHeight )
|
||||
: image;
|
||||
}
|
||||
|
||||
public static List<Image> getResolutionVariants( Image image ) {
|
||||
return (image instanceof MultiResolutionImage)
|
||||
? ((MultiResolutionImage)image).getResolutionVariants()
|
||||
: Collections.singletonList( image );
|
||||
}
|
||||
|
||||
//---- class MappedMultiResolutionImage -----------------------------------
|
||||
|
||||
private static class MappedMultiResolutionImage
|
||||
extends AbstractMultiResolutionImage
|
||||
{
|
||||
private final Image mrImage;
|
||||
private final Function<Image, Image> mapper;
|
||||
private final IdentityHashMap<Image, Image> cache = new IdentityHashMap<>();
|
||||
|
||||
MappedMultiResolutionImage( Image mrImage, Function<Image, Image> mapper ) {
|
||||
assert mrImage instanceof MultiResolutionImage;
|
||||
|
||||
this.mrImage = mrImage;
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Image getResolutionVariant( double destImageWidth, double destImageHeight ) {
|
||||
Image variant = ((MultiResolutionImage)mrImage).getResolutionVariant( destImageWidth, destImageHeight );
|
||||
return mapAndCacheImage( variant );
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Image> getResolutionVariants() {
|
||||
List<Image> variants = ((MultiResolutionImage)mrImage).getResolutionVariants();
|
||||
List<Image> mappedVariants = new ArrayList<>();
|
||||
for( Image image : variants )
|
||||
mappedVariants.add( mapAndCacheImage( image ) );
|
||||
return mappedVariants;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Image getBaseImage() {
|
||||
return mapAndCacheImage( mrImage );
|
||||
}
|
||||
|
||||
private Image mapAndCacheImage( Image image ) {
|
||||
return cache.computeIfAbsent( image, img -> {
|
||||
return new ImageIcon( mapper.apply( img ) ).getImage();
|
||||
} );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,5 +26,7 @@ module com.formdev.flatlaf {
|
||||
exports com.formdev.flatlaf.ui;
|
||||
exports com.formdev.flatlaf.util;
|
||||
|
||||
opens com.formdev.flatlaf.resources;
|
||||
|
||||
uses com.formdev.flatlaf.FlatDefaultsAddon;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ Button.default.boldText=true
|
||||
|
||||
Component.focusWidth=2
|
||||
Component.innerFocusWidth=0
|
||||
Component.innerOutlineWidth=0
|
||||
Component.arrowType=triangle
|
||||
|
||||
|
||||
|
||||
@@ -29,13 +29,12 @@
|
||||
@disabledText=#777777
|
||||
@textComponentBackground=#45494A
|
||||
@menuBackground=darken(@background,5%)
|
||||
@menuHoverBackground=lighten(@menuBackground,10%,derived)
|
||||
@menuCheckBackground=lighten(@menuBackground,10%,derived)
|
||||
@menuCheckHoverBackground=lighten(@menuBackground,20%,derived)
|
||||
@cellFocusColor=#000000
|
||||
@icon=#adadad
|
||||
|
||||
# Button
|
||||
@buttonHoverBackground=lighten(3%,autoInverse)
|
||||
@buttonPressedBackground=lighten(6%,autoInverse)
|
||||
|
||||
# Drop (use lazy colors for IntelliJ platform themes, which usually do not specify these colors)
|
||||
@dropCellBackground=darken(List.selectionBackground,10%,lazy)
|
||||
@dropCellForeground=lazy(List.selectionForeground)
|
||||
@@ -57,7 +56,7 @@
|
||||
*.disabledBackground=@background
|
||||
*.disabledForeground=@disabledText
|
||||
*.disabledText=@disabledText
|
||||
*.acceleratorForeground=#bbbbbb
|
||||
*.acceleratorForeground=darken(@foreground,15%)
|
||||
*.acceleratorSelectionForeground=@selectionForeground
|
||||
|
||||
|
||||
@@ -73,8 +72,8 @@ controlDkShadow=lighten($controlShadow,10%)
|
||||
#---- Button ----
|
||||
|
||||
Button.background=#4c5052
|
||||
Button.hoverBackground=@buttonHoverBackground
|
||||
Button.pressedBackground=@buttonPressedBackground
|
||||
Button.hoverBackground=lighten($Button.background,3%,derived)
|
||||
Button.pressedBackground=lighten($Button.background,6%,derived)
|
||||
|
||||
Button.borderColor=#5e6060
|
||||
Button.disabledBorderColor=#5e6060
|
||||
@@ -83,34 +82,53 @@ Button.hoverBorderColor=$Button.focusedBorderColor
|
||||
|
||||
Button.default.background=#365880
|
||||
Button.default.foreground=#bbbbbb
|
||||
Button.default.hoverBackground=@buttonHoverBackground
|
||||
Button.default.pressedBackground=@buttonPressedBackground
|
||||
Button.default.hoverBackground=lighten($Button.default.background,3%,derived)
|
||||
Button.default.pressedBackground=lighten($Button.default.background,6%,derived)
|
||||
Button.default.borderColor=#4c708c
|
||||
Button.default.hoverBorderColor=#537699
|
||||
Button.default.focusedBorderColor=#537699
|
||||
Button.default.focusColor=#43688c
|
||||
Button.default.boldText=true
|
||||
|
||||
Button.toolbar.hoverBackground=#4c5052
|
||||
Button.toolbar.pressedBackground=#555a5d
|
||||
Button.toolbar.hoverBackground=lighten($Button.background,1%,derived)
|
||||
Button.toolbar.pressedBackground=lighten($Button.background,4%,derived)
|
||||
|
||||
|
||||
#---- CheckBox ----
|
||||
|
||||
# enabled
|
||||
CheckBox.icon.borderColor=#6B6B6B
|
||||
CheckBox.icon.disabledBorderColor=#545556
|
||||
CheckBox.icon.selectedBorderColor=#6B6B6B
|
||||
CheckBox.icon.focusedBorderColor=#466D94
|
||||
CheckBox.icon.hoverBorderColor=$CheckBox.icon.focusedBorderColor
|
||||
CheckBox.icon.selectedFocusedBorderColor=#466D94
|
||||
CheckBox.icon.background=#43494A
|
||||
CheckBox.icon.disabledBackground=@background
|
||||
CheckBox.icon.hoverBackground=@buttonHoverBackground
|
||||
CheckBox.icon.pressedBackground=@buttonPressedBackground
|
||||
CheckBox.icon.selectedBackground=#43494A
|
||||
CheckBox.icon.selectedBorderColor=$CheckBox.icon.borderColor
|
||||
CheckBox.icon.selectedBackground=$CheckBox.icon.background
|
||||
CheckBox.icon.checkmarkColor=#A7A7A7
|
||||
|
||||
# disabled
|
||||
CheckBox.icon.disabledBorderColor=#545556
|
||||
CheckBox.icon.disabledBackground=@background
|
||||
CheckBox.icon.disabledCheckmarkColor=#606060
|
||||
|
||||
# focused
|
||||
CheckBox.icon.focusedBorderColor=#466D94
|
||||
CheckBox.icon.selectedFocusedBorderColor=#466D94
|
||||
|
||||
# hover
|
||||
CheckBox.icon.hoverBorderColor=$CheckBox.icon.focusedBorderColor
|
||||
CheckBox.icon.hoverBackground=lighten($CheckBox.icon.background,3%,derived)
|
||||
|
||||
# pressed
|
||||
CheckBox.icon.pressedBackground=lighten($CheckBox.icon.background,6%,derived)
|
||||
|
||||
# used if CheckBox.icon.style=filled
|
||||
# enabled
|
||||
CheckBox.icon[filled].selectedBorderColor=$CheckBox.icon.checkmarkColor
|
||||
CheckBox.icon[filled].selectedBackground=$CheckBox.icon.checkmarkColor
|
||||
CheckBox.icon[filled].checkmarkColor=$CheckBox.icon.background
|
||||
# hover
|
||||
CheckBox.icon[filled].selectedHoverBackground=darken($CheckBox.icon[filled].selectedBackground,3%)
|
||||
# pressed
|
||||
CheckBox.icon[filled].selectedPressedBackground=darken($CheckBox.icon[filled].selectedBackground,6%)
|
||||
|
||||
|
||||
#---- ComboBox ----
|
||||
|
||||
@@ -129,6 +147,13 @@ Component.disabledBorderColor=#646464
|
||||
Component.focusedBorderColor=#466d94
|
||||
Component.focusColor=#3d6185
|
||||
Component.linkColor=#589df6
|
||||
Component.grayFilter=-20,-70,100
|
||||
|
||||
Component.error.borderColor=desaturate($Component.error.focusedBorderColor,25%)
|
||||
Component.error.focusedBorderColor=#8b3c3c
|
||||
Component.warning.borderColor=darken(desaturate($Component.warning.focusedBorderColor,20%),10%)
|
||||
Component.warning.focusedBorderColor=#ac7920
|
||||
Component.custom.borderColor=desaturate(#f00,50%,relative derived noAutoInverse)
|
||||
|
||||
|
||||
#---- Desktop ----
|
||||
@@ -148,16 +173,19 @@ InternalFrame.activeTitleForeground=@foreground
|
||||
InternalFrame.inactiveTitleBackground=darken(@background,5%)
|
||||
InternalFrame.inactiveTitleForeground=@disabledText
|
||||
|
||||
InternalFrame.activeBorderColor=lighten($Component.borderColor,10%)
|
||||
InternalFrame.inactiveBorderColor=$Component.borderColor
|
||||
InternalFrame.activeBorderColor=darken(@background,7%)
|
||||
InternalFrame.inactiveBorderColor=darken(@background,3%)
|
||||
|
||||
InternalFrame.buttonHoverBackground=lighten(10%,autoInverse)
|
||||
InternalFrame.buttonPressedBackground=lighten(20%,autoInverse)
|
||||
InternalFrame.buttonHoverBackground=lighten($InternalFrame.activeTitleBackground,10%,derived)
|
||||
InternalFrame.buttonPressedBackground=lighten($InternalFrame.activeTitleBackground,20%,derived)
|
||||
InternalFrame.closeHoverBackground=lazy(Actions.Red)
|
||||
InternalFrame.closePressedBackground=darken(Actions.Red,10%,lazy)
|
||||
InternalFrame.closeHoverForeground=#fff
|
||||
InternalFrame.closePressedForeground=#fff
|
||||
|
||||
InternalFrame.activeDropShadowOpacity=0.5
|
||||
InternalFrame.inactiveDropShadowOpacity=0.75
|
||||
|
||||
|
||||
#---- List ----
|
||||
|
||||
@@ -173,7 +201,7 @@ Menu.icon.disabledArrowColor=#606060
|
||||
#---- MenuBar ----
|
||||
|
||||
MenuBar.borderColor=#515151
|
||||
MenuBar.hoverBackground=lighten($MenuBar.background,10%)
|
||||
MenuBar.hoverBackground=@menuHoverBackground
|
||||
|
||||
|
||||
#---- MenuItemCheckBox ----
|
||||
@@ -187,6 +215,12 @@ MenuItemCheckBox.icon.disabledCheckmarkColor=#606060
|
||||
PasswordField.capsLockIconColor=#ffffff64
|
||||
|
||||
|
||||
#---- Popup ----
|
||||
|
||||
Popup.dropShadowColor=#000
|
||||
Popup.dropShadowOpacity=0.25
|
||||
|
||||
|
||||
#---- PopupMenu ----
|
||||
|
||||
PopupMenu.borderColor=#5e5e5e
|
||||
@@ -200,12 +234,20 @@ ProgressBar.selectionForeground=@foreground
|
||||
ProgressBar.selectionBackground=@foreground
|
||||
|
||||
|
||||
#---- RadioButton ----
|
||||
|
||||
RadioButton.icon[filled].centerDiameter=5
|
||||
|
||||
|
||||
#---- ScrollBar ----
|
||||
|
||||
ScrollBar.track=#3F4244
|
||||
ScrollBar.thumb=lighten($ScrollBar.track,10%)
|
||||
ScrollBar.hoverTrackColor=lighten($ScrollBar.track,4%)
|
||||
ScrollBar.hoverThumbColor=lighten($ScrollBar.thumb,10%)
|
||||
ScrollBar.track=lighten(@background,1%,derived noAutoInverse)
|
||||
ScrollBar.thumb=lighten($ScrollBar.track,10%,derived noAutoInverse)
|
||||
ScrollBar.hoverTrackColor=lighten($ScrollBar.track,4%,derived noAutoInverse)
|
||||
ScrollBar.hoverThumbColor=lighten($ScrollBar.thumb,10%,derived noAutoInverse)
|
||||
ScrollBar.pressedThumbColor=lighten($ScrollBar.thumb,15%,derived noAutoInverse)
|
||||
ScrollBar.hoverButtonBackground=lighten(@background,5%,derived noAutoInverse)
|
||||
ScrollBar.pressedButtonBackground=lighten(@background,10%,derived noAutoInverse)
|
||||
|
||||
|
||||
#---- Separator ----
|
||||
@@ -218,7 +260,7 @@ Separator.foreground=#515151
|
||||
Slider.trackColor=#646464
|
||||
Slider.thumbColor=#A6A6A6
|
||||
Slider.tickColor=#888888
|
||||
Slider.hoverColor=darken(15%,autoInverse)
|
||||
Slider.hoverColor=darken($Slider.thumbColor,15%,derived)
|
||||
Slider.disabledForeground=#4c5052
|
||||
|
||||
|
||||
@@ -251,13 +293,20 @@ TableHeader.separatorColor=lighten($TableHeader.background,10%)
|
||||
TableHeader.bottomSeparatorColor=$TableHeader.separatorColor
|
||||
|
||||
|
||||
#---- TitlePane ----
|
||||
|
||||
TitlePane.embeddedForeground=darken($TitlePane.foreground,15%)
|
||||
TitlePane.buttonHoverBackground=lighten($TitlePane.background,10%,derived)
|
||||
TitlePane.buttonPressedBackground=lighten($TitlePane.background,20%,derived)
|
||||
|
||||
|
||||
#---- ToggleButton ----
|
||||
|
||||
ToggleButton.selectedBackground=#64696C
|
||||
ToggleButton.selectedBackground=lighten($ToggleButton.background,10%,derived)
|
||||
ToggleButton.selectedForeground=@foreground
|
||||
ToggleButton.disabledSelectedBackground=#525658
|
||||
ToggleButton.disabledSelectedBackground=lighten($ToggleButton.background,3%,derived)
|
||||
|
||||
ToggleButton.toolbar.selectedBackground=#5c6164
|
||||
ToggleButton.toolbar.selectedBackground=lighten($ToggleButton.background,7%,derived)
|
||||
|
||||
|
||||
#---- ToolTip ----
|
||||
|
||||
@@ -35,22 +35,13 @@ Button.default.borderWidth=1
|
||||
|
||||
#---- CheckBox ----
|
||||
|
||||
CheckBox.icon.selectedBorderColor=#4B97D9
|
||||
CheckBox.icon.selectedFocusedBorderColor=#ACCFF7
|
||||
CheckBox.icon.selectedBackground=#4F9EE3
|
||||
CheckBox.icon.checkmarkColor=#FFFFFF
|
||||
|
||||
CheckBox.icon.selectedHoverBackground=#5E94CE
|
||||
CheckBox.icon.selectedPressedBackground=#72A1D4
|
||||
CheckBox.icon.style=filled
|
||||
CheckBox.icon[filled].focusWidth=2
|
||||
|
||||
|
||||
#---- Component ----
|
||||
|
||||
Component.focusWidth=2
|
||||
Component.innerFocusWidth=0
|
||||
Component.innerOutlineWidth=0
|
||||
Component.arrowType=triangle
|
||||
|
||||
|
||||
#---- RadioButton ----
|
||||
|
||||
RadioButton.icon.centerDiameter=5
|
||||
|
||||
@@ -64,7 +64,7 @@ ViewportUI=com.formdev.flatlaf.ui.FlatViewportUI
|
||||
#---- variables ----
|
||||
|
||||
@textComponentMargin=2,6,2,6
|
||||
@menuItemMargin=2,8,2,8
|
||||
@menuItemMargin=3,6,3,6
|
||||
|
||||
|
||||
#---- system colors ----
|
||||
@@ -178,13 +178,18 @@ ColorChooser.swatchesDefaultRecentColor=$control
|
||||
|
||||
ComboBox.border=com.formdev.flatlaf.ui.FlatRoundBorder
|
||||
ComboBox.padding=2,6,2,6
|
||||
ComboBox.minimumWidth=72
|
||||
ComboBox.editorColumns=0
|
||||
ComboBox.maximumRowCount=20
|
||||
[mac]ComboBox.showPopupOnNavigation=true
|
||||
ComboBox.buttonStyle=auto
|
||||
|
||||
|
||||
#---- Component ----
|
||||
|
||||
Component.focusWidth=0
|
||||
Component.innerFocusWidth={float}0.5
|
||||
Component.innerOutlineWidth={float}1
|
||||
Component.arc=5
|
||||
Component.minimumWidth=64
|
||||
Component.arrowType=chevron
|
||||
@@ -258,9 +263,16 @@ InternalFrame.buttonSize=24,24
|
||||
InternalFrame.closeIcon=com.formdev.flatlaf.icons.FlatInternalFrameCloseIcon
|
||||
InternalFrame.iconifyIcon=com.formdev.flatlaf.icons.FlatInternalFrameIconifyIcon
|
||||
InternalFrame.maximizeIcon=com.formdev.flatlaf.icons.FlatInternalFrameMaximizeIcon
|
||||
InternalFrame.minimizeIcon=com.formdev.flatlaf.icons.FlatInternalFrameMinimizeIcon
|
||||
InternalFrame.minimizeIcon=com.formdev.flatlaf.icons.FlatInternalFrameRestoreIcon
|
||||
InternalFrame.windowBindings=null
|
||||
|
||||
# drop shadow
|
||||
InternalFrame.dropShadowPainted=true
|
||||
InternalFrame.activeDropShadowColor=null
|
||||
InternalFrame.activeDropShadowInsets=5,5,6,6
|
||||
InternalFrame.inactiveDropShadowColor=null
|
||||
InternalFrame.inactiveDropShadowInsets=3,3,4,4
|
||||
|
||||
|
||||
#---- InternalFrameTitlePane ----
|
||||
|
||||
@@ -299,7 +311,7 @@ Menu.background=@menuBackground
|
||||
|
||||
MenuBar.border=com.formdev.flatlaf.ui.FlatMenuBarBorder
|
||||
MenuBar.background=@menuBackground
|
||||
MenuBar.itemMargins=3,3,3,3
|
||||
MenuBar.itemMargins=3,8,3,8
|
||||
|
||||
|
||||
#---- MenuItem ----
|
||||
@@ -311,9 +323,23 @@ MenuItem.margin=@menuItemMargin
|
||||
MenuItem.opaque=false
|
||||
MenuItem.borderPainted=true
|
||||
MenuItem.background=@menuBackground
|
||||
MenuItem.checkBackground=@menuCheckBackground
|
||||
MenuItem.checkMargins=2,2,2,2
|
||||
MenuItem.minimumWidth=72
|
||||
MenuItem.minimumIconSize=16,16
|
||||
MenuItem.iconTextGap=6
|
||||
MenuItem.textAcceleratorGap=24
|
||||
MenuItem.textNoAcceleratorGap=6
|
||||
MenuItem.acceleratorArrowGap=2
|
||||
MenuItem.acceleratorDelimiter=-
|
||||
[mac]MenuItem.acceleratorDelimiter=
|
||||
|
||||
# for MenuItem.selectionType=underline
|
||||
MenuItem.underlineSelectionBackground=@menuHoverBackground
|
||||
MenuItem.underlineSelectionCheckBackground=@menuCheckHoverBackground
|
||||
MenuItem.underlineSelectionColor=$TabbedPane.underlineColor
|
||||
MenuItem.underlineSelectionHeight=3
|
||||
|
||||
|
||||
#---- OptionPane ----
|
||||
|
||||
@@ -348,6 +374,12 @@ PasswordField.echoChar=\u2022
|
||||
PasswordField.capsLockIcon=com.formdev.flatlaf.icons.FlatCapsLockIcon
|
||||
|
||||
|
||||
#---- Popup ----
|
||||
|
||||
Popup.dropShadowPainted=true
|
||||
Popup.dropShadowInsets=-4,-4,4,4
|
||||
|
||||
|
||||
#---- PopupMenu ----
|
||||
|
||||
PopupMenu.border=com.formdev.flatlaf.ui.FlatPopupMenuBorder
|
||||
@@ -393,15 +425,36 @@ RadioButtonMenuItem.borderPainted=true
|
||||
RadioButtonMenuItem.background=@menuBackground
|
||||
|
||||
|
||||
#---- RootPane ----
|
||||
|
||||
RootPane.border=com.formdev.flatlaf.ui.FlatRootPaneUI$FlatWindowBorder
|
||||
RootPane.borderDragThickness=5
|
||||
RootPane.cornerDragWidth=16
|
||||
RootPane.honorMinimumSizeOnResize=true
|
||||
|
||||
|
||||
#---- ScrollBar ----
|
||||
|
||||
ScrollBar.width=10
|
||||
ScrollBar.trackInsets=0,0,0,0
|
||||
ScrollBar.thumbInsets=0,0,0,0
|
||||
ScrollBar.trackArc=0
|
||||
ScrollBar.thumbArc=0
|
||||
ScrollBar.hoverThumbWithTrack=false
|
||||
ScrollBar.pressedThumbWithTrack=false
|
||||
ScrollBar.showButtons=false
|
||||
ScrollBar.squareButtons=false
|
||||
ScrollBar.buttonArrowColor=$ComboBox.buttonArrowColor
|
||||
ScrollBar.buttonDisabledArrowColor=$ComboBox.buttonDisabledArrowColor
|
||||
ScrollBar.allowsAbsolutePositioning=true
|
||||
|
||||
[mac]ScrollBar.thumbInsets=2,2,2,2
|
||||
[mac]ScrollBar.thumbArc=999
|
||||
[mac]ScrollBar.hoverThumbWithTrack=true
|
||||
|
||||
[linux]ScrollBar.thumbInsets=2,2,2,2
|
||||
[linux]ScrollBar.thumbArc=999
|
||||
|
||||
|
||||
#---- ScrollPane ----
|
||||
|
||||
@@ -435,6 +488,7 @@ Spinner.buttonDisabledArrowColor=$ComboBox.buttonDisabledArrowColor
|
||||
Spinner.buttonHoverArrowColor=$ComboBox.buttonHoverArrowColor
|
||||
Spinner.padding=@textComponentMargin
|
||||
Spinner.editorBorderPainted=false
|
||||
Spinner.buttonStyle=button
|
||||
|
||||
|
||||
#---- SplitPane ----
|
||||
@@ -532,6 +586,31 @@ TitledBorder.titleColor=@foreground
|
||||
TitledBorder.border=1,1,1,1,$Separator.foreground
|
||||
|
||||
|
||||
#---- TitlePane ----
|
||||
|
||||
TitlePane.menuBarEmbedded=true
|
||||
TitlePane.iconSize=16,16
|
||||
TitlePane.iconMargins=3,8,3,0
|
||||
TitlePane.menuBarMargins=0,8,0,22
|
||||
TitlePane.titleMargins=3,8,3,8
|
||||
TitlePane.buttonSize=44,30
|
||||
TitlePane.buttonMaximizedHeight=22
|
||||
TitlePane.closeIcon=com.formdev.flatlaf.icons.FlatWindowCloseIcon
|
||||
TitlePane.iconifyIcon=com.formdev.flatlaf.icons.FlatWindowIconifyIcon
|
||||
TitlePane.maximizeIcon=com.formdev.flatlaf.icons.FlatWindowMaximizeIcon
|
||||
TitlePane.restoreIcon=com.formdev.flatlaf.icons.FlatWindowRestoreIcon
|
||||
|
||||
TitlePane.background=$MenuBar.background
|
||||
TitlePane.inactiveBackground=$TitlePane.background
|
||||
TitlePane.foreground=@foreground
|
||||
TitlePane.inactiveForeground=@disabledText
|
||||
|
||||
TitlePane.closeHoverBackground=#e81123
|
||||
TitlePane.closePressedBackground=rgba($TitlePane.closeHoverBackground,60%)
|
||||
TitlePane.closeHoverForeground=#fff
|
||||
TitlePane.closePressedForeground=#fff
|
||||
|
||||
|
||||
#---- ToggleButton ----
|
||||
|
||||
ToggleButton.border=com.formdev.flatlaf.ui.FlatButtonBorder
|
||||
@@ -577,14 +656,6 @@ ToolBar.spacingBorder=$Button.toolbar.spacingInsets
|
||||
ToolTipManager.enableToolTipMode=activeApplication
|
||||
|
||||
|
||||
#---- ToolTip ----
|
||||
|
||||
ToolTip.border=4,6,4,6,$Component.borderColor
|
||||
ToolTip.borderInactive=null
|
||||
ToolTip.backgroundInactive=$ToolTip.background
|
||||
ToolTip.foregroundInactive=@disabledText
|
||||
|
||||
|
||||
#---- Tree ----
|
||||
|
||||
Tree.border=1,1,1,1
|
||||
|
||||
@@ -29,13 +29,12 @@
|
||||
@disabledText=#8C8C8C
|
||||
@textComponentBackground=#ffffff
|
||||
@menuBackground=#fff
|
||||
@menuHoverBackground=darken(@menuBackground,10%,derived)
|
||||
@menuCheckBackground=darken(@menuBackground,10%,derived)
|
||||
@menuCheckHoverBackground=darken(@menuBackground,20%,derived)
|
||||
@cellFocusColor=#000000
|
||||
@icon=#afafaf
|
||||
|
||||
# Button
|
||||
@buttonHoverBackground=darken(3%,autoInverse)
|
||||
@buttonPressedBackground=darken(10%,autoInverse)
|
||||
|
||||
# Drop (use lazy colors for IntelliJ platform themes, which usually do not specify these colors)
|
||||
@dropCellBackground=lighten(List.selectionBackground,10%,lazy)
|
||||
@dropCellForeground=lazy(List.selectionForeground)
|
||||
@@ -57,7 +56,7 @@
|
||||
*.disabledBackground=@background
|
||||
*.disabledForeground=@disabledText
|
||||
*.disabledText=@disabledText
|
||||
*.acceleratorForeground=#505050
|
||||
*.acceleratorForeground=lighten(@foreground,30%)
|
||||
*.acceleratorSelectionForeground=@selectionForeground
|
||||
|
||||
|
||||
@@ -74,8 +73,8 @@ controlDkShadow=darken($controlShadow,15%)
|
||||
|
||||
Button.background=#ffffff
|
||||
Button.focusedBackground=#e3f1fa
|
||||
Button.hoverBackground=@buttonHoverBackground
|
||||
Button.pressedBackground=@buttonPressedBackground
|
||||
Button.hoverBackground=darken($Button.background,3%,derived)
|
||||
Button.pressedBackground=darken($Button.background,10%,derived)
|
||||
|
||||
Button.borderColor=$Component.borderColor
|
||||
Button.disabledBorderColor=$Component.disabledBorderColor
|
||||
@@ -85,34 +84,58 @@ Button.hoverBorderColor=$Button.focusedBorderColor
|
||||
Button.default.background=$Button.background
|
||||
Button.default.foreground=@foreground
|
||||
Button.default.focusedBackground=$Button.focusedBackground
|
||||
Button.default.hoverBackground=@buttonHoverBackground
|
||||
Button.default.pressedBackground=@buttonPressedBackground
|
||||
Button.default.hoverBackground=$Button.hoverBackground
|
||||
Button.default.pressedBackground=$Button.pressedBackground
|
||||
Button.default.borderColor=#4F9EE3
|
||||
Button.default.hoverBorderColor=$Button.hoverBorderColor
|
||||
Button.default.focusedBorderColor=$Button.focusedBorderColor
|
||||
Button.default.focusColor=$Component.focusColor
|
||||
Button.default.borderWidth=2
|
||||
|
||||
Button.toolbar.hoverBackground=#dfdfdf
|
||||
Button.toolbar.pressedBackground=#d8d8d8
|
||||
Button.toolbar.hoverBackground=darken($Button.background,12%,derived)
|
||||
Button.toolbar.pressedBackground=darken($Button.background,15%,derived)
|
||||
|
||||
|
||||
#---- CheckBox ----
|
||||
|
||||
# enabled
|
||||
CheckBox.icon.borderColor=#b0b0b0
|
||||
CheckBox.icon.disabledBorderColor=#BDBDBD
|
||||
CheckBox.icon.selectedBorderColor=$CheckBox.icon.borderColor
|
||||
CheckBox.icon.focusedBorderColor=#7B9FC7
|
||||
CheckBox.icon.hoverBorderColor=$CheckBox.icon.focusedBorderColor
|
||||
CheckBox.icon.background=#FFFFFF
|
||||
CheckBox.icon.disabledBackground=@background
|
||||
CheckBox.icon.focusedBackground=$Button.focusedBackground
|
||||
CheckBox.icon.hoverBackground=@buttonHoverBackground
|
||||
CheckBox.icon.pressedBackground=@buttonPressedBackground
|
||||
CheckBox.icon.selectedBackground=#FFFFFF
|
||||
CheckBox.icon.selectedBorderColor=$CheckBox.icon.borderColor
|
||||
CheckBox.icon.selectedBackground=$CheckBox.icon.background
|
||||
CheckBox.icon.checkmarkColor=#4F9EE3
|
||||
|
||||
# disabled
|
||||
CheckBox.icon.disabledBorderColor=#BDBDBD
|
||||
CheckBox.icon.disabledBackground=@background
|
||||
CheckBox.icon.disabledCheckmarkColor=#ABABAB
|
||||
|
||||
# focused
|
||||
CheckBox.icon.focusedBorderColor=#7B9FC7
|
||||
CheckBox.icon.focusedBackground=$Button.focusedBackground
|
||||
|
||||
# hover
|
||||
CheckBox.icon.hoverBorderColor=$CheckBox.icon.focusedBorderColor
|
||||
CheckBox.icon.hoverBackground=$Button.hoverBackground
|
||||
|
||||
# pressed
|
||||
CheckBox.icon.pressedBackground=$Button.pressedBackground
|
||||
|
||||
|
||||
# used if CheckBox.icon.style=filled
|
||||
# enabled
|
||||
CheckBox.icon[filled].selectedBorderColor=#4B97D9
|
||||
CheckBox.icon[filled].selectedBackground=#4F9EE3
|
||||
CheckBox.icon[filled].checkmarkColor=#FFFFFF
|
||||
# focused
|
||||
CheckBox.icon[filled].selectedFocusedBorderColor=#ACCFF7
|
||||
CheckBox.icon[filled].selectedFocusedBackground=$CheckBox.icon[filled].selectedBackground
|
||||
CheckBox.icon[filled].selectedFocusedCheckmarkColor=$CheckBox.icon.focusedBackground
|
||||
# hover
|
||||
CheckBox.icon[filled].selectedHoverBackground=#5E94CE
|
||||
# pressed
|
||||
CheckBox.icon[filled].selectedPressedBackground=#72A1D4
|
||||
|
||||
|
||||
#---- ComboBox ----
|
||||
|
||||
@@ -131,6 +154,13 @@ Component.disabledBorderColor=#cfcfcf
|
||||
Component.focusedBorderColor=#87afda
|
||||
Component.focusColor=#97c3f3
|
||||
Component.linkColor=#2470B3
|
||||
Component.grayFilter=25,-25,100
|
||||
|
||||
Component.error.borderColor=lighten(desaturate($Component.error.focusedBorderColor,20%),25%)
|
||||
Component.error.focusedBorderColor=#e53e4d
|
||||
Component.warning.borderColor=lighten(saturate($Component.warning.focusedBorderColor,25%),20%)
|
||||
Component.warning.focusedBorderColor=#e2a53a
|
||||
Component.custom.borderColor=lighten(desaturate(#f00,20%,derived noAutoInverse),25%,derived noAutoInverse)
|
||||
|
||||
|
||||
#---- Desktop ----
|
||||
@@ -158,13 +188,16 @@ InternalFrame.inactiveTitleForeground=@disabledText
|
||||
InternalFrame.activeBorderColor=darken($Component.borderColor,20%)
|
||||
InternalFrame.inactiveBorderColor=$Component.borderColor
|
||||
|
||||
InternalFrame.buttonHoverBackground=darken(10%,autoInverse)
|
||||
InternalFrame.buttonPressedBackground=darken(20%,autoInverse)
|
||||
InternalFrame.buttonHoverBackground=darken($InternalFrame.activeTitleBackground,10%,derived)
|
||||
InternalFrame.buttonPressedBackground=darken($InternalFrame.activeTitleBackground,20%,derived)
|
||||
InternalFrame.closeHoverBackground=lazy(Actions.Red)
|
||||
InternalFrame.closePressedBackground=darken(Actions.Red,10%,lazy)
|
||||
InternalFrame.closeHoverForeground=#fff
|
||||
InternalFrame.closePressedForeground=#fff
|
||||
|
||||
InternalFrame.activeDropShadowOpacity=0.25
|
||||
InternalFrame.inactiveDropShadowOpacity=0.5
|
||||
|
||||
|
||||
#---- List ----
|
||||
|
||||
@@ -180,7 +213,7 @@ Menu.icon.disabledArrowColor=#ABABAB
|
||||
#---- MenuBar ----
|
||||
|
||||
MenuBar.borderColor=#cdcdcd
|
||||
MenuBar.hoverBackground=darken($MenuBar.background,10%)
|
||||
MenuBar.hoverBackground=@menuHoverBackground
|
||||
|
||||
|
||||
#---- MenuItemCheckBox ----
|
||||
@@ -194,6 +227,12 @@ MenuItemCheckBox.icon.disabledCheckmarkColor=#ABABAB
|
||||
PasswordField.capsLockIconColor=#00000064
|
||||
|
||||
|
||||
#---- Popup ----
|
||||
|
||||
Popup.dropShadowColor=#000
|
||||
Popup.dropShadowOpacity=0.15
|
||||
|
||||
|
||||
#---- PopupMenu ----
|
||||
|
||||
PopupMenu.borderColor=#adadad
|
||||
@@ -207,12 +246,20 @@ ProgressBar.selectionForeground=@textComponentBackground
|
||||
ProgressBar.selectionBackground=@foreground
|
||||
|
||||
|
||||
#---- RadioButton ----
|
||||
|
||||
RadioButton.icon[filled].centerDiameter=5
|
||||
|
||||
|
||||
#---- ScrollBar ----
|
||||
|
||||
ScrollBar.track=#F5F5F5
|
||||
ScrollBar.thumb=darken($ScrollBar.track,10%)
|
||||
ScrollBar.hoverTrackColor=darken($ScrollBar.track,3%)
|
||||
ScrollBar.hoverThumbColor=darken($ScrollBar.thumb,10%)
|
||||
ScrollBar.track=lighten(@background,1%,derived noAutoInverse)
|
||||
ScrollBar.thumb=darken($ScrollBar.track,10%,derived noAutoInverse)
|
||||
ScrollBar.hoverTrackColor=darken($ScrollBar.track,3%,derived noAutoInverse)
|
||||
ScrollBar.hoverThumbColor=darken($ScrollBar.thumb,10%,derived noAutoInverse)
|
||||
ScrollBar.pressedThumbColor=darken($ScrollBar.thumb,20%,derived noAutoInverse)
|
||||
ScrollBar.hoverButtonBackground=darken(@background,5%,derived noAutoInverse)
|
||||
ScrollBar.pressedButtonBackground=darken(@background,10%,derived noAutoInverse)
|
||||
|
||||
|
||||
#---- Separator ----
|
||||
@@ -225,7 +272,7 @@ Separator.foreground=#d1d1d1
|
||||
Slider.trackColor=#c4c4c4
|
||||
Slider.thumbColor=#6e6e6e
|
||||
Slider.tickColor=#888888
|
||||
Slider.hoverColor=lighten(15%,autoInverse)
|
||||
Slider.hoverColor=lighten($Slider.thumbColor,15%,derived)
|
||||
Slider.disabledForeground=#c0c0c0
|
||||
|
||||
|
||||
@@ -258,17 +305,25 @@ TableHeader.separatorColor=darken($TableHeader.background,10%)
|
||||
TableHeader.bottomSeparatorColor=$TableHeader.separatorColor
|
||||
|
||||
|
||||
#---- TitlePane ----
|
||||
|
||||
TitlePane.embeddedForeground=lighten($TitlePane.foreground,35%)
|
||||
TitlePane.buttonHoverBackground=darken($TitlePane.background,10%,derived)
|
||||
TitlePane.buttonPressedBackground=darken($TitlePane.background,20%,derived)
|
||||
|
||||
|
||||
#---- ToggleButton ----
|
||||
|
||||
ToggleButton.selectedBackground=#cfcfcf
|
||||
ToggleButton.selectedBackground=darken($ToggleButton.background,20%,derived)
|
||||
ToggleButton.selectedForeground=@foreground
|
||||
ToggleButton.disabledSelectedBackground=#dfdfdf
|
||||
ToggleButton.disabledSelectedBackground=darken($ToggleButton.background,13%,derived)
|
||||
|
||||
ToggleButton.toolbar.selectedBackground=#cfcfcf
|
||||
ToggleButton.toolbar.selectedBackground=$ToggleButton.selectedBackground
|
||||
|
||||
|
||||
#---- ToolTip ----
|
||||
|
||||
ToolTip.border=4,6,4,6,$InternalFrame.activeBorderColor
|
||||
ToolTip.background=#fafafa
|
||||
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user