mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2025-12-08 23:08:42 +03:00
Compare commits
165 Commits
1.6.1
...
styling-ty
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
19483b6464 | ||
|
|
1f6a23f909 | ||
|
|
e49459fd8b | ||
|
|
52f6e7fc32 | ||
|
|
c8ea61dc79 | ||
|
|
16a769ea61 | ||
|
|
475781db91 | ||
|
|
4dae082cd5 | ||
|
|
57405b2f56 | ||
|
|
88576f68fd | ||
|
|
aa4e013097 | ||
|
|
d67cfc911b | ||
|
|
00a3ad738f | ||
|
|
1d39d34d7c | ||
|
|
5f6013edd4 | ||
|
|
3e198ecd28 | ||
|
|
d48b98f582 | ||
|
|
9b839231f7 | ||
|
|
dd80614465 | ||
|
|
8c2be1b406 | ||
|
|
8152b7dad6 | ||
|
|
fb4fe175d9 | ||
|
|
5e03eb9b51 | ||
|
|
ef25575f85 | ||
|
|
b77b338c7a | ||
|
|
0e4fe4e9bb | ||
|
|
0156a9a9d5 | ||
|
|
3facbc0900 | ||
|
|
78cef1b3c7 | ||
|
|
d907c469ed | ||
|
|
cc238d3e34 | ||
|
|
0f9b38895e | ||
|
|
8fa1eae352 | ||
|
|
e13fb25f14 | ||
|
|
e36f942129 | ||
|
|
f8b9f4c1fa | ||
|
|
65a4f66d2c | ||
|
|
d10bcfc72f | ||
|
|
942e5b9cd1 | ||
|
|
51a90d32f8 | ||
|
|
ac46632e73 | ||
|
|
1192bef1ae | ||
|
|
b9ec382589 | ||
|
|
5ecf19ef4f | ||
|
|
9636809b4d | ||
|
|
ba1c1ed952 | ||
|
|
7452390614 | ||
|
|
69042e42b7 | ||
|
|
1e93deab2a | ||
|
|
16ea809bb3 | ||
|
|
78aa4343b7 | ||
|
|
6815109e15 | ||
|
|
e34fbcec58 | ||
|
|
bb2a21270b | ||
|
|
49b9ec9025 | ||
|
|
a2e896e102 | ||
|
|
2e1ef647a9 | ||
|
|
f0c314df80 | ||
|
|
4db39828ef | ||
|
|
b2d40825ac | ||
|
|
6df5d3334e | ||
|
|
0e982df90c | ||
|
|
3834d93c9d | ||
|
|
16920a5b82 | ||
|
|
d66e35fdde | ||
|
|
d93dde0a03 | ||
|
|
2d232124dd | ||
|
|
ac6702fcf7 | ||
|
|
c4b016c9c8 | ||
|
|
6baa583a28 | ||
|
|
82df2ecfa9 | ||
|
|
06b3de720a | ||
|
|
b0edd5659f | ||
|
|
bb5c2eea10 | ||
|
|
e31e4dfe3a | ||
|
|
caf2cd8487 | ||
|
|
15c6f11a5e | ||
|
|
a4ea88f4be | ||
|
|
36d5747fbf | ||
|
|
3d8c535ffa | ||
|
|
1c067d0284 | ||
|
|
b6be0462a5 | ||
|
|
cce91ea16d | ||
|
|
d756041b06 | ||
|
|
2d0eb0a05b | ||
|
|
02f3239669 | ||
|
|
14a9240c45 | ||
|
|
c659638fb4 | ||
|
|
fd15b63044 | ||
|
|
263e6c34b5 | ||
|
|
eb62a3dc17 | ||
|
|
161ee090a8 | ||
|
|
560ec437b9 | ||
|
|
ccd0597b35 | ||
|
|
c5c0a3768a | ||
|
|
5aa2d24d58 | ||
|
|
e0dddfceba | ||
|
|
08ca2aa266 | ||
|
|
fe15758e59 | ||
|
|
674efae184 | ||
|
|
4a65bc88d5 | ||
|
|
a8f3d59729 | ||
|
|
a2c0df5891 | ||
|
|
dc33c26960 | ||
|
|
cdbdccf1ad | ||
|
|
397c369114 | ||
|
|
6f9bbb184a | ||
|
|
b12c818862 | ||
|
|
9118dcf925 | ||
|
|
d333d0c9e4 | ||
|
|
7f9cf6f45c | ||
|
|
9b465cb550 | ||
|
|
9144b7206e | ||
|
|
dd14843f2e | ||
|
|
299bd67151 | ||
|
|
4d4bb3fd7f | ||
|
|
7fd64a1b73 | ||
|
|
e3e8765b91 | ||
|
|
943dfe0619 | ||
|
|
be7114d3e6 | ||
|
|
713a01bfa9 | ||
|
|
ac291b688d | ||
|
|
84f7e244f2 | ||
|
|
4a8207f367 | ||
|
|
9cfd4d27e9 | ||
|
|
1b23cfd747 | ||
|
|
5801bf3bdf | ||
|
|
2b1c55ee67 | ||
|
|
925ddaa63a | ||
|
|
2b60b18d47 | ||
|
|
d502406fa2 | ||
|
|
afdbf711f7 | ||
|
|
b4f7b1d71d | ||
|
|
69061cd41c | ||
|
|
8ba7f7f961 | ||
|
|
5e5aa17e14 | ||
|
|
551f5fc929 | ||
|
|
4e7b0d11d0 | ||
|
|
06bc53692a | ||
|
|
007ee38cb4 | ||
|
|
82192bef91 | ||
|
|
0c51dfe19c | ||
|
|
24a9fa1ccc | ||
|
|
14b06507cb | ||
|
|
b46233087b | ||
|
|
28fb2e2a08 | ||
|
|
20027c2db7 | ||
|
|
6affc70a66 | ||
|
|
ab4c9bdeda | ||
|
|
b4a9c9b7f5 | ||
|
|
5e20d50abf | ||
|
|
53abbbbe56 | ||
|
|
1938cb586d | ||
|
|
50490ece84 | ||
|
|
f291cc2bd3 | ||
|
|
2542c8bd53 | ||
|
|
b457fd634e | ||
|
|
041fd0e0cd | ||
|
|
a983edde1e | ||
|
|
7eb642dd13 | ||
|
|
e0bc93371e | ||
|
|
db56486506 | ||
|
|
c99be13697 | ||
|
|
0830c78728 | ||
|
|
edade93054 |
70
CHANGELOG.md
70
CHANGELOG.md
@@ -1,6 +1,70 @@
|
||||
FlatLaf Change Log
|
||||
==================
|
||||
|
||||
## 2.0-SNAPSHOT
|
||||
|
||||
#### New features and improvements
|
||||
|
||||
- Styling:
|
||||
- Styling individual components using string in CSS syntax or `java.util.Map`.
|
||||
(PR #341)\
|
||||
E.g.: `mySlider.putClientProperty( "FlatLaf.style", "trackWidth: 2" );`
|
||||
- Style classes allow defining style rules at a single place (in UI defaults)
|
||||
and use them in any component. (PR #388)\
|
||||
E.g.: `mySlider.putClientProperty( "FlatLaf.styleClass", "myclass" );`
|
||||
- TextField, FormattedTextField and PasswordField: Support leading and trailing
|
||||
icons (set client property `JTextField.leadingIcon` or
|
||||
`JTextField.trailingIcon` to an `Icon`). (PR #378; issue #368)
|
||||
- TextComponents: Double/triple-click-and-drag now extends selection by whole
|
||||
words/lines.
|
||||
- Theming improvements: Reworks core themes to make it easier to create new
|
||||
themes (e.g. reduced explicit colors by using color functions). **Note**:
|
||||
There are minor incompatible changes in FlatLaf properties files. (PR #390)
|
||||
- ToolBar:
|
||||
- Toolbars are no longer floatable by default (dots on left side of toolbar
|
||||
that allows dragging toolbar). Use `UIManager.put( "ToolBar.floatable", true
|
||||
)` if you want the old behavior.
|
||||
- Skip components with empty input map (e.g. `JLabel`) when using arrow keys
|
||||
to navigate in focusable buttons (if UI value `ToolBar.focusableButtons` is
|
||||
`true`).
|
||||
- Support arrow-keys-only navigation within focusable buttons of toolbar (if
|
||||
UI value `ToolBar.focusableButtons` is `true`):
|
||||
- arrow keys move focus within toolbar
|
||||
- tab-key moves focus out of toolbar
|
||||
- if moving focus into the toolbar, focus recently focused toolbar button
|
||||
- ComboBox, Spinner, TextField and subclasses: Support specifying width of
|
||||
border (see UI value `Component.borderWidth`).
|
||||
- CheckBox and RadioButton:
|
||||
- Made selected icon better recognizable in **FlatLaf Light** (use blue
|
||||
border), **Dark** and **Darcula** (use lighter border) themes. **IntelliJ**
|
||||
theme is not changed.
|
||||
- Support specifying width of icon border (see UI value
|
||||
`CheckBox.icon.borderWidth`).
|
||||
- Reworked icon UI defaults and added missing ones. **Note**: There are minor
|
||||
incompatible changes in FlatLaf properties files.
|
||||
- Slider: Support specifying width of thumb border (see UI value
|
||||
`Slider.thumbBorderWidth`).
|
||||
- Added more color functions to class `ColorFunctions` for easy use in
|
||||
applications: `lighten()`, `darken()`, `saturate()`, `desaturate()`, `spin()`,
|
||||
`tint()`, `shade()` and `luma()`.
|
||||
- Support defining fonts in FlatLaf properties files. (issue #384)
|
||||
- Extras: Added class `FlatDesktop` for easy integration into macOS screen menu
|
||||
(About, Preferences and Quit) when using Java 8.
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- ComboBox (not editable): Fixed background painted outside of border if round
|
||||
edges are enabled (client property `JComponent.roundRect` is `true`). (similar
|
||||
to issue #382; regression since fixing #330 in FlatLaf 1.4)
|
||||
- Tree: Fixed editing cell issue with custom cell renderer and cell editor that
|
||||
use same component for rendering and editing. (issue #385)
|
||||
- Table: Do not select text in cell editor when it gets focus (when
|
||||
`JTable.surrendersFocusOnKeystroke` is `true`) and
|
||||
`TextComponent.selectAllOnFocusPolicy` is `once` (the default) or `always`.
|
||||
(issue #395)
|
||||
- Linux: Fixed NPE when using `java.awt.TrayIcon`. (issue #405)
|
||||
|
||||
|
||||
## 1.6.1
|
||||
|
||||
#### Fixed bugs
|
||||
@@ -33,7 +97,7 @@ FlatLaf Change Log
|
||||
- ComboBox (editable): Fixed wrong border of internal text field under special
|
||||
circumstances.
|
||||
- Spinner: Fixed painting of border corners on left side. (issue #382;
|
||||
regression since FlatLaf 1.4)
|
||||
regression since fixing #330 in FlatLaf 1.4)
|
||||
- TableHeader: Do not show resize cursor for last column if resizing last column
|
||||
is not possible because auto resize mode of table is not off. (issue #332)
|
||||
- TableHeader: Fixed missing trailing vertical separator line if used in upper
|
||||
@@ -78,8 +142,8 @@ FlatLaf Change Log
|
||||
|
||||
#### New features and improvements
|
||||
|
||||
- TextField, FormattedTextField and PasswordField: Support adding extra padding.
|
||||
(set client property `JTextField.padding` to `Insets`).
|
||||
- TextField, FormattedTextField and PasswordField: Support adding extra padding
|
||||
(set client property `JTextField.padding` to an `Insets`).
|
||||
- PasswordField: UI delegate `FlatPasswordFieldUI` now extends `FlatTextFieldUI`
|
||||
(instead of `BasicPasswordFieldUI`) to avoid duplicate code and for easier
|
||||
extensibility.
|
||||
|
||||
2151
compare1.txt
Normal file
2151
compare1.txt
Normal file
File diff suppressed because it is too large
Load Diff
@@ -21,10 +21,15 @@ plugins {
|
||||
`flatlaf-publish`
|
||||
}
|
||||
|
||||
val sigtest = configurations.create( "sigtest" )
|
||||
|
||||
dependencies {
|
||||
testImplementation( "org.junit.jupiter:junit-jupiter-api:5.7.2" )
|
||||
testImplementation( "org.junit.jupiter:junit-jupiter-params" )
|
||||
testRuntimeOnly( "org.junit.jupiter:junit-jupiter-engine" )
|
||||
|
||||
// https://github.com/jtulach/netbeans-apitest
|
||||
sigtest( "org.netbeans.tools:sigtest-maven-plugin:1.4" )
|
||||
}
|
||||
|
||||
java {
|
||||
@@ -59,10 +64,60 @@ tasks {
|
||||
archiveBaseName.set( "flatlaf" )
|
||||
}
|
||||
|
||||
check {
|
||||
dependsOn( "sigtestCheck" )
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
testLogging.exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
|
||||
}
|
||||
|
||||
register( "sigtestGenerate" ) {
|
||||
group = "verification"
|
||||
dependsOn( "jar" )
|
||||
|
||||
doLast {
|
||||
ant.withGroovyBuilder {
|
||||
"taskdef"(
|
||||
"name" to "sigtest",
|
||||
"classname" to "org.netbeans.apitest.Sigtest",
|
||||
"classpath" to sigtest.asPath )
|
||||
|
||||
"sigtest"(
|
||||
"action" to "generate",
|
||||
"fileName" to "${project.name}-sigtest.txt",
|
||||
"classpath" to jar.get().outputs.files.asPath,
|
||||
"packages" to "com.formdev.flatlaf,com.formdev.flatlaf.util",
|
||||
"version" to version,
|
||||
"release" to "1.8", // Java version
|
||||
"failonerror" to "true" )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
register( "sigtestCheck" ) {
|
||||
group = "verification"
|
||||
dependsOn( "jar" )
|
||||
|
||||
doLast {
|
||||
ant.withGroovyBuilder {
|
||||
"taskdef"(
|
||||
"name" to "sigtest",
|
||||
"classname" to "org.netbeans.apitest.Sigtest",
|
||||
"classpath" to sigtest.asPath )
|
||||
|
||||
"sigtest"(
|
||||
"action" to "check",
|
||||
"fileName" to "${project.name}-sigtest.txt",
|
||||
"classpath" to jar.get().outputs.files.asPath,
|
||||
"packages" to "com.formdev.flatlaf,com.formdev.flatlaf.util",
|
||||
"version" to version,
|
||||
"release" to "1.8", // Java version
|
||||
"failonerror" to "true" )
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flatlafPublish {
|
||||
|
||||
1029
flatlaf-core/flatlaf-core-sigtest.txt
Normal file
1029
flatlaf-core/flatlaf-core-sigtest.txt
Normal file
File diff suppressed because it is too large
Load Diff
@@ -126,6 +126,57 @@ public interface FlatClientProperties
|
||||
|
||||
//---- JComponent ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Specifies the style of a component as String in CSS syntax ("key1: value1; key2: value2; ...")
|
||||
* or as {@link java.util.Map}<String, Object> with binary values.
|
||||
* <p>
|
||||
* The keys are the same as used in UI defaults, but without component type prefix.
|
||||
* E.g. for UI default {@code Slider.thumbSize} use key {@code thumbSize}.
|
||||
* <p>
|
||||
* The syntax of the CSS values is the same as used in FlatLaf properties files
|
||||
* (<a href="https://www.formdev.com/flatlaf/properties-files/">https://www.formdev.com/flatlaf/properties-files/</a>),
|
||||
* but some features are not supported (e.g. variables).
|
||||
* When using a map, the values are not parsed from a string. They must be binary.
|
||||
* <p>
|
||||
* <strong>Components</strong> {@link javax.swing.JComponent}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.String} or {@link java.util.Map}<String, Object><br>
|
||||
*
|
||||
* @since 2
|
||||
*/
|
||||
String STYLE = "FlatLaf.style";
|
||||
|
||||
/**
|
||||
* Specifies the style class(es) of a component as String (single class or multiple classes separated by space characters)
|
||||
* or as {@code String[]} or {@link java.util.List}<String> (multiple classes).
|
||||
* <p>
|
||||
* The style rules must be defined in UI defaults either as strings (in CSS syntax)
|
||||
* or as {@link java.util.Map}<String, Object> (with binary values).
|
||||
* The key must be in syntax: {@code [style]type.styleClass}, where the type is optional.
|
||||
* E.g. in FlatLaf properties file:
|
||||
* <pre>{@code
|
||||
* [style]Button.primary = borderColor: #08f; background: #08f; foreground: #fff
|
||||
* [style].secondary = borderColor: #0f8; background: #0f8
|
||||
* }</pre>
|
||||
* or in Java code:
|
||||
* <pre>{@code
|
||||
* UIManager.put( "[style]Button.primary", "borderColor: #08f; background: #08f; foreground: #fff" );
|
||||
* UIManager.put( "[style].secondary", "borderColor: #0f8; background: #0f8" );
|
||||
* }</pre>
|
||||
* The rule "Button.primary" can be applied to buttons only.
|
||||
* The rule ".secondary" can be applied to any component.
|
||||
* <p>
|
||||
* To have similar behavior as in CSS, first the rule without type is applied,
|
||||
* then the rule with type.
|
||||
* E.g. setting style class to "foo" on a {@code JButton} uses rules
|
||||
* from UI default keys "[style].foo" and "[style]Button.foo".
|
||||
* <p>
|
||||
* <strong>Components</strong> {@link javax.swing.JComponent}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.String}, {@code String[]} or {@link java.util.List}<String><br>
|
||||
*
|
||||
* @since 2
|
||||
*/
|
||||
String STYLE_CLASS = "FlatLaf.styleClass";
|
||||
|
||||
/**
|
||||
* Specifies minimum width of a component.
|
||||
* <p>
|
||||
@@ -745,6 +796,26 @@ public interface FlatClientProperties
|
||||
*/
|
||||
String TEXT_FIELD_PADDING = "JTextField.padding";
|
||||
|
||||
/**
|
||||
* Specifies an icon that will be placed at the leading edge of the text field.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTextField} (and subclasses)<br>
|
||||
* <strong>Value type</strong> {@link javax.swing.Icon}
|
||||
*
|
||||
* @since 2
|
||||
*/
|
||||
String TEXT_FIELD_LEADING_ICON = "JTextField.leadingIcon";
|
||||
|
||||
/**
|
||||
* Specifies an icon that will be placed at the trailing edge of the text field.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTextField} (and subclasses)<br>
|
||||
* <strong>Value type</strong> {@link javax.swing.Icon}
|
||||
*
|
||||
* @since 2
|
||||
*/
|
||||
String TEXT_FIELD_TRAILING_ICON = "JTextField.trailingIcon";
|
||||
|
||||
//---- JToggleButton ------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -813,8 +884,7 @@ public interface FlatClientProperties
|
||||
* If the client property is not set, or not a {@link Boolean}, defaultValue is returned.
|
||||
*/
|
||||
static Boolean clientPropertyBooleanStrict( JComponent c, String key, Boolean defaultValue ) {
|
||||
Object value = c.getClientProperty( key );
|
||||
return (value instanceof Boolean) ? (Boolean) value : defaultValue;
|
||||
return clientProperty( c, key, defaultValue, Boolean.class );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -831,7 +901,18 @@ public interface FlatClientProperties
|
||||
* If the client property is not set, or not a color, defaultValue is returned.
|
||||
*/
|
||||
static Color clientPropertyColor( JComponent c, String key, Color defaultValue ) {
|
||||
return clientProperty( c, key, defaultValue, Color.class );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the specified client property if it is an instance of
|
||||
* the specified type. Otherwise, defaultValue is returned.
|
||||
*
|
||||
* @since 2
|
||||
*/
|
||||
@SuppressWarnings( "unchecked" )
|
||||
static <T> T clientProperty( JComponent c, String key, T defaultValue, Class<T> type ) {
|
||||
Object value = c.getClientProperty( key );
|
||||
return (value instanceof Color) ? (Color) value : defaultValue;
|
||||
return type.isInstance( value ) ? (T) value : defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import java.beans.PropertyChangeListener;
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -43,6 +44,7 @@ import java.util.ResourceBundle;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.IntUnaryOperator;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
@@ -55,6 +57,7 @@ import javax.swing.RootPaneContainer;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIDefaults;
|
||||
import javax.swing.UIDefaults.ActiveValue;
|
||||
import javax.swing.UIDefaults.LazyValue;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.UnsupportedLookAndFeelException;
|
||||
import javax.swing.plaf.ColorUIResource;
|
||||
@@ -86,6 +89,8 @@ public abstract class FlatLaf
|
||||
private static final String DESKTOPFONTHINTS = "awt.font.desktophints";
|
||||
|
||||
private static List<Object> customDefaultsSources;
|
||||
private static Map<String, String> globalExtraDefaults;
|
||||
private Map<String, String> extraDefaults;
|
||||
|
||||
private String desktopPropertyName;
|
||||
private String desktopPropertyName2;
|
||||
@@ -264,6 +269,12 @@ public abstract class FlatLaf
|
||||
}
|
||||
};
|
||||
Toolkit toolkit = Toolkit.getDefaultToolkit();
|
||||
|
||||
// make sure that AWT desktop properties are initialized (on Linux)
|
||||
// before invoking toolkit.addPropertyChangeListener()
|
||||
// https://github.com/JFormDesigner/FlatLaf/issues/405#issuecomment-960242342
|
||||
toolkit.getDesktopProperty( "dummy" );
|
||||
|
||||
toolkit.addPropertyChangeListener( desktopPropertyName, desktopPropertyListener );
|
||||
if( desktopPropertyName2 != null )
|
||||
toolkit.addPropertyChangeListener( desktopPropertyName2, desktopPropertyListener );
|
||||
@@ -425,6 +436,10 @@ public abstract class FlatLaf
|
||||
else
|
||||
UIDefaultsLoader.loadDefaultsFromProperties( getClass(), addons, getAdditionalDefaults(), isDark(), defaults );
|
||||
|
||||
// setup default font after loading defaults from properties
|
||||
// to allow defining "defaultFont" in properties
|
||||
initDefaultFont( defaults );
|
||||
|
||||
// use Aqua MenuBarUI if Mac screen menubar is enabled
|
||||
if( SystemInfo.isMacOS && Boolean.getBoolean( "apple.laf.useScreenMenuBar" ) ) {
|
||||
defaults.put( "MenuBarUI", "com.apple.laf.AquaMenuBarUI" );
|
||||
@@ -464,7 +479,15 @@ public abstract class FlatLaf
|
||||
}
|
||||
|
||||
protected Properties getAdditionalDefaults() {
|
||||
return null;
|
||||
if( globalExtraDefaults == null && extraDefaults == null )
|
||||
return null;
|
||||
|
||||
Properties properties = new Properties();
|
||||
if( globalExtraDefaults != null )
|
||||
properties.putAll( globalExtraDefaults );
|
||||
if( extraDefaults != null )
|
||||
properties.putAll( extraDefaults );
|
||||
return properties;
|
||||
}
|
||||
|
||||
private void initResourceBundle( UIDefaults defaults, String bundleName ) {
|
||||
@@ -507,8 +530,22 @@ public abstract class FlatLaf
|
||||
}
|
||||
|
||||
private void initFonts( UIDefaults defaults ) {
|
||||
// use active value for all fonts to allow changing fonts in all components with:
|
||||
// UIManager.put( "defaultFont", myFont );
|
||||
// (this is similar as in Nimbus L&F)
|
||||
Object activeFont = new ActiveFont( null, -1, 0, 0, 0, 0 );
|
||||
|
||||
// override fonts
|
||||
for( Object key : defaults.keySet() ) {
|
||||
if( key instanceof String && (((String)key).endsWith( ".font" ) || ((String)key).endsWith( "Font" )) )
|
||||
defaults.put( key, activeFont );
|
||||
}
|
||||
}
|
||||
|
||||
private void initDefaultFont( UIDefaults defaults ) {
|
||||
FontUIResource uiFont = null;
|
||||
|
||||
// determine UI font based on operating system
|
||||
if( SystemInfo.isWindows ) {
|
||||
Font winFont = (Font) Toolkit.getDefaultToolkit().getDesktopProperty( "win.messagebox.font" );
|
||||
if( winFont != null ) {
|
||||
@@ -551,23 +588,21 @@ public abstract class FlatLaf
|
||||
if( uiFont == null )
|
||||
uiFont = createCompositeFont( Font.SANS_SERIF, Font.PLAIN, 12 );
|
||||
|
||||
// get/remove "defaultFont" from defaults if set in properties files
|
||||
// (use remove() to avoid that ActiveFont.createValue() gets invoked)
|
||||
Object defaultFont = defaults.remove( "defaultFont" );
|
||||
|
||||
// use font from OS as base font and derive the UI font from it
|
||||
if( defaultFont instanceof ActiveFont ) {
|
||||
Font baseFont = uiFont;
|
||||
uiFont = ((ActiveFont)defaultFont).derive( baseFont, fontSize -> {
|
||||
return Math.round( fontSize * UIScale.computeFontScaleFactor( baseFont ) );
|
||||
} );
|
||||
};
|
||||
|
||||
// increase font size if system property "flatlaf.uiScale" is set
|
||||
uiFont = UIScale.applyCustomScaleFactor( uiFont );
|
||||
|
||||
// use active value for all fonts to allow changing fonts in all components
|
||||
// (similar as in Nimbus L&F) with:
|
||||
// UIManager.put( "defaultFont", myFont );
|
||||
Object activeFont = new ActiveFont( 1 );
|
||||
|
||||
// override fonts
|
||||
for( Object key : defaults.keySet() ) {
|
||||
if( key instanceof String && (((String)key).endsWith( ".font" ) || ((String)key).endsWith( "Font" )) )
|
||||
defaults.put( key, activeFont );
|
||||
}
|
||||
|
||||
// use smaller font for progress bar
|
||||
defaults.put( "ProgressBar.font", new ActiveFont( 0.85f ) );
|
||||
|
||||
// set default font
|
||||
defaults.put( "defaultFont", uiFont );
|
||||
}
|
||||
@@ -580,11 +615,9 @@ public abstract class FlatLaf
|
||||
return (font instanceof FontUIResource) ? (FontUIResource) font : new FontUIResource( font );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.1
|
||||
*/
|
||||
/** @since 1.1 */
|
||||
public static ActiveValue createActiveFontValue( float scaleFactor ) {
|
||||
return new ActiveFont( scaleFactor );
|
||||
return new ActiveFont( null, -1, 0, 0, 0, scaleFactor );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -779,6 +812,102 @@ public abstract class FlatLaf
|
||||
customDefaultsSources.remove( folder );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets global extra UI defaults; or {@code null}.
|
||||
*
|
||||
* @since 2
|
||||
*/
|
||||
public static Map<String, String> getGlobalExtraDefaults() {
|
||||
return globalExtraDefaults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets global extra UI defaults, which are only used when setting up the application look and feel.
|
||||
* E.g. using {@link UIManager#setLookAndFeel(LookAndFeel)} or {@link #setup(LookAndFeel)}.
|
||||
* <p>
|
||||
* The global extra defaults are useful for smaller additional defaults that may change.
|
||||
* E.g. accent color. Otherwise FlatLaf properties files should be used.
|
||||
* See {@link #registerCustomDefaultsSource(String)}.
|
||||
* <p>
|
||||
* The keys and values are strings in same format as in FlatLaf properties files.
|
||||
* <p>
|
||||
* Sample that setups "FlatLaf Light" theme with red accent color:
|
||||
* <pre>{@code
|
||||
* FlatLaf.setGlobalExtraDefaults( Collections.singletonMap( "@accentColor", "#f00" ) );
|
||||
* FlatLightLaf.setup();
|
||||
* }</pre>
|
||||
*
|
||||
* @see #setExtraDefaults(Map)
|
||||
* @since 2
|
||||
*/
|
||||
public static void setGlobalExtraDefaults( Map<String, String> globalExtraDefaults ) {
|
||||
FlatLaf.globalExtraDefaults = globalExtraDefaults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets extra UI defaults; or {@code null}.
|
||||
*
|
||||
* @since 2
|
||||
*/
|
||||
public Map<String, String> getExtraDefaults() {
|
||||
return extraDefaults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets extra UI defaults, which are only used when setting up the application look and feel.
|
||||
* E.g. using {@link UIManager#setLookAndFeel(LookAndFeel)} or {@link #setup(LookAndFeel)}.
|
||||
* <p>
|
||||
* The extra defaults are useful for smaller additional defaults that may change.
|
||||
* E.g. accent color. Otherwise FlatLaf properties files should be used.
|
||||
* See {@link #registerCustomDefaultsSource(String)}.
|
||||
* <p>
|
||||
* The keys and values are strings in same format as in FlatLaf properties files.
|
||||
* <p>
|
||||
* Sample that setups "FlatLaf Light" theme with red accent color:
|
||||
* <pre>{@code
|
||||
* FlatLaf laf = new FlatLightLaf();
|
||||
* laf.setExtraDefaults( Collections.singletonMap( "@accentColor", "#f00" ) );
|
||||
* FlatLaf.setup( laf );
|
||||
* }</pre>
|
||||
*
|
||||
* @see #setGlobalExtraDefaults(Map)
|
||||
* @since 2
|
||||
*/
|
||||
public void setExtraDefaults( Map<String, String> extraDefaults ) {
|
||||
this.extraDefaults = extraDefaults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a UI defaults value string and converts it into a binary object.
|
||||
* <p>
|
||||
* See: <a href="https://www.formdev.com/flatlaf/properties-files/">https://www.formdev.com/flatlaf/properties-files/</a>
|
||||
*
|
||||
* @param key the key, which is used to determine the value type if parameter {@code valueType} is {@code null}
|
||||
* @param value the value string
|
||||
* @param valueType the expected value type, or {@code null}
|
||||
* @return the binary value
|
||||
* @throws IllegalArgumentException on syntax errors
|
||||
* @since 2
|
||||
*/
|
||||
public static Object parseDefaultsValue( String key, String value, Class<?> valueType )
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
// resolve variables
|
||||
value = UIDefaultsLoader.resolveValueFromUIManager( value );
|
||||
|
||||
// parse value
|
||||
Object val = UIDefaultsLoader.parseValue( key, value, valueType, null,
|
||||
v -> UIDefaultsLoader.resolveValueFromUIManager( v ), Collections.emptyList() );
|
||||
|
||||
// create actual value if lazy or active
|
||||
if( val instanceof LazyValue )
|
||||
val = ((LazyValue)val).createValue( null );
|
||||
else if( val instanceof ActiveValue )
|
||||
val = ((ActiveValue)val).createValue( null );
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
private static void reSetLookAndFeel() {
|
||||
EventQueue.invokeLater( () -> {
|
||||
LookAndFeel lookAndFeel = UIManager.getLookAndFeel();
|
||||
@@ -1059,17 +1188,38 @@ public abstract class FlatLaf
|
||||
|
||||
//---- class ActiveFont ---------------------------------------------------
|
||||
|
||||
private static class ActiveFont
|
||||
static class ActiveFont
|
||||
implements ActiveValue
|
||||
{
|
||||
private final float scaleFactor;
|
||||
private final List<String> families;
|
||||
private final int style;
|
||||
private final int styleChange;
|
||||
private final int absoluteSize;
|
||||
private final int relativeSize;
|
||||
private final float scaleSize;
|
||||
|
||||
// cache (scaled) font
|
||||
private Font font;
|
||||
// cache (scaled/derived) font
|
||||
private FontUIResource font;
|
||||
private Font lastDefaultFont;
|
||||
|
||||
ActiveFont( float scaleFactor ) {
|
||||
this.scaleFactor = scaleFactor;
|
||||
/**
|
||||
* @param families list of font families, or {@code null}
|
||||
* @param style new style of font, or {@code -1}
|
||||
* @param styleChange derive style of base font; or {@code 0}
|
||||
* (the lower 16 bits are added; the upper 16 bits are removed)
|
||||
* @param absoluteSize new size of font, or {@code 0}
|
||||
* @param relativeSize added to size of base font, or {@code 0}
|
||||
* @param scaleSize multiply size of base font, or {@code 0}
|
||||
*/
|
||||
ActiveFont( List<String> families, int style, int styleChange,
|
||||
int absoluteSize, int relativeSize, float scaleSize )
|
||||
{
|
||||
this.families = families;
|
||||
this.style = style;
|
||||
this.styleChange = styleChange;
|
||||
this.absoluteSize = absoluteSize;
|
||||
this.relativeSize = relativeSize;
|
||||
this.scaleSize = scaleSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1083,20 +1233,60 @@ public abstract class FlatLaf
|
||||
if( lastDefaultFont != defaultFont ) {
|
||||
lastDefaultFont = defaultFont;
|
||||
|
||||
if( scaleFactor != 1 ) {
|
||||
// scale font
|
||||
int newFontSize = Math.round( defaultFont.getSize() * scaleFactor );
|
||||
font = new FontUIResource( defaultFont.deriveFont( (float) newFontSize ) );
|
||||
} else {
|
||||
// make sure that font is a UIResource for LaF switching
|
||||
font = (defaultFont instanceof UIResource)
|
||||
? defaultFont
|
||||
: new FontUIResource( defaultFont );
|
||||
}
|
||||
font = derive( defaultFont, fontSize -> UIScale.scale( fontSize ) );
|
||||
}
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
FontUIResource derive( Font baseFont, IntUnaryOperator scale ) {
|
||||
int baseStyle = baseFont.getStyle();
|
||||
int baseSize = baseFont.getSize();
|
||||
|
||||
// new style
|
||||
int newStyle = (style != -1)
|
||||
? style
|
||||
: (styleChange != 0)
|
||||
? baseStyle & ~((styleChange >> 16) & 0xffff) | (styleChange & 0xffff)
|
||||
: baseStyle;
|
||||
|
||||
// new size
|
||||
int newSize = (absoluteSize > 0)
|
||||
? scale.applyAsInt( absoluteSize )
|
||||
: (relativeSize != 0)
|
||||
? (baseSize + scale.applyAsInt( relativeSize ))
|
||||
: (scaleSize > 0)
|
||||
? Math.round( baseSize * scaleSize )
|
||||
: baseSize;
|
||||
if( newSize <= 0 )
|
||||
newSize = 1;
|
||||
|
||||
// create font for family
|
||||
if( families != null && !families.isEmpty() ) {
|
||||
for( String family : families ) {
|
||||
Font font = createCompositeFont( family, newStyle, newSize );
|
||||
if( !isFallbackFont( font ) || family.equalsIgnoreCase( Font.DIALOG ) )
|
||||
return toUIResource( font );
|
||||
}
|
||||
}
|
||||
|
||||
// derive font
|
||||
if( newStyle != baseStyle || newSize != baseSize )
|
||||
return toUIResource( baseFont.deriveFont( newStyle, newSize ) );
|
||||
else
|
||||
return toUIResource( baseFont );
|
||||
}
|
||||
|
||||
private FontUIResource toUIResource( Font font ) {
|
||||
// make sure that font is a UIResource for LaF switching
|
||||
return (font instanceof FontUIResource)
|
||||
? (FontUIResource) font
|
||||
: new FontUIResource( font );
|
||||
}
|
||||
|
||||
private boolean isFallbackFont( Font font ) {
|
||||
return Font.DIALOG.equalsIgnoreCase( font.getFamily() );
|
||||
}
|
||||
}
|
||||
|
||||
//---- class ImageIconUIResource ------------------------------------------
|
||||
|
||||
@@ -249,7 +249,7 @@ public class IntelliJTheme
|
||||
// search for theme specific UI defaults keys
|
||||
ArrayList<String> themeSpecificKeys = new ArrayList<>();
|
||||
for( Object key : defaults.keySet() ) {
|
||||
if( key instanceof String && ((String)key).startsWith( "[" ) )
|
||||
if( key instanceof String && ((String)key).startsWith( "[" ) && !((String)key).startsWith( "[style]" ) )
|
||||
themeSpecificKeys.add( (String) key );
|
||||
}
|
||||
|
||||
@@ -338,7 +338,7 @@ public class IntelliJTheme
|
||||
|
||||
// parse value
|
||||
try {
|
||||
uiValue = UIDefaultsLoader.parseValue( key, valueStr );
|
||||
uiValue = UIDefaultsLoader.parseValue( key, valueStr, null );
|
||||
} catch( RuntimeException ex ) {
|
||||
UIDefaultsLoader.logParseError( key, valueStr, ex, false );
|
||||
return; // ignore invalid value
|
||||
@@ -504,7 +504,7 @@ public class IntelliJTheme
|
||||
// for filled checkbox/radiobutton used in light themes
|
||||
defaults.remove( "CheckBox.icon[filled].focusWidth" );
|
||||
defaults.put( "CheckBox.icon[filled].hoverBorderColor", defaults.get( "CheckBox.icon[filled].focusedBorderColor" ) );
|
||||
defaults.put( "CheckBox.icon[filled].selectedFocusedBackground", defaults.get( "CheckBox.icon[filled].selectedBackground" ) );
|
||||
defaults.put( "CheckBox.icon[filled].focusedSelectedBackground", defaults.get( "CheckBox.icon[filled].selectedBackground" ) );
|
||||
|
||||
if( dark ) {
|
||||
// IDEA Darcula checkBoxFocused.svg, checkBoxSelectedFocused.svg,
|
||||
@@ -513,9 +513,9 @@ public class IntelliJTheme
|
||||
// --> add alpha to focused border colors
|
||||
String[] focusedBorderColorKeys = new String[] {
|
||||
"CheckBox.icon.focusedBorderColor",
|
||||
"CheckBox.icon.selectedFocusedBorderColor",
|
||||
"CheckBox.icon.focusedSelectedBorderColor",
|
||||
"CheckBox.icon[filled].focusedBorderColor",
|
||||
"CheckBox.icon[filled].selectedFocusedBorderColor",
|
||||
"CheckBox.icon[filled].focusedSelectedBorderColor",
|
||||
};
|
||||
for( String key : focusedBorderColorKeys ) {
|
||||
Color color = defaults.getColor( key );
|
||||
@@ -549,6 +549,8 @@ public class IntelliJTheme
|
||||
uiKeyMapping.put( "ComboBox.ArrowButton.disabledIconColor", "ComboBox.buttonDisabledArrowColor" );
|
||||
uiKeyMapping.put( "ComboBox.ArrowButton.iconColor", "ComboBox.buttonArrowColor" );
|
||||
uiKeyMapping.put( "ComboBox.ArrowButton.nonEditableBackground", "ComboBox.buttonBackground" );
|
||||
uiKeyCopying.put( "ComboBox.buttonSeparatorColor", "Component.borderColor" );
|
||||
uiKeyCopying.put( "ComboBox.buttonDisabledSeparatorColor", "Component.disabledBorderColor" );
|
||||
|
||||
// Component
|
||||
uiKeyMapping.put( "Component.inactiveErrorFocusColor", "Component.error.borderColor" );
|
||||
@@ -594,6 +596,10 @@ public class IntelliJTheme
|
||||
uiKeyCopying.put( "Slider.thumbColor", "ProgressBar.foreground" );
|
||||
uiKeyCopying.put( "Slider.trackColor", "ProgressBar.background" );
|
||||
|
||||
// Spinner
|
||||
uiKeyCopying.put( "Spinner.buttonSeparatorColor", "Component.borderColor" );
|
||||
uiKeyCopying.put( "Spinner.buttonDisabledSeparatorColor", "Component.disabledBorderColor" );
|
||||
|
||||
// TitlePane
|
||||
uiKeyCopying.put( "TitlePane.inactiveBackground", "TitlePane.background" );
|
||||
uiKeyMapping.put( "TitlePane.infoForeground", "TitlePane.foreground" );
|
||||
@@ -618,7 +624,7 @@ public class IntelliJTheme
|
||||
checkboxKeyMapping.put( "Checkbox.Background.Selected", "CheckBox.icon.selectedBackground" );
|
||||
checkboxKeyMapping.put( "Checkbox.Border.Selected", "CheckBox.icon.selectedBorderColor" );
|
||||
checkboxKeyMapping.put( "Checkbox.Foreground.Selected", "CheckBox.icon.checkmarkColor" );
|
||||
checkboxKeyMapping.put( "Checkbox.Focus.Thin.Selected", "CheckBox.icon.selectedFocusedBorderColor" );
|
||||
checkboxKeyMapping.put( "Checkbox.Focus.Thin.Selected", "CheckBox.icon.focusedSelectedBorderColor" );
|
||||
|
||||
checkboxDuplicateColors.put( "Checkbox.Background.Default.Dark", "Checkbox.Background.Selected.Dark" );
|
||||
checkboxDuplicateColors.put( "Checkbox.Border.Default.Dark", "Checkbox.Border.Selected.Dark" );
|
||||
|
||||
@@ -18,11 +18,17 @@ package com.formdev.flatlaf;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.Insets;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StreamTokenizer;
|
||||
import java.io.StringReader;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
@@ -33,8 +39,10 @@ import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Properties;
|
||||
import java.util.function.Function;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.UIDefaults;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.UIDefaults.ActiveValue;
|
||||
import javax.swing.UIDefaults.LazyValue;
|
||||
import javax.swing.plaf.ColorUIResource;
|
||||
@@ -72,8 +80,12 @@ class UIDefaultsLoader
|
||||
private static final String OPTIONAL_PREFIX = "?";
|
||||
private static final String WILDCARD_PREFIX = "*.";
|
||||
|
||||
private static final String KEY_VARIABLES = "FlatLaf.internal.variables";
|
||||
|
||||
private static int parseColorDepth;
|
||||
|
||||
private static final Cache<String, Object> fontCache = new Cache<>();
|
||||
|
||||
static void loadDefaultsFromProperties( Class<?> lookAndFeelClass, List<FlatDefaultsAddon> addons,
|
||||
Properties additionalDefaults, boolean dark, UIDefaults defaults )
|
||||
{
|
||||
@@ -234,18 +246,24 @@ class UIDefaultsLoader
|
||||
};
|
||||
|
||||
// parse and add properties to UI defaults
|
||||
Map<String, String> variables = new HashMap<>( 50 );
|
||||
for( Map.Entry<Object, Object> e : properties.entrySet() ) {
|
||||
String key = (String) e.getKey();
|
||||
if( key.startsWith( VARIABLE_PREFIX ) )
|
||||
if( key.startsWith( VARIABLE_PREFIX ) ) {
|
||||
variables.put( key, (String) e.getValue() );
|
||||
continue;
|
||||
}
|
||||
|
||||
String value = resolveValue( (String) e.getValue(), propertiesGetter );
|
||||
try {
|
||||
defaults.put( key, parseValue( key, value, null, resolver, addonClassLoaders ) );
|
||||
defaults.put( key, parseValue( key, value, null, null, resolver, addonClassLoaders ) );
|
||||
} catch( RuntimeException ex ) {
|
||||
logParseError( key, value, ex, true );
|
||||
}
|
||||
}
|
||||
|
||||
// remember variables in defaults to allow using them in styles
|
||||
defaults.put( KEY_VARIABLES, variables );
|
||||
} catch( IOException ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to load properties files.", ex );
|
||||
}
|
||||
@@ -288,16 +306,47 @@ class UIDefaultsLoader
|
||||
return resolveValue( newValue, propertiesGetter );
|
||||
}
|
||||
|
||||
enum ValueType { UNKNOWN, STRING, BOOLEAN, CHARACTER, INTEGER, FLOAT, BORDER, ICON, INSETS, DIMENSION, COLOR,
|
||||
static String resolveValueFromUIManager( String value ) {
|
||||
if( value.startsWith( VARIABLE_PREFIX ) ) {
|
||||
@SuppressWarnings( "unchecked" )
|
||||
Map<String, String> variables = (Map<String, String>) UIManager.get( KEY_VARIABLES );
|
||||
String newValue = (variables != null) ? variables.get( value ) : null;
|
||||
if( newValue == null )
|
||||
throw new IllegalArgumentException( "variable '" + value + "' not found" );
|
||||
|
||||
return newValue;
|
||||
}
|
||||
|
||||
if( !value.startsWith( PROPERTY_PREFIX ) )
|
||||
return value;
|
||||
|
||||
String key = value.substring( PROPERTY_PREFIX.length() );
|
||||
Object newValue = UIManager.get( key );
|
||||
if( newValue == null )
|
||||
throw new IllegalArgumentException( "property '" + key + "' not found" );
|
||||
|
||||
// convert binary color to string
|
||||
if( newValue instanceof Color ) {
|
||||
Color color = (Color) newValue;
|
||||
int alpha = color.getAlpha();
|
||||
return String.format( (alpha != 255) ? "#%06x%02x" : "#%06x", color.getRGB() & 0xffffff, alpha );
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException( "property value type '" + newValue.getClass().getName() + "' not supported in references" );
|
||||
}
|
||||
|
||||
enum ValueType { UNKNOWN, STRING, BOOLEAN, CHARACTER, INTEGER, INTEGERORFLOAT, FLOAT, BORDER, ICON, INSETS, DIMENSION, COLOR, FONT,
|
||||
SCALEDINTEGER, SCALEDFLOAT, SCALEDINSETS, SCALEDDIMENSION, INSTANCE, CLASS, GRAYFILTER, NULL, LAZY }
|
||||
|
||||
private static ValueType[] tempResultValueType = new ValueType[1];
|
||||
private static Map<Class<?>, ValueType> javaValueTypes;
|
||||
private static Map<String, ValueType> knownValueTypes;
|
||||
|
||||
static Object parseValue( String key, String value ) {
|
||||
return parseValue( key, value, null, v -> v, Collections.emptyList() );
|
||||
static Object parseValue( String key, String value, Class<?> valueType ) {
|
||||
return parseValue( key, value, valueType, null, v -> v, Collections.emptyList() );
|
||||
}
|
||||
|
||||
static Object parseValue( String key, String value, ValueType[] resultValueType,
|
||||
static Object parseValue( String key, String value, Class<?> javaValueType, ValueType[] resultValueType,
|
||||
Function<String, String> resolver, List<ClassLoader> addonClassLoaders )
|
||||
{
|
||||
if( resultValueType == null )
|
||||
@@ -305,70 +354,149 @@ class UIDefaultsLoader
|
||||
|
||||
value = value.trim();
|
||||
|
||||
// null, false, true
|
||||
switch( value ) {
|
||||
case "null": resultValueType[0] = ValueType.NULL; return null;
|
||||
case "false": resultValueType[0] = ValueType.BOOLEAN; return false;
|
||||
case "true": resultValueType[0] = ValueType.BOOLEAN; return true;
|
||||
// null
|
||||
if( value.equals( "null" ) || value.isEmpty() ) {
|
||||
resultValueType[0] = ValueType.NULL;
|
||||
return null;
|
||||
}
|
||||
|
||||
// check for function "lazy"
|
||||
// Syntax: lazy(uiKey)
|
||||
if( value.startsWith( "lazy(" ) && value.endsWith( ")" ) ) {
|
||||
resultValueType[0] = ValueType.LAZY;
|
||||
String uiKey = value.substring( 5, value.length() - 1 ).trim();
|
||||
return (LazyValue) t -> {
|
||||
return lazyUIManagerGet( uiKey );
|
||||
};
|
||||
// check for function "if"
|
||||
// Syntax: if(condition,trueValue,falseValue)
|
||||
// - condition: evaluates to true if:
|
||||
// - is not "null"
|
||||
// - is not "false"
|
||||
// - is not an integer with zero value
|
||||
// - trueValue: used if condition is true
|
||||
// - falseValue: used if condition is false
|
||||
if( value.startsWith( "if(" ) && value.endsWith( ")" ) ) {
|
||||
List<String> params = splitFunctionParams( value.substring( 3, value.length() - 1 ), ',' );
|
||||
if( params.size() != 3 )
|
||||
throwMissingParametersException( value );
|
||||
|
||||
boolean ifCondition = parseCondition( params.get( 0 ), resolver, addonClassLoaders );
|
||||
String ifValue = params.get( ifCondition ? 1 : 2 );
|
||||
return parseValue( key, resolver.apply( ifValue ), javaValueType, resultValueType, resolver, addonClassLoaders );
|
||||
}
|
||||
|
||||
ValueType valueType = ValueType.UNKNOWN;
|
||||
|
||||
// check whether value type is specified in the value
|
||||
if( value.startsWith( "#" ) )
|
||||
valueType = ValueType.COLOR;
|
||||
else if( value.startsWith( "\"" ) && value.endsWith( "\"" ) ) {
|
||||
valueType = ValueType.STRING;
|
||||
value = value.substring( 1, value.length() - 1 );
|
||||
} else if( value.startsWith( TYPE_PREFIX ) ) {
|
||||
int end = value.indexOf( TYPE_PREFIX_END );
|
||||
if( end != -1 ) {
|
||||
try {
|
||||
String typeStr = value.substring( TYPE_PREFIX.length(), end );
|
||||
valueType = ValueType.valueOf( typeStr.toUpperCase( Locale.ENGLISH ) );
|
||||
if( javaValueType != null ) {
|
||||
if( javaValueTypes == null ) {
|
||||
// create lazy
|
||||
javaValueTypes = new HashMap<>();
|
||||
javaValueTypes.put( String.class, ValueType.STRING );
|
||||
javaValueTypes.put( boolean.class, ValueType.BOOLEAN );
|
||||
javaValueTypes.put( Boolean.class, ValueType.BOOLEAN );
|
||||
javaValueTypes.put( char.class, ValueType.CHARACTER );
|
||||
javaValueTypes.put( Character.class, ValueType.CHARACTER );
|
||||
javaValueTypes.put( int.class, ValueType.INTEGER );
|
||||
javaValueTypes.put( Integer.class, ValueType.INTEGER );
|
||||
javaValueTypes.put( float.class, ValueType.FLOAT );
|
||||
javaValueTypes.put( Float.class, ValueType.FLOAT );
|
||||
javaValueTypes.put( Border.class, ValueType.BORDER );
|
||||
javaValueTypes.put( Icon.class, ValueType.ICON );
|
||||
javaValueTypes.put( Insets.class, ValueType.INSETS );
|
||||
javaValueTypes.put( Dimension.class, ValueType.DIMENSION );
|
||||
javaValueTypes.put( Color.class, ValueType.COLOR );
|
||||
javaValueTypes.put( Font.class, ValueType.FONT );
|
||||
}
|
||||
|
||||
// remove type from value
|
||||
value = value.substring( end + TYPE_PREFIX_END.length() );
|
||||
} catch( IllegalArgumentException ex ) {
|
||||
// ignore
|
||||
// map java value type to parser value type
|
||||
valueType = javaValueTypes.get( javaValueType );
|
||||
if( valueType == null )
|
||||
throw new IllegalArgumentException( "unsupported value type '" + javaValueType.getName() + "'" );
|
||||
|
||||
// remove '"' from strings
|
||||
if( valueType == ValueType.STRING && value.startsWith( "\"" ) && value.endsWith( "\"" ) )
|
||||
value = value.substring( 1, value.length() - 1 );
|
||||
} else {
|
||||
// false, true
|
||||
switch( value ) {
|
||||
case "false": resultValueType[0] = ValueType.BOOLEAN; return false;
|
||||
case "true": resultValueType[0] = ValueType.BOOLEAN; return true;
|
||||
}
|
||||
|
||||
// check for function "lazy"
|
||||
// Syntax: lazy(uiKey)
|
||||
if( value.startsWith( "lazy(" ) && value.endsWith( ")" ) ) {
|
||||
resultValueType[0] = ValueType.LAZY;
|
||||
String uiKey = StringUtils.substringTrimmed( value, 5, value.length() - 1 );
|
||||
return (LazyValue) t -> {
|
||||
return lazyUIManagerGet( uiKey );
|
||||
};
|
||||
}
|
||||
|
||||
// check whether value type is specified in the value
|
||||
if( value.startsWith( "#" ) )
|
||||
valueType = ValueType.COLOR;
|
||||
else if( value.startsWith( "\"" ) && value.indexOf( '"', 1 ) == value.length() - 1 ) {
|
||||
valueType = ValueType.STRING;
|
||||
value = value.substring( 1, value.length() - 1 );
|
||||
} else if( value.startsWith( TYPE_PREFIX ) ) {
|
||||
int end = value.indexOf( TYPE_PREFIX_END );
|
||||
if( end != -1 ) {
|
||||
try {
|
||||
String typeStr = value.substring( TYPE_PREFIX.length(), end );
|
||||
valueType = ValueType.valueOf( typeStr.toUpperCase( Locale.ENGLISH ) );
|
||||
|
||||
// remove type from value
|
||||
value = value.substring( end + TYPE_PREFIX_END.length() );
|
||||
} catch( IllegalArgumentException ex ) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// determine value type from key
|
||||
if( valueType == ValueType.UNKNOWN ) {
|
||||
if( key.endsWith( "UI" ) )
|
||||
valueType = ValueType.STRING;
|
||||
else if( key.endsWith( "Color" ) ||
|
||||
(key.endsWith( "ground" ) &&
|
||||
(key.endsWith( ".background" ) || key.endsWith( "Background" ) ||
|
||||
key.endsWith( ".foreground" ) || key.endsWith( "Foreground" ))) )
|
||||
valueType = ValueType.COLOR;
|
||||
else if( key.endsWith( ".border" ) || key.endsWith( "Border" ) )
|
||||
valueType = ValueType.BORDER;
|
||||
else if( key.endsWith( ".icon" ) || key.endsWith( "Icon" ) )
|
||||
valueType = ValueType.ICON;
|
||||
else if( key.endsWith( ".margin" ) || key.endsWith( ".padding" ) ||
|
||||
key.endsWith( "Margins" ) || key.endsWith( "Insets" ) )
|
||||
valueType = ValueType.INSETS;
|
||||
else if( key.endsWith( "Size" ) )
|
||||
valueType = ValueType.DIMENSION;
|
||||
else if( key.endsWith( "Width" ) || key.endsWith( "Height" ) )
|
||||
valueType = ValueType.INTEGER;
|
||||
else if( key.endsWith( "Char" ) )
|
||||
valueType = ValueType.CHARACTER;
|
||||
else if( key.endsWith( "grayFilter" ) )
|
||||
valueType = ValueType.GRAYFILTER;
|
||||
if( valueType == ValueType.UNKNOWN ) {
|
||||
if( knownValueTypes == null ) {
|
||||
// create lazy
|
||||
knownValueTypes = new HashMap<>();
|
||||
// SplitPane
|
||||
knownValueTypes.put( "SplitPane.dividerSize", ValueType.INTEGER );
|
||||
knownValueTypes.put( "SplitPaneDivider.gripDotSize", ValueType.INTEGER );
|
||||
knownValueTypes.put( "dividerSize", ValueType.INTEGER );
|
||||
knownValueTypes.put( "gripDotSize", ValueType.INTEGER );
|
||||
// TabbedPane
|
||||
knownValueTypes.put( "TabbedPane.closeCrossPlainSize", ValueType.FLOAT );
|
||||
knownValueTypes.put( "TabbedPane.closeCrossFilledSize", ValueType.FLOAT );
|
||||
knownValueTypes.put( "closeCrossPlainSize", ValueType.FLOAT );
|
||||
knownValueTypes.put( "closeCrossFilledSize", ValueType.FLOAT );
|
||||
// Table
|
||||
knownValueTypes.put( "Table.intercellSpacing", ValueType.DIMENSION );
|
||||
knownValueTypes.put( "intercellSpacing", ValueType.DIMENSION );
|
||||
}
|
||||
|
||||
valueType = knownValueTypes.getOrDefault( key, ValueType.UNKNOWN );
|
||||
}
|
||||
|
||||
// determine value type from key
|
||||
if( valueType == ValueType.UNKNOWN ) {
|
||||
if( key.endsWith( "UI" ) )
|
||||
valueType = ValueType.STRING;
|
||||
else if( key.endsWith( "Color" ) ||
|
||||
(key.endsWith( "ground" ) &&
|
||||
(key.endsWith( ".background" ) || key.endsWith( "Background" ) || key.equals( "background" ) ||
|
||||
key.endsWith( ".foreground" ) || key.endsWith( "Foreground" ) || key.equals( "foreground" ))) )
|
||||
valueType = ValueType.COLOR;
|
||||
else if( key.endsWith( ".font" ) || key.endsWith( "Font" ) || key.equals( "font" ) )
|
||||
valueType = ValueType.FONT;
|
||||
else if( key.endsWith( ".border" ) || key.endsWith( "Border" ) || key.equals( "border" ) )
|
||||
valueType = ValueType.BORDER;
|
||||
else if( key.endsWith( ".icon" ) || key.endsWith( "Icon" ) || key.equals( "icon" ) )
|
||||
valueType = ValueType.ICON;
|
||||
else if( key.endsWith( ".margin" ) || key.equals( "margin" ) ||
|
||||
key.endsWith( ".padding" ) || key.equals( "padding" ) ||
|
||||
key.endsWith( "Margins" ) || key.endsWith( "Insets" ) )
|
||||
valueType = ValueType.INSETS;
|
||||
else if( key.endsWith( "Size" ) )
|
||||
valueType = ValueType.DIMENSION;
|
||||
else if( key.endsWith( "Width" ) || key.endsWith( "Height" ) )
|
||||
valueType = ValueType.INTEGERORFLOAT;
|
||||
else if( key.endsWith( "Char" ) )
|
||||
valueType = ValueType.CHARACTER;
|
||||
else if( key.endsWith( "grayFilter" ) )
|
||||
valueType = ValueType.GRAYFILTER;
|
||||
}
|
||||
}
|
||||
|
||||
resultValueType[0] = valueType;
|
||||
@@ -376,14 +504,17 @@ class UIDefaultsLoader
|
||||
// parse value
|
||||
switch( valueType ) {
|
||||
case STRING: return value;
|
||||
case BOOLEAN: return parseBoolean( value );
|
||||
case CHARACTER: return parseCharacter( value );
|
||||
case INTEGER: return parseInteger( value, true );
|
||||
case INTEGERORFLOAT:return parseIntegerOrFloat( value, true );
|
||||
case FLOAT: return parseFloat( value, true );
|
||||
case BORDER: return parseBorder( value, resolver, addonClassLoaders );
|
||||
case ICON: return parseInstance( value, addonClassLoaders );
|
||||
case INSETS: return parseInsets( value );
|
||||
case DIMENSION: return parseDimension( value );
|
||||
case COLOR: return parseColorOrFunction( value, resolver, true );
|
||||
case FONT: return parseFont( value );
|
||||
case SCALEDINTEGER: return parseScaledInteger( value );
|
||||
case SCALEDFLOAT: return parseScaledFloat( value );
|
||||
case SCALEDINSETS: return parseScaledInsets( value );
|
||||
@@ -420,10 +551,24 @@ class UIDefaultsLoader
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean parseCondition( String condition,
|
||||
Function<String, String> resolver, List<ClassLoader> addonClassLoaders )
|
||||
{
|
||||
try {
|
||||
Object conditionValue = parseValue( "", resolver.apply( condition ), null, null, resolver, addonClassLoaders );
|
||||
return (conditionValue != null &&
|
||||
!conditionValue.equals( false ) &&
|
||||
!conditionValue.equals( 0 ) );
|
||||
} catch( IllegalArgumentException ex ) {
|
||||
// ignore errors (e.g. variable or property not found) and evaluate to false
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static Object parseBorder( String value, Function<String, String> resolver, List<ClassLoader> addonClassLoaders ) {
|
||||
if( value.indexOf( ',' ) >= 0 ) {
|
||||
// top,left,bottom,right[,lineColor[,lineThickness]]
|
||||
List<String> parts = split( value, ',' );
|
||||
List<String> parts = splitFunctionParams( value, ',' );
|
||||
Insets insets = parseInsets( value );
|
||||
ColorUIResource lineColor = (parts.size() >= 5)
|
||||
? (ColorUIResource) parseColorOrFunction( resolver.apply( parts.get( 4 ) ), resolver, true )
|
||||
@@ -480,7 +625,7 @@ class UIDefaultsLoader
|
||||
}
|
||||
|
||||
private static Insets parseInsets( String value ) {
|
||||
List<String> numbers = split( value, ',' );
|
||||
List<String> numbers = StringUtils.split( value, ',', true, false );
|
||||
try {
|
||||
return new InsetsUIResource(
|
||||
Integer.parseInt( numbers.get( 0 ) ),
|
||||
@@ -493,7 +638,7 @@ class UIDefaultsLoader
|
||||
}
|
||||
|
||||
private static Dimension parseDimension( String value ) {
|
||||
List<String> numbers = split( value, ',' );
|
||||
List<String> numbers = StringUtils.split( value, ',', true, false );
|
||||
try {
|
||||
return new DimensionUIResource(
|
||||
Integer.parseInt( numbers.get( 0 ) ),
|
||||
@@ -581,10 +726,10 @@ class UIDefaultsLoader
|
||||
return null;
|
||||
}
|
||||
|
||||
String function = value.substring( 0, paramsStart ).trim();
|
||||
String function = StringUtils.substringTrimmed( value, 0, paramsStart );
|
||||
List<String> params = splitFunctionParams( value.substring( paramsStart + 1, value.length() - 1 ), ',' );
|
||||
if( params.isEmpty() )
|
||||
throw new IllegalArgumentException( "missing parameters in function '" + value + "'" );
|
||||
throwMissingParametersException( value );
|
||||
|
||||
if( parseColorDepth > 100 )
|
||||
throw new IllegalArgumentException( "endless recursion in color function '" + value + "'" );
|
||||
@@ -592,6 +737,7 @@ class UIDefaultsLoader
|
||||
parseColorDepth++;
|
||||
try {
|
||||
switch( function ) {
|
||||
case "if": return parseColorIf( value, params, resolver, reportError );
|
||||
case "rgb": return parseColorRgbOrRgba( false, params, resolver, reportError );
|
||||
case "rgba": return parseColorRgbOrRgba( true, params, resolver, reportError );
|
||||
case "hsl": return parseColorHslOrHsla( false, params );
|
||||
@@ -611,6 +757,7 @@ class UIDefaultsLoader
|
||||
case "mix": return parseColorMix( null, params, resolver, reportError );
|
||||
case "tint": return parseColorMix( "#fff", params, resolver, reportError );
|
||||
case "shade": return parseColorMix( "#000", params, resolver, reportError );
|
||||
case "contrast": return parseColorContrast( params, resolver, reportError );
|
||||
}
|
||||
} finally {
|
||||
parseColorDepth--;
|
||||
@@ -619,6 +766,21 @@ class UIDefaultsLoader
|
||||
throw new IllegalArgumentException( "unknown color function '" + value + "'" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Syntax: if(condition,trueValue,falseValue)
|
||||
* <p>
|
||||
* This "if" function is only used if the "if" is passed as parameter to another
|
||||
* color function. Otherwise the general "if" function is used.
|
||||
*/
|
||||
private static Object parseColorIf( String value, List<String> params, Function<String, String> resolver, boolean reportError ) {
|
||||
if( params.size() != 3 )
|
||||
throwMissingParametersException( value );
|
||||
|
||||
boolean ifCondition = parseCondition( params.get( 0 ), resolver, Collections.emptyList() );
|
||||
String ifValue = params.get( ifCondition ? 1 : 2 );
|
||||
return parseColorOrFunction( resolver.apply( ifValue ), resolver, reportError );
|
||||
}
|
||||
|
||||
/**
|
||||
* Syntax: rgb(red,green,blue) or rgba(red,green,blue,alpha)
|
||||
* - red: an integer 0-255 or a percentage 0-100%
|
||||
@@ -804,14 +966,10 @@ class UIDefaultsLoader
|
||||
if( color1Str == null )
|
||||
color1Str = params.get( i++ );
|
||||
String color2Str = params.get( i++ );
|
||||
int weight = 50;
|
||||
|
||||
if( params.size() > i )
|
||||
weight = parsePercentage( params.get( i++ ) );
|
||||
int weight = (params.size() > i) ? parsePercentage( params.get( i ) ) : 50;
|
||||
|
||||
// parse second color
|
||||
String resolvedColor2Str = resolver.apply( color2Str );
|
||||
ColorUIResource color2 = (ColorUIResource) parseColorOrFunction( resolvedColor2Str, resolver, reportError );
|
||||
ColorUIResource color2 = (ColorUIResource) parseColorOrFunction( resolver.apply( color2Str ), resolver, reportError );
|
||||
if( color2 == null )
|
||||
return null;
|
||||
|
||||
@@ -822,6 +980,34 @@ class UIDefaultsLoader
|
||||
return parseFunctionBaseColor( color1Str, function, false, resolver, reportError );
|
||||
}
|
||||
|
||||
/**
|
||||
* Syntax: contrast(color,dark,light[,threshold])
|
||||
* - color: a color to compare against
|
||||
* - dark: a designated dark color (e.g. #000) or a color function
|
||||
* - light: a designated light color (e.g. #fff) or a color function
|
||||
* - threshold: the threshold (in range 0-100%) to specify where the transition
|
||||
* from "dark" to "light" is (default is 43%)
|
||||
*/
|
||||
private static Object parseColorContrast( List<String> params, Function<String, String> resolver, boolean reportError ) {
|
||||
String colorStr = params.get( 0 );
|
||||
String darkStr = params.get( 1 );
|
||||
String lightStr = params.get( 2 );
|
||||
int threshold = (params.size() > 3) ? parsePercentage( params.get( 3 ) ) : 43;
|
||||
|
||||
// parse color to compare against
|
||||
ColorUIResource color = (ColorUIResource) parseColorOrFunction( resolver.apply( colorStr ), resolver, reportError );
|
||||
if( color == null )
|
||||
return null;
|
||||
|
||||
// check luma and determine whether to use dark or light color
|
||||
String darkOrLightColor = (ColorFunctions.luma( color ) * 100 < threshold)
|
||||
? lightStr
|
||||
: darkStr;
|
||||
|
||||
// parse dark or light color
|
||||
return parseColorOrFunction( resolver.apply( darkOrLightColor ), resolver, reportError );
|
||||
}
|
||||
|
||||
private static Object parseFunctionBaseColor( String colorStr, ColorFunction function,
|
||||
boolean derived, Function<String, String> resolver, boolean reportError )
|
||||
{
|
||||
@@ -852,6 +1038,100 @@ class UIDefaultsLoader
|
||||
return new ColorUIResource( newColor );
|
||||
}
|
||||
|
||||
/**
|
||||
* Syntax: [normal] [bold|+bold|-bold] [italic|+italic|-italic] [<size>|+<incr>|-<decr>|<percent>%] [family[, family]]
|
||||
*/
|
||||
private static Object parseFont( String value ) {
|
||||
Object font = fontCache.get( value );
|
||||
if( font != null )
|
||||
return font;
|
||||
|
||||
int style = -1;
|
||||
int styleChange = 0;
|
||||
int absoluteSize = 0;
|
||||
int relativeSize = 0;
|
||||
float scaleSize = 0;
|
||||
List<String> families = null;
|
||||
|
||||
// use StreamTokenizer to split string because it supports quoted strings
|
||||
StreamTokenizer st = new StreamTokenizer( new StringReader( value ) );
|
||||
st.resetSyntax();
|
||||
st.wordChars( ' ' + 1, 255 );
|
||||
st.whitespaceChars( 0, ' ' );
|
||||
st.whitespaceChars( ',', ',' ); // ignore ','
|
||||
st.quoteChar( '"' );
|
||||
st.quoteChar( '\'' );
|
||||
|
||||
try {
|
||||
while( st.nextToken() != StreamTokenizer.TT_EOF ) {
|
||||
String param = st.sval;
|
||||
switch( param ) {
|
||||
// font style
|
||||
case "normal":
|
||||
style = 0;
|
||||
break;
|
||||
|
||||
case "bold":
|
||||
if( style == -1 )
|
||||
style = 0;
|
||||
style |= Font.BOLD;
|
||||
break;
|
||||
|
||||
case "italic":
|
||||
if( style == -1 )
|
||||
style = 0;
|
||||
style |= Font.ITALIC;
|
||||
break;
|
||||
|
||||
case "+bold": styleChange |= Font.BOLD; break;
|
||||
case "-bold": styleChange |= Font.BOLD << 16; break;
|
||||
case "+italic": styleChange |= Font.ITALIC; break;
|
||||
case "-italic": styleChange |= Font.ITALIC << 16; break;
|
||||
|
||||
default:
|
||||
char firstChar = param.charAt( 0 );
|
||||
if( Character.isDigit( firstChar ) || firstChar == '+' || firstChar == '-' ) {
|
||||
// font size
|
||||
if( absoluteSize != 0 || relativeSize != 0 || scaleSize != 0 )
|
||||
throw new IllegalArgumentException( "size specified more than once in '" + value + "'" );
|
||||
|
||||
if( firstChar == '+' || firstChar == '-' )
|
||||
relativeSize = parseInteger( param, true );
|
||||
else if( param.endsWith( "%" ) )
|
||||
scaleSize = parseInteger( param.substring( 0, param.length() - 1 ), true ) / 100f;
|
||||
else
|
||||
absoluteSize = parseInteger( param, true );
|
||||
} else {
|
||||
// font family
|
||||
if( families == null )
|
||||
families = Collections.singletonList( param );
|
||||
else {
|
||||
if( families.size() == 1 )
|
||||
families = new ArrayList<>( families );
|
||||
families.add( param );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch( IOException ex ) {
|
||||
throw new IllegalArgumentException( ex );
|
||||
}
|
||||
|
||||
if( style != -1 && styleChange != 0 )
|
||||
throw new IllegalArgumentException( "can not mix absolute style (e.g. 'bold') with derived style (e.g. '+italic') in '" + value + "'" );
|
||||
if( styleChange != 0 ) {
|
||||
if( (styleChange & Font.BOLD) != 0 && (styleChange & (Font.BOLD << 16)) != 0 )
|
||||
throw new IllegalArgumentException( "can not use '+bold' and '-bold' in '" + value + "'" );
|
||||
if( (styleChange & Font.ITALIC) != 0 && (styleChange & (Font.ITALIC << 16)) != 0 )
|
||||
throw new IllegalArgumentException( "can not use '+italic' and '-italic' in '" + value + "'" );
|
||||
}
|
||||
|
||||
font = new FlatLaf.ActiveFont( families, style, styleChange, absoluteSize, relativeSize, scaleSize );
|
||||
fontCache.put( value, font );
|
||||
return font;
|
||||
}
|
||||
|
||||
private static int parsePercentage( String value ) {
|
||||
if( !value.endsWith( "%" ) )
|
||||
throw new NumberFormatException( "invalid percentage '" + value + "'" );
|
||||
@@ -868,6 +1148,14 @@ class UIDefaultsLoader
|
||||
return val;
|
||||
}
|
||||
|
||||
private static Boolean parseBoolean( String value ) {
|
||||
switch( value ) {
|
||||
case "false": return false;
|
||||
case "true": return true;
|
||||
}
|
||||
throw new IllegalArgumentException( "invalid boolean '" + value + "'" );
|
||||
}
|
||||
|
||||
private static Character parseCharacter( String value ) {
|
||||
if( value.length() != 1 )
|
||||
throw new IllegalArgumentException( "invalid character '" + value + "'" );
|
||||
@@ -896,6 +1184,20 @@ class UIDefaultsLoader
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Number parseIntegerOrFloat( String value, boolean reportError ) {
|
||||
try {
|
||||
return Integer.parseInt( value );
|
||||
} catch( NumberFormatException ex ) {
|
||||
try {
|
||||
return Float.parseFloat( value );
|
||||
} catch( NumberFormatException ex2 ) {
|
||||
if( reportError )
|
||||
throw new NumberFormatException( "invalid integer or float '" + value + "'" );
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Float parseFloat( String value, boolean reportError ) {
|
||||
try {
|
||||
return Float.parseFloat( value );
|
||||
@@ -935,7 +1237,7 @@ class UIDefaultsLoader
|
||||
}
|
||||
|
||||
private static Object parseGrayFilter( String value ) {
|
||||
List<String> numbers = split( value, ',' );
|
||||
List<String> numbers = StringUtils.split( value, ',', true, false );
|
||||
try {
|
||||
int brightness = Integer.parseInt( numbers.get( 0 ) );
|
||||
int contrast = Integer.parseInt( numbers.get( 1 ) );
|
||||
@@ -949,20 +1251,6 @@ class UIDefaultsLoader
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Split string and trim parts.
|
||||
*/
|
||||
private static List<String> split( String str, char delim ) {
|
||||
List<String> result = StringUtils.split( str, delim );
|
||||
|
||||
// trim strings
|
||||
int size = result.size();
|
||||
for( int i = 0; i < size; i++ )
|
||||
result.set( i, result.get( i ).trim() );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits function parameters and allows using functions as parameters.
|
||||
* In other words: Delimiters surrounded by '(' and ')' are ignored.
|
||||
@@ -979,11 +1267,11 @@ class UIDefaultsLoader
|
||||
else if( ch == ')' )
|
||||
nestLevel--;
|
||||
else if( nestLevel == 0 && ch == delim ) {
|
||||
strs.add( str.substring( start, i ).trim() );
|
||||
strs.add( StringUtils.substringTrimmed( str, start, i ) );
|
||||
start = i + 1;
|
||||
}
|
||||
}
|
||||
strs.add( str.substring( start ).trim() );
|
||||
strs.add( StringUtils.substringTrimmed( str, start ) );
|
||||
|
||||
return strs;
|
||||
}
|
||||
@@ -1004,4 +1292,47 @@ class UIDefaultsLoader
|
||||
LoggingFacade.INSTANCE.logSevere( "FlatLaf: '" + uiKey + "' not found in UI defaults.", null );
|
||||
return value;
|
||||
}
|
||||
|
||||
private static void throwMissingParametersException( String value ) {
|
||||
throw new IllegalArgumentException( "missing parameters in function '" + value + "'" );
|
||||
}
|
||||
|
||||
//---- class Cache --------------------------------------------------------
|
||||
|
||||
private static class Cache<K,V>
|
||||
{
|
||||
private final Map<K, CacheReference<K,V>> map = new HashMap<>();
|
||||
private final ReferenceQueue<V> queue = new ReferenceQueue<>();
|
||||
|
||||
V get( K key ) {
|
||||
expungeStaleEntries();
|
||||
CacheReference<K,V> ref = map.get( key );
|
||||
return (ref != null) ? ref.get() : null;
|
||||
}
|
||||
|
||||
void put( K key, V value ) {
|
||||
expungeStaleEntries();
|
||||
map.put( key, new CacheReference<>( key, value, queue ) );
|
||||
}
|
||||
|
||||
@SuppressWarnings( "unchecked" )
|
||||
void expungeStaleEntries() {
|
||||
Reference<? extends V> reference;
|
||||
while( (reference = queue.poll()) != null )
|
||||
map.remove( ((CacheReference<K,V>)reference).key );
|
||||
}
|
||||
|
||||
//---- class CacheReference ----
|
||||
|
||||
private static class CacheReference<K,V>
|
||||
extends SoftReference<V>
|
||||
{
|
||||
final K key;
|
||||
|
||||
public CacheReference( K key, V value, ReferenceQueue<? super V> queue ) {
|
||||
super( value, queue );
|
||||
this.key = key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ public abstract class FlatAbstractIcon
|
||||
{
|
||||
protected final int width;
|
||||
protected final int height;
|
||||
protected final Color color;
|
||||
protected Color color;
|
||||
|
||||
public FlatAbstractIcon( int width, int height, Color color ) {
|
||||
this.width = width;
|
||||
|
||||
@@ -21,7 +21,11 @@ import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Path2D;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.TableHeaderUI;
|
||||
import javax.swing.table.JTableHeader;
|
||||
import com.formdev.flatlaf.ui.FlatTableHeaderUI;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
|
||||
/**
|
||||
@@ -35,8 +39,8 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
public class FlatAscendingSortIcon
|
||||
extends FlatAbstractIcon
|
||||
{
|
||||
protected final boolean chevron = FlatUIUtils.isChevron( UIManager.getString( "Component.arrowType" ) );
|
||||
protected final Color sortIconColor = UIManager.getColor( "Table.sortIconColor" );
|
||||
protected boolean chevron = FlatUIUtils.isChevron( UIManager.getString( "Component.arrowType" ) );
|
||||
protected Color sortIconColor = UIManager.getColor( "Table.sortIconColor" );
|
||||
|
||||
public FlatAscendingSortIcon() {
|
||||
super( 10, 5, null );
|
||||
@@ -44,7 +48,28 @@ public class FlatAscendingSortIcon
|
||||
|
||||
@Override
|
||||
protected void paintIcon( Component c, Graphics2D g ) {
|
||||
boolean chevron = this.chevron;
|
||||
Color sortIconColor = this.sortIconColor;
|
||||
|
||||
// Because this icons are always shared for all table headers,
|
||||
// get icon specific style from FlatTableHeaderUI.
|
||||
JTableHeader tableHeader = (JTableHeader) SwingUtilities.getAncestorOfClass( JTableHeader.class, c );
|
||||
if( tableHeader != null ) {
|
||||
TableHeaderUI ui = tableHeader.getUI();
|
||||
if( ui instanceof FlatTableHeaderUI ) {
|
||||
FlatTableHeaderUI fui = (FlatTableHeaderUI) ui;
|
||||
if( fui.arrowType != null )
|
||||
chevron = FlatUIUtils.isChevron( fui.arrowType );
|
||||
if( fui.sortIconColor != null )
|
||||
sortIconColor = fui.sortIconColor;
|
||||
}
|
||||
}
|
||||
|
||||
g.setColor( sortIconColor );
|
||||
paintArrow( c, g, chevron );
|
||||
}
|
||||
|
||||
protected void paintArrow( Component c, Graphics2D g, boolean chevron ) {
|
||||
if( chevron ) {
|
||||
// chevron arrow
|
||||
Path2D path = FlatUIUtils.createPath( false, 1,4, 5,0, 9,4 );
|
||||
|
||||
@@ -16,12 +16,14 @@
|
||||
|
||||
package com.formdev.flatlaf.icons;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
import javax.swing.UIManager;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
|
||||
/**
|
||||
@@ -38,6 +40,15 @@ public class FlatCapsLockIcon
|
||||
super( 16, 16, UIManager.getColor( "PasswordField.capsLockIconColor" ) );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
public Object applyStyleProperty( String key, Object value ) {
|
||||
Object oldValue;
|
||||
switch( key ) {
|
||||
case "capsLockIconColor": oldValue = color; color = (Color) value; return oldValue;
|
||||
default: throw new UnknownStyleException( key );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintIcon( Component c, Graphics2D g ) {
|
||||
/*
|
||||
|
||||
@@ -23,83 +23,115 @@ import java.awt.Component;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
import java.util.Map;
|
||||
import javax.swing.AbstractButton;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.UIManager;
|
||||
import com.formdev.flatlaf.ui.FlatButtonUI;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
|
||||
/**
|
||||
* Icon for {@link javax.swing.JCheckBox}.
|
||||
*
|
||||
* Note: If Component.focusWidth is greater than zero, then the outline focus border
|
||||
* <p>
|
||||
* <strong>Note</strong>:
|
||||
* If Component.focusWidth is greater than zero, then the outer focus border
|
||||
* 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 CheckBox.icon.style String optional; "outlined"/null (default) or "filled"
|
||||
* @uiDefault Component.focusWidth int
|
||||
* @uiDefault Component.borderWidth int
|
||||
* @uiDefault Component.focusColor Color
|
||||
* @uiDefault CheckBox.icon.focusWidth int optional; defaults to Component.focusWidth
|
||||
* @uiDefault CheckBox.icon.focusWidth int or float optional; defaults to Component.focusWidth
|
||||
* @uiDefault CheckBox.icon.borderWidth int or float optional; defaults to Component.borderWidth
|
||||
* @uiDefault CheckBox.icon.selectedBorderWidth int or float optional; defaults to CheckBox.icon.borderWidth
|
||||
* @uiDefault CheckBox.icon.disabledSelectedBorderWidth int or float optional; defaults to CheckBox.icon.selectedBorderWidth
|
||||
* @uiDefault CheckBox.arc int
|
||||
*
|
||||
* @uiDefault CheckBox.icon.focusColor Color optional; defaults to Component.focusColor
|
||||
* @uiDefault CheckBox.icon.borderColor Color
|
||||
* @uiDefault CheckBox.icon.background Color
|
||||
* @uiDefault CheckBox.icon.selectedBorderColor Color
|
||||
* @uiDefault CheckBox.icon.selectedBackground Color
|
||||
* @uiDefault CheckBox.icon.checkmarkColor Color
|
||||
*
|
||||
* @uiDefault CheckBox.icon.disabledBorderColor Color
|
||||
* @uiDefault CheckBox.icon.disabledBackground Color
|
||||
* @uiDefault CheckBox.icon.disabledSelectedBorderColor Color optional; CheckBox.icon.disabledBorderColor is used if not specified
|
||||
* @uiDefault CheckBox.icon.disabledSelectedBackground Color optional; CheckBox.icon.disabledBackground is used if not specified
|
||||
* @uiDefault CheckBox.icon.disabledCheckmarkColor Color
|
||||
*
|
||||
* @uiDefault CheckBox.icon.focusedBorderColor Color optional
|
||||
* @uiDefault CheckBox.icon.focusedBackground Color optional
|
||||
* @uiDefault CheckBox.icon.selectedFocusedBorderColor Color optional; CheckBox.icon.focusedBorderColor is used if not specified
|
||||
* @uiDefault CheckBox.icon.selectedFocusedBackground Color optional; CheckBox.icon.focusedBackground is used if not specified
|
||||
* @uiDefault CheckBox.icon.selectedFocusedCheckmarkColor Color optional; CheckBox.icon.checkmarkColor is used if not specified
|
||||
* @uiDefault CheckBox.icon.focusedSelectedBorderColor Color optional; CheckBox.icon.focusedBorderColor is used if not specified
|
||||
* @uiDefault CheckBox.icon.focusedSelectedBackground Color optional; CheckBox.icon.focusedBackground is used if not specified
|
||||
* @uiDefault CheckBox.icon.focusedCheckmarkColor Color optional; CheckBox.icon.checkmarkColor is used if not specified
|
||||
*
|
||||
* @uiDefault CheckBox.icon.hoverBorderColor Color optional
|
||||
* @uiDefault CheckBox.icon.hoverBackground Color optional
|
||||
* @uiDefault CheckBox.icon.selectedHoverBackground Color optional; CheckBox.icon.hoverBackground is used if not specified
|
||||
* @uiDefault CheckBox.icon.hoverSelectedBorderColor Color optional; CheckBox.icon.hoverBorderColor is used if not specified
|
||||
* @uiDefault CheckBox.icon.hoverSelectedBackground Color optional; CheckBox.icon.hoverBackground is used if not specified
|
||||
* @uiDefault CheckBox.icon.hoverCheckmarkColor Color optional; CheckBox.icon.checkmarkColor is used if not specified
|
||||
*
|
||||
* @uiDefault CheckBox.icon.pressedBorderColor Color optional
|
||||
* @uiDefault CheckBox.icon.pressedBackground Color optional
|
||||
* @uiDefault CheckBox.icon.selectedPressedBackground Color optional; CheckBox.icon.pressedBackground is used if not specified
|
||||
* @uiDefault CheckBox.arc int
|
||||
* @uiDefault CheckBox.icon.pressedSelectedBorderColor Color optional; CheckBox.icon.pressedBorderColor is used if not specified
|
||||
* @uiDefault CheckBox.icon.pressedSelectedBackground Color optional; CheckBox.icon.pressedBackground is used if not specified
|
||||
* @uiDefault CheckBox.icon.pressedCheckmarkColor Color optional; CheckBox.icon.checkmarkColor is used if not specified
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatCheckBoxIcon
|
||||
extends FlatAbstractIcon
|
||||
{
|
||||
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 String style = UIManager.getString( getPropertyPrefix() + "icon.style" );
|
||||
@Styleable protected float focusWidth = getUIFloat( "CheckBox.icon.focusWidth", UIManager.getInt( "Component.focusWidth" ), style );
|
||||
@Styleable protected Color focusColor = FlatUIUtils.getUIColor( "CheckBox.icon.focusColor", UIManager.getColor( "Component.focusColor" ) );
|
||||
/** @since 2 */ @Styleable protected float borderWidth = getUIFloat( "CheckBox.icon.borderWidth", FlatUIUtils.getUIFloat( "Component.borderWidth", 1 ), style );
|
||||
/** @since 2 */ @Styleable protected float selectedBorderWidth = getUIFloat( "CheckBox.icon.selectedBorderWidth", Float.MIN_VALUE, style );
|
||||
/** @since 2 */ @Styleable protected float disabledSelectedBorderWidth = getUIFloat( "CheckBox.icon.disabledSelectedBorderWidth", Float.MIN_VALUE, style );
|
||||
@Styleable protected int arc = FlatUIUtils.getUIInt( "CheckBox.arc", 2 );
|
||||
|
||||
// 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 );
|
||||
@Styleable protected Color borderColor = getUIColor( "CheckBox.icon.borderColor", style );
|
||||
@Styleable protected Color background = getUIColor( "CheckBox.icon.background", style );
|
||||
@Styleable protected Color selectedBorderColor = getUIColor( "CheckBox.icon.selectedBorderColor", style );
|
||||
@Styleable protected Color selectedBackground = getUIColor( "CheckBox.icon.selectedBackground", style );
|
||||
@Styleable protected 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 );
|
||||
@Styleable protected Color disabledBorderColor = getUIColor( "CheckBox.icon.disabledBorderColor", style );
|
||||
@Styleable protected Color disabledBackground = getUIColor( "CheckBox.icon.disabledBackground", style );
|
||||
/** @since 2 */ @Styleable protected Color disabledSelectedBorderColor = getUIColor( "CheckBox.icon.disabledSelectedBorderColor", style );
|
||||
/** @since 2 */ @Styleable protected Color disabledSelectedBackground = getUIColor( "CheckBox.icon.disabledSelectedBackground", style );
|
||||
@Styleable protected 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 );
|
||||
@Styleable protected Color focusedBorderColor = getUIColor( "CheckBox.icon.focusedBorderColor", style );
|
||||
@Styleable protected Color focusedBackground = getUIColor( "CheckBox.icon.focusedBackground", style );
|
||||
/** @since 2 */ @Styleable protected Color focusedSelectedBorderColor = getUIColor( "CheckBox.icon.focusedSelectedBorderColor", style );
|
||||
/** @since 2 */ @Styleable protected Color focusedSelectedBackground = getUIColor( "CheckBox.icon.focusedSelectedBackground", style );
|
||||
/** @since 2 */ @Styleable protected Color focusedCheckmarkColor = getUIColor( "CheckBox.icon.focusedCheckmarkColor", 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 );
|
||||
@Styleable protected Color hoverBorderColor = getUIColor( "CheckBox.icon.hoverBorderColor", style );
|
||||
@Styleable protected Color hoverBackground = getUIColor( "CheckBox.icon.hoverBackground", style );
|
||||
/** @since 2 */ @Styleable protected Color hoverSelectedBorderColor = getUIColor( "CheckBox.icon.hoverSelectedBorderColor", style );
|
||||
/** @since 2 */ @Styleable protected Color hoverSelectedBackground = getUIColor( "CheckBox.icon.hoverSelectedBackground", style );
|
||||
/** @since 2 */ @Styleable protected Color hoverCheckmarkColor = getUIColor( "CheckBox.icon.hoverCheckmarkColor", style );
|
||||
|
||||
// pressed
|
||||
protected final Color pressedBackground = getUIColor( "CheckBox.icon.pressedBackground", style );
|
||||
protected final Color selectedPressedBackground = getUIColor( "CheckBox.icon.selectedPressedBackground", style );
|
||||
/** @since 2 */ @Styleable protected Color pressedBorderColor = getUIColor( "CheckBox.icon.pressedBorderColor", style );
|
||||
@Styleable protected Color pressedBackground = getUIColor( "CheckBox.icon.pressedBackground", style );
|
||||
/** @since 2 */ @Styleable protected Color pressedSelectedBorderColor = getUIColor( "CheckBox.icon.pressedSelectedBorderColor", style );
|
||||
/** @since 2 */ @Styleable protected Color pressedSelectedBackground = getUIColor( "CheckBox.icon.pressedSelectedBackground", style );
|
||||
/** @since 2 */ @Styleable protected Color pressedCheckmarkColor = getUIColor( "CheckBox.icon.pressedCheckmarkColor", style );
|
||||
|
||||
protected String getPropertyPrefix() {
|
||||
return "CheckBox.";
|
||||
}
|
||||
|
||||
protected static Color getUIColor( String key, String style ) {
|
||||
if( style != null ) {
|
||||
@@ -110,13 +142,14 @@ public class FlatCheckBoxIcon
|
||||
return UIManager.getColor( key );
|
||||
}
|
||||
|
||||
protected static int getUIInt( String key, int defaultValue, String style ) {
|
||||
/** @since 2 */
|
||||
protected static float getUIFloat( String key, float defaultValue, String style ) {
|
||||
if( style != null ) {
|
||||
Object value = UIManager.get( styleKey( key, style ) );
|
||||
if( value instanceof Integer )
|
||||
return (Integer) value;
|
||||
float value = FlatUIUtils.getUIFloat( styleKey( key, style ), Float.MIN_VALUE );
|
||||
if( value != Float.MIN_VALUE )
|
||||
return value;
|
||||
}
|
||||
return FlatUIUtils.getUIInt( key, defaultValue );
|
||||
return FlatUIUtils.getUIFloat( key, defaultValue );
|
||||
}
|
||||
|
||||
private static String styleKey( String key, String style ) {
|
||||
@@ -129,11 +162,26 @@ public class FlatCheckBoxIcon
|
||||
super( ICON_SIZE, ICON_SIZE, null );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
public Object applyStyleProperty( String key, Object value ) {
|
||||
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
public Map<String, Class<?>> getStyleableInfos() {
|
||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintIcon( Component c, Graphics2D g ) {
|
||||
boolean indeterminate = isIndeterminate( c );
|
||||
boolean selected = indeterminate || isSelected( c );
|
||||
boolean isFocused = FlatUIUtils.isPermanentFocusOwner( c );
|
||||
float bw = selected
|
||||
? (disabledSelectedBorderWidth != Float.MIN_VALUE && !c.isEnabled()
|
||||
? disabledSelectedBorderWidth
|
||||
: (selectedBorderWidth != Float.MIN_VALUE ? selectedBorderWidth : borderWidth))
|
||||
: borderWidth;
|
||||
|
||||
// paint focused border
|
||||
if( isFocused && focusWidth > 0 && FlatButtonUI.isFocusPainted( c ) ) {
|
||||
@@ -143,7 +191,7 @@ public class FlatCheckBoxIcon
|
||||
|
||||
// paint border
|
||||
g.setColor( getBorderColor( c, selected ) );
|
||||
paintBorder( c, g );
|
||||
paintBorder( c, g, bw );
|
||||
|
||||
// paint background
|
||||
Color bg = FlatUIUtils.deriveColor( getBackground( c, selected ),
|
||||
@@ -151,14 +199,14 @@ public class FlatCheckBoxIcon
|
||||
if( bg.getAlpha() < 255 ) {
|
||||
// fill background with default color before filling with non-opaque background
|
||||
g.setColor( selected ? selectedBackground : background );
|
||||
paintBackground( c, g );
|
||||
paintBackground( c, g, bw );
|
||||
}
|
||||
g.setColor( bg );
|
||||
paintBackground( c, g );
|
||||
paintBackground( c, g, bw );
|
||||
|
||||
// paint checkmark
|
||||
if( selected || indeterminate ) {
|
||||
g.setColor( getCheckmarkColor( c, selected, isFocused ) );
|
||||
if( selected ) {
|
||||
g.setColor( getCheckmarkColor( c ) );
|
||||
if( indeterminate )
|
||||
paintIndeterminate( c, g );
|
||||
else
|
||||
@@ -167,20 +215,25 @@ public class FlatCheckBoxIcon
|
||||
}
|
||||
|
||||
protected void paintFocusBorder( Component c, Graphics2D g ) {
|
||||
// the outline focus border is painted outside of the icon
|
||||
int wh = ICON_SIZE - 1 + (focusWidth * 2);
|
||||
int arcwh = arc + (focusWidth * 2);
|
||||
g.fillRoundRect( -focusWidth + 1, -focusWidth, wh, wh, arcwh, arcwh );
|
||||
// the outer focus border is painted outside of the icon
|
||||
float wh = ICON_SIZE - 1 + (focusWidth * 2);
|
||||
float arcwh = arc + (focusWidth * 2);
|
||||
g.fill( new RoundRectangle2D.Float( -focusWidth + 1, -focusWidth, wh, wh, arcwh, arcwh ) );
|
||||
}
|
||||
|
||||
protected void paintBorder( Component c, Graphics2D g ) {
|
||||
protected void paintBorder( Component c, Graphics2D g, float borderWidth ) {
|
||||
if( borderWidth == 0 )
|
||||
return;
|
||||
|
||||
int arcwh = arc;
|
||||
g.fillRoundRect( 1, 0, 14, 14, arcwh, arcwh );
|
||||
}
|
||||
|
||||
protected void paintBackground( Component c, Graphics2D g ) {
|
||||
int arcwh = arc - 1;
|
||||
g.fillRoundRect( 2, 1, 12, 12, arcwh, arcwh );
|
||||
protected void paintBackground( Component c, Graphics2D g, float borderWidth ) {
|
||||
float xy = borderWidth;
|
||||
float wh = 14 - (borderWidth * 2);
|
||||
float arcwh = arc - borderWidth;
|
||||
g.fill( new RoundRectangle2D.Float( 1 + xy, xy, wh, wh, arcwh, arcwh ) );
|
||||
}
|
||||
|
||||
protected void paintCheckmark( Component c, Graphics2D g ) {
|
||||
@@ -205,6 +258,11 @@ public class FlatCheckBoxIcon
|
||||
return c instanceof AbstractButton && ((AbstractButton)c).isSelected();
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
public float getFocusWidth() {
|
||||
return focusWidth;
|
||||
}
|
||||
|
||||
protected Color getFocusColor( Component c ) {
|
||||
return focusColor;
|
||||
}
|
||||
@@ -212,26 +270,27 @@ public class FlatCheckBoxIcon
|
||||
protected Color getBorderColor( Component c, boolean selected ) {
|
||||
return FlatButtonUI.buttonStateColor( c,
|
||||
selected ? selectedBorderColor : borderColor,
|
||||
disabledBorderColor,
|
||||
selected && selectedFocusedBorderColor != null ? selectedFocusedBorderColor : focusedBorderColor,
|
||||
hoverBorderColor,
|
||||
null );
|
||||
(selected && disabledSelectedBorderColor != null) ? disabledSelectedBorderColor : disabledBorderColor,
|
||||
(selected && focusedSelectedBorderColor != null) ? focusedSelectedBorderColor : focusedBorderColor,
|
||||
(selected && hoverSelectedBorderColor != null) ? hoverSelectedBorderColor : hoverBorderColor,
|
||||
(selected && pressedSelectedBorderColor != null) ? pressedSelectedBorderColor : pressedBorderColor );
|
||||
}
|
||||
|
||||
protected Color getBackground( Component c, boolean selected ) {
|
||||
return FlatButtonUI.buttonStateColor( c,
|
||||
selected ? selectedBackground : background,
|
||||
disabledBackground,
|
||||
(selected && selectedFocusedBackground != null) ? selectedFocusedBackground : focusedBackground,
|
||||
(selected && selectedHoverBackground != null) ? selectedHoverBackground : hoverBackground,
|
||||
(selected && selectedPressedBackground != null) ? selectedPressedBackground : pressedBackground );
|
||||
(selected && disabledSelectedBackground != null) ? disabledSelectedBackground : disabledBackground,
|
||||
(selected && focusedSelectedBackground != null) ? focusedSelectedBackground : focusedBackground,
|
||||
(selected && hoverSelectedBackground != null) ? hoverSelectedBackground : hoverBackground,
|
||||
(selected && pressedSelectedBackground != null) ? pressedSelectedBackground : pressedBackground );
|
||||
}
|
||||
|
||||
protected Color getCheckmarkColor( Component c, boolean selected, boolean isFocused ) {
|
||||
return c.isEnabled()
|
||||
? ((selected && isFocused && selectedFocusedCheckmarkColor != null)
|
||||
? selectedFocusedCheckmarkColor
|
||||
: checkmarkColor)
|
||||
: disabledCheckmarkColor;
|
||||
protected Color getCheckmarkColor( Component c ) {
|
||||
return FlatButtonUI.buttonStateColor( c,
|
||||
checkmarkColor,
|
||||
disabledCheckmarkColor,
|
||||
focusedCheckmarkColor,
|
||||
hoverCheckmarkColor,
|
||||
pressedCheckmarkColor );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,15 +21,18 @@ import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.util.Map;
|
||||
import javax.swing.AbstractButton;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.UIManager;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
|
||||
/**
|
||||
* Icon for {@link javax.swing.JCheckBoxMenuItem}.
|
||||
*
|
||||
* @uiDefault MenuItemCheckBox.icon.checkmarkColor Color
|
||||
* @uiDefault MenuItemCheckBox.icon.disabledCheckmarkColor Color
|
||||
* @uiDefault CheckBoxMenuItem.icon.checkmarkColor Color
|
||||
* @uiDefault CheckBoxMenuItem.icon.disabledCheckmarkColor Color
|
||||
* @uiDefault MenuItem.selectionForeground Color
|
||||
* @uiDefault MenuItem.selectionType String
|
||||
*
|
||||
@@ -38,14 +41,24 @@ import javax.swing.UIManager;
|
||||
public class FlatCheckBoxMenuItemIcon
|
||||
extends FlatAbstractIcon
|
||||
{
|
||||
protected final Color checkmarkColor = UIManager.getColor( "MenuItemCheckBox.icon.checkmarkColor" );
|
||||
protected final Color disabledCheckmarkColor = UIManager.getColor( "MenuItemCheckBox.icon.disabledCheckmarkColor" );
|
||||
protected final Color selectionForeground = UIManager.getColor( "MenuItem.selectionForeground" );
|
||||
@Styleable protected Color checkmarkColor = UIManager.getColor( "CheckBoxMenuItem.icon.checkmarkColor" );
|
||||
@Styleable protected Color disabledCheckmarkColor = UIManager.getColor( "CheckBoxMenuItem.icon.disabledCheckmarkColor" );
|
||||
@Styleable protected Color selectionForeground = UIManager.getColor( "MenuItem.selectionForeground" );
|
||||
|
||||
public FlatCheckBoxMenuItemIcon() {
|
||||
super( 15, 15, null );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
public Object applyStyleProperty( String key, Object value ) {
|
||||
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
public Map<String, Class<?>> getStyleableInfos() {
|
||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintIcon( Component c, Graphics2D g2 ) {
|
||||
boolean selected = (c instanceof AbstractButton) && ((AbstractButton)c).isSelected();
|
||||
|
||||
@@ -22,9 +22,12 @@ import java.awt.Graphics2D;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Line2D;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.util.Map;
|
||||
import javax.swing.AbstractButton;
|
||||
import javax.swing.ButtonModel;
|
||||
import javax.swing.UIManager;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
|
||||
/**
|
||||
@@ -40,14 +43,24 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
public class FlatClearIcon
|
||||
extends FlatAbstractIcon
|
||||
{
|
||||
protected Color clearIconColor = UIManager.getColor( "SearchField.clearIconColor" );
|
||||
protected Color clearIconHoverColor = UIManager.getColor( "SearchField.clearIconHoverColor" );
|
||||
protected Color clearIconPressedColor = UIManager.getColor( "SearchField.clearIconPressedColor" );
|
||||
@Styleable protected Color clearIconColor = UIManager.getColor( "SearchField.clearIconColor" );
|
||||
@Styleable protected Color clearIconHoverColor = UIManager.getColor( "SearchField.clearIconHoverColor" );
|
||||
@Styleable protected Color clearIconPressedColor = UIManager.getColor( "SearchField.clearIconPressedColor" );
|
||||
|
||||
public FlatClearIcon() {
|
||||
super( 16, 16, null );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
public Object applyStyleProperty( String key, Object value ) {
|
||||
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
public Map<String, Class<?>> getStyleableInfos() {
|
||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintIcon( Component c, Graphics2D g ) {
|
||||
if( c instanceof AbstractButton ) {
|
||||
|
||||
@@ -17,11 +17,9 @@
|
||||
package com.formdev.flatlaf.icons;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Path2D;
|
||||
import javax.swing.UIManager;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
|
||||
/**
|
||||
@@ -33,18 +31,14 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatDescendingSortIcon
|
||||
extends FlatAbstractIcon
|
||||
extends FlatAscendingSortIcon
|
||||
{
|
||||
protected final boolean chevron = FlatUIUtils.isChevron( UIManager.getString( "Component.arrowType" ) );
|
||||
protected final Color sortIconColor = UIManager.getColor( "Table.sortIconColor" );
|
||||
|
||||
public FlatDescendingSortIcon() {
|
||||
super( 10, 5, null );
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintIcon( Component c, Graphics2D g ) {
|
||||
g.setColor( sortIconColor );
|
||||
protected void paintArrow( Component c, Graphics2D g, boolean chevron ) {
|
||||
if( chevron ) {
|
||||
// chevron arrow
|
||||
Path2D path = FlatUIUtils.createPath( false, 1,0, 5,4, 9,0 );
|
||||
|
||||
@@ -22,8 +22,11 @@ import java.awt.Component;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.util.Map;
|
||||
import javax.swing.UIManager;
|
||||
import com.formdev.flatlaf.ui.FlatButtonUI;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
|
||||
/**
|
||||
@@ -50,29 +53,37 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
public class FlatHelpButtonIcon
|
||||
extends FlatAbstractIcon
|
||||
{
|
||||
protected final int focusWidth = UIManager.getInt( "Component.focusWidth" );
|
||||
protected final Color focusColor = UIManager.getColor( "Component.focusColor" );
|
||||
protected final float innerFocusWidth = FlatUIUtils.getUIFloat( "HelpButton.innerFocusWidth", FlatUIUtils.getUIFloat( "Component.innerFocusWidth", 0 ) );
|
||||
protected final int borderWidth = FlatUIUtils.getUIInt( "HelpButton.borderWidth", 1 );
|
||||
@Styleable protected int focusWidth = UIManager.getInt( "Component.focusWidth" );
|
||||
@Styleable protected Color focusColor = UIManager.getColor( "Component.focusColor" );
|
||||
@Styleable protected float innerFocusWidth = FlatUIUtils.getUIFloat( "HelpButton.innerFocusWidth", FlatUIUtils.getUIFloat( "Component.innerFocusWidth", 0 ) );
|
||||
@Styleable protected int borderWidth = FlatUIUtils.getUIInt( "HelpButton.borderWidth", 1 );
|
||||
|
||||
protected final Color borderColor = UIManager.getColor( "HelpButton.borderColor" );
|
||||
protected final Color disabledBorderColor = UIManager.getColor( "HelpButton.disabledBorderColor" );
|
||||
protected final Color focusedBorderColor = UIManager.getColor( "HelpButton.focusedBorderColor" );
|
||||
protected final Color hoverBorderColor = UIManager.getColor( "HelpButton.hoverBorderColor" );
|
||||
protected final Color background = UIManager.getColor( "HelpButton.background" );
|
||||
protected final Color disabledBackground = UIManager.getColor( "HelpButton.disabledBackground" );
|
||||
protected final Color focusedBackground = UIManager.getColor( "HelpButton.focusedBackground" );
|
||||
protected final Color hoverBackground = UIManager.getColor( "HelpButton.hoverBackground" );
|
||||
protected final Color pressedBackground = UIManager.getColor( "HelpButton.pressedBackground" );
|
||||
protected final Color questionMarkColor = UIManager.getColor( "HelpButton.questionMarkColor" );
|
||||
protected final Color disabledQuestionMarkColor = UIManager.getColor( "HelpButton.disabledQuestionMarkColor" );
|
||||
|
||||
protected final int iconSize = 22 + (focusWidth * 2);
|
||||
@Styleable protected Color borderColor = UIManager.getColor( "HelpButton.borderColor" );
|
||||
@Styleable protected Color disabledBorderColor = UIManager.getColor( "HelpButton.disabledBorderColor" );
|
||||
@Styleable protected Color focusedBorderColor = UIManager.getColor( "HelpButton.focusedBorderColor" );
|
||||
@Styleable protected Color hoverBorderColor = UIManager.getColor( "HelpButton.hoverBorderColor" );
|
||||
@Styleable protected Color background = UIManager.getColor( "HelpButton.background" );
|
||||
@Styleable protected Color disabledBackground = UIManager.getColor( "HelpButton.disabledBackground" );
|
||||
@Styleable protected Color focusedBackground = UIManager.getColor( "HelpButton.focusedBackground" );
|
||||
@Styleable protected Color hoverBackground = UIManager.getColor( "HelpButton.hoverBackground" );
|
||||
@Styleable protected Color pressedBackground = UIManager.getColor( "HelpButton.pressedBackground" );
|
||||
@Styleable protected Color questionMarkColor = UIManager.getColor( "HelpButton.questionMarkColor" );
|
||||
@Styleable protected Color disabledQuestionMarkColor = UIManager.getColor( "HelpButton.disabledQuestionMarkColor" );
|
||||
|
||||
public FlatHelpButtonIcon() {
|
||||
super( 0, 0, null );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
public Object applyStyleProperty( String key, Object value ) {
|
||||
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
public Map<String, Class<?>> getStyleableInfos() {
|
||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintIcon( Component c, Graphics2D g2 ) {
|
||||
/*
|
||||
@@ -89,7 +100,7 @@ public class FlatHelpButtonIcon
|
||||
boolean focused = FlatUIUtils.isPermanentFocusOwner( c );
|
||||
|
||||
float xy = 0.5f;
|
||||
float wh = iconSize - 1;
|
||||
float wh = iconSize() - 1;
|
||||
|
||||
// paint outer focus border
|
||||
if( focused && FlatButtonUI.isFocusPainted( c ) ) {
|
||||
@@ -151,11 +162,15 @@ public class FlatHelpButtonIcon
|
||||
|
||||
@Override
|
||||
public int getIconWidth() {
|
||||
return scale( iconSize );
|
||||
return scale( iconSize() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconHeight() {
|
||||
return scale( iconSize );
|
||||
return scale( iconSize() );
|
||||
}
|
||||
|
||||
private int iconSize() {
|
||||
return 22 + (focusWidth * 2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,9 +21,12 @@ import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.util.Map;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.UIManager;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
|
||||
/**
|
||||
* "arrow" icon for {@link javax.swing.JMenu}.
|
||||
@@ -39,22 +42,32 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
public class FlatMenuArrowIcon
|
||||
extends FlatAbstractIcon
|
||||
{
|
||||
protected final boolean chevron = FlatUIUtils.isChevron( UIManager.getString( "Component.arrowType" ) );
|
||||
protected final Color arrowColor = UIManager.getColor( "Menu.icon.arrowColor" );
|
||||
protected final Color disabledArrowColor = UIManager.getColor( "Menu.icon.disabledArrowColor" );
|
||||
protected final Color selectionForeground = UIManager.getColor( "Menu.selectionForeground" );
|
||||
@Styleable protected String arrowType = UIManager.getString( "Component.arrowType" );
|
||||
@Styleable protected Color arrowColor = UIManager.getColor( "Menu.icon.arrowColor" );
|
||||
@Styleable protected Color disabledArrowColor = UIManager.getColor( "Menu.icon.disabledArrowColor" );
|
||||
@Styleable protected Color selectionForeground = UIManager.getColor( "Menu.selectionForeground" );
|
||||
|
||||
public FlatMenuArrowIcon() {
|
||||
super( 6, 10, null );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
public Object applyStyleProperty( String key, Object value ) {
|
||||
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
public Map<String, Class<?>> getStyleableInfos() {
|
||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintIcon( Component c, Graphics2D g ) {
|
||||
if( !c.getComponentOrientation().isLeftToRight() )
|
||||
g.rotate( Math.toRadians( 180 ), width / 2., height / 2. );
|
||||
|
||||
g.setColor( getArrowColor( c ) );
|
||||
if( chevron ) {
|
||||
if( FlatUIUtils.isChevron( arrowType ) ) {
|
||||
// chevron arrow
|
||||
Path2D path = FlatUIUtils.createPath( false, 1,1, 5,5, 1,9 );
|
||||
g.setStroke( new BasicStroke( 1f ) );
|
||||
|
||||
@@ -19,38 +19,51 @@ package com.formdev.flatlaf.icons;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
|
||||
/**
|
||||
* Icon for {@link javax.swing.JRadioButton}.
|
||||
*
|
||||
* Note: If Component.focusWidth is greater than zero, then the outline focus border
|
||||
* <p>
|
||||
* <strong>Note</strong>:
|
||||
* If Component.focusWidth is greater than zero, then the outer focus border
|
||||
* is painted outside of the icon bounds. Make sure that the radiobutton
|
||||
* has margins, which are equal or greater than focusWidth.
|
||||
*
|
||||
* @uiDefault RadioButton.icon.centerDiameter int
|
||||
* @uiDefault RadioButton.icon.style String optional; "outlined"/null (default) or "filled"
|
||||
* @uiDefault RadioButton.icon.centerDiameter int or float
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatRadioButtonIcon
|
||||
extends FlatCheckBoxIcon
|
||||
{
|
||||
protected final int centerDiameter = getUIInt( "RadioButton.icon.centerDiameter", 8, style );
|
||||
@Styleable protected float centerDiameter = getUIFloat( "RadioButton.icon.centerDiameter", 8, style );
|
||||
|
||||
@Override
|
||||
protected void paintFocusBorder( Component c, Graphics2D g ) {
|
||||
// the outline focus border is painted outside of the icon
|
||||
int wh = ICON_SIZE + (focusWidth * 2);
|
||||
g.fillOval( -focusWidth, -focusWidth, wh, wh );
|
||||
protected String getPropertyPrefix() {
|
||||
return "RadioButton.";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintBorder( Component c, Graphics2D g ) {
|
||||
protected void paintFocusBorder( Component c, Graphics2D g ) {
|
||||
// the outer focus border is painted outside of the icon
|
||||
float wh = ICON_SIZE + (focusWidth * 2);
|
||||
g.fill( new Ellipse2D.Float( -focusWidth, -focusWidth, wh, wh ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintBorder( Component c, Graphics2D g, float borderWidth ) {
|
||||
if( borderWidth == 0 )
|
||||
return;
|
||||
|
||||
g.fillOval( 0, 0, 15, 15 );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintBackground( Component c, Graphics2D g ) {
|
||||
g.fillOval( 1, 1, 13, 13 );
|
||||
protected void paintBackground( Component c, Graphics2D g, float borderWidth ) {
|
||||
float xy = borderWidth;
|
||||
float wh = 15 - (borderWidth * 2);
|
||||
g.fill( new Ellipse2D.Float( xy, xy, wh, wh ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -21,8 +21,11 @@ import java.awt.Component;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Area;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.util.Map;
|
||||
import javax.swing.UIManager;
|
||||
import com.formdev.flatlaf.ui.FlatButtonUI;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
|
||||
/**
|
||||
@@ -38,14 +41,24 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
public class FlatSearchIcon
|
||||
extends FlatAbstractIcon
|
||||
{
|
||||
protected Color searchIconColor = UIManager.getColor( "SearchField.searchIconColor" );
|
||||
protected Color searchIconHoverColor = UIManager.getColor( "SearchField.searchIconHoverColor" );
|
||||
protected Color searchIconPressedColor = UIManager.getColor( "SearchField.searchIconPressedColor" );
|
||||
@Styleable protected Color searchIconColor = UIManager.getColor( "SearchField.searchIconColor" );
|
||||
@Styleable protected Color searchIconHoverColor = UIManager.getColor( "SearchField.searchIconHoverColor" );
|
||||
@Styleable protected Color searchIconPressedColor = UIManager.getColor( "SearchField.searchIconPressedColor" );
|
||||
|
||||
public FlatSearchIcon() {
|
||||
super( 16, 16, null );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
public Object applyStyleProperty( String key, Object value ) {
|
||||
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
public Map<String, Class<?>> getStyleableInfos() {
|
||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintIcon( Component c, Graphics2D g ) {
|
||||
/*
|
||||
|
||||
@@ -23,8 +23,11 @@ import java.awt.Dimension;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Line2D;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.util.Map;
|
||||
import javax.swing.UIManager;
|
||||
import com.formdev.flatlaf.ui.FlatButtonUI;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
|
||||
/**
|
||||
@@ -47,39 +50,49 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
public class FlatTabbedPaneCloseIcon
|
||||
extends FlatAbstractIcon
|
||||
{
|
||||
protected final Dimension size = UIManager.getDimension( "TabbedPane.closeSize" );
|
||||
protected final int arc = UIManager.getInt( "TabbedPane.closeArc" );
|
||||
protected final float crossPlainSize = FlatUIUtils.getUIFloat( "TabbedPane.closeCrossPlainSize", 7.5f );
|
||||
protected final float crossFilledSize = FlatUIUtils.getUIFloat( "TabbedPane.closeCrossFilledSize", crossPlainSize );
|
||||
protected final float closeCrossLineWidth = FlatUIUtils.getUIFloat( "TabbedPane.closeCrossLineWidth", 1f );
|
||||
protected final Color background = UIManager.getColor( "TabbedPane.closeBackground" );
|
||||
protected final Color foreground = UIManager.getColor( "TabbedPane.closeForeground" );
|
||||
protected final Color hoverBackground = UIManager.getColor( "TabbedPane.closeHoverBackground" );
|
||||
protected final Color hoverForeground = UIManager.getColor( "TabbedPane.closeHoverForeground" );
|
||||
protected final Color pressedBackground = UIManager.getColor( "TabbedPane.closePressedBackground" );
|
||||
protected final Color pressedForeground = UIManager.getColor( "TabbedPane.closePressedForeground" );
|
||||
@Styleable protected Dimension closeSize = UIManager.getDimension( "TabbedPane.closeSize" );
|
||||
@Styleable protected int closeArc = UIManager.getInt( "TabbedPane.closeArc" );
|
||||
@Styleable protected float closeCrossPlainSize = FlatUIUtils.getUIFloat( "TabbedPane.closeCrossPlainSize", 7.5f );
|
||||
@Styleable protected float closeCrossFilledSize = FlatUIUtils.getUIFloat( "TabbedPane.closeCrossFilledSize", closeCrossPlainSize );
|
||||
@Styleable protected float closeCrossLineWidth = FlatUIUtils.getUIFloat( "TabbedPane.closeCrossLineWidth", 1f );
|
||||
@Styleable protected Color closeBackground = UIManager.getColor( "TabbedPane.closeBackground" );
|
||||
@Styleable protected Color closeForeground = UIManager.getColor( "TabbedPane.closeForeground" );
|
||||
@Styleable protected Color closeHoverBackground = UIManager.getColor( "TabbedPane.closeHoverBackground" );
|
||||
@Styleable protected Color closeHoverForeground = UIManager.getColor( "TabbedPane.closeHoverForeground" );
|
||||
@Styleable protected Color closePressedBackground = UIManager.getColor( "TabbedPane.closePressedBackground" );
|
||||
@Styleable protected Color closePressedForeground = UIManager.getColor( "TabbedPane.closePressedForeground" );
|
||||
|
||||
public FlatTabbedPaneCloseIcon() {
|
||||
super( 16, 16, null );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
public Object applyStyleProperty( String key, Object value ) {
|
||||
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
public Map<String, Class<?>> getStyleableInfos() {
|
||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintIcon( Component c, Graphics2D g ) {
|
||||
// paint background
|
||||
Color bg = FlatButtonUI.buttonStateColor( c, background, null, null, hoverBackground, pressedBackground );
|
||||
Color bg = FlatButtonUI.buttonStateColor( c, closeBackground, null, null, closeHoverBackground, closePressedBackground );
|
||||
if( bg != null ) {
|
||||
g.setColor( FlatUIUtils.deriveColor( bg, c.getBackground() ) );
|
||||
g.fillRoundRect( (width - size.width) / 2, (height - size.height) / 2,
|
||||
size.width, size.height, arc, arc );
|
||||
g.fillRoundRect( (width - closeSize.width) / 2, (height - closeSize.height) / 2,
|
||||
closeSize.width, closeSize.height, closeArc, closeArc );
|
||||
}
|
||||
|
||||
// set cross color
|
||||
Color fg = FlatButtonUI.buttonStateColor( c, foreground, null, null, hoverForeground, pressedForeground );
|
||||
Color fg = FlatButtonUI.buttonStateColor( c, closeForeground, null, null, closeHoverForeground, closePressedForeground );
|
||||
g.setColor( FlatUIUtils.deriveColor( fg, c.getForeground() ) );
|
||||
|
||||
float mx = width / 2;
|
||||
float my = height / 2;
|
||||
float r = ((bg != null) ? crossFilledSize : crossPlainSize) / 2;
|
||||
float r = ((bg != null) ? closeCrossFilledSize : closeCrossPlainSize) / 2;
|
||||
|
||||
// paint cross
|
||||
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
||||
|
||||
@@ -37,6 +37,8 @@ public class FlatTreeClosedIcon
|
||||
|
||||
@Override
|
||||
protected void paintIcon( Component c, Graphics2D g ) {
|
||||
FlatTreeCollapsedIcon.setStyleColorFromTreeUI( c, g, ui -> ui.iconClosedColor );
|
||||
|
||||
/*
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<polygon fill="#6E6E6E" fill-rule="evenodd" points="1 2 6 2 8 4 15 4 15 13 1 13"/>
|
||||
|
||||
@@ -19,7 +19,12 @@ package com.formdev.flatlaf.icons;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics2D;
|
||||
import java.util.function.Function;
|
||||
import javax.swing.JTree;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.TreeUI;
|
||||
import com.formdev.flatlaf.ui.FlatTreeUI;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
|
||||
/**
|
||||
@@ -46,8 +51,12 @@ public class FlatTreeCollapsedIcon
|
||||
|
||||
@Override
|
||||
protected void paintIcon( Component c, Graphics2D g ) {
|
||||
setStyleColorFromTreeUI( c, g );
|
||||
rotate( c, g );
|
||||
|
||||
String arrowType = getStyleFromTreeUI( c, ui -> ui.iconArrowType );
|
||||
boolean chevron = (arrowType != null) ? FlatUIUtils.isChevron( arrowType ) : this.chevron;
|
||||
|
||||
if( chevron ) {
|
||||
// chevron arrow
|
||||
g.fill( FlatUIUtils.createPath( 3,1, 3,2.5, 6,5.5, 3,8.5, 3,10, 4.5,10, 9,5.5, 4.5,1 ) );
|
||||
@@ -57,8 +66,34 @@ public class FlatTreeCollapsedIcon
|
||||
}
|
||||
}
|
||||
|
||||
void setStyleColorFromTreeUI( Component c, Graphics2D g ) {
|
||||
setStyleColorFromTreeUI( c, g, ui -> ui.iconCollapsedColor );
|
||||
}
|
||||
|
||||
void rotate( Component c, Graphics2D g ) {
|
||||
if( !c.getComponentOrientation().isLeftToRight() )
|
||||
g.rotate( Math.toRadians( 180 ), width / 2., height / 2. );
|
||||
}
|
||||
|
||||
/**
|
||||
* Because this icons are always shared for all trees,
|
||||
* get icon specific style from FlatTreeUI.
|
||||
*/
|
||||
static <T> T getStyleFromTreeUI( Component c, Function<FlatTreeUI, T> f ) {
|
||||
JTree tree = (c instanceof JTree)
|
||||
? (JTree) c
|
||||
: (JTree) SwingUtilities.getAncestorOfClass( JTree.class, c );
|
||||
if( tree != null ) {
|
||||
TreeUI ui = tree.getUI();
|
||||
if( ui instanceof FlatTreeUI )
|
||||
return f.apply( (FlatTreeUI) ui );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static void setStyleColorFromTreeUI( Component c, Graphics2D g, Function<FlatTreeUI, Color> f ) {
|
||||
Color color = getStyleFromTreeUI( c, f );
|
||||
if( color != null )
|
||||
g.setColor( color );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,11 @@ public class FlatTreeExpandedIcon
|
||||
super( UIManager.getColor( "Tree.icon.expandedColor" ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
void setStyleColorFromTreeUI( Component c, Graphics2D g ) {
|
||||
setStyleColorFromTreeUI( c, g, ui -> ui.iconExpandedColor );
|
||||
}
|
||||
|
||||
@Override
|
||||
void rotate( Component c, Graphics2D g ) {
|
||||
g.rotate( Math.toRadians( 90 ), width / 2., height / 2. );
|
||||
|
||||
@@ -37,6 +37,8 @@ public class FlatTreeLeafIcon
|
||||
|
||||
@Override
|
||||
protected void paintIcon( Component c, Graphics2D g ) {
|
||||
FlatTreeCollapsedIcon.setStyleColorFromTreeUI( c, g, ui -> ui.iconLeafColor );
|
||||
|
||||
/*
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
|
||||
@@ -37,6 +37,8 @@ public class FlatTreeOpenIcon
|
||||
|
||||
@Override
|
||||
protected void paintIcon( Component c, Graphics2D g ) {
|
||||
FlatTreeCollapsedIcon.setStyleColorFromTreeUI( c, g, ui -> ui.iconOpenColor );
|
||||
|
||||
/*
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
|
||||
@@ -39,13 +39,13 @@ public class FlatArrowButton
|
||||
{
|
||||
public static final int DEFAULT_ARROW_WIDTH = 8;
|
||||
|
||||
protected final boolean chevron;
|
||||
protected final Color foreground;
|
||||
protected final Color disabledForeground;
|
||||
protected final Color hoverForeground;
|
||||
protected final Color hoverBackground;
|
||||
protected final Color pressedForeground;
|
||||
protected final Color pressedBackground;
|
||||
protected boolean chevron;
|
||||
protected Color foreground;
|
||||
protected Color disabledForeground;
|
||||
protected Color hoverForeground;
|
||||
protected Color hoverBackground;
|
||||
protected Color pressedForeground;
|
||||
protected Color pressedBackground;
|
||||
|
||||
private int arrowWidth = DEFAULT_ARROW_WIDTH;
|
||||
private float xOffset = 0;
|
||||
@@ -58,14 +58,8 @@ public class FlatArrowButton
|
||||
Color hoverForeground, Color hoverBackground, Color pressedForeground, Color pressedBackground )
|
||||
{
|
||||
super( direction, Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE );
|
||||
|
||||
this.chevron = FlatUIUtils.isChevron( type );
|
||||
this.foreground = foreground;
|
||||
this.disabledForeground = disabledForeground;
|
||||
this.hoverForeground = hoverForeground;
|
||||
this.hoverBackground = hoverBackground;
|
||||
this.pressedForeground = pressedForeground;
|
||||
this.pressedBackground = pressedBackground;
|
||||
updateStyle( type, foreground, disabledForeground, hoverForeground, hoverBackground,
|
||||
pressedForeground, pressedBackground );
|
||||
|
||||
setOpaque( false );
|
||||
setBorder( null );
|
||||
@@ -101,6 +95,19 @@ public class FlatArrowButton
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
public void updateStyle( String type, Color foreground, Color disabledForeground,
|
||||
Color hoverForeground, Color hoverBackground, Color pressedForeground, Color pressedBackground )
|
||||
{
|
||||
this.chevron = FlatUIUtils.isChevron( type );
|
||||
this.foreground = foreground;
|
||||
this.disabledForeground = disabledForeground;
|
||||
this.hoverForeground = hoverForeground;
|
||||
this.hoverBackground = hoverBackground;
|
||||
this.pressedForeground = pressedForeground;
|
||||
this.pressedBackground = pressedBackground;
|
||||
}
|
||||
|
||||
public int getArrowWidth() {
|
||||
return arrowWidth;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Paint;
|
||||
import java.util.Map;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JScrollPane;
|
||||
@@ -31,21 +32,25 @@ import javax.swing.JViewport;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.basic.BasicBorders;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableBorder;
|
||||
import com.formdev.flatlaf.util.DerivedColor;
|
||||
|
||||
/**
|
||||
* Border for various components (e.g. {@link javax.swing.JTextField}).
|
||||
*
|
||||
* <p>
|
||||
* There is empty space around the component border, if Component.focusWidth is greater than zero,
|
||||
* which is used to paint outer focus border.
|
||||
*
|
||||
* <p>
|
||||
* Because there is empty space (if outer focus border is not painted),
|
||||
* UI delegates that use this border (or subclasses) must invoke
|
||||
* {@link FlatUIUtils#paintParentBackground} to paint the empty space correctly.
|
||||
* {@link FlatUIUtils#paintParentBackground} to fill the empty space correctly.
|
||||
*
|
||||
* @uiDefault Component.focusWidth int
|
||||
* @uiDefault Component.innerFocusWidth int or float
|
||||
* @uiDefault Component.innerOutlineWidth int or float
|
||||
* @uiDefault Component.borderWidth int or float
|
||||
*
|
||||
* @uiDefault Component.focusColor Color
|
||||
* @uiDefault Component.borderColor Color
|
||||
* @uiDefault Component.disabledBorderColor Color
|
||||
@@ -61,20 +66,40 @@ import com.formdev.flatlaf.util.DerivedColor;
|
||||
*/
|
||||
public class FlatBorder
|
||||
extends BasicBorders.MarginBorder
|
||||
implements StyleableBorder
|
||||
{
|
||||
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" );
|
||||
@Styleable protected int focusWidth = UIManager.getInt( "Component.focusWidth" );
|
||||
@Styleable protected float innerFocusWidth = FlatUIUtils.getUIFloat( "Component.innerFocusWidth", 0 );
|
||||
@Styleable protected float innerOutlineWidth = FlatUIUtils.getUIFloat( "Component.innerOutlineWidth", 0 );
|
||||
/** @since 2 */ @Styleable protected float borderWidth = FlatUIUtils.getUIFloat( "Component.borderWidth", 1 );
|
||||
|
||||
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" );
|
||||
@Styleable protected Color focusColor = UIManager.getColor( "Component.focusColor" );
|
||||
@Styleable protected Color borderColor = UIManager.getColor( "Component.borderColor" );
|
||||
@Styleable protected Color disabledBorderColor = UIManager.getColor( "Component.disabledBorderColor" );
|
||||
@Styleable protected Color focusedBorderColor = UIManager.getColor( "Component.focusedBorderColor" );
|
||||
|
||||
@Styleable(dot=true) protected Color errorBorderColor = UIManager.getColor( "Component.error.borderColor" );
|
||||
@Styleable(dot=true) protected Color errorFocusedBorderColor = UIManager.getColor( "Component.error.focusedBorderColor" );
|
||||
@Styleable(dot=true) protected Color warningBorderColor = UIManager.getColor( "Component.warning.borderColor" );
|
||||
@Styleable(dot=true) protected Color warningFocusedBorderColor = UIManager.getColor( "Component.warning.focusedBorderColor" );
|
||||
@Styleable(dot=true) protected Color customBorderColor = UIManager.getColor( "Component.custom.borderColor" );
|
||||
|
||||
// only used via styling (not in UI defaults, but has likewise client properties)
|
||||
/** @since 2 */ @Styleable protected String outline;
|
||||
/** @since 2 */ @Styleable protected Color outlineColor;
|
||||
/** @since 2 */ @Styleable protected Color outlineFocusedColor;
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Object applyStyleProperty( String key, Object value ) {
|
||||
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos() {
|
||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||
@@ -83,9 +108,11 @@ public class FlatBorder
|
||||
FlatUIUtils.setRenderingHints( g2 );
|
||||
|
||||
float focusWidth = scale( (float) getFocusWidth( c ) );
|
||||
float borderWidth = scale( (float) getBorderWidth( c ) );
|
||||
float focusInnerWidth = 0;
|
||||
float borderWidth = scale( getBorderWidth( c ) );
|
||||
float arc = scale( (float) getArc( c ) );
|
||||
Color outlineColor = getOutlineColor( c );
|
||||
Color focusColor = null;
|
||||
|
||||
// paint outer border
|
||||
if( outlineColor != null || isFocused( c ) ) {
|
||||
@@ -94,15 +121,16 @@ public class FlatBorder
|
||||
: 0;
|
||||
|
||||
if( focusWidth > 0 || innerWidth > 0 ) {
|
||||
g2.setColor( (outlineColor != null) ? outlineColor : getFocusColor( c ) );
|
||||
FlatUIUtils.paintComponentOuterBorder( g2, x, y, width, height,
|
||||
focusWidth, borderWidth + scale( innerWidth ), arc );
|
||||
focusColor = (outlineColor != null) ? outlineColor : getFocusColor( c );
|
||||
focusInnerWidth = borderWidth + scale( innerWidth );
|
||||
}
|
||||
}
|
||||
|
||||
// paint border
|
||||
g2.setPaint( (outlineColor != null) ? outlineColor : getBorderColor( c ) );
|
||||
FlatUIUtils.paintComponentBorder( g2, x, y, width, height, focusWidth, borderWidth, arc );
|
||||
Paint borderColor = (outlineColor != null) ? outlineColor : getBorderColor( c );
|
||||
FlatUIUtils.paintOutlinedComponent( g2, x, y, width, height,
|
||||
focusWidth, 1, focusInnerWidth, borderWidth, arc,
|
||||
focusColor, borderColor, null );
|
||||
} finally {
|
||||
g2.dispose();
|
||||
}
|
||||
@@ -117,6 +145,17 @@ public class FlatBorder
|
||||
return null;
|
||||
|
||||
Object outline = ((JComponent)c).getClientProperty( FlatClientProperties.OUTLINE );
|
||||
if( outline == null )
|
||||
outline = this.outline;
|
||||
if( outline == null ) {
|
||||
if( outlineColor != null && outlineFocusedColor != null )
|
||||
outline = new Color[] { outlineFocusedColor, outlineColor };
|
||||
else if( outlineColor != null )
|
||||
outline = outlineColor;
|
||||
else if( outlineFocusedColor != null )
|
||||
outline = outlineFocusedColor;
|
||||
}
|
||||
|
||||
if( outline instanceof String ) {
|
||||
switch( (String) outline ) {
|
||||
case FlatClientProperties.OUTLINE_ERROR:
|
||||
@@ -229,8 +268,8 @@ public class FlatBorder
|
||||
* 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 getBorderWidth( Component c ) {
|
||||
return borderWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -26,57 +26,66 @@ import java.awt.Paint;
|
||||
import javax.swing.AbstractButton;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
* Border for {@link javax.swing.JButton}.
|
||||
*
|
||||
* @uiDefault Button.arc int
|
||||
* @uiDefault Button.innerFocusWidth int or float optional; defaults to Component.innerFocusWidth
|
||||
* @uiDefault Button.borderWidth int or float optional; defaults to Component.borderWidth
|
||||
*
|
||||
* @uiDefault Button.borderColor Color
|
||||
* @uiDefault Button.startBorderColor Color optional; if set, a gradient paint is used and Button.borderColor is ignored
|
||||
* @uiDefault Button.endBorderColor Color optional; if set, a gradient paint is used
|
||||
* @uiDefault Button.disabledBorderColor Color
|
||||
* @uiDefault Button.focusedBorderColor Color
|
||||
* @uiDefault Button.hoverBorderColor Color optional
|
||||
*
|
||||
* @uiDefault Button.default.borderWidth int or float
|
||||
* @uiDefault Button.default.borderColor Color
|
||||
* @uiDefault Button.default.startBorderColor Color optional; if set, a gradient paint is used and Button.default.borderColor is ignored
|
||||
* @uiDefault Button.default.endBorderColor Color optional; if set, a gradient paint is used
|
||||
* @uiDefault Button.default.hoverBorderColor Color optional
|
||||
* @uiDefault Button.default.focusedBorderColor Color
|
||||
* @uiDefault Button.default.focusColor Color
|
||||
* @uiDefault Button.default.hoverBorderColor Color optional
|
||||
*
|
||||
* @uiDefault Button.toolbar.focusWidth int or float optional; default is 1.5
|
||||
* @uiDefault Button.toolbar.focusColor Color optional; defaults to Component.focusColor
|
||||
* @uiDefault Button.borderWidth int
|
||||
* @uiDefault Button.default.borderWidth int
|
||||
* @uiDefault Button.innerFocusWidth int or float optional; defaults to Component.innerFocusWidth
|
||||
* @uiDefault Button.toolbar.margin Insets
|
||||
* @uiDefault Button.toolbar.spacingInsets Insets
|
||||
* @uiDefault Button.toolbar.focusWidth int or float optional; default is 1
|
||||
* @uiDefault Button.arc int
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatButtonBorder
|
||||
extends FlatBorder
|
||||
{
|
||||
protected final Color borderColor = FlatUIUtils.getUIColor( "Button.startBorderColor", "Button.borderColor" );
|
||||
protected final Color endBorderColor = UIManager.getColor( "Button.endBorderColor" );
|
||||
protected final Color disabledBorderColor = UIManager.getColor( "Button.disabledBorderColor" );
|
||||
protected final Color focusedBorderColor = UIManager.getColor( "Button.focusedBorderColor" );
|
||||
protected final Color hoverBorderColor = UIManager.getColor( "Button.hoverBorderColor" );
|
||||
protected final Color defaultBorderColor = FlatUIUtils.getUIColor( "Button.default.startBorderColor", "Button.default.borderColor" );
|
||||
protected final Color defaultEndBorderColor = UIManager.getColor( "Button.default.endBorderColor" );
|
||||
protected final Color defaultHoverBorderColor = UIManager.getColor( "Button.default.hoverBorderColor" );
|
||||
protected final Color defaultFocusedBorderColor = UIManager.getColor( "Button.default.focusedBorderColor" );
|
||||
protected final Color defaultFocusColor = UIManager.getColor( "Button.default.focusColor" );
|
||||
/** @since 1.4 */
|
||||
protected final Color toolbarFocusColor = UIManager.getColor( "Button.toolbar.focusColor" );
|
||||
protected final int borderWidth = UIManager.getInt( "Button.borderWidth" );
|
||||
protected final int defaultBorderWidth = UIManager.getInt( "Button.default.borderWidth" );
|
||||
protected final float buttonInnerFocusWidth = FlatUIUtils.getUIFloat( "Button.innerFocusWidth", innerFocusWidth );
|
||||
protected final Insets toolbarMargin = UIManager.getInsets( "Button.toolbar.margin" );
|
||||
protected final Insets toolbarSpacingInsets = UIManager.getInsets( "Button.toolbar.spacingInsets" );
|
||||
/** @since 1.4 */
|
||||
protected final float toolbarFocusWidth = FlatUIUtils.getUIFloat( "Button.toolbar.focusWidth", 1.5f );
|
||||
protected final int arc = UIManager.getInt( "Button.arc" );
|
||||
@Styleable protected int arc = UIManager.getInt( "Button.arc" );
|
||||
|
||||
protected Color endBorderColor = UIManager.getColor( "Button.endBorderColor" );
|
||||
@Styleable protected Color hoverBorderColor = UIManager.getColor( "Button.hoverBorderColor" );
|
||||
|
||||
@Styleable(dot=true) protected float defaultBorderWidth = FlatUIUtils.getUIFloat( "Button.default.borderWidth", 1 );
|
||||
@Styleable(dot=true) protected Color defaultBorderColor = FlatUIUtils.getUIColor( "Button.default.startBorderColor", "Button.default.borderColor" );
|
||||
protected Color defaultEndBorderColor = UIManager.getColor( "Button.default.endBorderColor" );
|
||||
@Styleable(dot=true) protected Color defaultFocusedBorderColor = UIManager.getColor( "Button.default.focusedBorderColor" );
|
||||
@Styleable(dot=true) protected Color defaultFocusColor = UIManager.getColor( "Button.default.focusColor" );
|
||||
@Styleable(dot=true) protected Color defaultHoverBorderColor = UIManager.getColor( "Button.default.hoverBorderColor" );
|
||||
|
||||
/** @since 1.4 */ @Styleable(dot=true) protected float toolbarFocusWidth = FlatUIUtils.getUIFloat( "Button.toolbar.focusWidth", 1.5f );
|
||||
/** @since 1.4 */ @Styleable(dot=true) protected Color toolbarFocusColor = UIManager.getColor( "Button.toolbar.focusColor" );
|
||||
@Styleable(dot=true) protected Insets toolbarMargin = UIManager.getInsets( "Button.toolbar.margin" );
|
||||
@Styleable(dot=true) protected Insets toolbarSpacingInsets = UIManager.getInsets( "Button.toolbar.spacingInsets" );
|
||||
|
||||
public FlatButtonBorder() {
|
||||
innerFocusWidth = FlatUIUtils.getUIFloat( "Button.innerFocusWidth", innerFocusWidth );
|
||||
borderWidth = FlatUIUtils.getUIFloat( "Button.borderWidth", borderWidth );
|
||||
|
||||
borderColor = FlatUIUtils.getUIColor( "Button.startBorderColor", "Button.borderColor" );
|
||||
disabledBorderColor = UIManager.getColor( "Button.disabledBorderColor" );
|
||||
focusedBorderColor = UIManager.getColor( "Button.focusedBorderColor" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||
@@ -90,9 +99,7 @@ public class FlatButtonBorder
|
||||
paintToolBarFocus( c, g, x, y, width, height );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.4
|
||||
*/
|
||||
/** @since 1.4 */
|
||||
protected void paintToolBarFocus( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
try {
|
||||
@@ -108,9 +115,10 @@ public class FlatButtonBorder
|
||||
width -= spacing.left + spacing.right;
|
||||
height -= spacing.top + spacing.bottom;
|
||||
|
||||
g2.setColor( (outlineColor != null) ? outlineColor : getFocusColor( c ) );
|
||||
// not using paintComponentOuterBorder() here because its round edges look too "thick"
|
||||
FlatUIUtils.paintComponentBorder( g2, x, y, width, height, 0, focusWidth, arc );
|
||||
Color color = (outlineColor != null) ? outlineColor : getFocusColor( c );
|
||||
// not using focus border painting of paintOutlinedComponent() here
|
||||
// because its round edges look too "thick"
|
||||
FlatUIUtils.paintOutlinedComponent( g2, x, y, width, height, 0, 0, 0, focusWidth, arc, null, color, null );
|
||||
} finally {
|
||||
g2.dispose();
|
||||
}
|
||||
@@ -175,12 +183,7 @@ public class FlatButtonBorder
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getInnerFocusWidth( Component c ) {
|
||||
return buttonInnerFocusWidth;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getBorderWidth( Component c ) {
|
||||
protected float getBorderWidth( Component c ) {
|
||||
return FlatButtonUI.isDefaultButton( c ) ? defaultBorderWidth : borderWidth;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,9 @@ import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import javax.swing.AbstractButton;
|
||||
import javax.swing.ButtonModel;
|
||||
import javax.swing.Icon;
|
||||
@@ -40,11 +42,17 @@ import javax.swing.JToggleButton;
|
||||
import javax.swing.JToolBar;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ButtonUI;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicButtonListener;
|
||||
import javax.swing.plaf.basic.BasicButtonUI;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.icons.FlatHelpButtonIcon;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
@@ -94,8 +102,9 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
*/
|
||||
public class FlatButtonUI
|
||||
extends BasicButtonUI
|
||||
implements StyleableUI
|
||||
{
|
||||
protected int minimumWidth;
|
||||
@Styleable protected int minimumWidth;
|
||||
protected int iconTextGap;
|
||||
|
||||
protected Color background;
|
||||
@@ -103,39 +112,62 @@ public class FlatButtonUI
|
||||
|
||||
protected Color startBackground;
|
||||
protected Color endBackground;
|
||||
protected Color focusedBackground;
|
||||
protected Color hoverBackground;
|
||||
protected Color pressedBackground;
|
||||
protected Color selectedBackground;
|
||||
protected Color selectedForeground;
|
||||
protected Color disabledBackground;
|
||||
protected Color disabledText;
|
||||
protected Color disabledSelectedBackground;
|
||||
@Styleable protected Color focusedBackground;
|
||||
@Styleable protected Color hoverBackground;
|
||||
@Styleable protected Color pressedBackground;
|
||||
@Styleable protected Color selectedBackground;
|
||||
@Styleable protected Color selectedForeground;
|
||||
@Styleable protected Color disabledBackground;
|
||||
@Styleable protected Color disabledText;
|
||||
@Styleable protected Color disabledSelectedBackground;
|
||||
|
||||
protected Color defaultBackground;
|
||||
@Styleable(dot=true) protected Color defaultBackground;
|
||||
protected Color defaultEndBackground;
|
||||
protected Color defaultForeground;
|
||||
protected Color defaultFocusedBackground;
|
||||
protected Color defaultHoverBackground;
|
||||
protected Color defaultPressedBackground;
|
||||
protected boolean defaultBoldText;
|
||||
@Styleable(dot=true) protected Color defaultForeground;
|
||||
@Styleable(dot=true) protected Color defaultFocusedBackground;
|
||||
@Styleable(dot=true) protected Color defaultHoverBackground;
|
||||
@Styleable(dot=true) protected Color defaultPressedBackground;
|
||||
@Styleable(dot=true) protected boolean defaultBoldText;
|
||||
|
||||
protected int shadowWidth;
|
||||
protected Color shadowColor;
|
||||
protected Color defaultShadowColor;
|
||||
@Styleable protected boolean paintShadow;
|
||||
@Styleable protected int shadowWidth;
|
||||
@Styleable protected Color shadowColor;
|
||||
@Styleable(dot=true) protected Color defaultShadowColor;
|
||||
|
||||
protected Insets toolbarSpacingInsets;
|
||||
protected Color toolbarHoverBackground;
|
||||
protected Color toolbarPressedBackground;
|
||||
protected Color toolbarSelectedBackground;
|
||||
@Styleable(dot=true) protected Color toolbarHoverBackground;
|
||||
@Styleable(dot=true) protected Color toolbarPressedBackground;
|
||||
@Styleable(dot=true) protected Color toolbarSelectedBackground;
|
||||
|
||||
// only used via styling (not in UI defaults, but has likewise client properties)
|
||||
/** @since 2 */ @Styleable protected String buttonType;
|
||||
/** @since 2 */ @Styleable protected boolean squareSize;
|
||||
/** @since 2 */ @Styleable protected int minimumHeight;
|
||||
|
||||
private Icon helpButtonIcon;
|
||||
private Insets defaultMargin;
|
||||
|
||||
private final boolean shared;
|
||||
private boolean helpButtonIconShared = true;
|
||||
private boolean defaults_initialized = false;
|
||||
private Map<String, Object> oldStyleValues;
|
||||
private AtomicBoolean borderShared;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return FlatUIUtils.createSharedUI( FlatButtonUI.class, FlatButtonUI::new );
|
||||
return FlatUIUtils.canUseSharedUI( c )
|
||||
? FlatUIUtils.createSharedUI( FlatButtonUI.class, () -> new FlatButtonUI( true ) )
|
||||
: new FlatButtonUI( false );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected FlatButtonUI( boolean shared ) {
|
||||
this.shared = shared;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
installStyle( (AbstractButton) c );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -162,16 +194,6 @@ public class FlatButtonUI
|
||||
disabledText = UIManager.getColor( prefix + "disabledText" );
|
||||
disabledSelectedBackground = UIManager.getColor( prefix + "disabledSelectedBackground" );
|
||||
|
||||
if( UIManager.getBoolean( "Button.paintShadow" ) ) {
|
||||
shadowWidth = FlatUIUtils.getUIInt( "Button.shadowWidth", 2 );
|
||||
shadowColor = UIManager.getColor( "Button.shadowColor" );
|
||||
defaultShadowColor = UIManager.getColor( "Button.default.shadowColor" );
|
||||
} else {
|
||||
shadowWidth = 0;
|
||||
shadowColor = null;
|
||||
defaultShadowColor = null;
|
||||
}
|
||||
|
||||
defaultBackground = FlatUIUtils.getUIColor( "Button.default.startBackground", "Button.default.background" );
|
||||
defaultEndBackground = UIManager.getColor( "Button.default.endBackground" );
|
||||
defaultForeground = UIManager.getColor( "Button.default.foreground" );
|
||||
@@ -180,7 +202,11 @@ public class FlatButtonUI
|
||||
defaultPressedBackground = UIManager.getColor( "Button.default.pressedBackground" );
|
||||
defaultBoldText = UIManager.getBoolean( "Button.default.boldText" );
|
||||
|
||||
toolbarSpacingInsets = UIManager.getInsets( "Button.toolbar.spacingInsets" );
|
||||
paintShadow = UIManager.getBoolean( "Button.paintShadow" );
|
||||
shadowWidth = FlatUIUtils.getUIInt( "Button.shadowWidth", 2 );
|
||||
shadowColor = UIManager.getColor( "Button.shadowColor" );
|
||||
defaultShadowColor = UIManager.getColor( "Button.default.shadowColor" );
|
||||
|
||||
toolbarHoverBackground = UIManager.getColor( prefix + "toolbar.hoverBackground" );
|
||||
toolbarPressedBackground = UIManager.getColor( prefix + "toolbar.pressedBackground" );
|
||||
toolbarSelectedBackground = UIManager.getColor( prefix + "toolbar.selectedBackground" );
|
||||
@@ -188,6 +214,7 @@ public class FlatButtonUI
|
||||
helpButtonIcon = UIManager.getIcon( "HelpButton.icon" );
|
||||
defaultMargin = UIManager.getInsets( prefix + "margin" );
|
||||
|
||||
helpButtonIconShared = true;
|
||||
defaults_initialized = true;
|
||||
}
|
||||
|
||||
@@ -207,6 +234,9 @@ public class FlatButtonUI
|
||||
protected void uninstallDefaults( AbstractButton b ) {
|
||||
super.uninstallDefaults( b );
|
||||
|
||||
oldStyleValues = null;
|
||||
borderShared = null;
|
||||
|
||||
MigLayoutVisualPadding.uninstall( b );
|
||||
defaults_initialized = false;
|
||||
}
|
||||
@@ -228,9 +258,70 @@ public class FlatButtonUI
|
||||
b.revalidate();
|
||||
b.repaint();
|
||||
break;
|
||||
|
||||
case STYLE:
|
||||
case STYLE_CLASS:
|
||||
if( shared && FlatStylingSupport.hasStyleProperty( b ) ) {
|
||||
// unshare component UI if necessary
|
||||
// updateUI() invokes applyStyle() from installUI()
|
||||
b.updateUI();
|
||||
} else
|
||||
installStyle( b );
|
||||
b.revalidate();
|
||||
b.repaint();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void installStyle( AbstractButton b ) {
|
||||
try {
|
||||
applyStyle( b, FlatStylingSupport.getResolvedStyle( b, getStyleType() ) );
|
||||
} catch( RuntimeException ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
String getStyleType() {
|
||||
return "Button";
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void applyStyle( AbstractButton b, Object style ) {
|
||||
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style,
|
||||
(key, value) -> applyStyleProperty( b, key, value ) );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected Object applyStyleProperty( AbstractButton b, String key, Object value ) {
|
||||
if( key.startsWith( "help." ) ) {
|
||||
if( !(helpButtonIcon instanceof FlatHelpButtonIcon) )
|
||||
return new UnknownStyleException( key );
|
||||
|
||||
if( helpButtonIconShared ) {
|
||||
helpButtonIcon = FlatStylingSupport.cloneIcon( helpButtonIcon );
|
||||
helpButtonIconShared = false;
|
||||
}
|
||||
|
||||
key = key.substring( "help.".length() );
|
||||
return ((FlatHelpButtonIcon)helpButtonIcon).applyStyleProperty( key, value );
|
||||
}
|
||||
|
||||
if( borderShared == null )
|
||||
borderShared = new AtomicBoolean( true );
|
||||
return FlatStylingSupport.applyToAnnotatedObjectOrBorder( this, key, value, b, borderShared );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||
Map<String, Class<?>> infos = FlatStylingSupport.getAnnotatedStyleableInfos( this, c.getBorder() );
|
||||
if( helpButtonIcon instanceof FlatHelpButtonIcon )
|
||||
FlatStylingSupport.putAllPrefixKey( infos, "help.", ((FlatHelpButtonIcon)helpButtonIcon).getStyleableInfos() );
|
||||
return infos;
|
||||
}
|
||||
|
||||
static boolean isContentAreaFilled( Component c ) {
|
||||
return !(c instanceof AbstractButton) || ((AbstractButton)c).isContentAreaFilled();
|
||||
}
|
||||
@@ -268,11 +359,11 @@ public class FlatButtonUI
|
||||
if( !(c instanceof AbstractButton) )
|
||||
return TYPE_OTHER;
|
||||
|
||||
Object value = ((AbstractButton)c).getClientProperty( BUTTON_TYPE );
|
||||
if( !(value instanceof String) )
|
||||
String value = getButtonTypeStr( (AbstractButton) c );
|
||||
if( value == null )
|
||||
return TYPE_OTHER;
|
||||
|
||||
switch( (String) value ) {
|
||||
switch( value ) {
|
||||
case BUTTON_TYPE_SQUARE: return TYPE_SQUARE;
|
||||
case BUTTON_TYPE_ROUND_RECT: return TYPE_ROUND_RECT;
|
||||
default: return TYPE_OTHER;
|
||||
@@ -280,16 +371,27 @@ public class FlatButtonUI
|
||||
}
|
||||
|
||||
static boolean isHelpButton( Component c ) {
|
||||
return c instanceof JButton && clientPropertyEquals( (JButton) c, BUTTON_TYPE, BUTTON_TYPE_HELP );
|
||||
return c instanceof JButton && BUTTON_TYPE_HELP.equals( getButtonTypeStr( (JButton) c ) );
|
||||
}
|
||||
|
||||
static boolean isToolBarButton( Component c ) {
|
||||
return c.getParent() instanceof JToolBar ||
|
||||
(c instanceof AbstractButton && clientPropertyEquals( (AbstractButton) c, BUTTON_TYPE, BUTTON_TYPE_TOOLBAR_BUTTON ));
|
||||
(c instanceof AbstractButton && BUTTON_TYPE_TOOLBAR_BUTTON.equals( getButtonTypeStr( (AbstractButton) c ) ));
|
||||
}
|
||||
|
||||
static boolean isBorderlessButton( Component c ) {
|
||||
return c instanceof AbstractButton && clientPropertyEquals( (AbstractButton) c, BUTTON_TYPE, BUTTON_TYPE_BORDERLESS );
|
||||
return c instanceof AbstractButton && BUTTON_TYPE_BORDERLESS.equals( getButtonTypeStr( (AbstractButton) c ) );
|
||||
}
|
||||
|
||||
static String getButtonTypeStr( AbstractButton c ) {
|
||||
// get from client property
|
||||
Object value = c.getClientProperty( BUTTON_TYPE );
|
||||
if( value instanceof String )
|
||||
return (String) value;
|
||||
|
||||
// get from styling property
|
||||
ButtonUI ui = c.getUI();
|
||||
return (ui instanceof FlatButtonUI) ? ((FlatButtonUI)ui).buttonType : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -329,8 +431,8 @@ public class FlatButtonUI
|
||||
int width = c.getWidth();
|
||||
int height = c.getHeight();
|
||||
|
||||
if( isToolBarButton ) {
|
||||
Insets spacing = UIScale.scale( toolbarSpacingInsets );
|
||||
if( isToolBarButton && c.getBorder() instanceof FlatButtonBorder ) {
|
||||
Insets spacing = UIScale.scale( ((FlatButtonBorder)c.getBorder()).toolbarSpacingInsets );
|
||||
x += spacing.left;
|
||||
y += spacing.top;
|
||||
width -= spacing.left + spacing.right;
|
||||
@@ -339,7 +441,8 @@ public class FlatButtonUI
|
||||
|
||||
// paint shadow
|
||||
Color shadowColor = def ? defaultShadowColor : this.shadowColor;
|
||||
if( shadowColor != null && shadowWidth > 0 && focusWidth > 0 && c.isEnabled() &&
|
||||
if( paintShadow &&
|
||||
shadowColor != null && shadowWidth > 0 && focusWidth > 0 && c.isEnabled() &&
|
||||
!isToolBarButton && !isBorderlessButton( c ) &&
|
||||
!(isFocusPainted( c ) && FlatUIUtils.isPermanentFocusOwner( c )) )
|
||||
{
|
||||
@@ -496,7 +599,7 @@ public class FlatButtonUI
|
||||
|
||||
// make square or apply minimum width/height
|
||||
boolean isIconOnlyOrSingleCharacter = isIconOnlyOrSingleCharacterButton( c );
|
||||
if( clientPropertyBoolean( c, SQUARE_SIZE, false ) ) {
|
||||
if( clientPropertyBoolean( c, SQUARE_SIZE, squareSize ) ) {
|
||||
// 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 ) {
|
||||
@@ -508,7 +611,7 @@ public class FlatButtonUI
|
||||
// apply minimum width/height
|
||||
int fw = Math.round( FlatUIUtils.getBorderFocusWidth( c ) * 2 );
|
||||
prefSize.width = Math.max( prefSize.width, scale( FlatUIUtils.minimumWidth( c, minimumWidth ) ) + fw );
|
||||
prefSize.height = Math.max( prefSize.height, scale( FlatUIUtils.minimumHeight( c, 0 ) ) + fw );
|
||||
prefSize.height = Math.max( prefSize.height, scale( FlatUIUtils.minimumHeight( c, minimumHeight ) ) + fw );
|
||||
}
|
||||
|
||||
return prefSize;
|
||||
|
||||
@@ -18,19 +18,27 @@ package com.formdev.flatlaf.ui;
|
||||
|
||||
import static com.formdev.flatlaf.FlatClientProperties.*;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import javax.swing.Action;
|
||||
import javax.swing.ActionMap;
|
||||
import javax.swing.JFormattedTextField;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.text.BadLocationException;
|
||||
import javax.swing.text.DefaultCaret;
|
||||
import javax.swing.text.DefaultEditorKit;
|
||||
import javax.swing.text.Document;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import javax.swing.text.Utilities;
|
||||
|
||||
/**
|
||||
* Caret that can select all text on focus gained.
|
||||
* Also fixes Swing's double-click-and-drag behavior so that dragging after
|
||||
* a double-click extends selection by whole words.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
@@ -38,12 +46,19 @@ public class FlatCaret
|
||||
extends DefaultCaret
|
||||
implements UIResource
|
||||
{
|
||||
private static final String KEY_CARET_INFO = "FlatLaf.internal.caretInfo";
|
||||
|
||||
private final String selectAllOnFocusPolicy;
|
||||
private final boolean selectAllOnMouseClick;
|
||||
|
||||
private boolean inInstall;
|
||||
private boolean wasFocused;
|
||||
private boolean wasTemporaryLost;
|
||||
private boolean isMousePressed;
|
||||
private boolean isWordSelection;
|
||||
private boolean isLineSelection;
|
||||
private int dragSelectionStart;
|
||||
private int dragSelectionEnd;
|
||||
|
||||
public FlatCaret( String selectAllOnFocusPolicy, boolean selectAllOnMouseClick ) {
|
||||
this.selectAllOnFocusPolicy = selectAllOnFocusPolicy;
|
||||
@@ -52,34 +67,79 @@ public class FlatCaret
|
||||
|
||||
@Override
|
||||
public void install( JTextComponent c ) {
|
||||
super.install( c );
|
||||
// get caret info if switched theme
|
||||
long[] ci = (long[]) c.getClientProperty( KEY_CARET_INFO );
|
||||
if( ci != null ) {
|
||||
c.putClientProperty( KEY_CARET_INFO, null );
|
||||
|
||||
// the dot and mark are lost when switching LaF
|
||||
// --> move dot to end of text so that all text may be selected when it gains focus
|
||||
Document doc = c.getDocument();
|
||||
if( doc != null && getDot() == 0 && getMark() == 0 ) {
|
||||
int length = doc.getLength();
|
||||
if( length > 0 )
|
||||
setDot( length );
|
||||
// if caret info is too old assume that switched from FlatLaf
|
||||
// to another Laf and back to FlatLaf
|
||||
if( System.currentTimeMillis() - 500 > ci[3] )
|
||||
ci = null;
|
||||
}
|
||||
if( ci != null ) {
|
||||
// when switching theme, it is necessary to set blink rate before
|
||||
// invoking super.install() otherwise the caret does not blink
|
||||
setBlinkRate( (int) ci[2] );
|
||||
}
|
||||
|
||||
inInstall = true;
|
||||
try {
|
||||
super.install( c );
|
||||
} finally {
|
||||
inInstall = false;
|
||||
}
|
||||
|
||||
if( ci != null ) {
|
||||
// restore selection
|
||||
select( (int) ci[1], (int) ci[0] );
|
||||
|
||||
// if text component is focused, then caret and selection are visible,
|
||||
// but when switching theme, the component does not yet have
|
||||
// an highlighter and the selection is not painted
|
||||
// --> make selection temporary invisible later, then the caret
|
||||
// adds selection highlights to the text component highlighter
|
||||
if( isSelectionVisible() ) {
|
||||
EventQueue.invokeLater( () -> {
|
||||
if( isSelectionVisible() ) {
|
||||
setSelectionVisible( false );
|
||||
setSelectionVisible( true );
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deinstall( JTextComponent c ) {
|
||||
// remember dot and mark (the selection) when switching theme
|
||||
c.putClientProperty( KEY_CARET_INFO, new long[] {
|
||||
getDot(),
|
||||
getMark(),
|
||||
getBlinkRate(),
|
||||
System.currentTimeMillis(),
|
||||
} );
|
||||
|
||||
super.deinstall( c );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void adjustVisibility( Rectangle nloc ) {
|
||||
JTextComponent c = getComponent();
|
||||
if( c != null && c.getUI() instanceof FlatTextFieldUI ) {
|
||||
Insets padding = ((FlatTextFieldUI)c.getUI()).getPadding();
|
||||
if( padding != null ) {
|
||||
nloc.x -= padding.left;
|
||||
nloc.y -= padding.top;
|
||||
}
|
||||
// need to fix x location because JTextField.scrollRectToVisible() uses insets.left
|
||||
// (as BasicTextUI.getVisibleEditorRect() does),
|
||||
// but FlatTextFieldUI.getVisibleEditorRect() may add some padding
|
||||
Rectangle r = ((FlatTextFieldUI)c.getUI()).getVisibleEditorRect();
|
||||
if( r != null )
|
||||
nloc.x -= r.x - c.getInsets().left;
|
||||
}
|
||||
super.adjustVisibility( nloc );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focusGained( FocusEvent e ) {
|
||||
if( !wasTemporaryLost && (!isMousePressed || selectAllOnMouseClick) )
|
||||
if( !inInstall && !wasTemporaryLost && (!isMousePressed || selectAllOnMouseClick) )
|
||||
selectAllOnFocusGained();
|
||||
wasTemporaryLost = false;
|
||||
wasFocused = true;
|
||||
@@ -97,18 +157,76 @@ public class FlatCaret
|
||||
public void mousePressed( MouseEvent e ) {
|
||||
isMousePressed = true;
|
||||
super.mousePressed( e );
|
||||
|
||||
JTextComponent c = getComponent();
|
||||
|
||||
// left double-click starts word selection
|
||||
isWordSelection = e.getClickCount() == 2 && SwingUtilities.isLeftMouseButton( e ) && !e.isConsumed();
|
||||
|
||||
// left triple-click starts line selection
|
||||
isLineSelection = e.getClickCount() == 3 && SwingUtilities.isLeftMouseButton( e ) && (!e.isConsumed() || c.getDragEnabled());
|
||||
|
||||
// select line
|
||||
// (this is also done in DefaultCaret.mouseClicked(), but this event is
|
||||
// sent when the mouse is released, which is too late for triple-click-and-drag)
|
||||
if( isLineSelection ) {
|
||||
ActionMap actionMap = c.getActionMap();
|
||||
Action selectLineAction = (actionMap != null)
|
||||
? actionMap.get( DefaultEditorKit.selectLineAction )
|
||||
: null;
|
||||
if( selectLineAction != null ) {
|
||||
selectLineAction.actionPerformed( new ActionEvent( c,
|
||||
ActionEvent.ACTION_PERFORMED, null, e.getWhen(), e.getModifiers() ) );
|
||||
}
|
||||
}
|
||||
|
||||
// remember selection where word/line selection starts to keep it always selected while dragging
|
||||
if( isWordSelection || isLineSelection ) {
|
||||
int mark = getMark();
|
||||
int dot = getDot();
|
||||
dragSelectionStart = Math.min( dot, mark );
|
||||
dragSelectionEnd = Math.max( dot, mark );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased( MouseEvent e ) {
|
||||
isMousePressed = false;
|
||||
isWordSelection = false;
|
||||
isLineSelection = false;
|
||||
super.mouseReleased( e );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDragged( MouseEvent e ) {
|
||||
if( (isWordSelection || isLineSelection) &&
|
||||
!e.isConsumed() && SwingUtilities.isLeftMouseButton( e ) )
|
||||
{
|
||||
// fix Swing's double/triple-click-and-drag behavior so that dragging after
|
||||
// a double/triple-click extends selection by whole words/lines
|
||||
JTextComponent c = getComponent();
|
||||
int pos = c.viewToModel( e.getPoint() );
|
||||
if( pos < 0 )
|
||||
return;
|
||||
|
||||
try {
|
||||
if( pos > dragSelectionEnd )
|
||||
select( dragSelectionStart, isWordSelection ? Utilities.getWordEnd( c, pos ) : Utilities.getRowEnd( c, pos ) );
|
||||
else if( pos < dragSelectionStart )
|
||||
select( dragSelectionEnd, isWordSelection ? Utilities.getWordStart( c, pos ) : Utilities.getRowStart( c, pos ) );
|
||||
else
|
||||
select( dragSelectionStart, dragSelectionEnd );
|
||||
} catch( BadLocationException ex ) {
|
||||
UIManager.getLookAndFeel().provideErrorFeedback( c );
|
||||
}
|
||||
} else
|
||||
super.mouseDragged( e );
|
||||
}
|
||||
|
||||
protected void selectAllOnFocusGained() {
|
||||
JTextComponent c = getComponent();
|
||||
Document doc = c.getDocument();
|
||||
if( doc == null || !c.isEnabled() || !c.isEditable() )
|
||||
if( doc == null || !c.isEnabled() || !c.isEditable() || FlatUIUtils.isCellEditor( c ) )
|
||||
return;
|
||||
|
||||
Object selectAllOnFocusPolicy = c.getClientProperty( SELECT_ALL_ON_FOCUS_POLICY );
|
||||
@@ -135,18 +253,21 @@ public class FlatCaret
|
||||
// select all
|
||||
if( c instanceof JFormattedTextField ) {
|
||||
EventQueue.invokeLater( () -> {
|
||||
setDot( 0 );
|
||||
moveDot( doc.getLength() );
|
||||
select( 0, doc.getLength() );
|
||||
} );
|
||||
} else {
|
||||
setDot( 0 );
|
||||
moveDot( doc.getLength() );
|
||||
select( 0, doc.getLength() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.4
|
||||
*/
|
||||
private void select( int mark, int dot ) {
|
||||
if( mark != getMark() )
|
||||
setDot( mark );
|
||||
if( dot != getDot() )
|
||||
moveDot( dot );
|
||||
}
|
||||
|
||||
/** @since 1.4 */
|
||||
public void scrollCaretToVisible() {
|
||||
JTextComponent c = getComponent();
|
||||
if( c == null || c.getUI() == null )
|
||||
|
||||
@@ -16,13 +16,19 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Map;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicCheckBoxMenuItemUI;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JCheckBoxMenuItem}.
|
||||
@@ -54,13 +60,22 @@ import javax.swing.plaf.basic.BasicCheckBoxMenuItemUI;
|
||||
*/
|
||||
public class FlatCheckBoxMenuItemUI
|
||||
extends BasicCheckBoxMenuItemUI
|
||||
implements StyleableUI
|
||||
{
|
||||
private FlatMenuItemRenderer renderer;
|
||||
private Map<String, Object> oldStyleValues;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatCheckBoxMenuItemUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
installStyle();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
@@ -75,12 +90,59 @@ public class FlatCheckBoxMenuItemUI
|
||||
super.uninstallDefaults();
|
||||
|
||||
renderer = null;
|
||||
oldStyleValues = null;
|
||||
}
|
||||
|
||||
protected FlatMenuItemRenderer createRenderer() {
|
||||
return new FlatMenuItemRenderer( menuItem, checkIcon, arrowIcon, acceleratorFont, acceleratorDelimiter );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PropertyChangeListener createPropertyChangeListener( JComponent c ) {
|
||||
return FlatStylingSupport.createPropertyChangeListener( c, this::installStyle, super.createPropertyChangeListener( c ) );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void installStyle() {
|
||||
try {
|
||||
applyStyle( FlatStylingSupport.getResolvedStyle( menuItem, "CheckBoxMenuItem" ) );
|
||||
} catch( RuntimeException ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void applyStyle( Object style ) {
|
||||
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected Object applyStyleProperty( String key, Object value ) {
|
||||
try {
|
||||
return renderer.applyStyleProperty( key, value );
|
||||
} catch ( UnknownStyleException ex ) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
Object oldValue;
|
||||
switch( key ) {
|
||||
// BasicMenuItemUI
|
||||
case "selectionBackground": oldValue = selectionBackground; selectionBackground = (Color) value; return oldValue;
|
||||
case "selectionForeground": oldValue = selectionForeground; selectionForeground = (Color) value; return oldValue;
|
||||
case "disabledForeground": oldValue = disabledForeground; disabledForeground = (Color) value; return oldValue;
|
||||
case "acceleratorForeground": oldValue = acceleratorForeground; acceleratorForeground = (Color) value; return oldValue;
|
||||
case "acceleratorSelectionForeground": oldValue = acceleratorSelectionForeground; acceleratorSelectionForeground = (Color) value; return oldValue;
|
||||
}
|
||||
|
||||
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, menuItem, key, value );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||
return FlatMenuItemUI.getStyleableInfos( renderer );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dimension getPreferredMenuItemSize( JComponent c, Icon checkIcon, Icon arrowIcon, int defaultTextIconGap ) {
|
||||
return renderer.getPreferredMenuItemSize();
|
||||
|
||||
@@ -43,11 +43,24 @@ public class FlatCheckBoxUI
|
||||
extends FlatRadioButtonUI
|
||||
{
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return FlatUIUtils.createSharedUI( FlatCheckBoxUI.class, FlatCheckBoxUI::new );
|
||||
return FlatUIUtils.canUseSharedUI( c )
|
||||
? FlatUIUtils.createSharedUI( FlatCheckBoxUI.class, () -> new FlatCheckBoxUI( true ) )
|
||||
: new FlatCheckBoxUI( false );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected FlatCheckBoxUI( boolean shared ) {
|
||||
super( shared );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPropertyPrefix() {
|
||||
return "CheckBox.";
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
String getStyleType() {
|
||||
return "CheckBox";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import static com.formdev.flatlaf.FlatClientProperties.*;
|
||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import static com.formdev.flatlaf.util.UIScale.unscale;
|
||||
import java.awt.Color;
|
||||
@@ -41,6 +42,8 @@ import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.CellRendererPane;
|
||||
@@ -66,7 +69,9 @@ import javax.swing.plaf.basic.BasicComboBoxUI;
|
||||
import javax.swing.plaf.basic.BasicComboPopup;
|
||||
import javax.swing.plaf.basic.ComboPopup;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
|
||||
/**
|
||||
@@ -89,8 +94,6 @@ import com.formdev.flatlaf.util.SystemInfo;
|
||||
* @uiDefault ComboBox.buttonStyle String auto (default), button or none
|
||||
* @uiDefault Component.arrowType String chevron (default) or triangle
|
||||
* @uiDefault Component.isIntelliJTheme boolean
|
||||
* @uiDefault Component.borderColor Color
|
||||
* @uiDefault Component.disabledBorderColor Color
|
||||
* @uiDefault ComboBox.editableBackground Color optional; defaults to ComboBox.background
|
||||
* @uiDefault ComboBox.focusedBackground Color optional
|
||||
* @uiDefault ComboBox.disabledBackground Color
|
||||
@@ -98,6 +101,9 @@ import com.formdev.flatlaf.util.SystemInfo;
|
||||
* @uiDefault ComboBox.buttonBackground Color
|
||||
* @uiDefault ComboBox.buttonEditableBackground Color
|
||||
* @uiDefault ComboBox.buttonFocusedBackground Color optional; defaults to ComboBox.focusedBackground
|
||||
* @uiDefault ComboBox.buttonSeparatorWidth int or float optional; defaults to Component.borderWidth
|
||||
* @uiDefault ComboBox.buttonSeparatorColor Color optional
|
||||
* @uiDefault ComboBox.buttonDisabledSeparatorColor Color optional
|
||||
* @uiDefault ComboBox.buttonArrowColor Color
|
||||
* @uiDefault ComboBox.buttonDisabledArrowColor Color
|
||||
* @uiDefault ComboBox.buttonHoverArrowColor Color
|
||||
@@ -108,29 +114,31 @@ import com.formdev.flatlaf.util.SystemInfo;
|
||||
*/
|
||||
public class FlatComboBoxUI
|
||||
extends BasicComboBoxUI
|
||||
implements StyleableUI
|
||||
{
|
||||
protected int minimumWidth;
|
||||
protected int editorColumns;
|
||||
protected String buttonStyle;
|
||||
protected String arrowType;
|
||||
@Styleable protected int minimumWidth;
|
||||
@Styleable protected int editorColumns;
|
||||
@Styleable protected String buttonStyle;
|
||||
@Styleable protected String arrowType;
|
||||
protected boolean isIntelliJTheme;
|
||||
protected Color borderColor;
|
||||
protected Color disabledBorderColor;
|
||||
|
||||
protected Color editableBackground;
|
||||
protected Color focusedBackground;
|
||||
protected Color disabledBackground;
|
||||
protected Color disabledForeground;
|
||||
@Styleable protected Color editableBackground;
|
||||
@Styleable protected Color focusedBackground;
|
||||
@Styleable protected Color disabledBackground;
|
||||
@Styleable protected Color disabledForeground;
|
||||
|
||||
protected Color buttonBackground;
|
||||
protected Color buttonEditableBackground;
|
||||
protected Color buttonFocusedBackground;
|
||||
protected Color buttonArrowColor;
|
||||
protected Color buttonDisabledArrowColor;
|
||||
protected Color buttonHoverArrowColor;
|
||||
protected Color buttonPressedArrowColor;
|
||||
@Styleable protected Color buttonBackground;
|
||||
@Styleable protected Color buttonEditableBackground;
|
||||
@Styleable protected Color buttonFocusedBackground;
|
||||
/** @since 2 */ @Styleable protected float buttonSeparatorWidth;
|
||||
/** @since 2 */ @Styleable protected Color buttonSeparatorColor;
|
||||
/** @since 2 */ @Styleable protected Color buttonDisabledSeparatorColor;
|
||||
@Styleable protected Color buttonArrowColor;
|
||||
@Styleable protected Color buttonDisabledArrowColor;
|
||||
@Styleable protected Color buttonHoverArrowColor;
|
||||
@Styleable protected Color buttonPressedArrowColor;
|
||||
|
||||
protected Color popupBackground;
|
||||
@Styleable protected Color popupBackground;
|
||||
|
||||
private MouseListener hoverListener;
|
||||
protected boolean hover;
|
||||
@@ -138,10 +146,20 @@ public class FlatComboBoxUI
|
||||
|
||||
private CellPaddingBorder paddingBorder;
|
||||
|
||||
private Map<String, Object> oldStyleValues;
|
||||
private AtomicBoolean borderShared;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatComboBoxUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
installStyle();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installListeners() {
|
||||
super.installListeners();
|
||||
@@ -198,8 +216,6 @@ public class FlatComboBoxUI
|
||||
buttonStyle = UIManager.getString( "ComboBox.buttonStyle" );
|
||||
arrowType = UIManager.getString( "Component.arrowType" );
|
||||
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
||||
borderColor = UIManager.getColor( "Component.borderColor" );
|
||||
disabledBorderColor = UIManager.getColor( "Component.disabledBorderColor" );
|
||||
|
||||
editableBackground = UIManager.getColor( "ComboBox.editableBackground" );
|
||||
focusedBackground = UIManager.getColor( "ComboBox.focusedBackground" );
|
||||
@@ -209,6 +225,9 @@ public class FlatComboBoxUI
|
||||
buttonBackground = UIManager.getColor( "ComboBox.buttonBackground" );
|
||||
buttonFocusedBackground = UIManager.getColor( "ComboBox.buttonFocusedBackground" );
|
||||
buttonEditableBackground = UIManager.getColor( "ComboBox.buttonEditableBackground" );
|
||||
buttonSeparatorWidth = FlatUIUtils.getUIFloat( "ComboBox.buttonSeparatorWidth", FlatUIUtils.getUIFloat( "Component.borderWidth", 1 ) );
|
||||
buttonSeparatorColor = UIManager.getColor( "ComboBox.buttonSeparatorColor" );
|
||||
buttonDisabledSeparatorColor = UIManager.getColor( "ComboBox.buttonDisabledSeparatorColor" );
|
||||
buttonArrowColor = UIManager.getColor( "ComboBox.buttonArrowColor" );
|
||||
buttonDisabledArrowColor = UIManager.getColor( "ComboBox.buttonDisabledArrowColor" );
|
||||
buttonHoverArrowColor = UIManager.getColor( "ComboBox.buttonHoverArrowColor" );
|
||||
@@ -230,9 +249,6 @@ public class FlatComboBoxUI
|
||||
protected void uninstallDefaults() {
|
||||
super.uninstallDefaults();
|
||||
|
||||
borderColor = null;
|
||||
disabledBorderColor = null;
|
||||
|
||||
editableBackground = null;
|
||||
focusedBackground = null;
|
||||
disabledBackground = null;
|
||||
@@ -241,6 +257,8 @@ public class FlatComboBoxUI
|
||||
buttonBackground = null;
|
||||
buttonEditableBackground = null;
|
||||
buttonFocusedBackground = null;
|
||||
buttonSeparatorColor = null;
|
||||
buttonDisabledSeparatorColor = null;
|
||||
buttonArrowColor = null;
|
||||
buttonDisabledArrowColor = null;
|
||||
buttonHoverArrowColor = null;
|
||||
@@ -250,6 +268,9 @@ public class FlatComboBoxUI
|
||||
|
||||
paddingBorder.uninstall();
|
||||
|
||||
oldStyleValues = null;
|
||||
borderShared = null;
|
||||
|
||||
MigLayoutVisualPadding.uninstall( comboBox );
|
||||
}
|
||||
|
||||
@@ -322,12 +343,29 @@ public class FlatComboBoxUI
|
||||
} else if( editor != null && source == comboBox && propertyName == "componentOrientation" ) {
|
||||
ComponentOrientation o = (ComponentOrientation) e.getNewValue();
|
||||
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();
|
||||
} else {
|
||||
switch( propertyName ) {
|
||||
case PLACEHOLDER_TEXT:
|
||||
if( editor != null )
|
||||
editor.repaint();
|
||||
break;
|
||||
|
||||
case COMPONENT_ROUND_RECT:
|
||||
comboBox.repaint();
|
||||
break;
|
||||
|
||||
case MINIMUM_WIDTH:
|
||||
comboBox.revalidate();
|
||||
break;
|
||||
|
||||
case STYLE:
|
||||
case STYLE_CLASS:
|
||||
installStyle();
|
||||
comboBox.revalidate();
|
||||
comboBox.repaint();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -395,7 +433,7 @@ public class FlatComboBoxUI
|
||||
unscale( Math.max( scale( padding.right ) - insets.right, 0 ) )
|
||||
);
|
||||
}
|
||||
textField.putClientProperty( FlatClientProperties.TEXT_FIELD_PADDING, pad );
|
||||
textField.putClientProperty( TEXT_FIELD_PADDING, pad );
|
||||
}
|
||||
|
||||
private void updateEditorColors() {
|
||||
@@ -414,6 +452,58 @@ public class FlatComboBoxUI
|
||||
return new FlatComboBoxButton();
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void installStyle() {
|
||||
try {
|
||||
applyStyle( FlatStylingSupport.getResolvedStyle( comboBox, "ComboBox" ) );
|
||||
} catch( RuntimeException ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void applyStyle( Object style ) {
|
||||
Insets oldPadding = padding;
|
||||
int oldEditorColumns = editorColumns;
|
||||
|
||||
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
|
||||
|
||||
if( !padding.equals( oldPadding ) ) {
|
||||
paddingBorder.padding = padding;
|
||||
updateEditorPadding();
|
||||
}
|
||||
if( arrowButton instanceof FlatComboBoxButton )
|
||||
((FlatComboBoxButton)arrowButton).updateStyle();
|
||||
if( popup instanceof FlatComboPopup )
|
||||
((FlatComboPopup)popup).updateStyle();
|
||||
if( editorColumns != oldEditorColumns && editor instanceof JTextField )
|
||||
((JTextField)editor).setColumns( editorColumns );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected Object applyStyleProperty( String key, Object value ) {
|
||||
// BasicComboBoxUI
|
||||
if( key.equals( "padding" ) ) {
|
||||
Object oldValue = padding;
|
||||
padding = (Insets) value;
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
if( borderShared == null )
|
||||
borderShared = new AtomicBoolean( true );
|
||||
return FlatStylingSupport.applyToAnnotatedObjectOrBorder( this, key, value, comboBox, borderShared );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||
Map<String, Class<?>> infos = new FlatStylingSupport.StyleableInfosMap<>();
|
||||
infos.put( "padding", Insets.class );
|
||||
FlatStylingSupport.collectAnnotatedStyleableInfos( this, infos );
|
||||
FlatStylingSupport.collectStyleableInfos( comboBox.getBorder(), infos );
|
||||
return infos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update( Graphics g, JComponent c ) {
|
||||
float focusWidth = FlatUIUtils.getBorderFocusWidth( c );
|
||||
@@ -466,10 +556,13 @@ public class FlatComboBoxUI
|
||||
|
||||
// paint vertical line between value and arrow button
|
||||
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)) );
|
||||
Color separatorColor = enabled ? buttonSeparatorColor : buttonDisabledSeparatorColor;
|
||||
if( separatorColor != null ) {
|
||||
g2.setColor( separatorColor );
|
||||
float lw = scale( buttonSeparatorWidth );
|
||||
float lx = isLeftToRight ? arrowX : arrowX + arrowWidth - lw;
|
||||
g2.fill( new Rectangle2D.Float( lx, focusWidth, lw, height - 1 - (focusWidth * 2)) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -482,6 +575,22 @@ public class FlatComboBoxUI
|
||||
@Override
|
||||
@SuppressWarnings( "unchecked" )
|
||||
public void paintCurrentValue( Graphics g, Rectangle bounds, boolean hasFocus ) {
|
||||
// apply clipping using rounded rectangle to avoid that renderer paints
|
||||
// outside of border if combobox uses larger arc for edges
|
||||
// (e.g. FlatClientProperties.COMPONENT_ROUND_RECT is true)
|
||||
FlatBorder border = FlatUIUtils.getOutsideFlatBorder( comboBox );
|
||||
if( border != null ) {
|
||||
int clipArc = border.getArc( comboBox ) - (border.getLineWidth( comboBox ) * 2);
|
||||
if( clipArc > 0 ) {
|
||||
int x = bounds.x;
|
||||
int width = bounds.width + bounds.height;
|
||||
if( !comboBox.getComponentOrientation().isLeftToRight() )
|
||||
x -= bounds.height;
|
||||
((Graphics2D)g).clip( FlatUIUtils.createComponentRectangle(
|
||||
x, bounds.y, width, bounds.height, scale( (float) clipArc ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
paddingBorder.uninstall();
|
||||
|
||||
ListCellRenderer<Object> renderer = comboBox.getRenderer();
|
||||
@@ -584,11 +693,12 @@ public class FlatComboBoxUI
|
||||
return parentParent != null && !comboBox.getBackground().equals( parentParent.getBackground() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.3
|
||||
*/
|
||||
/** @since 1.3 */
|
||||
public static boolean isPermanentFocusOwner( JComboBox<?> comboBox ) {
|
||||
if( comboBox.isEditable() ) {
|
||||
if( FlatUIUtils.isPermanentFocusOwner( comboBox ) )
|
||||
return true;
|
||||
|
||||
Component editorComponent = comboBox.getEditor().getEditorComponent();
|
||||
return (editorComponent != null) ? FlatUIUtils.isPermanentFocusOwner( editorComponent ) : false;
|
||||
} else
|
||||
@@ -612,6 +722,11 @@ public class FlatComboBoxUI
|
||||
hoverForeground, hoverBackground, pressedForeground, pressedBackground );
|
||||
}
|
||||
|
||||
protected void updateStyle() {
|
||||
updateStyle( arrowType, buttonArrowColor, buttonDisabledArrowColor,
|
||||
buttonHoverArrowColor, null, buttonPressedArrowColor, null );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isHover() {
|
||||
return super.isHover() || (!comboBox.isEditable() ? hover : false);
|
||||
@@ -708,6 +823,10 @@ public class FlatComboBoxUI
|
||||
super.configureList();
|
||||
|
||||
list.setCellRenderer( new PopupListCellRenderer() );
|
||||
updateStyle();
|
||||
}
|
||||
|
||||
void updateStyle() {
|
||||
if( popupBackground != null )
|
||||
list.setBackground( popupBackground );
|
||||
}
|
||||
@@ -788,7 +907,7 @@ public class FlatComboBoxUI
|
||||
private static class CellPaddingBorder
|
||||
extends AbstractBorder
|
||||
{
|
||||
private final Insets padding;
|
||||
private Insets padding;
|
||||
private JComponent rendererComponent;
|
||||
private Border rendererBorder;
|
||||
|
||||
@@ -819,7 +938,7 @@ public class FlatComboBoxUI
|
||||
|
||||
// remember old border and replace it
|
||||
rendererBorder = jc.getBorder();
|
||||
rendererComponent.setBorder( this );
|
||||
jc.setBorder( this );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,6 +24,9 @@ import java.awt.Image;
|
||||
import java.awt.Insets;
|
||||
import java.awt.RadialGradientPaint;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.Map;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableBorder;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
@@ -40,14 +43,17 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
*/
|
||||
public class FlatDropShadowBorder
|
||||
extends FlatEmptyBorder
|
||||
implements StyleableBorder
|
||||
{
|
||||
private final Color shadowColor;
|
||||
private final Insets shadowInsets;
|
||||
private final float shadowOpacity;
|
||||
@Styleable protected Color shadowColor;
|
||||
@Styleable protected Insets shadowInsets;
|
||||
@Styleable protected float shadowOpacity;
|
||||
|
||||
private final int shadowSize;
|
||||
private int shadowSize;
|
||||
private Image shadowImage;
|
||||
private Color lastShadowColor;
|
||||
private float lastShadowOpacity;
|
||||
private int lastShadowSize;
|
||||
private double lastSystemScaleFactor;
|
||||
private float lastUserScaleFactor;
|
||||
|
||||
@@ -64,17 +70,43 @@ public class FlatDropShadowBorder
|
||||
}
|
||||
|
||||
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 ) );
|
||||
super( nonNegativeInsets( shadowInsets ) );
|
||||
|
||||
this.shadowColor = shadowColor;
|
||||
this.shadowInsets = shadowInsets;
|
||||
this.shadowOpacity = shadowOpacity;
|
||||
|
||||
shadowSize = Math.max(
|
||||
shadowSize = maxInset( shadowInsets );
|
||||
}
|
||||
|
||||
private static Insets nonNegativeInsets( Insets shadowInsets ) {
|
||||
return new Insets( Math.max( shadowInsets.top, 0 ), Math.max( shadowInsets.left, 0 ),
|
||||
Math.max( shadowInsets.bottom, 0 ), Math.max( shadowInsets.right, 0 ) );
|
||||
}
|
||||
|
||||
private int maxInset( Insets shadowInsets ) {
|
||||
return Math.max(
|
||||
Math.max( shadowInsets.left, shadowInsets.right ),
|
||||
Math.max( shadowInsets.top, shadowInsets.bottom ) );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Object applyStyleProperty( String key, Object value ) {
|
||||
Object oldValue = FlatStylingSupport.applyToAnnotatedObject( this, key, value );
|
||||
if( key.equals( "shadowInsets" ) ) {
|
||||
applyStyleProperty( nonNegativeInsets( shadowInsets ) );
|
||||
shadowSize = maxInset( shadowInsets );
|
||||
}
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos() {
|
||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||
if( shadowSize <= 0 )
|
||||
@@ -91,12 +123,16 @@ public class FlatDropShadowBorder
|
||||
float userScaleFactor = UIScale.getUserScaleFactor();
|
||||
if( shadowImage == null ||
|
||||
!shadowColor.equals( lastShadowColor ) ||
|
||||
lastShadowOpacity != shadowOpacity ||
|
||||
lastShadowSize != shadowSize ||
|
||||
lastSystemScaleFactor != scaleFactor ||
|
||||
lastUserScaleFactor != userScaleFactor )
|
||||
{
|
||||
shadowImage = createShadowImage( shadowColor, shadowSize, shadowOpacity,
|
||||
(float) (scaleFactor * userScaleFactor) );
|
||||
lastShadowColor = shadowColor;
|
||||
lastShadowOpacity = shadowOpacity;
|
||||
lastShadowSize = shadowSize;
|
||||
lastSystemScaleFactor = scaleFactor;
|
||||
lastUserScaleFactor = userScaleFactor;
|
||||
}
|
||||
|
||||
@@ -24,14 +24,19 @@ import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.util.Map;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JEditorPane;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicEditorPaneUI;
|
||||
import javax.swing.text.Caret;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JEditorPane}.
|
||||
@@ -61,20 +66,35 @@ import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
*/
|
||||
public class FlatEditorPaneUI
|
||||
extends BasicEditorPaneUI
|
||||
implements StyleableUI
|
||||
{
|
||||
protected int minimumWidth;
|
||||
@Styleable protected int minimumWidth;
|
||||
protected boolean isIntelliJTheme;
|
||||
protected Color focusedBackground;
|
||||
private Color background;
|
||||
@Styleable protected Color disabledBackground;
|
||||
@Styleable protected Color inactiveBackground;
|
||||
@Styleable protected Color focusedBackground;
|
||||
|
||||
private Color oldDisabledBackground;
|
||||
private Color oldInactiveBackground;
|
||||
|
||||
private Insets defaultMargin;
|
||||
|
||||
private Object oldHonorDisplayProperties;
|
||||
private FocusListener focusListener;
|
||||
private Map<String, Object> oldStyleValues;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatEditorPaneUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
installStyle();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
@@ -82,6 +102,9 @@ public class FlatEditorPaneUI
|
||||
String prefix = getPropertyPrefix();
|
||||
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
||||
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
||||
background = UIManager.getColor( prefix + ".background" );
|
||||
disabledBackground = UIManager.getColor( prefix + ".disabledBackground" );
|
||||
inactiveBackground = UIManager.getColor( prefix + ".inactiveBackground" );
|
||||
focusedBackground = UIManager.getColor( prefix + ".focusedBackground" );
|
||||
|
||||
defaultMargin = UIManager.getInsets( prefix + ".margin" );
|
||||
@@ -95,8 +118,16 @@ public class FlatEditorPaneUI
|
||||
protected void uninstallDefaults() {
|
||||
super.uninstallDefaults();
|
||||
|
||||
background = null;
|
||||
disabledBackground = null;
|
||||
inactiveBackground = null;
|
||||
focusedBackground = null;
|
||||
|
||||
oldDisabledBackground = null;
|
||||
oldInactiveBackground = null;
|
||||
|
||||
oldStyleValues = null;
|
||||
|
||||
getComponent().putClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES, oldHonorDisplayProperties );
|
||||
}
|
||||
|
||||
@@ -118,19 +149,72 @@ public class FlatEditorPaneUI
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void propertyChange( PropertyChangeEvent e ) {
|
||||
super.propertyChange( e );
|
||||
propertyChange( getComponent(), e );
|
||||
protected Caret createCaret() {
|
||||
return new FlatCaret( null, false );
|
||||
}
|
||||
|
||||
static void propertyChange( JTextComponent c, PropertyChangeEvent e ) {
|
||||
@Override
|
||||
protected void propertyChange( PropertyChangeEvent e ) {
|
||||
// invoke updateBackground() before super.propertyChange()
|
||||
String propertyName = e.getPropertyName();
|
||||
if( "editable".equals( propertyName ) || "enabled".equals( propertyName ) )
|
||||
updateBackground();
|
||||
|
||||
super.propertyChange( e );
|
||||
propertyChange( getComponent(), e, this::installStyle );
|
||||
}
|
||||
|
||||
static void propertyChange( JTextComponent c, PropertyChangeEvent e, Runnable installStyle ) {
|
||||
switch( e.getPropertyName() ) {
|
||||
case FlatClientProperties.MINIMUM_WIDTH:
|
||||
c.revalidate();
|
||||
break;
|
||||
|
||||
case FlatClientProperties.STYLE:
|
||||
case FlatClientProperties.STYLE_CLASS:
|
||||
installStyle.run();
|
||||
c.revalidate();
|
||||
c.repaint();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void installStyle() {
|
||||
try {
|
||||
applyStyle( FlatStylingSupport.getResolvedStyle( getComponent(), "EditorPane" ) );
|
||||
} catch( RuntimeException ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void applyStyle( Object style ) {
|
||||
oldDisabledBackground = disabledBackground;
|
||||
oldInactiveBackground = inactiveBackground;
|
||||
|
||||
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
|
||||
|
||||
updateBackground();
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected Object applyStyleProperty( String key, Object value ) {
|
||||
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, getComponent(), key, value );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
||||
}
|
||||
|
||||
private void updateBackground() {
|
||||
FlatTextFieldUI.updateBackground( getComponent(), background,
|
||||
disabledBackground, inactiveBackground,
|
||||
oldDisabledBackground, oldInactiveBackground );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize( JComponent c ) {
|
||||
return applyMinimumWidth( c, super.getPreferredSize( c ), minimumWidth, defaultMargin );
|
||||
|
||||
@@ -50,6 +50,12 @@ public class FlatEmptyBorder
|
||||
|
||||
@Override
|
||||
public Insets getBorderInsets( Component c, Insets insets ) {
|
||||
return scaleInsets( c, insets, top, left, bottom, right );
|
||||
}
|
||||
|
||||
protected static Insets scaleInsets( Component c, Insets insets,
|
||||
int top, int left, int bottom, int right )
|
||||
{
|
||||
boolean leftToRight = left == right || c.getComponentOrientation().isLeftToRight();
|
||||
insets.left = scale( leftToRight ? left : right );
|
||||
insets.top = scale( top );
|
||||
@@ -61,4 +67,13 @@ public class FlatEmptyBorder
|
||||
public Insets getUnscaledBorderInsets() {
|
||||
return super.getBorderInsets();
|
||||
}
|
||||
|
||||
public Object applyStyleProperty( Insets insets ) {
|
||||
Insets oldInsets = getUnscaledBorderInsets();
|
||||
top = insets.top;
|
||||
left = insets.left;
|
||||
bottom = insets.bottom;
|
||||
right = insets.right;
|
||||
return oldInsets;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ import javax.swing.plaf.ComponentUI;
|
||||
* @uiDefault Component.isIntelliJTheme boolean
|
||||
* @uiDefault FormattedTextField.placeholderForeground Color
|
||||
* @uiDefault FormattedTextField.focusedBackground Color optional
|
||||
* @uiDefault FormattedTextField.iconTextGap int optional, default is 4
|
||||
* @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always
|
||||
* @uiDefault TextComponent.selectAllOnMouseClick boolean
|
||||
*
|
||||
@@ -59,4 +60,10 @@ public class FlatFormattedTextFieldUI
|
||||
protected String getPropertyPrefix() {
|
||||
return "FormattedTextField";
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
String getStyleType() {
|
||||
return "FormattedTextField";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,9 @@ import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JInternalFrame;
|
||||
import javax.swing.LookAndFeel;
|
||||
@@ -31,6 +34,10 @@ import javax.swing.UIManager;
|
||||
import javax.swing.event.MouseInputAdapter;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicInternalFrameUI;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableBorder;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JInternalFrame}.
|
||||
@@ -86,9 +93,13 @@ import javax.swing.plaf.basic.BasicInternalFrameUI;
|
||||
*/
|
||||
public class FlatInternalFrameUI
|
||||
extends BasicInternalFrameUI
|
||||
implements StyleableUI
|
||||
{
|
||||
protected FlatWindowResizer windowResizer;
|
||||
|
||||
private Map<String, Object> oldStyleValues;
|
||||
private AtomicBoolean borderShared;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatInternalFrameUI( (JInternalFrame) c );
|
||||
}
|
||||
@@ -104,6 +115,8 @@ public class FlatInternalFrameUI
|
||||
LookAndFeel.installProperty( frame, "opaque", false );
|
||||
|
||||
windowResizer = createWindowResizer();
|
||||
|
||||
installStyle();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -114,6 +127,9 @@ public class FlatInternalFrameUI
|
||||
windowResizer.uninstall();
|
||||
windowResizer = null;
|
||||
}
|
||||
|
||||
oldStyleValues = null;
|
||||
borderShared = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -130,15 +146,49 @@ public class FlatInternalFrameUI
|
||||
return new FlatBorderListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PropertyChangeListener createPropertyChangeListener() {
|
||||
return FlatStylingSupport.createPropertyChangeListener( frame, this::installStyle,
|
||||
super.createPropertyChangeListener() );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void installStyle() {
|
||||
try {
|
||||
applyStyle( FlatStylingSupport.getResolvedStyle( frame, "InternalFrame" ) );
|
||||
} catch( RuntimeException ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void applyStyle( Object style ) {
|
||||
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected Object applyStyleProperty( String key, Object value ) {
|
||||
if( borderShared == null )
|
||||
borderShared = new AtomicBoolean( true );
|
||||
return FlatStylingSupport.applyToAnnotatedObjectOrBorder( this, key, value, frame, borderShared );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this, frame.getBorder() );
|
||||
}
|
||||
|
||||
//---- class FlatInternalFrameBorder --------------------------------------
|
||||
|
||||
public static class FlatInternalFrameBorder
|
||||
extends FlatEmptyBorder
|
||||
implements StyleableBorder
|
||||
{
|
||||
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" );
|
||||
@Styleable protected Color activeBorderColor = UIManager.getColor( "InternalFrame.activeBorderColor" );
|
||||
@Styleable protected Color inactiveBorderColor = UIManager.getColor( "InternalFrame.inactiveBorderColor" );
|
||||
@Styleable protected int borderLineWidth = FlatUIUtils.getUIInt( "InternalFrame.borderLineWidth", 1 );
|
||||
@Styleable protected boolean dropShadowPainted = UIManager.getBoolean( "InternalFrame.dropShadowPainted" );
|
||||
|
||||
private final FlatDropShadowBorder activeDropShadowBorder = new FlatDropShadowBorder(
|
||||
UIManager.getColor( "InternalFrame.activeDropShadowColor" ),
|
||||
@@ -153,6 +203,36 @@ public class FlatInternalFrameUI
|
||||
super( UIManager.getInsets( "InternalFrame.borderMargins" ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object applyStyleProperty( String key, Object value ) {
|
||||
switch( key ) {
|
||||
case "borderMargins": return applyStyleProperty( (Insets) value );
|
||||
|
||||
case "activeDropShadowColor": return activeDropShadowBorder.applyStyleProperty( "shadowColor", value );
|
||||
case "activeDropShadowInsets": return activeDropShadowBorder.applyStyleProperty( "shadowInsets", value );
|
||||
case "activeDropShadowOpacity": return activeDropShadowBorder.applyStyleProperty( "shadowOpacity", value );
|
||||
case "inactiveDropShadowColor": return inactiveDropShadowBorder.applyStyleProperty( "shadowColor", value );
|
||||
case "inactiveDropShadowInsets": return inactiveDropShadowBorder.applyStyleProperty( "shadowInsets", value );
|
||||
case "inactiveDropShadowOpacity": return inactiveDropShadowBorder.applyStyleProperty( "shadowOpacity", value );
|
||||
}
|
||||
|
||||
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos() {
|
||||
Map<String, Class<?>> infos = new FlatStylingSupport.StyleableInfosMap<>();
|
||||
FlatStylingSupport.collectAnnotatedStyleableInfos( this, infos );
|
||||
infos.put( "borderMargins", Insets.class );
|
||||
infos.put( "activeDropShadowColor", Color.class );
|
||||
infos.put( "activeDropShadowInsets", Insets.class );
|
||||
infos.put( "activeDropShadowOpacity", float.class );
|
||||
infos.put( "inactiveDropShadowColor", Color.class );
|
||||
infos.put( "inactiveDropShadowInsets", Insets.class );
|
||||
infos.put( "inactiveDropShadowOpacity", float.class );
|
||||
return infos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Insets getBorderInsets( Component c, Insets insets ) {
|
||||
if( c instanceof JInternalFrame && ((JInternalFrame)c).isMaximum() ) {
|
||||
@@ -206,9 +286,7 @@ public class FlatInternalFrameUI
|
||||
|
||||
//---- class FlatBorderListener -------------------------------------------
|
||||
|
||||
/**
|
||||
* @since 1.6
|
||||
*/
|
||||
/** @since 1.6 */
|
||||
protected class FlatBorderListener
|
||||
extends BorderListener
|
||||
{
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.awt.Rectangle;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComponent;
|
||||
@@ -33,8 +34,12 @@ import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicHTML;
|
||||
import javax.swing.plaf.basic.BasicLabelUI;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
@@ -54,13 +59,30 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
*/
|
||||
public class FlatLabelUI
|
||||
extends BasicLabelUI
|
||||
implements StyleableUI
|
||||
{
|
||||
private Color disabledForeground;
|
||||
@Styleable protected Color disabledForeground;
|
||||
|
||||
private final boolean shared;
|
||||
private boolean defaults_initialized = false;
|
||||
private Map<String, Object> oldStyleValues;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return FlatUIUtils.createSharedUI( FlatLabelUI.class, FlatLabelUI::new );
|
||||
return FlatUIUtils.canUseSharedUI( c )
|
||||
? FlatUIUtils.createSharedUI( FlatLabelUI.class, () -> new FlatLabelUI( true ) )
|
||||
: new FlatLabelUI( false );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected FlatLabelUI( boolean shared ) {
|
||||
this.shared = shared;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
installStyle( (JLabel) c );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -77,7 +99,9 @@ public class FlatLabelUI
|
||||
@Override
|
||||
protected void uninstallDefaults( JLabel c ) {
|
||||
super.uninstallDefaults( c );
|
||||
|
||||
defaults_initialized = false;
|
||||
oldStyleValues = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -94,10 +118,46 @@ public class FlatLabelUI
|
||||
if( name == "text" || name == "font" || name == "foreground" ) {
|
||||
JLabel label = (JLabel) e.getSource();
|
||||
updateHTMLRenderer( label, label.getText(), true );
|
||||
} else if( name.equals( FlatClientProperties.STYLE ) || name.equals( FlatClientProperties.STYLE_CLASS ) ) {
|
||||
JLabel label = (JLabel) e.getSource();
|
||||
if( shared && FlatStylingSupport.hasStyleProperty( label ) ) {
|
||||
// unshare component UI if necessary
|
||||
// updateUI() invokes applyStyle() from installUI()
|
||||
label.updateUI();
|
||||
} else
|
||||
installStyle( label );
|
||||
label.revalidate();
|
||||
label.repaint();
|
||||
} else
|
||||
super.propertyChange( e );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void installStyle( JLabel c ) {
|
||||
try {
|
||||
applyStyle( c, FlatStylingSupport.getResolvedStyle( c, "Label" ) );
|
||||
} catch( RuntimeException ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void applyStyle( JLabel c, Object style ) {
|
||||
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style,
|
||||
(key, value) -> applyStyleProperty( c, key, value ) );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected Object applyStyleProperty( JLabel c, String key, Object value ) {
|
||||
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, c, key, value );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether text contains HTML tags that use "absolute-size" keywords
|
||||
* (e.g. "x-large") for font-size in default style sheet
|
||||
|
||||
@@ -61,8 +61,8 @@ public class FlatLineBorder
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
try {
|
||||
FlatUIUtils.setRenderingHints( g2 );
|
||||
g2.setColor( lineColor );
|
||||
FlatUIUtils.paintComponentBorder( g2, x, y, width, height, 0f, scale( lineThickness ), 0f );
|
||||
FlatUIUtils.paintOutlinedComponent( g2, x, y, width, height,
|
||||
0, 0, 0, scale( getLineThickness() ), 0, null, getLineColor(), null );
|
||||
} finally {
|
||||
g2.dispose();
|
||||
}
|
||||
|
||||
@@ -16,11 +16,15 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Insets;
|
||||
import java.util.function.Function;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ListUI;
|
||||
|
||||
/**
|
||||
* Cell border for {@link javax.swing.DefaultListCellRenderer}
|
||||
@@ -33,12 +37,54 @@ import javax.swing.UIManager;
|
||||
public class FlatListCellBorder
|
||||
extends FlatLineBorder
|
||||
{
|
||||
final boolean showCellFocusIndicator = UIManager.getBoolean( "List.showCellFocusIndicator" );
|
||||
protected boolean showCellFocusIndicator = UIManager.getBoolean( "List.showCellFocusIndicator" );
|
||||
|
||||
private Component c;
|
||||
|
||||
protected FlatListCellBorder() {
|
||||
super( UIManager.getInsets( "List.cellMargins" ), UIManager.getColor( "List.cellFocusColor" ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Insets getBorderInsets( Component c, Insets insets ) {
|
||||
Insets m = getStyleFromListUI( c, ui -> ui.cellMargins );
|
||||
if( m != null )
|
||||
return scaleInsets( c, insets, m.top, m.left, m.bottom, m.right );
|
||||
|
||||
return super.getBorderInsets( c, insets );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getLineColor() {
|
||||
if( c != null ) {
|
||||
Color color = getStyleFromListUI( c, ui -> ui.cellFocusColor );
|
||||
if( color != null )
|
||||
return color;
|
||||
}
|
||||
return super.getLineColor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||
this.c = c;
|
||||
super.paintBorder( c, g, x, y, width, height );
|
||||
this.c = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Because this borders are always shared for all lists,
|
||||
* get border specific style from FlatListUI.
|
||||
*/
|
||||
static <T> T getStyleFromListUI( Component c, Function<FlatListUI, T> f ) {
|
||||
JList<?> list = (JList<?>) SwingUtilities.getAncestorOfClass( JList.class, c );
|
||||
if( list != null ) {
|
||||
ListUI ui = list.getUI();
|
||||
if( ui instanceof FlatListUI )
|
||||
return f.apply( (FlatListUI) ui );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
//---- class Default ------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -74,6 +120,8 @@ public class FlatListCellBorder
|
||||
{
|
||||
@Override
|
||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||
Boolean b = getStyleFromListUI( c, ui -> ui.showCellFocusIndicator );
|
||||
boolean showCellFocusIndicator = (b != null) ? b : this.showCellFocusIndicator;
|
||||
if( !showCellFocusIndicator )
|
||||
return;
|
||||
|
||||
|
||||
@@ -18,14 +18,19 @@ package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Insets;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Map;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicListUI;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JList}.
|
||||
@@ -65,16 +70,31 @@ import com.formdev.flatlaf.FlatClientProperties;
|
||||
*/
|
||||
public class FlatListUI
|
||||
extends BasicListUI
|
||||
implements StyleableUI
|
||||
{
|
||||
protected Color selectionBackground;
|
||||
protected Color selectionForeground;
|
||||
protected Color selectionInactiveBackground;
|
||||
protected Color selectionInactiveForeground;
|
||||
@Styleable protected Color selectionBackground;
|
||||
@Styleable protected Color selectionForeground;
|
||||
@Styleable protected Color selectionInactiveBackground;
|
||||
@Styleable protected Color selectionInactiveForeground;
|
||||
|
||||
// for FlatListCellBorder
|
||||
@Styleable protected Insets cellMargins;
|
||||
@Styleable protected Color cellFocusColor;
|
||||
@Styleable protected boolean showCellFocusIndicator;
|
||||
|
||||
private Map<String, Object> oldStyleValues;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatListUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
installStyle();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
@@ -95,17 +115,8 @@ public class FlatListUI
|
||||
selectionForeground = null;
|
||||
selectionInactiveBackground = null;
|
||||
selectionInactiveForeground = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PropertyChangeListener createPropertyChangeListener() {
|
||||
PropertyChangeListener superListener = super.createPropertyChangeListener();
|
||||
return e -> {
|
||||
superListener.propertyChange( e );
|
||||
|
||||
if( FlatClientProperties.COMPONENT_FOCUS_OWNER.equals( e.getPropertyName() ) )
|
||||
toggleSelectionColors();
|
||||
};
|
||||
oldStyleValues = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -129,6 +140,75 @@ public class FlatListUI
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PropertyChangeListener createPropertyChangeListener() {
|
||||
PropertyChangeListener superListener = super.createPropertyChangeListener();
|
||||
return e -> {
|
||||
superListener.propertyChange( e );
|
||||
|
||||
switch( e.getPropertyName() ) {
|
||||
case FlatClientProperties.COMPONENT_FOCUS_OWNER:
|
||||
toggleSelectionColors();
|
||||
break;
|
||||
|
||||
case FlatClientProperties.STYLE:
|
||||
case FlatClientProperties.STYLE_CLASS:
|
||||
installStyle();
|
||||
list.revalidate();
|
||||
list.repaint();
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void installStyle() {
|
||||
try {
|
||||
applyStyle( FlatStylingSupport.getResolvedStyle( list, "List" ) );
|
||||
} catch( RuntimeException ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void applyStyle( Object style ) {
|
||||
Color oldSelectionBackground = selectionBackground;
|
||||
Color oldSelectionForeground = selectionForeground;
|
||||
Color oldSelectionInactiveBackground = selectionInactiveBackground;
|
||||
Color oldSelectionInactiveForeground = selectionInactiveForeground;
|
||||
|
||||
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
|
||||
|
||||
// update selection background
|
||||
if( selectionBackground != oldSelectionBackground ) {
|
||||
Color selBg = list.getSelectionBackground();
|
||||
if( selBg == oldSelectionBackground )
|
||||
list.setSelectionBackground( selectionBackground );
|
||||
else if( selBg == oldSelectionInactiveBackground )
|
||||
list.setSelectionBackground( selectionInactiveBackground );
|
||||
}
|
||||
|
||||
// update selection foreground
|
||||
if( selectionForeground != oldSelectionForeground ) {
|
||||
Color selFg = list.getSelectionForeground();
|
||||
if( selFg == oldSelectionForeground )
|
||||
list.setSelectionForeground( selectionForeground );
|
||||
else if( selFg == oldSelectionInactiveForeground )
|
||||
list.setSelectionForeground( selectionInactiveForeground );
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected Object applyStyleProperty( String key, Object value ) {
|
||||
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, list, key, value );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle selection colors from focused to inactive and vice versa.
|
||||
*
|
||||
|
||||
@@ -29,7 +29,7 @@ import javax.swing.plaf.basic.BasicBorders;
|
||||
public class FlatMarginBorder
|
||||
extends BasicBorders.MarginBorder
|
||||
{
|
||||
private final int left, right, top, bottom;
|
||||
protected int left, right, top, bottom;
|
||||
|
||||
public FlatMarginBorder() {
|
||||
left = right = top = bottom = 0;
|
||||
|
||||
@@ -21,8 +21,11 @@ import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Insets;
|
||||
import java.util.Map;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.UIManager;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableBorder;
|
||||
|
||||
/**
|
||||
* Border for {@link javax.swing.JMenuBar}.
|
||||
@@ -33,8 +36,20 @@ import javax.swing.UIManager;
|
||||
*/
|
||||
public class FlatMenuBarBorder
|
||||
extends FlatMarginBorder
|
||||
implements StyleableBorder
|
||||
{
|
||||
private final Color borderColor = UIManager.getColor( "MenuBar.borderColor" );
|
||||
@Styleable protected Color borderColor = UIManager.getColor( "MenuBar.borderColor" );
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Object applyStyleProperty( String key, Object value ) {
|
||||
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos() {
|
||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||
|
||||
@@ -18,8 +18,12 @@ package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.ActionMap;
|
||||
import javax.swing.JComponent;
|
||||
@@ -36,6 +40,9 @@ import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicMenuBarUI;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
|
||||
/**
|
||||
@@ -47,13 +54,30 @@ import com.formdev.flatlaf.util.SystemInfo;
|
||||
* @uiDefault MenuBar.background Color
|
||||
* @uiDefault MenuBar.foreground Color
|
||||
* @uiDefault MenuBar.border Border
|
||||
*
|
||||
* <!-- FlatMenuBarUI -->
|
||||
*
|
||||
* @uiDefault TitlePane.unifiedBackground boolean
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatMenuBarUI
|
||||
extends BasicMenuBarUI
|
||||
implements StyleableUI
|
||||
{
|
||||
// used in FlatMenuItemBorder
|
||||
/** @since 2 */ @Styleable protected Insets itemMargins;
|
||||
|
||||
// used in FlatMenuUI
|
||||
/** @since 2 */ @Styleable protected Color hoverBackground;
|
||||
/** @since 2 */ @Styleable protected Color underlineSelectionBackground;
|
||||
/** @since 2 */ @Styleable protected Color underlineSelectionColor;
|
||||
/** @since 2 */ @Styleable protected int underlineSelectionHeight = -1;
|
||||
|
||||
private PropertyChangeListener propertyChangeListener;
|
||||
private Map<String, Object> oldStyleValues;
|
||||
private AtomicBoolean borderShared;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatMenuBarUI();
|
||||
}
|
||||
@@ -63,6 +87,13 @@ public class FlatMenuBarUI
|
||||
* Do not add any functionality here.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
installStyle();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
@@ -70,6 +101,30 @@ public class FlatMenuBarUI
|
||||
LookAndFeel.installProperty( menuBar, "opaque", false );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void uninstallDefaults() {
|
||||
super.uninstallDefaults();
|
||||
|
||||
oldStyleValues = null;
|
||||
borderShared = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installListeners() {
|
||||
super.installListeners();
|
||||
|
||||
propertyChangeListener = FlatStylingSupport.createPropertyChangeListener( menuBar, this::installStyle, null );
|
||||
menuBar.addPropertyChangeListener( propertyChangeListener );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void uninstallListeners() {
|
||||
super.uninstallListeners();
|
||||
|
||||
menuBar.removePropertyChangeListener( propertyChangeListener );
|
||||
propertyChangeListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installKeyboardActions() {
|
||||
super.installKeyboardActions();
|
||||
@@ -82,6 +137,33 @@ public class FlatMenuBarUI
|
||||
map.put( "takeFocus", new TakeFocus() );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void installStyle() {
|
||||
try {
|
||||
applyStyle( FlatStylingSupport.getResolvedStyle( menuBar, "MenuBar" ) );
|
||||
} catch( RuntimeException ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void applyStyle( Object style ) {
|
||||
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected Object applyStyleProperty( String key, Object value ) {
|
||||
if( borderShared == null )
|
||||
borderShared = new AtomicBoolean( true );
|
||||
return FlatStylingSupport.applyToAnnotatedObjectOrBorder( this, key, value, menuBar, borderShared );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this, menuBar.getBorder() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update( Graphics g, JComponent c ) {
|
||||
// paint background
|
||||
|
||||
@@ -18,9 +18,11 @@ package com.formdev.flatlaf.ui;
|
||||
|
||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Insets;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.MenuBarUI;
|
||||
|
||||
/**
|
||||
* Border for {@link javax.swing.JMenu}, {@link javax.swing.JMenuItem},
|
||||
@@ -33,15 +35,22 @@ import javax.swing.UIManager;
|
||||
public class FlatMenuItemBorder
|
||||
extends FlatMarginBorder
|
||||
{
|
||||
// only used if parent menubar is not a instance of FlatMenuBarUI
|
||||
private final Insets menuBarItemMargins = UIManager.getInsets( "MenuBar.itemMargins" );
|
||||
|
||||
@Override
|
||||
public Insets getBorderInsets( Component c, Insets insets ) {
|
||||
if( c.getParent() instanceof JMenuBar ) {
|
||||
insets.top = scale( menuBarItemMargins.top );
|
||||
insets.left = scale( menuBarItemMargins.left );
|
||||
insets.bottom = scale( menuBarItemMargins.bottom );
|
||||
insets.right = scale( menuBarItemMargins.right );
|
||||
Container parent = c.getParent();
|
||||
if( parent instanceof JMenuBar ) {
|
||||
// get margins from FlatMenuBarUI to allow styling
|
||||
MenuBarUI ui = ((JMenuBar)parent).getUI();
|
||||
Insets margins = (ui instanceof FlatMenuBarUI && ((FlatMenuBarUI)ui).itemMargins != null)
|
||||
? ((FlatMenuBarUI)ui).itemMargins
|
||||
: this.menuBarItemMargins;
|
||||
insets.top = scale( margins.top );
|
||||
insets.left = scale( margins.left );
|
||||
insets.bottom = scale( margins.bottom );
|
||||
insets.right = scale( margins.right );
|
||||
return insets;
|
||||
} else
|
||||
return super.getBorderInsets( c, insets );
|
||||
|
||||
@@ -30,6 +30,7 @@ import java.awt.Rectangle;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.text.AttributedCharacterIterator;
|
||||
import java.util.Map;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
@@ -39,6 +40,10 @@ import javax.swing.UIManager;
|
||||
import javax.swing.plaf.basic.BasicHTML;
|
||||
import javax.swing.text.View;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.icons.FlatCheckBoxMenuItemIcon;
|
||||
import com.formdev.flatlaf.icons.FlatMenuArrowIcon;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
|
||||
import com.formdev.flatlaf.util.DerivedColor;
|
||||
import com.formdev.flatlaf.util.Graphics2DProxy;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
@@ -57,33 +62,32 @@ import com.formdev.flatlaf.util.SystemInfo;
|
||||
* @uiDefault MenuItem.underlineSelectionCheckBackground Color
|
||||
* @uiDefault MenuItem.underlineSelectionColor Color
|
||||
* @uiDefault MenuItem.underlineSelectionHeight int
|
||||
* @uiDefault MenuItem.selectionBackground Color
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatMenuItemRenderer
|
||||
{
|
||||
protected final JMenuItem menuItem;
|
||||
protected final Icon checkIcon;
|
||||
protected final Icon arrowIcon;
|
||||
protected Icon checkIcon;
|
||||
protected 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 );
|
||||
@Styleable protected int minimumWidth = UIManager.getInt( "MenuItem.minimumWidth" );
|
||||
@Styleable protected Dimension minimumIconSize;
|
||||
@Styleable protected int textAcceleratorGap = FlatUIUtils.getUIInt( "MenuItem.textAcceleratorGap", 28 );
|
||||
@Styleable protected int textNoAcceleratorGap = FlatUIUtils.getUIInt( "MenuItem.textNoAcceleratorGap", 6 );
|
||||
@Styleable protected int acceleratorArrowGap = FlatUIUtils.getUIInt( "MenuItem.acceleratorArrowGap", 2 );
|
||||
|
||||
protected final Color checkBackground = UIManager.getColor( "MenuItem.checkBackground" );
|
||||
protected final Insets checkMargins = UIManager.getInsets( "MenuItem.checkMargins" );
|
||||
@Styleable protected Color checkBackground = UIManager.getColor( "MenuItem.checkBackground" );
|
||||
@Styleable protected 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" );
|
||||
@Styleable protected Color underlineSelectionBackground = UIManager.getColor( "MenuItem.underlineSelectionBackground" );
|
||||
@Styleable protected Color underlineSelectionCheckBackground = UIManager.getColor( "MenuItem.underlineSelectionCheckBackground" );
|
||||
@Styleable protected Color underlineSelectionColor = UIManager.getColor( "MenuItem.underlineSelectionColor" );
|
||||
@Styleable protected int underlineSelectionHeight = UIManager.getInt( "MenuItem.underlineSelectionHeight" );
|
||||
|
||||
protected final Color selectionBackground = UIManager.getColor( "MenuItem.selectionBackground" );
|
||||
private boolean iconsShared = true;
|
||||
|
||||
protected FlatMenuItemRenderer( JMenuItem menuItem, Icon checkIcon, Icon arrowIcon,
|
||||
Font acceleratorFont, String acceleratorDelimiter )
|
||||
@@ -98,6 +102,64 @@ public class FlatMenuItemRenderer
|
||||
this.minimumIconSize = (minimumIconSize != null) ? minimumIconSize : new Dimension( 16, 16 );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected Object applyStyleProperty( String key, Object value ) {
|
||||
// style icon
|
||||
if( key.startsWith( "icon." ) || key.equals( "selectionForeground" ) ) {
|
||||
if( iconsShared ) {
|
||||
if( checkIcon instanceof FlatCheckBoxMenuItemIcon )
|
||||
checkIcon = FlatStylingSupport.cloneIcon( checkIcon );
|
||||
if( arrowIcon instanceof FlatMenuArrowIcon )
|
||||
arrowIcon = FlatStylingSupport.cloneIcon( arrowIcon );
|
||||
iconsShared = false;
|
||||
}
|
||||
|
||||
if( key.startsWith( "icon." ) ) {
|
||||
String key2 = key.substring( "icon.".length() );
|
||||
|
||||
try {
|
||||
if( checkIcon instanceof FlatCheckBoxMenuItemIcon )
|
||||
return ((FlatCheckBoxMenuItemIcon)checkIcon).applyStyleProperty( key2, value );
|
||||
} catch ( UnknownStyleException ex ) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
try {
|
||||
if( arrowIcon instanceof FlatMenuArrowIcon )
|
||||
return ((FlatMenuArrowIcon)arrowIcon).applyStyleProperty( key2, value );
|
||||
} catch ( UnknownStyleException ex ) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
// keys with prefix "icon." are only for icons
|
||||
throw new UnknownStyleException( key );
|
||||
} else if( key.equals( "selectionForeground" ) ) {
|
||||
// special case: same key is used in icons and in menuitem
|
||||
if( checkIcon instanceof FlatCheckBoxMenuItemIcon )
|
||||
((FlatCheckBoxMenuItemIcon)checkIcon).applyStyleProperty( key, value );
|
||||
if( arrowIcon instanceof FlatMenuArrowIcon )
|
||||
((FlatMenuArrowIcon)arrowIcon).applyStyleProperty( key, value );
|
||||
|
||||
// throw exception because the caller should also apply this key
|
||||
throw new UnknownStyleException( key );
|
||||
}
|
||||
}
|
||||
|
||||
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
public Map<String, Class<?>> getStyleableInfos() {
|
||||
Map<String, Class<?>> infos = FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
||||
if( checkIcon instanceof FlatCheckBoxMenuItemIcon )
|
||||
FlatStylingSupport.putAllPrefixKey( infos, "icon.", ((FlatCheckBoxMenuItemIcon)checkIcon).getStyleableInfos() );
|
||||
infos.remove( "icon.selectionForeground" );
|
||||
if( arrowIcon instanceof FlatMenuArrowIcon )
|
||||
FlatStylingSupport.putAllPrefixKey( infos, "icon.", ((FlatMenuArrowIcon)arrowIcon).getStyleableInfos() );
|
||||
infos.remove( "icon.selectionForeground" );
|
||||
return infos;
|
||||
}
|
||||
|
||||
protected Dimension getPreferredMenuItemSize() {
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
@@ -254,7 +316,7 @@ debug*/
|
||||
paintBackground( g, underlineSelection ? underlineSelectionBackground : selectionBackground );
|
||||
if( underlineSelection && isArmedOrSelected( menuItem ) )
|
||||
paintUnderlineSelection( g, underlineSelectionColor, underlineSelectionHeight );
|
||||
paintIcon( g, iconRect, getIconForPainting(), underlineSelection ? underlineSelectionCheckBackground : checkBackground );
|
||||
paintIcon( g, iconRect, getIconForPainting(), underlineSelection ? underlineSelectionCheckBackground : checkBackground, selectionBackground );
|
||||
paintText( g, textRect, menuItem.getText(), selectionForeground, disabledForeground );
|
||||
paintAccelerator( g, accelRect, getAcceleratorText(), acceleratorForeground, acceleratorSelectionForeground, disabledForeground );
|
||||
if( !isTopLevelMenu( menuItem ) )
|
||||
@@ -301,7 +363,7 @@ debug*/
|
||||
return FlatUIUtils.deriveColor( background, baseColor );
|
||||
}
|
||||
|
||||
protected void paintIcon( Graphics g, Rectangle iconRect, Icon icon, Color checkBackground ) {
|
||||
protected void paintIcon( Graphics g, Rectangle iconRect, Icon icon, Color checkBackground, Color selectionBackground ) {
|
||||
// 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 ) {
|
||||
|
||||
@@ -16,13 +16,19 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Map;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicMenuItemUI;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JMenuItem}.
|
||||
@@ -54,13 +60,22 @@ import javax.swing.plaf.basic.BasicMenuItemUI;
|
||||
*/
|
||||
public class FlatMenuItemUI
|
||||
extends BasicMenuItemUI
|
||||
implements StyleableUI
|
||||
{
|
||||
private FlatMenuItemRenderer renderer;
|
||||
private Map<String, Object> oldStyleValues;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatMenuItemUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
installStyle();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
@@ -75,12 +90,70 @@ public class FlatMenuItemUI
|
||||
super.uninstallDefaults();
|
||||
|
||||
renderer = null;
|
||||
oldStyleValues = null;
|
||||
}
|
||||
|
||||
protected FlatMenuItemRenderer createRenderer() {
|
||||
return new FlatMenuItemRenderer( menuItem, checkIcon, arrowIcon, acceleratorFont, acceleratorDelimiter );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PropertyChangeListener createPropertyChangeListener( JComponent c ) {
|
||||
return FlatStylingSupport.createPropertyChangeListener( c, this::installStyle, super.createPropertyChangeListener( c ) );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void installStyle() {
|
||||
try {
|
||||
applyStyle( FlatStylingSupport.getResolvedStyle( menuItem, "MenuItem" ) );
|
||||
} catch( RuntimeException ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void applyStyle( Object style ) {
|
||||
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected Object applyStyleProperty( String key, Object value ) {
|
||||
try {
|
||||
return renderer.applyStyleProperty( key, value );
|
||||
} catch ( UnknownStyleException ex ) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
Object oldValue;
|
||||
switch( key ) {
|
||||
// BasicMenuItemUI
|
||||
case "selectionBackground": oldValue = selectionBackground; selectionBackground = (Color) value; return oldValue;
|
||||
case "selectionForeground": oldValue = selectionForeground; selectionForeground = (Color) value; return oldValue;
|
||||
case "disabledForeground": oldValue = disabledForeground; disabledForeground = (Color) value; return oldValue;
|
||||
case "acceleratorForeground": oldValue = acceleratorForeground; acceleratorForeground = (Color) value; return oldValue;
|
||||
case "acceleratorSelectionForeground": oldValue = acceleratorSelectionForeground; acceleratorSelectionForeground = (Color) value; return oldValue;
|
||||
}
|
||||
|
||||
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, menuItem, key, value );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||
return getStyleableInfos( renderer );
|
||||
}
|
||||
|
||||
static Map<String, Class<?>> getStyleableInfos( FlatMenuItemRenderer renderer ) {
|
||||
Map<String, Class<?>> infos = new FlatStylingSupport.StyleableInfosMap<>();
|
||||
infos.put( "selectionBackground", Color.class );
|
||||
infos.put( "selectionForeground", Color.class );
|
||||
infos.put( "disabledForeground", Color.class );
|
||||
infos.put( "acceleratorForeground", Color.class );
|
||||
infos.put( "acceleratorSelectionForeground", Color.class );
|
||||
infos.putAll( renderer.getStyleableInfos() );
|
||||
return infos;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dimension getPreferredMenuItemSize( JComponent c, Icon checkIcon, Icon arrowIcon, int defaultTextIconGap ) {
|
||||
return renderer.getPreferredMenuItemSize();
|
||||
|
||||
@@ -21,16 +21,24 @@ import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import javax.swing.ButtonModel;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.event.MouseInputListener;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.MenuBarUI;
|
||||
import javax.swing.plaf.basic.BasicMenuUI;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JMenu}.
|
||||
@@ -60,10 +68,10 @@ import javax.swing.plaf.basic.BasicMenuUI;
|
||||
* <!-- FlatMenuUI -->
|
||||
*
|
||||
* @uiDefault MenuItem.iconTextGap int
|
||||
* @uiDefault MenuBar.hoverBackground Color
|
||||
*
|
||||
* <!-- FlatMenuRenderer -->
|
||||
*
|
||||
* @uiDefault MenuBar.hoverBackground Color
|
||||
* @uiDefault MenuBar.underlineSelectionBackground Color
|
||||
* @uiDefault MenuBar.underlineSelectionColor Color
|
||||
* @uiDefault MenuBar.underlineSelectionHeight int
|
||||
@@ -72,14 +80,22 @@ import javax.swing.plaf.basic.BasicMenuUI;
|
||||
*/
|
||||
public class FlatMenuUI
|
||||
extends BasicMenuUI
|
||||
implements StyleableUI
|
||||
{
|
||||
private Color hoverBackground;
|
||||
private FlatMenuItemRenderer renderer;
|
||||
private Map<String, Object> oldStyleValues;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatMenuUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
installStyle();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
@@ -88,7 +104,6 @@ public class FlatMenuUI
|
||||
|
||||
menuItem.setRolloverEnabled( true );
|
||||
|
||||
hoverBackground = UIManager.getColor( "MenuBar.hoverBackground" );
|
||||
renderer = createRenderer();
|
||||
}
|
||||
|
||||
@@ -96,8 +111,8 @@ public class FlatMenuUI
|
||||
protected void uninstallDefaults() {
|
||||
super.uninstallDefaults();
|
||||
|
||||
hoverBackground = null;
|
||||
renderer = null;
|
||||
oldStyleValues = null;
|
||||
}
|
||||
|
||||
protected FlatMenuItemRenderer createRenderer() {
|
||||
@@ -129,6 +144,52 @@ public class FlatMenuUI
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PropertyChangeListener createPropertyChangeListener( JComponent c ) {
|
||||
return FlatStylingSupport.createPropertyChangeListener( c, this::installStyle, super.createPropertyChangeListener( c ) );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void installStyle() {
|
||||
try {
|
||||
applyStyle( FlatStylingSupport.getResolvedStyle( menuItem, "Menu" ) );
|
||||
} catch( RuntimeException ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void applyStyle( Object style ) {
|
||||
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected Object applyStyleProperty( String key, Object value ) {
|
||||
try {
|
||||
return renderer.applyStyleProperty( key, value );
|
||||
} catch ( UnknownStyleException ex ) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
Object oldValue;
|
||||
switch( key ) {
|
||||
// BasicMenuItemUI
|
||||
case "selectionBackground": oldValue = selectionBackground; selectionBackground = (Color) value; return oldValue;
|
||||
case "selectionForeground": oldValue = selectionForeground; selectionForeground = (Color) value; return oldValue;
|
||||
case "disabledForeground": oldValue = disabledForeground; disabledForeground = (Color) value; return oldValue;
|
||||
case "acceleratorForeground": oldValue = acceleratorForeground; acceleratorForeground = (Color) value; return oldValue;
|
||||
case "acceleratorSelectionForeground": oldValue = acceleratorSelectionForeground; acceleratorSelectionForeground = (Color) value; return oldValue;
|
||||
}
|
||||
|
||||
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, menuItem, key, value );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||
return FlatMenuItemUI.getStyleableInfos( renderer );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize( JComponent c ) {
|
||||
// avoid that top-level menus (in menu bar) are made smaller if horizontal space is rare
|
||||
@@ -153,9 +214,10 @@ public class FlatMenuUI
|
||||
protected class FlatMenuRenderer
|
||||
extends FlatMenuItemRenderer
|
||||
{
|
||||
protected final Color menuBarUnderlineSelectionBackground = FlatUIUtils.getUIColor( "MenuBar.underlineSelectionBackground", underlineSelectionBackground );
|
||||
protected final Color menuBarUnderlineSelectionColor = FlatUIUtils.getUIColor( "MenuBar.underlineSelectionColor", underlineSelectionColor );
|
||||
protected final int menuBarUnderlineSelectionHeight = FlatUIUtils.getUIInt( "MenuBar.underlineSelectionHeight", underlineSelectionHeight );
|
||||
protected Color hoverBackground = UIManager.getColor( "MenuBar.hoverBackground" );
|
||||
protected Color menuBarUnderlineSelectionBackground = FlatUIUtils.getUIColor( "MenuBar.underlineSelectionBackground", underlineSelectionBackground );
|
||||
protected Color menuBarUnderlineSelectionColor = FlatUIUtils.getUIColor( "MenuBar.underlineSelectionColor", underlineSelectionColor );
|
||||
protected int menuBarUnderlineSelectionHeight = FlatUIUtils.getUIInt( "MenuBar.underlineSelectionHeight", underlineSelectionHeight );
|
||||
|
||||
protected FlatMenuRenderer( JMenuItem menuItem, Icon checkIcon, Icon arrowIcon,
|
||||
Font acceleratorFont, String acceleratorDelimiter )
|
||||
@@ -165,27 +227,39 @@ public class FlatMenuUI
|
||||
|
||||
@Override
|
||||
protected void paintBackground( Graphics g, Color selectionBackground ) {
|
||||
if( isUnderlineSelection() && ((JMenu)menuItem).isTopLevelMenu() )
|
||||
selectionBackground = menuBarUnderlineSelectionBackground;
|
||||
if( ((JMenu)menuItem).isTopLevelMenu() ) {
|
||||
if( isUnderlineSelection() )
|
||||
selectionBackground = getStyleFromMenuBarUI( ui -> ui.underlineSelectionBackground, menuBarUnderlineSelectionBackground );
|
||||
|
||||
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 );
|
||||
ButtonModel model = menuItem.getModel();
|
||||
if( model.isRollover() && !model.isArmed() && !model.isSelected() && model.isEnabled() ) {
|
||||
g.setColor( deriveBackground( getStyleFromMenuBarUI( ui -> ui.hoverBackground, hoverBackground ) ) );
|
||||
g.fillRect( 0, 0, menuItem.getWidth(), menuItem.getHeight() );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
super.paintBackground( g, selectionBackground );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintUnderlineSelection( Graphics g, Color underlineSelectionColor, int underlineSelectionHeight ) {
|
||||
if( ((JMenu)menuItem).isTopLevelMenu() ) {
|
||||
underlineSelectionColor = menuBarUnderlineSelectionColor;
|
||||
underlineSelectionHeight = menuBarUnderlineSelectionHeight;
|
||||
underlineSelectionColor = getStyleFromMenuBarUI( ui -> ui.underlineSelectionColor, menuBarUnderlineSelectionColor );
|
||||
underlineSelectionHeight = getStyleFromMenuBarUI( ui -> (ui.underlineSelectionHeight != -1)
|
||||
? ui.underlineSelectionHeight : null, menuBarUnderlineSelectionHeight );
|
||||
}
|
||||
|
||||
super.paintUnderlineSelection( g, underlineSelectionColor, underlineSelectionHeight );
|
||||
}
|
||||
|
||||
private <T> T getStyleFromMenuBarUI( Function<FlatMenuBarUI, T> f, T defaultValue ) {
|
||||
MenuBarUI ui = ((JMenuBar)menuItem.getParent()).getUI();
|
||||
if( !(ui instanceof FlatMenuBarUI) )
|
||||
return defaultValue;
|
||||
|
||||
T value = f.apply( (FlatMenuBarUI) ui );
|
||||
return (value != null) ? value : defaultValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,9 +277,7 @@ public class FlatNativeWindowBorder
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.1.1
|
||||
*/
|
||||
/** @since 1.1.1 */
|
||||
public static void setNativeProvider( Provider provider ) {
|
||||
if( nativeProvider != null )
|
||||
throw new IllegalStateException();
|
||||
|
||||
@@ -16,13 +16,14 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Shape;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.KeyListener;
|
||||
import java.util.Map;
|
||||
import javax.swing.Action;
|
||||
import javax.swing.ActionMap;
|
||||
import javax.swing.Icon;
|
||||
@@ -36,6 +37,9 @@ import javax.swing.text.Element;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import javax.swing.text.PasswordView;
|
||||
import javax.swing.text.View;
|
||||
import com.formdev.flatlaf.icons.FlatCapsLockIcon;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JPasswordField}.
|
||||
@@ -61,6 +65,7 @@ import javax.swing.text.View;
|
||||
* @uiDefault Component.isIntelliJTheme boolean
|
||||
* @uiDefault PasswordField.placeholderForeground Color
|
||||
* @uiDefault PasswordField.focusedBackground Color optional
|
||||
* @uiDefault PasswordField.iconTextGap int optional, default is 4
|
||||
* @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always
|
||||
* @uiDefault TextComponent.selectAllOnMouseClick boolean
|
||||
*
|
||||
@@ -75,10 +80,11 @@ import javax.swing.text.View;
|
||||
public class FlatPasswordFieldUI
|
||||
extends FlatTextFieldUI
|
||||
{
|
||||
protected boolean showCapsLock;
|
||||
@Styleable protected boolean showCapsLock;
|
||||
protected Icon capsLockIcon;
|
||||
|
||||
private KeyListener capsLockListener;
|
||||
private boolean capsLockIconShared = true;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatPasswordFieldUI();
|
||||
@@ -100,6 +106,7 @@ public class FlatPasswordFieldUI
|
||||
|
||||
showCapsLock = UIManager.getBoolean( "PasswordField.showCapsLock" );
|
||||
capsLockIcon = UIManager.getIcon( "PasswordField.capsLockIcon" );
|
||||
capsLockIconShared = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -155,37 +162,72 @@ public class FlatPasswordFieldUI
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
String getStyleType() {
|
||||
return "PasswordField";
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
protected Object applyStyleProperty( String key, Object value ) {
|
||||
if( key.equals( "capsLockIconColor" ) && capsLockIcon instanceof FlatCapsLockIcon ) {
|
||||
if( capsLockIconShared ) {
|
||||
capsLockIcon = FlatStylingSupport.cloneIcon( capsLockIcon );
|
||||
capsLockIconShared = false;
|
||||
}
|
||||
return ((FlatCapsLockIcon)capsLockIcon).applyStyleProperty( key, value );
|
||||
}
|
||||
|
||||
return super.applyStyleProperty( key, value );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||
Map<String, Class<?>> infos = super.getStyleableInfos( c );
|
||||
infos.put( "capsLockIconColor", Color.class );
|
||||
return infos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View create( Element elem ) {
|
||||
return new PasswordView( elem );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
protected void paintSafely( Graphics g ) {
|
||||
// safe and restore clipping area because super.paintSafely() modifies it
|
||||
// and the caps lock icon would be truncated
|
||||
Shape oldClip = g.getClip();
|
||||
super.paintSafely( g );
|
||||
g.setClip( oldClip );
|
||||
protected void paintIcons( Graphics g, Rectangle r ) {
|
||||
super.paintIcons( g, r );
|
||||
|
||||
paintCapsLock( g );
|
||||
if( isCapsLockVisible() )
|
||||
paintCapsLock( g, r );
|
||||
}
|
||||
|
||||
protected void paintCapsLock( Graphics g ) {
|
||||
if( !isCapsLockVisible() )
|
||||
return;
|
||||
|
||||
/** @since 2 */
|
||||
protected void paintCapsLock( Graphics g, Rectangle r ) {
|
||||
JTextComponent c = getComponent();
|
||||
int y = (c.getHeight() - capsLockIcon.getIconHeight()) / 2;
|
||||
int x = c.getComponentOrientation().isLeftToRight()
|
||||
? c.getWidth() - capsLockIcon.getIconWidth() - y
|
||||
: y;
|
||||
? r.x + r.width - capsLockIcon.getIconWidth()
|
||||
: r.x;
|
||||
int y = r.y + Math.round( (r.height - capsLockIcon.getIconHeight()) / 2f );
|
||||
capsLockIcon.paintIcon( c, g, x, y );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.4
|
||||
*/
|
||||
/** @since 2 */
|
||||
@Override
|
||||
protected boolean hasTrailingIcon() {
|
||||
return super.hasTrailingIcon() || isCapsLockVisible();
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
protected int getTrailingIconWidth() {
|
||||
return super.getTrailingIconWidth()
|
||||
+ (isCapsLockVisible() ? capsLockIcon.getIconWidth() + UIScale.scale( iconTextGap ) : 0);
|
||||
}
|
||||
|
||||
/** @since 1.4 */
|
||||
protected boolean isCapsLockVisible() {
|
||||
if( !showCapsLock )
|
||||
return false;
|
||||
@@ -194,18 +236,4 @@ public class FlatPasswordFieldUI
|
||||
return FlatUIUtils.isPermanentFocusOwner( c ) &&
|
||||
Toolkit.getDefaultToolkit().getLockingKeyState( KeyEvent.VK_CAPS_LOCK );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.4
|
||||
*/
|
||||
@Override
|
||||
protected Insets getPadding() {
|
||||
Insets padding = super.getPadding();
|
||||
if( !isCapsLockVisible() )
|
||||
return padding;
|
||||
|
||||
boolean ltr = getComponent().getComponentOrientation().isLeftToRight();
|
||||
int iconWidth = capsLockIcon.getIconWidth();
|
||||
return FlatUIUtils.addInsets( padding, new Insets( 0, ltr ? 0 : iconWidth, 0, ltr ? iconWidth : 0 ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,11 +16,15 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Insets;
|
||||
import java.util.Map;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.UIManager;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableBorder;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
@@ -33,12 +37,40 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
*/
|
||||
public class FlatPopupMenuBorder
|
||||
extends FlatLineBorder
|
||||
implements StyleableBorder
|
||||
{
|
||||
private Color borderColor;
|
||||
|
||||
public FlatPopupMenuBorder() {
|
||||
super( UIManager.getInsets( "PopupMenu.borderInsets" ),
|
||||
UIManager.getColor( "PopupMenu.borderColor" ) );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Object applyStyleProperty( String key, Object value ) {
|
||||
Object oldValue;
|
||||
switch( key ) {
|
||||
case "borderInsets": return applyStyleProperty( (Insets) value );
|
||||
case "borderColor": oldValue = getLineColor(); borderColor = (Color) value; return oldValue;
|
||||
}
|
||||
throw new UnknownStyleException( key );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos() {
|
||||
Map<String, Class<?>> infos = new FlatStylingSupport.StyleableInfosMap<>();
|
||||
infos.put( "borderInsets", Insets.class );
|
||||
infos.put( "borderColor", Color.class );
|
||||
return infos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getLineColor() {
|
||||
return (borderColor != null) ? borderColor : super.getLineColor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Insets getBorderInsets( Component c, Insets insets ) {
|
||||
if( c instanceof Container &&
|
||||
|
||||
@@ -39,11 +39,24 @@ public class FlatPopupMenuSeparatorUI
|
||||
extends FlatSeparatorUI
|
||||
{
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return FlatUIUtils.createSharedUI( FlatPopupMenuSeparatorUI.class, FlatPopupMenuSeparatorUI::new );
|
||||
return FlatUIUtils.canUseSharedUI( c )
|
||||
? FlatUIUtils.createSharedUI( FlatPopupMenuSeparatorUI.class, () -> new FlatPopupMenuSeparatorUI( true ) )
|
||||
: new FlatPopupMenuSeparatorUI( false );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected FlatPopupMenuSeparatorUI( boolean shared ) {
|
||||
super( shared );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getPropertyPrefix() {
|
||||
return "PopupMenuSeparator";
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
String getStyleType() {
|
||||
return "PopupMenuSeparator";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,14 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicPopupMenuUI;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JPopupMenu}.
|
||||
@@ -34,8 +39,71 @@ import javax.swing.plaf.basic.BasicPopupMenuUI;
|
||||
*/
|
||||
public class FlatPopupMenuUI
|
||||
extends BasicPopupMenuUI
|
||||
implements StyleableUI
|
||||
{
|
||||
private PropertyChangeListener propertyChangeListener;
|
||||
private Map<String, Object> oldStyleValues;
|
||||
private AtomicBoolean borderShared;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatPopupMenuUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
installStyle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uninstallUI( JComponent c ) {
|
||||
super.uninstallUI( c );
|
||||
|
||||
oldStyleValues = null;
|
||||
borderShared = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installListeners() {
|
||||
super.installListeners();
|
||||
|
||||
propertyChangeListener = FlatStylingSupport.createPropertyChangeListener( popupMenu, this::installStyle, null );
|
||||
popupMenu.addPropertyChangeListener( propertyChangeListener );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void uninstallListeners() {
|
||||
super.uninstallListeners();
|
||||
|
||||
popupMenu.removePropertyChangeListener( propertyChangeListener );
|
||||
propertyChangeListener = null;
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void installStyle() {
|
||||
try {
|
||||
applyStyle( FlatStylingSupport.getResolvedStyle( popupMenu, "PopupMenu" ) );
|
||||
} catch( RuntimeException ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void applyStyle( Object style ) {
|
||||
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected Object applyStyleProperty( String key, Object value ) {
|
||||
if( borderShared == null )
|
||||
borderShared = new AtomicBoolean( true );
|
||||
return FlatStylingSupport.applyToAnnotatedObjectOrBorder( this, key, value, popupMenu, borderShared );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this, popupMenu.getBorder() );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,13 +25,17 @@ import java.awt.Insets;
|
||||
import java.awt.geom.Area;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Map;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JProgressBar;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicProgressBarUI;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
@@ -58,17 +62,30 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
*/
|
||||
public class FlatProgressBarUI
|
||||
extends BasicProgressBarUI
|
||||
implements StyleableUI
|
||||
{
|
||||
protected int arc;
|
||||
protected Dimension horizontalSize;
|
||||
protected Dimension verticalSize;
|
||||
@Styleable protected int arc;
|
||||
@Styleable protected Dimension horizontalSize;
|
||||
@Styleable protected Dimension verticalSize;
|
||||
|
||||
// only used via styling (not in UI defaults, but has likewise client properties)
|
||||
/** @since 2 */ @Styleable protected boolean largeHeight;
|
||||
/** @since 2 */ @Styleable protected boolean square;
|
||||
|
||||
private PropertyChangeListener propertyChangeListener;
|
||||
private Map<String, Object> oldStyleValues;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatProgressBarUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
installStyle();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
@@ -80,6 +97,13 @@ public class FlatProgressBarUI
|
||||
verticalSize = UIManager.getDimension( "ProgressBar.verticalSize" );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void uninstallDefaults() {
|
||||
super.uninstallDefaults();
|
||||
|
||||
oldStyleValues = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installListeners() {
|
||||
super.installListeners();
|
||||
@@ -91,6 +115,13 @@ public class FlatProgressBarUI
|
||||
progressBar.revalidate();
|
||||
progressBar.repaint();
|
||||
break;
|
||||
|
||||
case STYLE:
|
||||
case STYLE_CLASS:
|
||||
installStyle();
|
||||
progressBar.revalidate();
|
||||
progressBar.repaint();
|
||||
break;
|
||||
}
|
||||
};
|
||||
progressBar.addPropertyChangeListener( propertyChangeListener );
|
||||
@@ -104,11 +135,36 @@ public class FlatProgressBarUI
|
||||
propertyChangeListener = null;
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void installStyle() {
|
||||
try {
|
||||
applyStyle( FlatStylingSupport.getResolvedStyle( progressBar, "ProgressBar" ) );
|
||||
} catch( RuntimeException ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void applyStyle( Object style ) {
|
||||
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected Object applyStyleProperty( String key, Object value ) {
|
||||
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, progressBar, key, value );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize( JComponent c ) {
|
||||
Dimension size = super.getPreferredSize( c );
|
||||
|
||||
if( progressBar.isStringPainted() || clientPropertyBoolean( c, PROGRESS_BAR_LARGE_HEIGHT, false ) ) {
|
||||
if( progressBar.isStringPainted() || clientPropertyBoolean( c, PROGRESS_BAR_LARGE_HEIGHT, largeHeight ) ) {
|
||||
// recalculate progress height/width to make it smaller
|
||||
Insets insets = progressBar.getInsets();
|
||||
FontMetrics fm = progressBar.getFontMetrics( progressBar.getFont() );
|
||||
@@ -151,7 +207,7 @@ public class FlatProgressBarUI
|
||||
return;
|
||||
|
||||
boolean horizontal = (progressBar.getOrientation() == JProgressBar.HORIZONTAL);
|
||||
int arc = clientPropertyBoolean( c, PROGRESS_BAR_SQUARE, false )
|
||||
int arc = clientPropertyBoolean( c, PROGRESS_BAR_SQUARE, square )
|
||||
? 0
|
||||
: Math.min( UIScale.scale( this.arc ), horizontal ? height : width );
|
||||
|
||||
|
||||
@@ -16,13 +16,19 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Map;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicRadioButtonMenuItemUI;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JRadioButtonMenuItem}.
|
||||
@@ -54,13 +60,22 @@ import javax.swing.plaf.basic.BasicRadioButtonMenuItemUI;
|
||||
*/
|
||||
public class FlatRadioButtonMenuItemUI
|
||||
extends BasicRadioButtonMenuItemUI
|
||||
implements StyleableUI
|
||||
{
|
||||
private FlatMenuItemRenderer renderer;
|
||||
private Map<String, Object> oldStyleValues;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatRadioButtonMenuItemUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
installStyle();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
@@ -75,12 +90,59 @@ public class FlatRadioButtonMenuItemUI
|
||||
super.uninstallDefaults();
|
||||
|
||||
renderer = null;
|
||||
oldStyleValues = null;
|
||||
}
|
||||
|
||||
protected FlatMenuItemRenderer createRenderer() {
|
||||
return new FlatMenuItemRenderer( menuItem, checkIcon, arrowIcon, acceleratorFont, acceleratorDelimiter );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PropertyChangeListener createPropertyChangeListener( JComponent c ) {
|
||||
return FlatStylingSupport.createPropertyChangeListener( c, this::installStyle, super.createPropertyChangeListener( c ) );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void installStyle() {
|
||||
try {
|
||||
applyStyle( FlatStylingSupport.getResolvedStyle( menuItem, "RadioButtonMenuItem" ) );
|
||||
} catch( RuntimeException ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void applyStyle( Object style ) {
|
||||
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected Object applyStyleProperty( String key, Object value ) {
|
||||
try {
|
||||
return renderer.applyStyleProperty( key, value );
|
||||
} catch ( UnknownStyleException ex ) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
Object oldValue;
|
||||
switch( key ) {
|
||||
// BasicMenuItemUI
|
||||
case "selectionBackground": oldValue = selectionBackground; selectionBackground = (Color) value; return oldValue;
|
||||
case "selectionForeground": oldValue = selectionForeground; selectionForeground = (Color) value; return oldValue;
|
||||
case "disabledForeground": oldValue = disabledForeground; disabledForeground = (Color) value; return oldValue;
|
||||
case "acceleratorForeground": oldValue = acceleratorForeground; acceleratorForeground = (Color) value; return oldValue;
|
||||
case "acceleratorSelectionForeground": oldValue = acceleratorSelectionForeground; acceleratorSelectionForeground = (Color) value; return oldValue;
|
||||
}
|
||||
|
||||
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, menuItem, key, value );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||
return FlatMenuItemUI.getStyleableInfos( renderer );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dimension getPreferredMenuItemSize( JComponent c, Icon checkIcon, Icon arrowIcon, int defaultTextIconGap ) {
|
||||
return renderer.getPreferredMenuItemSize();
|
||||
|
||||
@@ -23,15 +23,24 @@ import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import javax.swing.AbstractButton;
|
||||
import javax.swing.CellRendererPane;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicButtonListener;
|
||||
import javax.swing.plaf.basic.BasicRadioButtonUI;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.icons.FlatCheckBoxIcon;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
@@ -56,16 +65,34 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
*/
|
||||
public class FlatRadioButtonUI
|
||||
extends BasicRadioButtonUI
|
||||
implements StyleableUI
|
||||
{
|
||||
protected int iconTextGap;
|
||||
protected Color disabledText;
|
||||
@Styleable protected Color disabledText;
|
||||
|
||||
private Color defaultBackground;
|
||||
|
||||
private final boolean shared;
|
||||
private boolean iconShared = true;
|
||||
private boolean defaults_initialized = false;
|
||||
private Map<String, Object> oldStyleValues;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return FlatUIUtils.createSharedUI( FlatRadioButtonUI.class, FlatRadioButtonUI::new );
|
||||
return FlatUIUtils.canUseSharedUI( c )
|
||||
? FlatUIUtils.createSharedUI( FlatRadioButtonUI.class, () -> new FlatRadioButtonUI( true ) )
|
||||
: new FlatRadioButtonUI( false );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected FlatRadioButtonUI( boolean shared ) {
|
||||
this.shared = shared;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
installStyle( (AbstractButton) c );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -80,6 +107,7 @@ public class FlatRadioButtonUI
|
||||
|
||||
defaultBackground = UIManager.getColor( prefix + "background" );
|
||||
|
||||
iconShared = true;
|
||||
defaults_initialized = true;
|
||||
}
|
||||
|
||||
@@ -93,10 +121,84 @@ public class FlatRadioButtonUI
|
||||
protected void uninstallDefaults( AbstractButton b ) {
|
||||
super.uninstallDefaults( b );
|
||||
|
||||
oldStyleValues = null;
|
||||
|
||||
MigLayoutVisualPadding.uninstall( b );
|
||||
defaults_initialized = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BasicButtonListener createButtonListener( AbstractButton b ) {
|
||||
return new FlatRadioButtonListener( b );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void propertyChange( AbstractButton b, PropertyChangeEvent e ) {
|
||||
switch( e.getPropertyName() ) {
|
||||
case FlatClientProperties.STYLE:
|
||||
case FlatClientProperties.STYLE_CLASS:
|
||||
if( shared && FlatStylingSupport.hasStyleProperty( b ) ) {
|
||||
// unshare component UI if necessary
|
||||
// updateUI() invokes applyStyle() from installUI()
|
||||
b.updateUI();
|
||||
} else
|
||||
installStyle( b );
|
||||
b.revalidate();
|
||||
b.repaint();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void installStyle( AbstractButton b ) {
|
||||
try {
|
||||
applyStyle( b, FlatStylingSupport.getResolvedStyle( b, getStyleType() ) );
|
||||
} catch( RuntimeException ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
String getStyleType() {
|
||||
return "RadioButton";
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void applyStyle( AbstractButton b, Object style ) {
|
||||
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style,
|
||||
(key, value) -> applyStyleProperty( b, key, value ) );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected Object applyStyleProperty( AbstractButton b, String key, Object value ) {
|
||||
// style icon
|
||||
if( key.startsWith( "icon." ) ) {
|
||||
if( !(icon instanceof FlatCheckBoxIcon) )
|
||||
return new UnknownStyleException( key );
|
||||
|
||||
if( iconShared ) {
|
||||
icon = FlatStylingSupport.cloneIcon( icon );
|
||||
iconShared = false;
|
||||
}
|
||||
|
||||
key = key.substring( "icon.".length() );
|
||||
return ((FlatCheckBoxIcon)icon).applyStyleProperty( key, value );
|
||||
}
|
||||
|
||||
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, b, key, value );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||
Map<String, Class<?>> infos = FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
||||
if( icon instanceof FlatCheckBoxIcon ) {
|
||||
for( Map.Entry<String, Class<?>> e : ((FlatCheckBoxIcon)icon).getStyleableInfos().entrySet() )
|
||||
infos.put( "icon.".concat( e.getKey() ), e.getValue() );
|
||||
}
|
||||
return infos;
|
||||
}
|
||||
|
||||
private static Insets tempInsets = new Insets( 0, 0, 0, 0 );
|
||||
|
||||
@Override
|
||||
@@ -178,8 +280,32 @@ public class FlatRadioButtonUI
|
||||
|
||||
private int getIconFocusWidth( JComponent c ) {
|
||||
AbstractButton b = (AbstractButton) c;
|
||||
return (b.getIcon() == null && getDefaultIcon() instanceof FlatCheckBoxIcon)
|
||||
? UIScale.scale( ((FlatCheckBoxIcon)getDefaultIcon()).focusWidth )
|
||||
Icon icon = b.getIcon();
|
||||
if( icon == null )
|
||||
icon = getDefaultIcon();
|
||||
|
||||
return (icon instanceof FlatCheckBoxIcon)
|
||||
? Math.round( UIScale.scale( ((FlatCheckBoxIcon)icon).getFocusWidth() ) )
|
||||
: 0;
|
||||
}
|
||||
|
||||
//---- class FlatRadioButtonListener --------------------------------------
|
||||
|
||||
/** @since 2 */
|
||||
protected class FlatRadioButtonListener
|
||||
extends BasicButtonListener
|
||||
{
|
||||
private final AbstractButton b;
|
||||
|
||||
protected FlatRadioButtonListener( AbstractButton b ) {
|
||||
super( b );
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void propertyChange( PropertyChangeEvent e ) {
|
||||
super.propertyChange( e );
|
||||
FlatRadioButtonUI.this.propertyChange( b, e );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,24 +198,18 @@ public class FlatRootPaneUI
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.1.2
|
||||
*/
|
||||
/** @since 1.1.2 */
|
||||
protected void installNativeWindowBorder() {
|
||||
nativeWindowBorderData = FlatNativeWindowBorder.install( rootPane );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.1.2
|
||||
*/
|
||||
/** @since 1.1.2 */
|
||||
protected void uninstallNativeWindowBorder() {
|
||||
FlatNativeWindowBorder.uninstall( rootPane, nativeWindowBorderData );
|
||||
nativeWindowBorderData = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.1.2
|
||||
*/
|
||||
/** @since 1.1.2 */
|
||||
public static void updateNativeWindowBorder( JRootPane rootPane ) {
|
||||
RootPaneUI rui = rootPane.getUI();
|
||||
if( !(rui instanceof FlatRootPaneUI) )
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Component;
|
||||
import javax.swing.UIManager;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
|
||||
/**
|
||||
* Border for various components (e.g. {@link javax.swing.JComboBox}).
|
||||
@@ -29,7 +30,10 @@ import javax.swing.UIManager;
|
||||
public class FlatRoundBorder
|
||||
extends FlatBorder
|
||||
{
|
||||
protected final int arc = UIManager.getInt( "Component.arc" );
|
||||
@Styleable protected int arc = UIManager.getInt( "Component.arc" );
|
||||
|
||||
// only used via styling (not in UI defaults, but has likewise client properties)
|
||||
/** @since 2 */ @Styleable protected Boolean roundRect;
|
||||
|
||||
@Override
|
||||
protected int getArc( Component c ) {
|
||||
@@ -37,6 +41,8 @@ public class FlatRoundBorder
|
||||
return 0;
|
||||
|
||||
Boolean roundRect = FlatUIUtils.isRoundRect( c );
|
||||
if( roundRect == null )
|
||||
roundRect = this.roundRect;
|
||||
return roundRect != null ? (roundRect ? Short.MAX_VALUE : 0) : arc;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.awt.Rectangle;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import javax.swing.InputMap;
|
||||
import javax.swing.JButton;
|
||||
@@ -35,6 +36,9 @@ import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicScrollBarUI;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
@@ -74,33 +78,46 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
*/
|
||||
public class FlatScrollBarUI
|
||||
extends BasicScrollBarUI
|
||||
implements StyleableUI
|
||||
{
|
||||
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;
|
||||
// overrides BasicScrollBarUI.supportsAbsolutePositioning (which is private)
|
||||
@Styleable protected boolean allowsAbsolutePositioning;
|
||||
|
||||
protected boolean showButtons;
|
||||
protected String arrowType;
|
||||
protected Color buttonArrowColor;
|
||||
protected Color buttonDisabledArrowColor;
|
||||
protected Color hoverButtonBackground;
|
||||
protected Color pressedButtonBackground;
|
||||
@Styleable protected Insets trackInsets;
|
||||
@Styleable protected Insets thumbInsets;
|
||||
@Styleable protected int trackArc;
|
||||
@Styleable protected int thumbArc;
|
||||
@Styleable protected Color hoverTrackColor;
|
||||
@Styleable protected Color hoverThumbColor;
|
||||
@Styleable protected boolean hoverThumbWithTrack;
|
||||
@Styleable protected Color pressedTrackColor;
|
||||
@Styleable protected Color pressedThumbColor;
|
||||
@Styleable protected boolean pressedThumbWithTrack;
|
||||
|
||||
@Styleable protected boolean showButtons;
|
||||
@Styleable protected String arrowType;
|
||||
@Styleable protected Color buttonArrowColor;
|
||||
@Styleable protected Color buttonDisabledArrowColor;
|
||||
@Styleable protected Color hoverButtonBackground;
|
||||
@Styleable protected Color pressedButtonBackground;
|
||||
|
||||
private MouseAdapter hoverListener;
|
||||
protected boolean hoverTrack;
|
||||
protected boolean hoverThumb;
|
||||
|
||||
private Map<String, Object> oldStyleValues;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatScrollBarUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
installStyle();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installListeners() {
|
||||
super.installListeners();
|
||||
@@ -123,6 +140,8 @@ public class FlatScrollBarUI
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
|
||||
allowsAbsolutePositioning = super.getSupportsAbsolutePositioning();
|
||||
|
||||
trackInsets = UIManager.getInsets( "ScrollBar.trackInsets" );
|
||||
thumbInsets = UIManager.getInsets( "ScrollBar.thumbInsets" );
|
||||
trackArc = UIManager.getInt( "ScrollBar.trackArc" );
|
||||
@@ -163,6 +182,8 @@ public class FlatScrollBarUI
|
||||
buttonDisabledArrowColor = null;
|
||||
hoverButtonBackground = null;
|
||||
pressedButtonBackground = null;
|
||||
|
||||
oldStyleValues = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -177,6 +198,13 @@ public class FlatScrollBarUI
|
||||
scrollbar.repaint();
|
||||
break;
|
||||
|
||||
case FlatClientProperties.STYLE:
|
||||
case FlatClientProperties.STYLE_CLASS:
|
||||
installStyle();
|
||||
scrollbar.revalidate();
|
||||
scrollbar.repaint();
|
||||
break;
|
||||
|
||||
case "componentOrientation":
|
||||
// this is missing in BasicScrollBarUI.Handler.propertyChange()
|
||||
InputMap inputMap = (InputMap) UIManager.get( "ScrollBar.ancestorInputMap" );
|
||||
@@ -193,6 +221,53 @@ public class FlatScrollBarUI
|
||||
};
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void installStyle() {
|
||||
try {
|
||||
applyStyle( FlatStylingSupport.getResolvedStyle( scrollbar, "ScrollBar" ) );
|
||||
} catch( RuntimeException ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void applyStyle( Object style ) {
|
||||
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
|
||||
|
||||
if( incrButton instanceof FlatScrollBarButton )
|
||||
((FlatScrollBarButton)incrButton).updateStyle();
|
||||
if( decrButton instanceof FlatScrollBarButton )
|
||||
((FlatScrollBarButton)decrButton).updateStyle();
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected Object applyStyleProperty( String key, Object value ) {
|
||||
Object oldValue;
|
||||
switch( key ) {
|
||||
// BasicScrollBarUI
|
||||
case "track": oldValue = trackColor; trackColor = (Color) value; return oldValue;
|
||||
case "thumb": oldValue = thumbColor; thumbColor = (Color) value; return oldValue;
|
||||
case "width": oldValue = scrollBarWidth; scrollBarWidth = (int) value; return oldValue;
|
||||
case "minimumThumbSize": oldValue = minimumThumbSize; minimumThumbSize = (Dimension) value; return oldValue;
|
||||
case "maximumThumbSize": oldValue = maximumThumbSize; maximumThumbSize = (Dimension) value; return oldValue;
|
||||
}
|
||||
|
||||
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, scrollbar, key, value );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||
Map<String, Class<?>> infos = new FlatStylingSupport.StyleableInfosMap<>();
|
||||
infos.put( "track", Color.class );
|
||||
infos.put( "thumb", Color.class );
|
||||
infos.put( "width", int.class );
|
||||
infos.put( "minimumThumbSize", Dimension.class );
|
||||
infos.put( "maximumThumbSize", Dimension.class );
|
||||
FlatStylingSupport.collectAnnotatedStyleableInfos( this, infos );
|
||||
return infos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize( JComponent c ) {
|
||||
return UIScale.scale( super.getPreferredSize( c ) );
|
||||
@@ -209,9 +284,17 @@ public class FlatScrollBarUI
|
||||
}
|
||||
|
||||
protected boolean isShowButtons() {
|
||||
// check client property on scroll bar
|
||||
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 );
|
||||
if( showButtons == null && scrollbar.getParent() instanceof JScrollPane ) {
|
||||
JScrollPane scrollPane = (JScrollPane) scrollbar.getParent();
|
||||
// check client property on scroll pane
|
||||
showButtons = scrollPane.getClientProperty( FlatClientProperties.SCROLL_BAR_SHOW_BUTTONS );
|
||||
if( showButtons == null && scrollPane.getUI() instanceof FlatScrollPaneUI ) {
|
||||
// check styling property on scroll pane
|
||||
showButtons = ((FlatScrollPaneUI)scrollPane.getUI()).showButtons;
|
||||
}
|
||||
}
|
||||
return (showButtons != null) ? Objects.equals( showButtons, true ) : this.showButtons;
|
||||
}
|
||||
|
||||
@@ -295,6 +378,11 @@ public class FlatScrollBarUI
|
||||
return UIScale.scale( FlatUIUtils.addInsets( super.getMaximumThumbSize(), thumbInsets ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getSupportsAbsolutePositioning() {
|
||||
return allowsAbsolutePositioning;
|
||||
}
|
||||
|
||||
//---- class ScrollBarHoverListener ---------------------------------------
|
||||
|
||||
// using static field to disabling hover for other scroll bars
|
||||
@@ -368,6 +456,11 @@ public class FlatScrollBarUI
|
||||
setRequestFocusEnabled( false );
|
||||
}
|
||||
|
||||
protected void updateStyle() {
|
||||
updateStyle( arrowType, buttonArrowColor, buttonDisabledArrowColor,
|
||||
null, hoverButtonBackground, null, pressedButtonBackground );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Color deriveBackground( Color background ) {
|
||||
return FlatUIUtils.deriveColor( background, scrollbar.getBackground() );
|
||||
|
||||
@@ -29,6 +29,8 @@ import java.awt.event.MouseWheelEvent;
|
||||
import java.awt.event.MouseWheelListener;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComponent;
|
||||
@@ -46,6 +48,9 @@ import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicScrollPaneUI;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JScrollPane}.
|
||||
@@ -66,9 +71,16 @@ import com.formdev.flatlaf.FlatClientProperties;
|
||||
*/
|
||||
public class FlatScrollPaneUI
|
||||
extends BasicScrollPaneUI
|
||||
implements StyleableUI
|
||||
{
|
||||
// only used via styling (not in UI defaults, but has likewise client properties)
|
||||
/** @since 2 */ @Styleable protected Boolean showButtons;
|
||||
|
||||
private Handler handler;
|
||||
|
||||
private Map<String, Object> oldStyleValues;
|
||||
private AtomicBoolean borderShared;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatScrollPaneUI();
|
||||
}
|
||||
@@ -80,6 +92,8 @@ public class FlatScrollPaneUI
|
||||
int focusWidth = UIManager.getInt( "Component.focusWidth" );
|
||||
LookAndFeel.installProperty( c, "opaque", focusWidth == 0 );
|
||||
|
||||
installStyle();
|
||||
|
||||
MigLayoutVisualPadding.install( scrollpane );
|
||||
}
|
||||
|
||||
@@ -88,6 +102,9 @@ public class FlatScrollPaneUI
|
||||
MigLayoutVisualPadding.uninstall( scrollpane );
|
||||
|
||||
super.uninstallUI( c );
|
||||
|
||||
oldStyleValues = null;
|
||||
borderShared = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -272,7 +289,14 @@ public class FlatScrollPaneUI
|
||||
((JButton)corner).setBorder( BorderFactory.createEmptyBorder() );
|
||||
((JButton)corner).setFocusable( false );
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
case FlatClientProperties.STYLE:
|
||||
case FlatClientProperties.STYLE_CLASS:
|
||||
installStyle();
|
||||
scrollpane.revalidate();
|
||||
scrollpane.repaint();
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -283,6 +307,38 @@ public class FlatScrollPaneUI
|
||||
return handler;
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void installStyle() {
|
||||
try {
|
||||
applyStyle( FlatStylingSupport.getResolvedStyle( scrollpane, "ScrollPane" ) );
|
||||
} catch( RuntimeException ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void applyStyle( Object style ) {
|
||||
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected Object applyStyleProperty( String key, Object value ) {
|
||||
if( key.equals( "focusWidth" ) ) {
|
||||
int focusWidth = (value instanceof Integer) ? (int) value : UIManager.getInt( "Component.focusWidth" );
|
||||
LookAndFeel.installProperty( scrollpane, "opaque", focusWidth == 0 );
|
||||
}
|
||||
|
||||
if( borderShared == null )
|
||||
borderShared = new AtomicBoolean( true );
|
||||
return FlatStylingSupport.applyToAnnotatedObjectOrBorder( this, key, value, scrollpane, borderShared );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this, scrollpane.getBorder() );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateViewport( PropertyChangeEvent e ) {
|
||||
super.updateViewport( e );
|
||||
@@ -332,9 +388,7 @@ public class FlatScrollPaneUI
|
||||
paint( g, c );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.3
|
||||
*/
|
||||
/** @since 1.3 */
|
||||
public static boolean isPermanentFocusOwner( JScrollPane scrollPane ) {
|
||||
JViewport viewport = scrollPane.getViewport();
|
||||
Component view = (viewport != null) ? viewport.getView() : null;
|
||||
|
||||
@@ -21,11 +21,16 @@ import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Map;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JSeparator;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicSeparatorUI;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JSeparator}.
|
||||
@@ -45,15 +50,37 @@ import javax.swing.plaf.basic.BasicSeparatorUI;
|
||||
*/
|
||||
public class FlatSeparatorUI
|
||||
extends BasicSeparatorUI
|
||||
implements StyleableUI
|
||||
{
|
||||
protected int height;
|
||||
protected int stripeWidth;
|
||||
protected int stripeIndent;
|
||||
@Styleable protected int height;
|
||||
@Styleable protected int stripeWidth;
|
||||
@Styleable protected int stripeIndent;
|
||||
|
||||
private final boolean shared;
|
||||
private boolean defaults_initialized = false;
|
||||
private PropertyChangeListener propertyChangeListener;
|
||||
private Map<String, Object> oldStyleValues;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return FlatUIUtils.createSharedUI( FlatSeparatorUI.class, FlatSeparatorUI::new );
|
||||
return FlatUIUtils.canUseSharedUI( c )
|
||||
? FlatUIUtils.createSharedUI( FlatSeparatorUI.class, () -> new FlatSeparatorUI( true ) )
|
||||
: new FlatSeparatorUI( false );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected FlatSeparatorUI( boolean shared ) {
|
||||
this.shared = shared;
|
||||
}
|
||||
|
||||
protected String getPropertyPrefix() {
|
||||
return "Separator";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
installStyle( (JSeparator) c );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -73,13 +100,70 @@ public class FlatSeparatorUI
|
||||
@Override
|
||||
protected void uninstallDefaults( JSeparator s ) {
|
||||
super.uninstallDefaults( s );
|
||||
|
||||
defaults_initialized = false;
|
||||
oldStyleValues = null;
|
||||
}
|
||||
|
||||
protected String getPropertyPrefix() {
|
||||
@Override
|
||||
protected void installListeners( JSeparator s ) {
|
||||
super.installListeners( s );
|
||||
|
||||
propertyChangeListener = FlatStylingSupport.createPropertyChangeListener(
|
||||
s, () -> stylePropertyChange( s ), null );
|
||||
s.addPropertyChangeListener( propertyChangeListener );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void uninstallListeners( JSeparator s ) {
|
||||
super.uninstallListeners( s );
|
||||
|
||||
s.removePropertyChangeListener( propertyChangeListener );
|
||||
propertyChangeListener = null;
|
||||
}
|
||||
|
||||
private void stylePropertyChange( JSeparator s ) {
|
||||
if( shared && FlatStylingSupport.hasStyleProperty( s ) ) {
|
||||
// unshare component UI if necessary
|
||||
// updateUI() invokes applyStyle() from installUI()
|
||||
s.updateUI();
|
||||
} else
|
||||
installStyle( s );
|
||||
s.revalidate();
|
||||
s.repaint();
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void installStyle( JSeparator s ) {
|
||||
try {
|
||||
applyStyle( s, FlatStylingSupport.getResolvedStyle( s, getStyleType() ) );
|
||||
} catch( RuntimeException ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
String getStyleType() {
|
||||
return "Separator";
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void applyStyle( JSeparator s, Object style ) {
|
||||
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style,
|
||||
(key, value) -> applyStyleProperty( s, key, value ) );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected Object applyStyleProperty( JSeparator s, String key, Object value ) {
|
||||
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, s, key, value );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint( Graphics g, JComponent c ) {
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
|
||||
@@ -29,6 +29,8 @@ import java.awt.event.MouseEvent;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Map;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JSlider;
|
||||
import javax.swing.LookAndFeel;
|
||||
@@ -36,7 +38,11 @@ import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicSliderUI;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.Graphics2DProxy;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
@@ -59,6 +65,8 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault Slider.trackWidth int
|
||||
* @uiDefault Slider.thumbSize Dimension
|
||||
* @uiDefault Slider.focusWidth int
|
||||
* @uiDefault Slider.thumbBorderWidth int or float
|
||||
*
|
||||
* @uiDefault Slider.trackValueColor Color optional; defaults to Slider.thumbColor
|
||||
* @uiDefault Slider.trackColor Color
|
||||
* @uiDefault Slider.thumbColor Color
|
||||
@@ -75,23 +83,26 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
*/
|
||||
public class FlatSliderUI
|
||||
extends BasicSliderUI
|
||||
implements StyleableUI
|
||||
{
|
||||
protected int trackWidth;
|
||||
protected Dimension thumbSize;
|
||||
protected int focusWidth;
|
||||
@Styleable protected int trackWidth;
|
||||
@Styleable protected Dimension thumbSize;
|
||||
@Styleable protected int focusWidth;
|
||||
/** @since 2 */ @Styleable protected float thumbBorderWidth;
|
||||
|
||||
protected Color trackValueColor;
|
||||
protected Color trackColor;
|
||||
protected Color thumbColor;
|
||||
protected Color thumbBorderColor;
|
||||
@Styleable protected Color trackValueColor;
|
||||
@Styleable protected Color trackColor;
|
||||
@Styleable protected Color thumbColor;
|
||||
@Styleable protected Color thumbBorderColor;
|
||||
protected Color focusBaseColor;
|
||||
protected Color focusedColor;
|
||||
protected Color focusedThumbBorderColor;
|
||||
protected Color hoverThumbColor;
|
||||
protected Color pressedThumbColor;
|
||||
protected Color disabledTrackColor;
|
||||
protected Color disabledThumbColor;
|
||||
protected Color disabledThumbBorderColor;
|
||||
@Styleable protected Color focusedColor;
|
||||
@Styleable protected Color focusedThumbBorderColor;
|
||||
@Styleable protected Color hoverThumbColor;
|
||||
@Styleable protected Color pressedThumbColor;
|
||||
@Styleable protected Color disabledTrackColor;
|
||||
@Styleable protected Color disabledThumbColor;
|
||||
@Styleable protected Color disabledThumbBorderColor;
|
||||
@Styleable protected Color tickColor;
|
||||
|
||||
private Color defaultBackground;
|
||||
private Color defaultForeground;
|
||||
@@ -100,6 +111,7 @@ public class FlatSliderUI
|
||||
protected boolean thumbPressed;
|
||||
|
||||
private Object[] oldRenderingHints;
|
||||
private Map<String, Object> oldStyleValues;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatSliderUI();
|
||||
@@ -109,6 +121,13 @@ public class FlatSliderUI
|
||||
super( null );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
installStyle();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installDefaults( JSlider slider ) {
|
||||
super.installDefaults( slider );
|
||||
@@ -123,6 +142,7 @@ public class FlatSliderUI
|
||||
thumbSize = new Dimension( thumbWidth, thumbWidth );
|
||||
}
|
||||
focusWidth = FlatUIUtils.getUIInt( "Slider.focusWidth", 4 );
|
||||
thumbBorderWidth = FlatUIUtils.getUIFloat( "Slider.thumbBorderWidth", 1 );
|
||||
|
||||
trackValueColor = FlatUIUtils.getUIColor( "Slider.trackValueColor", "Slider.thumbColor" );
|
||||
trackColor = UIManager.getColor( "Slider.trackColor" );
|
||||
@@ -136,6 +156,7 @@ public class FlatSliderUI
|
||||
disabledTrackColor = UIManager.getColor( "Slider.disabledTrackColor" );
|
||||
disabledThumbColor = UIManager.getColor( "Slider.disabledThumbColor" );
|
||||
disabledThumbBorderColor = FlatUIUtils.getUIColor( "Slider.disabledThumbBorderColor", "Component.disabledBorderColor" );
|
||||
tickColor = FlatUIUtils.getUIColor( "Slider.tickColor", Color.BLACK ); // see BasicSliderUI.paintTicks()
|
||||
|
||||
defaultBackground = UIManager.getColor( "Slider.background" );
|
||||
defaultForeground = UIManager.getColor( "Slider.foreground" );
|
||||
@@ -157,9 +178,12 @@ public class FlatSliderUI
|
||||
disabledTrackColor = null;
|
||||
disabledThumbColor = null;
|
||||
disabledThumbBorderColor = null;
|
||||
tickColor = null;
|
||||
|
||||
defaultBackground = null;
|
||||
defaultForeground = null;
|
||||
|
||||
oldStyleValues = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -167,6 +191,37 @@ public class FlatSliderUI
|
||||
return new FlatTrackListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PropertyChangeListener createPropertyChangeListener( JSlider slider ) {
|
||||
return FlatStylingSupport.createPropertyChangeListener( slider, this::installStyle,
|
||||
super.createPropertyChangeListener( slider ) );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void installStyle() {
|
||||
try {
|
||||
applyStyle( FlatStylingSupport.getResolvedStyle( slider, "Slider" ) );
|
||||
} catch( RuntimeException ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void applyStyle( Object style ) {
|
||||
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected Object applyStyleProperty( String key, Object value ) {
|
||||
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, slider, key, value );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBaseline( JComponent c, int width, int height ) {
|
||||
if( c == null )
|
||||
@@ -326,6 +381,19 @@ debug*/
|
||||
((Graphics2D)g).fill( track );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintTicks( Graphics g ) {
|
||||
// because BasicSliderUI.paintTicks() always uses
|
||||
// g.setColor( UIManager.getColor("Slider.tickColor") )
|
||||
// we override this method and use our tickColor field to allow styling
|
||||
super.paintTicks( new Graphics2DProxy( (Graphics2D) g ) {
|
||||
@Override
|
||||
public void setColor( Color c ) {
|
||||
super.setColor( tickColor );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintThumb( Graphics g ) {
|
||||
Color thumbColor = getThumbColor();
|
||||
@@ -341,11 +409,11 @@ debug*/
|
||||
Color focusedColor = FlatUIUtils.deriveColor( this.focusedColor,
|
||||
(foreground != defaultForeground) ? foreground : focusBaseColor );
|
||||
|
||||
paintThumb( g, slider, thumbRect, isRoundThumb(), color, borderColor, focusedColor, focusWidth );
|
||||
paintThumb( g, slider, thumbRect, isRoundThumb(), color, borderColor, focusedColor, thumbBorderWidth, focusWidth );
|
||||
}
|
||||
|
||||
public static void paintThumb( Graphics g, JSlider slider, Rectangle thumbRect, boolean roundThumb,
|
||||
Color thumbColor, Color thumbBorderColor, Color focusedColor, int focusWidth )
|
||||
Color thumbColor, Color thumbBorderColor, Color focusedColor, float thumbBorderWidth, int focusWidth )
|
||||
{
|
||||
double systemScaleFactor = UIScale.getSystemScaleFactor( (Graphics2D) g );
|
||||
if( systemScaleFactor != 1 && systemScaleFactor != 2 ) {
|
||||
@@ -354,18 +422,20 @@ debug*/
|
||||
(g2d, x2, y2, width2, height2, scaleFactor) -> {
|
||||
paintThumbImpl( g, slider, x2, y2, width2, height2,
|
||||
roundThumb, thumbColor, thumbBorderColor, focusedColor,
|
||||
(float) (thumbBorderWidth * scaleFactor),
|
||||
(float) (focusWidth * scaleFactor) );
|
||||
} );
|
||||
return;
|
||||
}
|
||||
|
||||
paintThumbImpl( g, slider, thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height,
|
||||
roundThumb, thumbColor, thumbBorderColor, focusedColor, focusWidth );
|
||||
roundThumb, thumbColor, thumbBorderColor, focusedColor, thumbBorderWidth, focusWidth );
|
||||
|
||||
}
|
||||
|
||||
private static void paintThumbImpl( Graphics g, JSlider slider, int x, int y, int width, int height,
|
||||
boolean roundThumb, Color thumbColor, Color thumbBorderColor, Color focusedColor, float focusWidth )
|
||||
boolean roundThumb, Color thumbColor, Color thumbBorderColor, Color focusedColor,
|
||||
float thumbBorderWidth, float focusWidth )
|
||||
{
|
||||
int fw = Math.round( UIScale.scale( focusWidth ) );
|
||||
int tx = x + fw;
|
||||
@@ -387,7 +457,7 @@ debug*/
|
||||
((Graphics2D)g).fill( createRoundThumbShape( tx, ty, tw, th ) );
|
||||
|
||||
// paint thumb background
|
||||
float lw = UIScale.scale( 1f );
|
||||
float lw = UIScale.scale( thumbBorderWidth );
|
||||
g.setColor( thumbColor );
|
||||
((Graphics2D)g).fill( createRoundThumbShape( tx + lw, ty + lw,
|
||||
tw - lw - lw, th - lw - lw ) );
|
||||
@@ -428,7 +498,7 @@ debug*/
|
||||
g2.fill( createDirectionalThumbShape( fw, fw, tw, th, 0 ) );
|
||||
|
||||
// paint thumb background
|
||||
float lw = UIScale.scale( 1f );
|
||||
float lw = UIScale.scale( thumbBorderWidth );
|
||||
g2.setColor( thumbColor );
|
||||
g2.fill( createDirectionalThumbShape( fw + lw, fw + lw,
|
||||
tw - lw - lw, th - lw - lw - (lw * 0.4142f), 0 ) );
|
||||
|
||||
@@ -33,6 +33,8 @@ import java.awt.event.FocusListener;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JSpinner;
|
||||
import javax.swing.JTextField;
|
||||
@@ -43,6 +45,9 @@ import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicSpinnerUI;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JSpinner}.
|
||||
@@ -63,12 +68,13 @@ import com.formdev.flatlaf.FlatClientProperties;
|
||||
* @uiDefault Spinner.buttonStyle String button (default) or none
|
||||
* @uiDefault Component.arrowType String chevron (default) or triangle
|
||||
* @uiDefault Component.isIntelliJTheme boolean
|
||||
* @uiDefault Component.borderColor Color
|
||||
* @uiDefault Component.disabledBorderColor Color
|
||||
* @uiDefault Spinner.disabledBackground Color
|
||||
* @uiDefault Spinner.disabledForeground Color
|
||||
* @uiDefault Spinner.focusedBackground Color optional
|
||||
* @uiDefault Spinner.buttonBackground Color
|
||||
* @uiDefault Spinner.buttonSeparatorWidth int or float optional; defaults to Component.borderWidth
|
||||
* @uiDefault Spinner.buttonSeparatorColor Color optional
|
||||
* @uiDefault Spinner.buttonDisabledSeparatorColor Color optional
|
||||
* @uiDefault Spinner.buttonArrowColor Color
|
||||
* @uiDefault Spinner.buttonDisabledArrowColor Color
|
||||
* @uiDefault Spinner.buttonHoverArrowColor Color
|
||||
@@ -79,29 +85,41 @@ import com.formdev.flatlaf.FlatClientProperties;
|
||||
*/
|
||||
public class FlatSpinnerUI
|
||||
extends BasicSpinnerUI
|
||||
implements StyleableUI
|
||||
{
|
||||
private Handler handler;
|
||||
|
||||
protected int minimumWidth;
|
||||
protected String buttonStyle;
|
||||
protected String arrowType;
|
||||
@Styleable protected int minimumWidth;
|
||||
@Styleable protected String buttonStyle;
|
||||
@Styleable protected String arrowType;
|
||||
protected boolean isIntelliJTheme;
|
||||
protected Color borderColor;
|
||||
protected Color disabledBorderColor;
|
||||
protected Color disabledBackground;
|
||||
protected Color disabledForeground;
|
||||
protected Color focusedBackground;
|
||||
protected Color buttonBackground;
|
||||
protected Color buttonArrowColor;
|
||||
protected Color buttonDisabledArrowColor;
|
||||
protected Color buttonHoverArrowColor;
|
||||
protected Color buttonPressedArrowColor;
|
||||
protected Insets padding;
|
||||
@Styleable protected Color disabledBackground;
|
||||
@Styleable protected Color disabledForeground;
|
||||
@Styleable protected Color focusedBackground;
|
||||
@Styleable protected Color buttonBackground;
|
||||
/** @since 2 */ @Styleable protected float buttonSeparatorWidth;
|
||||
/** @since 2 */ @Styleable protected Color buttonSeparatorColor;
|
||||
/** @since 2 */ @Styleable protected Color buttonDisabledSeparatorColor;
|
||||
@Styleable protected Color buttonArrowColor;
|
||||
@Styleable protected Color buttonDisabledArrowColor;
|
||||
@Styleable protected Color buttonHoverArrowColor;
|
||||
@Styleable protected Color buttonPressedArrowColor;
|
||||
@Styleable protected Insets padding;
|
||||
|
||||
private Map<String, Object> oldStyleValues;
|
||||
private AtomicBoolean borderShared;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatSpinnerUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
installStyle();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
@@ -112,12 +130,13 @@ public class FlatSpinnerUI
|
||||
buttonStyle = UIManager.getString( "Spinner.buttonStyle" );
|
||||
arrowType = UIManager.getString( "Component.arrowType" );
|
||||
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
||||
borderColor = UIManager.getColor( "Component.borderColor" );
|
||||
disabledBorderColor = UIManager.getColor( "Component.disabledBorderColor" );
|
||||
disabledBackground = UIManager.getColor( "Spinner.disabledBackground" );
|
||||
disabledForeground = UIManager.getColor( "Spinner.disabledForeground" );
|
||||
focusedBackground = UIManager.getColor( "Spinner.focusedBackground" );
|
||||
buttonBackground = UIManager.getColor( "Spinner.buttonBackground" );
|
||||
buttonSeparatorWidth = FlatUIUtils.getUIFloat( "Spinner.buttonSeparatorWidth", FlatUIUtils.getUIFloat( "Component.borderWidth", 1 ) );
|
||||
buttonSeparatorColor = UIManager.getColor( "Spinner.buttonSeparatorColor" );
|
||||
buttonDisabledSeparatorColor = UIManager.getColor( "Spinner.buttonDisabledSeparatorColor" );
|
||||
buttonArrowColor = UIManager.getColor( "Spinner.buttonArrowColor" );
|
||||
buttonDisabledArrowColor = UIManager.getColor( "Spinner.buttonDisabledArrowColor" );
|
||||
buttonHoverArrowColor = UIManager.getColor( "Spinner.buttonHoverArrowColor" );
|
||||
@@ -131,18 +150,21 @@ public class FlatSpinnerUI
|
||||
protected void uninstallDefaults() {
|
||||
super.uninstallDefaults();
|
||||
|
||||
borderColor = null;
|
||||
disabledBorderColor = null;
|
||||
disabledBackground = null;
|
||||
disabledForeground = null;
|
||||
focusedBackground = null;
|
||||
buttonBackground = null;
|
||||
buttonSeparatorColor = null;
|
||||
buttonDisabledSeparatorColor = null;
|
||||
buttonArrowColor = null;
|
||||
buttonDisabledArrowColor = null;
|
||||
buttonHoverArrowColor = null;
|
||||
buttonPressedArrowColor = null;
|
||||
padding = null;
|
||||
|
||||
oldStyleValues = null;
|
||||
borderShared = null;
|
||||
|
||||
MigLayoutVisualPadding.uninstall( spinner );
|
||||
}
|
||||
|
||||
@@ -172,6 +194,35 @@ public class FlatSpinnerUI
|
||||
return handler;
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void installStyle() {
|
||||
try {
|
||||
applyStyle( FlatStylingSupport.getResolvedStyle( spinner, "Spinner" ) );
|
||||
} catch( RuntimeException ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void applyStyle( Object style ) {
|
||||
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
|
||||
updateEditorPadding();
|
||||
updateArrowButtonsStyle();
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected Object applyStyleProperty( String key, Object value ) {
|
||||
if( borderShared == null )
|
||||
borderShared = new AtomicBoolean( true );
|
||||
return FlatStylingSupport.applyToAnnotatedObjectOrBorder( this, key, value, spinner, borderShared );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this, spinner.getBorder() );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JComponent createEditor() {
|
||||
JComponent editor = super.createEditor();
|
||||
@@ -236,9 +287,7 @@ public class FlatSpinnerUI
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.3
|
||||
*/
|
||||
/** @since 1.3 */
|
||||
public static boolean isPermanentFocusOwner( JSpinner spinner ) {
|
||||
if( FlatUIUtils.isPermanentFocusOwner( spinner ) )
|
||||
return true;
|
||||
@@ -297,6 +346,15 @@ public class FlatSpinnerUI
|
||||
return button;
|
||||
}
|
||||
|
||||
private void updateArrowButtonsStyle() {
|
||||
for( Component c : spinner.getComponents() ) {
|
||||
if( c instanceof FlatArrowButton ) {
|
||||
((FlatArrowButton)c).updateStyle( arrowType, buttonArrowColor,
|
||||
buttonDisabledArrowColor, buttonHoverArrowColor, null, buttonPressedArrowColor, null );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update( Graphics g, JComponent c ) {
|
||||
float focusWidth = FlatUIUtils.getBorderFocusWidth( c );
|
||||
@@ -339,10 +397,13 @@ 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) ) );
|
||||
Color separatorColor = enabled ? buttonSeparatorColor : buttonDisabledSeparatorColor;
|
||||
if( separatorColor != null ) {
|
||||
g2.setColor( separatorColor );
|
||||
float lw = scale( buttonSeparatorWidth );
|
||||
float lx = isLeftToRight ? arrowX : arrowX + arrowWidth - lw;
|
||||
g2.fill( new Rectangle2D.Float( lx, focusWidth, lw, height - 1 - (focusWidth * 2) ) );
|
||||
}
|
||||
}
|
||||
|
||||
paint( g, c );
|
||||
@@ -483,6 +544,13 @@ public class FlatSpinnerUI
|
||||
case FlatClientProperties.MINIMUM_WIDTH:
|
||||
spinner.revalidate();
|
||||
break;
|
||||
|
||||
case FlatClientProperties.STYLE:
|
||||
case FlatClientProperties.STYLE_CLASS:
|
||||
installStyle();
|
||||
spinner.revalidate();
|
||||
spinner.repaint();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ import java.awt.Graphics;
|
||||
import java.awt.Insets;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Map;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JSplitPane;
|
||||
@@ -32,6 +34,10 @@ import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicSplitPaneDivider;
|
||||
import javax.swing.plaf.basic.BasicSplitPaneUI;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
@@ -66,16 +72,27 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
*/
|
||||
public class FlatSplitPaneUI
|
||||
extends BasicSplitPaneUI
|
||||
implements StyleableUI
|
||||
{
|
||||
protected String arrowType;
|
||||
protected Color oneTouchArrowColor;
|
||||
protected Color oneTouchHoverArrowColor;
|
||||
protected Color oneTouchPressedArrowColor;
|
||||
@Styleable protected String arrowType;
|
||||
@Styleable protected Color oneTouchArrowColor;
|
||||
@Styleable protected Color oneTouchHoverArrowColor;
|
||||
@Styleable protected Color oneTouchPressedArrowColor;
|
||||
|
||||
private PropertyChangeListener propertyChangeListener;
|
||||
private Map<String, Object> oldStyleValues;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatSplitPaneUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
installStyle();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installDefaults() {
|
||||
arrowType = UIManager.getString( "Component.arrowType" );
|
||||
@@ -96,6 +113,24 @@ public class FlatSplitPaneUI
|
||||
oneTouchArrowColor = null;
|
||||
oneTouchHoverArrowColor = null;
|
||||
oneTouchPressedArrowColor = null;
|
||||
|
||||
oldStyleValues = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installListeners() {
|
||||
super.installListeners();
|
||||
|
||||
propertyChangeListener = FlatStylingSupport.createPropertyChangeListener( splitPane, this::installStyle, null );
|
||||
splitPane.addPropertyChangeListener( propertyChangeListener );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void uninstallListeners() {
|
||||
super.uninstallListeners();
|
||||
|
||||
splitPane.removePropertyChangeListener( propertyChangeListener );
|
||||
propertyChangeListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -103,16 +138,53 @@ public class FlatSplitPaneUI
|
||||
return new FlatSplitPaneDivider( this );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void installStyle() {
|
||||
try {
|
||||
applyStyle( FlatStylingSupport.getResolvedStyle( splitPane, "SplitPane" ) );
|
||||
} catch( RuntimeException ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void applyStyle( Object style ) {
|
||||
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
|
||||
|
||||
if( divider instanceof FlatSplitPaneDivider )
|
||||
((FlatSplitPaneDivider)divider).updateStyle();
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected Object applyStyleProperty( String key, Object value ) {
|
||||
try {
|
||||
if( divider instanceof FlatSplitPaneDivider )
|
||||
return ((FlatSplitPaneDivider)divider).applyStyleProperty( key, value );
|
||||
} catch( UnknownStyleException ex ) {
|
||||
// ignore
|
||||
}
|
||||
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, splitPane, key, value );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||
Map<String, Class<?>> infos = FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
||||
if( divider instanceof FlatSplitPaneDivider )
|
||||
infos.putAll( ((FlatSplitPaneDivider)divider).getStyleableInfos() );
|
||||
return infos;
|
||||
}
|
||||
|
||||
//---- class FlatSplitPaneDivider -----------------------------------------
|
||||
|
||||
protected class FlatSplitPaneDivider
|
||||
extends BasicSplitPaneDivider
|
||||
{
|
||||
protected final String style = UIManager.getString( "SplitPaneDivider.style" );
|
||||
protected final Color gripColor = UIManager.getColor( "SplitPaneDivider.gripColor" );
|
||||
protected final int gripDotCount = FlatUIUtils.getUIInt( "SplitPaneDivider.gripDotCount", 3 );
|
||||
protected final int gripDotSize = FlatUIUtils.getUIInt( "SplitPaneDivider.gripDotSize", 3 );
|
||||
protected final int gripGap = FlatUIUtils.getUIInt( "SplitPaneDivider.gripGap", 2 );
|
||||
@Styleable protected String style = UIManager.getString( "SplitPaneDivider.style" );
|
||||
@Styleable protected Color gripColor = UIManager.getColor( "SplitPaneDivider.gripColor" );
|
||||
@Styleable protected int gripDotCount = FlatUIUtils.getUIInt( "SplitPaneDivider.gripDotCount", 3 );
|
||||
@Styleable protected int gripDotSize = FlatUIUtils.getUIInt( "SplitPaneDivider.gripDotSize", 3 );
|
||||
@Styleable protected int gripGap = FlatUIUtils.getUIInt( "SplitPaneDivider.gripGap", 2 );
|
||||
|
||||
protected FlatSplitPaneDivider( BasicSplitPaneUI ui ) {
|
||||
super( ui );
|
||||
@@ -120,6 +192,27 @@ public class FlatSplitPaneUI
|
||||
setLayout( new FlatDividerLayout() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2
|
||||
*/
|
||||
protected Object applyStyleProperty( String key, Object value ) {
|
||||
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2
|
||||
*/
|
||||
public Map<String, Class<?>> getStyleableInfos() {
|
||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
||||
}
|
||||
|
||||
void updateStyle() {
|
||||
if( leftButton instanceof FlatOneTouchButton )
|
||||
((FlatOneTouchButton)leftButton).updateStyle();
|
||||
if( rightButton instanceof FlatOneTouchButton )
|
||||
((FlatOneTouchButton)rightButton).updateStyle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDividerSize( int newSize ) {
|
||||
super.setDividerSize( UIScale.scale( newSize ) );
|
||||
@@ -200,6 +293,11 @@ public class FlatSplitPaneUI
|
||||
this.left = left;
|
||||
}
|
||||
|
||||
protected void updateStyle() {
|
||||
updateStyle( arrowType, oneTouchArrowColor, null,
|
||||
oneTouchHoverArrowColor, null, oneTouchPressedArrowColor, null );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDirection() {
|
||||
return (orientation == JSplitPane.VERTICAL_SPLIT)
|
||||
|
||||
@@ -0,0 +1,758 @@
|
||||
/*
|
||||
* Copyright 2021 FormDev Software GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Predicate;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.Border;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.util.StringUtils;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
|
||||
/**
|
||||
* Support for styling components in CSS syntax.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
* @since 2
|
||||
*/
|
||||
public class FlatStylingSupport
|
||||
{
|
||||
/**
|
||||
* Indicates that a field is intended to be used by FlatLaf styling support.
|
||||
* <p>
|
||||
* <strong>Do not rename fields annotated with this annotation.</strong>
|
||||
*
|
||||
* @since 2
|
||||
*/
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Styleable {
|
||||
boolean dot() default false;
|
||||
Class<?> type() default Void.class;
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
public interface StyleableUI {
|
||||
Map<String, Class<?>> getStyleableInfos( JComponent c );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
public interface StyleableBorder {
|
||||
Object applyStyleProperty( String key, Object value );
|
||||
Map<String, Class<?>> getStyleableInfos();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the style specified in client property {@link FlatClientProperties#STYLE}.
|
||||
*/
|
||||
public static Object getStyle( JComponent c ) {
|
||||
return c.getClientProperty( FlatClientProperties.STYLE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the style class(es) specified in client property {@link FlatClientProperties#STYLE_CLASS}.
|
||||
*/
|
||||
public static Object getStyleClass( JComponent c ) {
|
||||
return c.getClientProperty( FlatClientProperties.STYLE_CLASS );
|
||||
}
|
||||
|
||||
static boolean hasStyleProperty( JComponent c ) {
|
||||
return getStyle( c ) != null || getStyleClass( c ) != null;
|
||||
}
|
||||
|
||||
public static Object getResolvedStyle( JComponent c, String type ) {
|
||||
Object style = getStyle( c );
|
||||
Object styleClass = getStyleClass( c );
|
||||
Object styleForClasses = getStyleForClasses( styleClass, type );
|
||||
Object styleForType = getStyleForType( type );
|
||||
return joinStyles( joinStyles( styleForType, styleForClasses ), style );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the styles for the given style class(es) and the given type.
|
||||
* <p>
|
||||
* The style rules must be defined in UI defaults either as strings (in CSS syntax)
|
||||
* or as {@link java.util.Map}<String, Object> (with binary values).
|
||||
* The key must be in syntax: {@code [style]type.styleClass}, where the type is optional.
|
||||
* E.g. in FlatLaf properties file:
|
||||
* <pre>{@code
|
||||
* [style]Button.primary = borderColor: #08f; background: #08f; foreground: #fff
|
||||
* [style].secondary = borderColor: #0f8; background: #0f8
|
||||
* }</pre>
|
||||
* or in Java code:
|
||||
* <pre>{@code
|
||||
* UIManager.put( "[style]Button.primary", "borderColor: #08f; background: #08f; foreground: #fff" );
|
||||
* UIManager.put( "[style].secondary", "borderColor: #0f8; background: #0f8" );
|
||||
* }</pre>
|
||||
* The rule "Button.primary" can be applied to buttons only.
|
||||
* The rule ".secondary" can be applied to any component.
|
||||
* <p>
|
||||
* To have similar behavior as in CSS, this method first gets the rule without type,
|
||||
* then the rule with type and concatenates both rules.
|
||||
* E.g. invoking this method with parameters styleClass="foo" and type="Button" does following:
|
||||
* <pre>{@code
|
||||
* return joinStyles(
|
||||
* UIManager.get( "[style].foo" ),
|
||||
* UIManager.get( "[style]Button.foo" ) );
|
||||
* }</pre>
|
||||
*
|
||||
* @param styleClass the style class(es) either as string (single class or multiple classes separated by space characters)
|
||||
* or as {@code String[]} or {@link java.util.List}<String> (multiple classes)
|
||||
* @param type the type of the component
|
||||
* @return the styles
|
||||
*/
|
||||
public static Object getStyleForClasses( Object styleClass, String type ) {
|
||||
if( styleClass == null )
|
||||
return null;
|
||||
|
||||
if( styleClass instanceof String && ((String)styleClass).indexOf( ' ' ) >= 0 )
|
||||
styleClass = StringUtils.split( (String) styleClass, ' ', true, true );
|
||||
|
||||
if( styleClass instanceof String )
|
||||
return getStyleForClass( ((String)styleClass).trim(), type );
|
||||
else if( styleClass instanceof String[] ) {
|
||||
Object style = null;
|
||||
for( String cls : (String[]) styleClass )
|
||||
style = joinStyles( style, getStyleForClass( cls, type ) );
|
||||
return style;
|
||||
} else if( styleClass instanceof List<?> ) {
|
||||
Object style = null;
|
||||
for( Object cls : (List<?>) styleClass )
|
||||
style = joinStyles( style, getStyleForClass( (String) cls, type ) );
|
||||
return style;
|
||||
} else
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Object getStyleForClass( String styleClass, String type ) {
|
||||
return joinStyles(
|
||||
UIManager.get( "[style]." + styleClass ),
|
||||
UIManager.get( "[style]" + type + '.' + styleClass ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the styles for the given type.
|
||||
* <p>
|
||||
* The style rules must be defined in UI defaults either as strings (in CSS syntax)
|
||||
* or as {@link java.util.Map}<String, Object> (with binary values).
|
||||
* The key must be in syntax: {@code [style]type}.
|
||||
* E.g. in FlatLaf properties file:
|
||||
* <pre>{@code
|
||||
* [style]Button = borderColor: #08f; background: #08f; foreground: #fff
|
||||
* }</pre>
|
||||
* or in Java code:
|
||||
* <pre>{@code
|
||||
* UIManager.put( "[style]Button", "borderColor: #08f; background: #08f; foreground: #fff" );
|
||||
* }</pre>
|
||||
*
|
||||
* @param type the type of the component
|
||||
* @return the styles
|
||||
*/
|
||||
public static Object getStyleForType( String type ) {
|
||||
return UIManager.get( "[style]" + type );
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins two styles. They can be either strings (in CSS syntax)
|
||||
* or {@link java.util.Map}<String, Object> (with binary values).
|
||||
* <p>
|
||||
* If both styles are strings, then a joined string is returned.
|
||||
* If both styles are maps, then a joined map is returned.
|
||||
* If one style is a map and the other style a string, then the string
|
||||
* is parsed (using {@link #parse(String)}) to a map and a joined map is returned.
|
||||
*
|
||||
* @param style1 first style as string or map, or {@code null}
|
||||
* @param style2 second style as string or map, or {@code null}
|
||||
* @return new joined style
|
||||
*/
|
||||
@SuppressWarnings( "unchecked" )
|
||||
public static Object joinStyles( Object style1, Object style2 ) {
|
||||
if( style1 == null )
|
||||
return style2;
|
||||
if( style2 == null )
|
||||
return style1;
|
||||
|
||||
// join two strings
|
||||
if( style1 instanceof String && style2 instanceof String )
|
||||
return style1 + "; " + style2;
|
||||
|
||||
// convert first style to map
|
||||
Map<String, Object> map1 = (style1 instanceof String)
|
||||
? parse( (String) style1 )
|
||||
: (Map<String, Object>) style1;
|
||||
if( map1 == null )
|
||||
return style2;
|
||||
|
||||
// convert second style to map
|
||||
Map<String, Object> map2 = (style2 instanceof String)
|
||||
? parse( (String) style2 )
|
||||
: (Map<String, Object>) style2;
|
||||
if( map2 == null )
|
||||
return style1;
|
||||
|
||||
// join two maps
|
||||
Map<String, Object> map = new HashMap<>( map1 );
|
||||
map.putAll( map2 );
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenates two styles in CSS syntax.
|
||||
*
|
||||
* @param style1 first style, or {@code null}
|
||||
* @param style2 second style, or {@code null}
|
||||
* @return concatenation of the two styles separated by a semicolon
|
||||
*/
|
||||
public static String concatStyles( String style1, String style2 ) {
|
||||
if( style1 == null )
|
||||
return style2;
|
||||
if( style2 == null )
|
||||
return style1;
|
||||
return style1 + "; " + style2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses styles in CSS syntax ("key1: value1; key2: value2; ..."),
|
||||
* converts the value strings into binary and invokes the given function
|
||||
* to apply the properties.
|
||||
*
|
||||
* @param oldStyleValues map of old values modified by the previous invocation, or {@code null}
|
||||
* @param style the style in CSS syntax as string, or a Map, or {@code null}
|
||||
* @param applyProperty function that is invoked to apply the properties;
|
||||
* first parameter is the key, second the binary value;
|
||||
* the function must return the old value
|
||||
* @return map of old values modified by the given style, or {@code null}
|
||||
* @throws UnknownStyleException on unknown style keys
|
||||
* @throws IllegalArgumentException on syntax errors
|
||||
* @throws ClassCastException if value type does not fit to expected type
|
||||
*/
|
||||
public static Map<String, Object> parseAndApply( Map<String, Object> oldStyleValues,
|
||||
Object style, BiFunction<String, Object, Object> applyProperty )
|
||||
throws UnknownStyleException, IllegalArgumentException
|
||||
{
|
||||
// restore previous values
|
||||
if( oldStyleValues != null ) {
|
||||
for( Map.Entry<String, Object> e : oldStyleValues.entrySet() )
|
||||
applyProperty.apply( e.getKey(), e.getValue() );
|
||||
}
|
||||
|
||||
// ignore empty style
|
||||
if( style == null )
|
||||
return null;
|
||||
|
||||
if( style instanceof String ) {
|
||||
// handle style in CSS syntax
|
||||
String str = (String) style;
|
||||
if( StringUtils.isTrimmedEmpty( str ) )
|
||||
return null;
|
||||
|
||||
return applyStyle( parse( str ), applyProperty );
|
||||
} else if( style instanceof Map ) {
|
||||
// handle style of type Map
|
||||
@SuppressWarnings( "unchecked" )
|
||||
Map<String, Object> map = (Map<String, Object>) style;
|
||||
return applyStyle( map, applyProperty );
|
||||
} else
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Map<String, Object> applyStyle( Map<String, Object> style,
|
||||
BiFunction<String, Object, Object> applyProperty )
|
||||
{
|
||||
if( style.isEmpty() )
|
||||
return null;
|
||||
|
||||
Map<String, Object> oldValues = new HashMap<>();
|
||||
for( Map.Entry<String, Object> e : style.entrySet() ) {
|
||||
String key = e.getKey();
|
||||
Object newValue = e.getValue();
|
||||
|
||||
// handle key prefix
|
||||
if( key.startsWith( "[" ) ) {
|
||||
if( (SystemInfo.isWindows && key.startsWith( "[win]" )) ||
|
||||
(SystemInfo.isMacOS && key.startsWith( "[mac]" )) ||
|
||||
(SystemInfo.isLinux && key.startsWith( "[linux]" )) ||
|
||||
(key.startsWith( "[light]" ) && !FlatLaf.isLafDark()) ||
|
||||
(key.startsWith( "[dark]" ) && FlatLaf.isLafDark()) )
|
||||
{
|
||||
// prefix is known and enabled --> remove prefix
|
||||
key = key.substring( key.indexOf( ']' ) + 1 );
|
||||
} else
|
||||
continue;
|
||||
}
|
||||
|
||||
Object oldValue = applyProperty.apply( key, newValue );
|
||||
oldValues.put( key, oldValue );
|
||||
}
|
||||
return oldValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses styles in CSS syntax ("key1: value1; key2: value2; ..."),
|
||||
* converts the value strings into binary and returns all key/value pairs as map.
|
||||
*
|
||||
* @param style the style in CSS syntax, or {@code null}
|
||||
* @return map of parsed styles, or {@code null}
|
||||
* @throws IllegalArgumentException on syntax errors
|
||||
*/
|
||||
public static Map<String, Object> parse( String style )
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
if( style == null || StringUtils.isTrimmedEmpty( style ) )
|
||||
return null;
|
||||
|
||||
Map<String, Object> map = null;
|
||||
|
||||
// split style into parts and process them
|
||||
for( String part : StringUtils.split( style, ';', true, true ) ) {
|
||||
// find separator colon
|
||||
int sepIndex = part.indexOf( ':' );
|
||||
if( sepIndex < 0 )
|
||||
throw new IllegalArgumentException( "missing colon in '" + part + "'" );
|
||||
|
||||
// split into key and value
|
||||
String key = StringUtils.substringTrimmed( part, 0, sepIndex );
|
||||
String value = StringUtils.substringTrimmed( part, sepIndex + 1 );
|
||||
if( key.isEmpty() )
|
||||
throw new IllegalArgumentException( "missing key in '" + part + "'" );
|
||||
if( value.isEmpty() )
|
||||
throw new IllegalArgumentException( "missing value in '" + part + "'" );
|
||||
|
||||
// parse value string and convert it into binary value
|
||||
if( map == null )
|
||||
map = new LinkedHashMap<>();
|
||||
map.put( key, parseValue( key, value ) );
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
private static Object parseValue( String key, String value ) {
|
||||
// simple reference
|
||||
if( value.startsWith( "$" ) )
|
||||
return UIManager.get( value.substring( 1 ) );
|
||||
|
||||
// remove key prefix for correct value type detection
|
||||
// (e.g. "[light]padding" would not parse to Insets)
|
||||
if( key.startsWith( "[" ) )
|
||||
key = key.substring( key.indexOf( ']' ) + 1 );
|
||||
|
||||
// parse string
|
||||
return FlatLaf.parseDefaultsValue( key, value, null );
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the given value to an annotated field of the given object.
|
||||
* The field must be annotated with {@link Styleable}.
|
||||
*
|
||||
* @param obj the object
|
||||
* @param key the name of the field
|
||||
* @param value the new value
|
||||
* @return the old value of the field
|
||||
* @throws UnknownStyleException if object does not have a annotated field with given name
|
||||
* @throws IllegalArgumentException if value type does not fit to expected type
|
||||
*/
|
||||
public static Object applyToAnnotatedObject( Object obj, String key, Object value )
|
||||
throws UnknownStyleException, IllegalArgumentException
|
||||
{
|
||||
String fieldName = key;
|
||||
int dotIndex = key.indexOf( '.' );
|
||||
if( dotIndex >= 0 ) {
|
||||
// remove first dot in key and change subsequent character to uppercase
|
||||
fieldName = key.substring( 0, dotIndex )
|
||||
+ Character.toUpperCase( key.charAt( dotIndex + 1 ) )
|
||||
+ key.substring( dotIndex + 2 );
|
||||
}
|
||||
|
||||
return applyToField( obj, fieldName, key, value, field -> {
|
||||
Styleable styleable = field.getAnnotation( Styleable.class );
|
||||
return styleable != null && styleable.dot() == (dotIndex >= 0);
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the given value to a field of the given object.
|
||||
*
|
||||
* @param obj the object
|
||||
* @param fieldName the name of the field
|
||||
* @param key the key (only used for error reporting)
|
||||
* @param value the new value
|
||||
* @return the old value of the field
|
||||
* @throws UnknownStyleException if object does not have a field with given name
|
||||
* @throws IllegalArgumentException if value type does not fit to expected type
|
||||
*/
|
||||
static Object applyToField( Object obj, String fieldName, String key, Object value )
|
||||
throws UnknownStyleException, IllegalArgumentException
|
||||
{
|
||||
return applyToField( obj, fieldName, key, value, null );
|
||||
}
|
||||
|
||||
private static Object applyToField( Object obj, String fieldName, String key, Object value, Predicate<Field> predicate )
|
||||
throws UnknownStyleException, IllegalArgumentException
|
||||
{
|
||||
Class<?> cls = obj.getClass();
|
||||
|
||||
for(;;) {
|
||||
try {
|
||||
Field f = cls.getDeclaredField( fieldName );
|
||||
if( predicate == null || predicate.test( f ) ) {
|
||||
if( !isValidField( f ) )
|
||||
throw new IllegalArgumentException( "field '" + cls.getName() + "." + fieldName + "' is final or static" );
|
||||
|
||||
try {
|
||||
// necessary to access protected fields in other packages
|
||||
f.setAccessible( true );
|
||||
|
||||
// get old value and set new value
|
||||
Object oldValue = f.get( obj );
|
||||
f.set( obj, convertToEnum( value, f.getType() ) );
|
||||
return oldValue;
|
||||
} catch( IllegalAccessException ex ) {
|
||||
throw new IllegalArgumentException( "failed to access field '" + cls.getName() + "." + fieldName + "'", ex );
|
||||
}
|
||||
}
|
||||
} catch( NoSuchFieldException ex ) {
|
||||
// field not found in class --> try superclass
|
||||
}
|
||||
|
||||
cls = cls.getSuperclass();
|
||||
if( cls == null )
|
||||
throw new UnknownStyleException( key );
|
||||
|
||||
if( predicate != null ) {
|
||||
String superclassName = cls.getName();
|
||||
if( superclassName.startsWith( "java." ) || superclassName.startsWith( "javax." ) )
|
||||
throw new UnknownStyleException( key );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isValidField( Field f ) {
|
||||
int modifiers = f.getModifiers();
|
||||
return (modifiers & (Modifier.FINAL|Modifier.STATIC)) == 0 && !f.isSynthetic();
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the given value to a property of the given object.
|
||||
* Works only for properties that have public getter and setter methods.
|
||||
* First the property getter is invoked to get the old value,
|
||||
* then the property setter is invoked to set the new value.
|
||||
*
|
||||
* @param obj the object
|
||||
* @param name the name of the property
|
||||
* @param value the new value
|
||||
* @return the old value of the property
|
||||
* @throws UnknownStyleException if object does not have a property with given name
|
||||
* @throws IllegalArgumentException if value type does not fit to expected type
|
||||
*/
|
||||
private static Object applyToProperty( Object obj, String name, Object value )
|
||||
throws UnknownStyleException, IllegalArgumentException
|
||||
{
|
||||
Class<?> cls = obj.getClass();
|
||||
String getterName = buildMethodName( "get", name );
|
||||
String setterName = buildMethodName( "set", name );
|
||||
|
||||
for(;;) {
|
||||
try {
|
||||
Method getter;
|
||||
try {
|
||||
getter = cls.getMethod( getterName );
|
||||
} catch( NoSuchMethodException ex ) {
|
||||
getter = cls.getMethod( buildMethodName( "is", name ) );
|
||||
}
|
||||
Method setter = cls.getMethod( setterName, getter.getReturnType() );
|
||||
Object oldValue = getter.invoke( obj );
|
||||
setter.invoke( obj, convertToEnum( value, getter.getReturnType() ) );
|
||||
return oldValue;
|
||||
} catch( NoSuchMethodException ex ) {
|
||||
throw new UnknownStyleException( name );
|
||||
} catch( Exception ex ) {
|
||||
if( ex instanceof IllegalAccessException ) {
|
||||
// this may happen for private subclasses of public Swing classes
|
||||
// that override public property getter/setter
|
||||
// e.g. class JSlider.SmartHashtable.LabelUIResource.getForeground()
|
||||
// --> try again with superclass
|
||||
cls = cls.getSuperclass();
|
||||
if( cls != null && cls != Object.class )
|
||||
continue;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException( "failed to invoke property methods '" + cls.getName() + "."
|
||||
+ getterName + "()' or '" + setterName + "(...)'", ex );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String buildMethodName( String prefix, String name ) {
|
||||
int prefixLength = prefix.length();
|
||||
int nameLength = name.length();
|
||||
char[] chars = new char[prefixLength + nameLength];
|
||||
prefix.getChars( 0, prefixLength, chars, 0 );
|
||||
name.getChars( 0, nameLength, chars, prefixLength );
|
||||
chars[prefixLength] = Character.toUpperCase( chars[prefixLength] );
|
||||
return new String( chars );
|
||||
}
|
||||
|
||||
@SuppressWarnings( { "unchecked", "rawtypes" } )
|
||||
private static Object convertToEnum( Object value, Class<?> type )
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
// if type is an enum, convert string to enum value
|
||||
if( Enum.class.isAssignableFrom( type ) && value instanceof String ) {
|
||||
try {
|
||||
value = Enum.valueOf( (Class<? extends Enum>) type, (String) value );
|
||||
} catch( IllegalArgumentException ex ) {
|
||||
throw new IllegalArgumentException( "unknown enum value '" + value + "' in enum '" + type.getName() + "'", ex );
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the given value to an annotated field of the given object
|
||||
* or to a property of the given component.
|
||||
* The field must be annotated with {@link Styleable}.
|
||||
* The component property must have public getter and setter methods.
|
||||
*
|
||||
* @param obj the object
|
||||
* @param comp the component, or {@code null}
|
||||
* @param key the name of the field
|
||||
* @param value the new value
|
||||
* @return the old value of the field
|
||||
* @throws UnknownStyleException if object does not have a annotated field with given name
|
||||
* @throws IllegalArgumentException if value type does not fit to expected type
|
||||
*/
|
||||
public static Object applyToAnnotatedObjectOrComponent( Object obj, Object comp, String key, Object value )
|
||||
throws UnknownStyleException, IllegalArgumentException
|
||||
{
|
||||
try {
|
||||
return applyToAnnotatedObject( obj, key, value );
|
||||
} catch( UnknownStyleException ex ) {
|
||||
try {
|
||||
if( comp != null )
|
||||
return applyToProperty( comp, key, value );
|
||||
} catch( UnknownStyleException ex2 ) {
|
||||
// ignore
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
static Object applyToAnnotatedObjectOrBorder( Object obj, String key, Object value,
|
||||
JComponent c, AtomicBoolean borderShared )
|
||||
{
|
||||
try {
|
||||
return applyToAnnotatedObject( obj, key, value );
|
||||
} catch( UnknownStyleException ex ) {
|
||||
// apply to border
|
||||
Border border = c.getBorder();
|
||||
if( border instanceof StyleableBorder ) {
|
||||
if( borderShared.get() ) {
|
||||
border = cloneBorder( border );
|
||||
c.setBorder( border );
|
||||
borderShared.set( false );
|
||||
}
|
||||
|
||||
try {
|
||||
return ((StyleableBorder)border).applyStyleProperty( key, value );
|
||||
} catch( UnknownStyleException ex2 ) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
// apply to component property
|
||||
try {
|
||||
return applyToProperty( c, key, value );
|
||||
} catch( UnknownStyleException ex2 ) {
|
||||
// ignore
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
static PropertyChangeListener createPropertyChangeListener( JComponent c,
|
||||
Runnable installStyle, PropertyChangeListener superListener )
|
||||
{
|
||||
return e -> {
|
||||
if( superListener != null )
|
||||
superListener.propertyChange( e );
|
||||
|
||||
switch( e.getPropertyName() ) {
|
||||
case FlatClientProperties.STYLE:
|
||||
case FlatClientProperties.STYLE_CLASS:
|
||||
installStyle.run();
|
||||
c.revalidate();
|
||||
c.repaint();
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static Border cloneBorder( Border border ) {
|
||||
Class<? extends Border> borderClass = border.getClass();
|
||||
try {
|
||||
return borderClass.getDeclaredConstructor().newInstance();
|
||||
} catch( Exception ex ) {
|
||||
throw new IllegalArgumentException( "failed to clone border '" + borderClass.getName() + "'", ex );
|
||||
}
|
||||
}
|
||||
|
||||
static Icon cloneIcon( Icon icon ) {
|
||||
Class<? extends Icon> iconClass = icon.getClass();
|
||||
try {
|
||||
return iconClass.getDeclaredConstructor().newInstance();
|
||||
} catch( Exception ex ) {
|
||||
throw new IllegalArgumentException( "failed to clone icon '" + iconClass.getName() + "'", ex );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a map of all fields annotated with {@link Styleable}.
|
||||
* The key is the name of the field and the value the type of the field.
|
||||
*/
|
||||
public static Map<String, Class<?>> getAnnotatedStyleableInfos( Object obj ) {
|
||||
return getAnnotatedStyleableInfos( obj, null );
|
||||
}
|
||||
|
||||
public static Map<String, Class<?>> getAnnotatedStyleableInfos( Object obj, Border border ) {
|
||||
Map<String, Class<?>> infos = new StyleableInfosMap<>();
|
||||
collectAnnotatedStyleableInfos( obj, infos );
|
||||
collectStyleableInfos( border, infos );
|
||||
return infos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for all fields annotated with {@link Styleable} and add them to the given map.
|
||||
* The key is the name of the field and the value the type of the field.
|
||||
*/
|
||||
public static void collectAnnotatedStyleableInfos( Object obj, Map<String, Class<?>> infos ) {
|
||||
HashSet<String> processedFields = new HashSet<>();
|
||||
Class<?> cls = obj.getClass();
|
||||
|
||||
for(;;) {
|
||||
for( Field f : cls.getDeclaredFields() ) {
|
||||
if( !isValidField( f ) )
|
||||
continue;
|
||||
|
||||
Styleable styleable = f.getAnnotation( Styleable.class );
|
||||
if( styleable == null )
|
||||
continue;
|
||||
|
||||
String name = f.getName();
|
||||
Class<?> type = f.getType();
|
||||
|
||||
// for the case that the same field name is used in a class and in
|
||||
// one of its superclasses (e.g. field 'borderColor' in FlatButtonBorder
|
||||
// and in FlatBorder), do not process field in superclass
|
||||
if( processedFields.contains( name ) )
|
||||
continue;
|
||||
processedFields.add( name );
|
||||
|
||||
// handle "dot" keys (e.g. change field name "iconArrowType" to style key "icon.arrowType")
|
||||
if( styleable.dot() ) {
|
||||
int len = name.length();
|
||||
for( int i = 0; i < len; i++ ) {
|
||||
if( Character.isUpperCase( name.charAt( i ) ) ) {
|
||||
name = name.substring( 0, i ) + '.'
|
||||
+ Character.toLowerCase( name.charAt( i ) )
|
||||
+ name.substring( i + 1 );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// field has a different type
|
||||
if( styleable.type() != Void.class )
|
||||
type = styleable.type();
|
||||
|
||||
infos.put( name, type );
|
||||
}
|
||||
|
||||
cls = cls.getSuperclass();
|
||||
if( cls == null )
|
||||
return;
|
||||
|
||||
String superclassName = cls.getName();
|
||||
if( superclassName.startsWith( "java." ) || superclassName.startsWith( "javax." ) )
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public static void collectStyleableInfos( Border border, Map<String, Class<?>> infos ) {
|
||||
if( border instanceof StyleableBorder )
|
||||
infos.putAll( ((StyleableBorder)border).getStyleableInfos() );
|
||||
}
|
||||
|
||||
public static void putAllPrefixKey( Map<String, Class<?>> infos, String keyPrefix, Map<String, Class<?>> infos2 ) {
|
||||
for( Map.Entry<String, Class<?>> e : infos2.entrySet() )
|
||||
infos.put( keyPrefix.concat( e.getKey() ), e.getValue() );
|
||||
}
|
||||
|
||||
//---- class UnknownStyleException ----------------------------------------
|
||||
|
||||
public static class UnknownStyleException
|
||||
extends IllegalArgumentException
|
||||
{
|
||||
public UnknownStyleException( String key ) {
|
||||
super( key );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return "unknown style '" + super.getMessage() + "'";
|
||||
}
|
||||
}
|
||||
|
||||
//---- class StyleableInfosMap --------------------------------------------
|
||||
|
||||
static class StyleableInfosMap<K,V>
|
||||
extends LinkedHashMap<K,V>
|
||||
{
|
||||
@Override
|
||||
public V put( K key, V value ) {
|
||||
V oldValue = super.put( key, value );
|
||||
if( oldValue != null )
|
||||
throw new IllegalArgumentException( "duplicate key '" + key + "'" );
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll( Map<? extends K, ? extends V> m ) {
|
||||
for( Map.Entry<? extends K, ? extends V> e : m.entrySet() )
|
||||
put( e.getKey(), e.getValue() );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,6 +53,7 @@ import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Collections;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.IntConsumer;
|
||||
@@ -84,9 +85,14 @@ import javax.swing.plaf.basic.BasicTabbedPaneUI;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import javax.swing.text.View;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.icons.FlatTabbedPaneCloseIcon;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
|
||||
import com.formdev.flatlaf.util.Animator;
|
||||
import com.formdev.flatlaf.util.CubicBezierEasing;
|
||||
import com.formdev.flatlaf.util.JavaCompatibility;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.StringUtils;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
@@ -101,7 +107,7 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault TabbedPane.font Font
|
||||
* @uiDefault TabbedPane.background Color
|
||||
* @uiDefault TabbedPane.foreground Color
|
||||
* @uiDefault TabbedPane.shadow Color used for scroll arrows and cropped line
|
||||
* @uiDefault TabbedPane.shadow Color used for cropped line
|
||||
* @uiDefault TabbedPane.textIconGap int
|
||||
* @uiDefault TabbedPane.tabInsets Insets
|
||||
* @uiDefault TabbedPane.selectedTabPadInsets Insets unused
|
||||
@@ -151,11 +157,13 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault TabbedPane.buttonPressedBackground Color
|
||||
*
|
||||
* @uiDefault TabbedPane.moreTabsButtonToolTipText String
|
||||
* @uiDefault TabbedPane.tabCloseToolTipText String
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatTabbedPaneUI
|
||||
extends BasicTabbedPaneUI
|
||||
implements StyleableUI
|
||||
{
|
||||
// tabs popup policy / scroll arrows policy
|
||||
protected static final int NEVER = 0;
|
||||
@@ -177,43 +185,50 @@ public class FlatTabbedPaneUI
|
||||
private static Set<KeyStroke> focusBackwardTraversalKeys;
|
||||
|
||||
protected Color foreground;
|
||||
protected Color disabledForeground;
|
||||
protected Color selectedBackground;
|
||||
protected Color selectedForeground;
|
||||
protected Color underlineColor;
|
||||
protected Color disabledUnderlineColor;
|
||||
protected Color hoverColor;
|
||||
protected Color focusColor;
|
||||
protected Color tabSeparatorColor;
|
||||
protected Color contentAreaColor;
|
||||
@Styleable protected Color disabledForeground;
|
||||
@Styleable protected Color selectedBackground;
|
||||
@Styleable protected Color selectedForeground;
|
||||
@Styleable protected Color underlineColor;
|
||||
@Styleable protected Color disabledUnderlineColor;
|
||||
@Styleable protected Color hoverColor;
|
||||
@Styleable protected Color focusColor;
|
||||
@Styleable protected Color tabSeparatorColor;
|
||||
@Styleable protected Color contentAreaColor;
|
||||
|
||||
private int textIconGapUnscaled;
|
||||
protected int minimumTabWidth;
|
||||
protected int maximumTabWidth;
|
||||
protected int tabHeight;
|
||||
protected int tabSelectionHeight;
|
||||
protected int contentSeparatorHeight;
|
||||
protected boolean showTabSeparators;
|
||||
protected boolean tabSeparatorsFullHeight;
|
||||
protected boolean hasFullBorder;
|
||||
protected boolean tabsOpaque = true;
|
||||
@Styleable protected int minimumTabWidth;
|
||||
@Styleable protected int maximumTabWidth;
|
||||
@Styleable protected int tabHeight;
|
||||
@Styleable protected int tabSelectionHeight;
|
||||
@Styleable protected int contentSeparatorHeight;
|
||||
@Styleable protected boolean showTabSeparators;
|
||||
@Styleable protected boolean tabSeparatorsFullHeight;
|
||||
@Styleable protected boolean hasFullBorder;
|
||||
@Styleable protected boolean tabsOpaque = true;
|
||||
|
||||
private int tabsPopupPolicy;
|
||||
private int scrollButtonsPolicy;
|
||||
private int scrollButtonsPlacement;
|
||||
@Styleable(type=String.class) private int tabsPopupPolicy;
|
||||
@Styleable(type=String.class) private int scrollButtonsPolicy;
|
||||
@Styleable(type=String.class) private int scrollButtonsPlacement;
|
||||
|
||||
private int tabAreaAlignment;
|
||||
private int tabAlignment;
|
||||
private int tabWidthMode;
|
||||
@Styleable(type=String.class) private int tabAreaAlignment;
|
||||
@Styleable(type=String.class) private int tabAlignment;
|
||||
@Styleable(type=String.class) private int tabWidthMode;
|
||||
protected Icon closeIcon;
|
||||
|
||||
protected String arrowType;
|
||||
protected Insets buttonInsets;
|
||||
protected int buttonArc;
|
||||
protected Color buttonHoverBackground;
|
||||
protected Color buttonPressedBackground;
|
||||
@Styleable protected String arrowType;
|
||||
@Styleable protected Insets buttonInsets;
|
||||
@Styleable protected int buttonArc;
|
||||
@Styleable protected Color buttonHoverBackground;
|
||||
@Styleable protected Color buttonPressedBackground;
|
||||
|
||||
protected String moreTabsButtonToolTipText;
|
||||
@Styleable protected String moreTabsButtonToolTipText;
|
||||
/** @since 2 */ @Styleable protected String tabCloseToolTipText;
|
||||
|
||||
// only used via styling (not in UI defaults, but has likewise client properties)
|
||||
/** @since 2 */ @Styleable protected boolean showContentSeparator = true;
|
||||
/** @since 2 */ @Styleable protected boolean hideTabAreaWithOneTab;
|
||||
/** @since 2 */ @Styleable protected boolean tabClosable;
|
||||
/** @since 2 */ @Styleable protected int tabIconPlacement = LEADING;
|
||||
|
||||
protected JViewport tabViewport;
|
||||
protected FlatWheelTabScroller wheelTabScroller;
|
||||
@@ -231,6 +246,8 @@ public class FlatTabbedPaneUI
|
||||
private boolean pressedTabClose;
|
||||
|
||||
private Object[] oldRenderingHints;
|
||||
private Map<String, Object> oldStyleValues;
|
||||
private boolean closeIconShared = true;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatTabbedPaneUI();
|
||||
@@ -259,6 +276,8 @@ public class FlatTabbedPaneUI
|
||||
buttonPressedBackground = UIManager.getColor( "TabbedPane.buttonPressedBackground" );
|
||||
|
||||
super.installUI( c );
|
||||
|
||||
installStyle();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -313,12 +332,14 @@ public class FlatTabbedPaneUI
|
||||
tabAlignment = parseAlignment( UIManager.getString( "TabbedPane.tabAlignment" ), CENTER );
|
||||
tabWidthMode = parseTabWidthMode( UIManager.getString( "TabbedPane.tabWidthMode" ) );
|
||||
closeIcon = UIManager.getIcon( "TabbedPane.closeIcon" );
|
||||
closeIconShared = true;
|
||||
|
||||
buttonInsets = UIManager.getInsets( "TabbedPane.buttonInsets" );
|
||||
buttonArc = UIManager.getInt( "TabbedPane.buttonArc" );
|
||||
|
||||
Locale l = tabPane.getLocale();
|
||||
moreTabsButtonToolTipText = UIManager.getString( "TabbedPane.moreTabsButtonToolTipText", l );
|
||||
tabCloseToolTipText = UIManager.getString( "TabbedPane.tabCloseToolTipText", l );
|
||||
|
||||
// scale
|
||||
textIconGap = scale( textIconGapUnscaled );
|
||||
@@ -361,6 +382,8 @@ public class FlatTabbedPaneUI
|
||||
buttonHoverBackground = null;
|
||||
buttonPressedBackground = null;
|
||||
|
||||
oldStyleValues = null;
|
||||
|
||||
MigLayoutVisualPadding.uninstall( tabPane );
|
||||
}
|
||||
|
||||
@@ -558,6 +581,83 @@ public class FlatTabbedPaneUI
|
||||
return new FlatScrollableTabButton( direction );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void installStyle() {
|
||||
try {
|
||||
applyStyle( FlatStylingSupport.getResolvedStyle( tabPane, "TabbedPane" ) );
|
||||
} catch( RuntimeException ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void applyStyle( Object style ) {
|
||||
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
|
||||
|
||||
// update buttons
|
||||
for( Component c : tabPane.getComponents() ) {
|
||||
if( c instanceof FlatTabAreaButton )
|
||||
((FlatTabAreaButton)c).updateStyle();
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected Object applyStyleProperty( String key, Object value ) {
|
||||
// close icon
|
||||
if( key.startsWith( "close" ) ) {
|
||||
if( !(closeIcon instanceof FlatTabbedPaneCloseIcon) )
|
||||
return new UnknownStyleException( key );
|
||||
|
||||
if( closeIconShared ) {
|
||||
closeIcon = FlatStylingSupport.cloneIcon( closeIcon );
|
||||
closeIconShared = false;
|
||||
}
|
||||
|
||||
return ((FlatTabbedPaneCloseIcon)closeIcon).applyStyleProperty( key, value );
|
||||
}
|
||||
|
||||
if( value instanceof String ) {
|
||||
switch( key ) {
|
||||
case "tabsPopupPolicy": value = parseTabsPopupPolicy( (String) value ); break;
|
||||
case "scrollButtonsPolicy": value = parseScrollButtonsPolicy( (String) value ); break;
|
||||
case "scrollButtonsPlacement": value = parseScrollButtonsPlacement( (String) value ); break;
|
||||
|
||||
case "tabAreaAlignment": value = parseAlignment( (String) value, LEADING ); break;
|
||||
case "tabAlignment": value = parseAlignment( (String) value, CENTER ); break;
|
||||
case "tabWidthMode": value = parseTabWidthMode( (String) value ); break;
|
||||
|
||||
case "tabIconPlacement": value = parseTabIconPlacement( (String) value ); break;
|
||||
}
|
||||
} else {
|
||||
Object oldValue = null;
|
||||
switch( key ) {
|
||||
// BasicTabbedPaneUI
|
||||
case "tabInsets": oldValue = tabInsets; tabInsets = (Insets) value; return oldValue;
|
||||
case "tabAreaInsets": oldValue = tabAreaInsets; tabAreaInsets = (Insets) value; return oldValue;
|
||||
case "textIconGap":
|
||||
oldValue = textIconGapUnscaled;
|
||||
textIconGapUnscaled = (int) value;
|
||||
textIconGap = scale( textIconGapUnscaled );
|
||||
return oldValue;
|
||||
}
|
||||
}
|
||||
|
||||
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, tabPane, key, value );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||
Map<String, Class<?>> infos = new FlatStylingSupport.StyleableInfosMap<>();
|
||||
infos.put( "tabInsets", Insets.class );
|
||||
infos.put( "tabAreaInsets", Insets.class );
|
||||
infos.put( "textIconGap", int.class );
|
||||
FlatStylingSupport.collectAnnotatedStyleableInfos( this, infos );
|
||||
if( closeIcon instanceof FlatTabbedPaneCloseIcon )
|
||||
infos.putAll( ((FlatTabbedPaneCloseIcon)closeIcon).getStyleableInfos() );
|
||||
return infos;
|
||||
}
|
||||
|
||||
protected void setRolloverTab( int x, int y ) {
|
||||
setRolloverTab( tabForCoordinate( tabPane, x, y ) );
|
||||
}
|
||||
@@ -639,7 +739,7 @@ public class FlatTabbedPaneUI
|
||||
Insets tabInsets = getTabInsets( tabPlacement, tabIndex );
|
||||
tabWidth = icon.getIconWidth() + tabInsets.left + tabInsets.right;
|
||||
} else {
|
||||
int iconPlacement = clientPropertyInt( tabPane, TABBED_PANE_TAB_ICON_PLACEMENT, LEADING );
|
||||
int iconPlacement = clientPropertyInt( tabPane, TABBED_PANE_TAB_ICON_PLACEMENT, tabIconPlacement );
|
||||
if( (iconPlacement == TOP || iconPlacement == BOTTOM) &&
|
||||
tabPane.getTabComponentAt( tabIndex ) == null &&
|
||||
(icon = getIconForTab( tabIndex )) != null )
|
||||
@@ -682,7 +782,7 @@ public class FlatTabbedPaneUI
|
||||
int tabHeight;
|
||||
|
||||
Icon icon;
|
||||
int iconPlacement = clientPropertyInt( tabPane, TABBED_PANE_TAB_ICON_PLACEMENT, LEADING );
|
||||
int iconPlacement = clientPropertyInt( tabPane, TABBED_PANE_TAB_ICON_PLACEMENT, tabIconPlacement );
|
||||
if( (iconPlacement == TOP || iconPlacement == BOTTOM) &&
|
||||
tabPane.getTabComponentAt( tabIndex ) == null &&
|
||||
(icon = getIconForTab( tabIndex )) != null )
|
||||
@@ -790,7 +890,7 @@ public class FlatTabbedPaneUI
|
||||
*/
|
||||
@Override
|
||||
protected Insets getContentBorderInsets( int tabPlacement ) {
|
||||
if( hideTabArea() || contentSeparatorHeight == 0 || !clientPropertyBoolean( tabPane, TABBED_PANE_SHOW_CONTENT_SEPARATOR, true ) )
|
||||
if( hideTabArea() || contentSeparatorHeight == 0 || !clientPropertyBoolean( tabPane, TABBED_PANE_SHOW_CONTENT_SEPARATOR, showContentSeparator ) )
|
||||
return new Insets( 0, 0, 0, 0 );
|
||||
|
||||
boolean hasFullBorder = clientPropertyBoolean( tabPane, TABBED_PANE_HAS_FULL_BORDER, this.hasFullBorder );
|
||||
@@ -1046,7 +1146,7 @@ public class FlatTabbedPaneUI
|
||||
protected void paintContentBorder( Graphics g, int tabPlacement, int selectedIndex ) {
|
||||
if( tabPane.getTabCount() <= 0 ||
|
||||
contentSeparatorHeight == 0 ||
|
||||
!clientPropertyBoolean( tabPane, TABBED_PANE_SHOW_CONTENT_SEPARATOR, true ) )
|
||||
!clientPropertyBoolean( tabPane, TABBED_PANE_SHOW_CONTENT_SEPARATOR, showContentSeparator ) )
|
||||
return;
|
||||
|
||||
Insets insets = tabPane.getInsets();
|
||||
@@ -1137,7 +1237,7 @@ public class FlatTabbedPaneUI
|
||||
// icon placement
|
||||
int verticalTextPosition;
|
||||
int horizontalTextPosition;
|
||||
switch( clientPropertyInt( tabPane, TABBED_PANE_TAB_ICON_PLACEMENT, LEADING ) ) {
|
||||
switch( clientPropertyInt( tabPane, TABBED_PANE_TAB_ICON_PLACEMENT, tabIconPlacement ) ) {
|
||||
default:
|
||||
case LEADING: verticalTextPosition = CENTER; horizontalTextPosition = TRAILING; break;
|
||||
case TRAILING: verticalTextPosition = CENTER; horizontalTextPosition = LEADING; break;
|
||||
@@ -1218,8 +1318,11 @@ public class FlatTabbedPaneUI
|
||||
}
|
||||
|
||||
protected boolean isTabClosable( int tabIndex ) {
|
||||
if( tabIndex < 0 )
|
||||
return false;
|
||||
|
||||
Object value = getTabClientProperty( tabIndex, TABBED_PANE_TAB_CLOSABLE );
|
||||
return (value instanceof Boolean) ? (boolean) value : false;
|
||||
return (value instanceof Boolean) ? (boolean) value : tabClosable;
|
||||
}
|
||||
|
||||
@SuppressWarnings( { "unchecked" } )
|
||||
@@ -1293,7 +1396,7 @@ public class FlatTabbedPaneUI
|
||||
return tabPane.getTabCount() == 1 &&
|
||||
leadingComponent == null &&
|
||||
trailingComponent == null &&
|
||||
clientPropertyBoolean( tabPane, TABBED_PANE_HIDE_TAB_AREA_WITH_ONE_TAB, false );
|
||||
clientPropertyBoolean( tabPane, TABBED_PANE_HIDE_TAB_AREA_WITH_ONE_TAB, hideTabAreaWithOneTab );
|
||||
}
|
||||
|
||||
protected int getTabsPopupPolicy() {
|
||||
@@ -1407,6 +1510,19 @@ public class FlatTabbedPaneUI
|
||||
}
|
||||
}
|
||||
|
||||
protected static int parseTabIconPlacement( String str ) {
|
||||
if( str == null )
|
||||
return LEADING;
|
||||
|
||||
switch( str ) {
|
||||
default:
|
||||
case "leading": return LEADING;
|
||||
case "trailing": return TRAILING;
|
||||
case "top": return TOP;
|
||||
case "bottom": return BOTTOM;
|
||||
}
|
||||
}
|
||||
|
||||
private void runWithOriginalLayoutManager( Runnable runnable ) {
|
||||
LayoutManager layout = tabPane.getLayout();
|
||||
if( layout instanceof FlatTabbedPaneScrollLayout ) {
|
||||
@@ -1567,6 +1683,12 @@ public class FlatTabbedPaneUI
|
||||
setArrowWidth( 10 );
|
||||
}
|
||||
|
||||
protected void updateStyle() {
|
||||
updateStyle( arrowType,
|
||||
FlatTabbedPaneUI.this.foreground, FlatTabbedPaneUI.this.disabledForeground,
|
||||
null, buttonHoverBackground, null, buttonPressedBackground );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Color deriveBackground( Color background ) {
|
||||
return FlatUIUtils.deriveColor( background, tabPane.getBackground() );
|
||||
@@ -2252,6 +2374,8 @@ public class FlatTabbedPaneUI
|
||||
// update tooltip
|
||||
if( tabIndex >= 0 && hitClose ) {
|
||||
Object closeTip = getTabClientProperty( tabIndex, TABBED_PANE_TAB_CLOSE_TOOLTIPTEXT );
|
||||
if( closeTip == null )
|
||||
closeTip = tabCloseToolTipText;
|
||||
if( closeTip instanceof String )
|
||||
setCloseToolTip( tabIndex, (String) closeTip );
|
||||
else
|
||||
@@ -2351,6 +2475,13 @@ public class FlatTabbedPaneUI
|
||||
tabPane.repaint();
|
||||
ensureSelectedTabIsVisibleLater();
|
||||
break;
|
||||
|
||||
case STYLE:
|
||||
case STYLE_CLASS:
|
||||
installStyle();
|
||||
tabPane.revalidate();
|
||||
tabPane.repaint();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,11 +16,15 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Insets;
|
||||
import java.util.function.Function;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.TableUI;
|
||||
|
||||
/**
|
||||
* Cell border for {@link javax.swing.table.DefaultTableCellRenderer}
|
||||
@@ -33,12 +37,54 @@ import javax.swing.UIManager;
|
||||
public class FlatTableCellBorder
|
||||
extends FlatLineBorder
|
||||
{
|
||||
final boolean showCellFocusIndicator = UIManager.getBoolean( "Table.showCellFocusIndicator" );
|
||||
protected boolean showCellFocusIndicator = UIManager.getBoolean( "Table.showCellFocusIndicator" );
|
||||
|
||||
private Component c;
|
||||
|
||||
protected FlatTableCellBorder() {
|
||||
super( UIManager.getInsets( "Table.cellMargins" ), UIManager.getColor( "Table.cellFocusColor" ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Insets getBorderInsets( Component c, Insets insets ) {
|
||||
Insets m = getStyleFromTableUI( c, ui -> ui.cellMargins );
|
||||
if( m != null )
|
||||
return scaleInsets( c, insets, m.top, m.left, m.bottom, m.right );
|
||||
|
||||
return super.getBorderInsets( c, insets );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getLineColor() {
|
||||
if( c != null ) {
|
||||
Color color = getStyleFromTableUI( c, ui -> ui.cellFocusColor );
|
||||
if( color != null )
|
||||
return color;
|
||||
}
|
||||
return super.getLineColor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||
this.c = c;
|
||||
super.paintBorder( c, g, x, y, width, height );
|
||||
this.c = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Because this borders are always shared for all tables,
|
||||
* get border specific style from FlatTableUI.
|
||||
*/
|
||||
static <T> T getStyleFromTableUI( Component c, Function<FlatTableUI, T> f ) {
|
||||
JTable table = (JTable) SwingUtilities.getAncestorOfClass( JTable.class, c );
|
||||
if( table != null ) {
|
||||
TableUI ui = table.getUI();
|
||||
if( ui instanceof FlatTableUI )
|
||||
return f.apply( (FlatTableUI) ui );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
//---- class Default ------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -74,6 +120,9 @@ public class FlatTableCellBorder
|
||||
{
|
||||
@Override
|
||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||
Boolean b = getStyleFromTableUI( c, ui -> ui.showCellFocusIndicator );
|
||||
boolean showCellFocusIndicator = (b != null) ? b : this.showCellFocusIndicator;
|
||||
|
||||
if( !showCellFocusIndicator ) {
|
||||
JTable table = (JTable) SwingUtilities.getAncestorOfClass( JTable.class, c );
|
||||
if( table != null && !isSelectionEditable( table ) )
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import javax.swing.JScrollBar;
|
||||
import javax.swing.JScrollPane;
|
||||
@@ -51,12 +52,30 @@ public class FlatTableHeaderBorder
|
||||
super( UIManager.getInsets( "TableHeader.cellMargins" ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Insets getBorderInsets( Component c, Insets insets ) {
|
||||
JTableHeader header = (JTableHeader) SwingUtilities.getAncestorOfClass( JTableHeader.class, c );
|
||||
if( header != null ) {
|
||||
if( header.getUI() instanceof FlatTableHeaderUI ) {
|
||||
FlatTableHeaderUI ui = (FlatTableHeaderUI) header.getUI();
|
||||
if( ui.cellMargins != null ) {
|
||||
Insets m = ui.cellMargins;
|
||||
return scaleInsets( c, insets, m.top, m.left, m.bottom, m.right );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return super.getBorderInsets( c, insets );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||
JTableHeader header = (JTableHeader) SwingUtilities.getAncestorOfClass( JTableHeader.class, c );
|
||||
boolean leftToRight = (header != null ? header : c).getComponentOrientation().isLeftToRight();
|
||||
boolean paintLeft = !leftToRight;
|
||||
boolean paintRight = leftToRight;
|
||||
Color separatorColor = this.separatorColor;
|
||||
Color bottomSeparatorColor = this.bottomSeparatorColor;
|
||||
|
||||
if( header != null ) {
|
||||
int hx = SwingUtilities.convertPoint( c, x, y, header ).x;
|
||||
@@ -68,6 +87,16 @@ public class FlatTableHeaderBorder
|
||||
if( hx + width >= header.getWidth() && leftToRight && hideTrailingVerticalLine( header ) )
|
||||
paintRight = false;
|
||||
}
|
||||
|
||||
// Because this border is always shared for all table headers,
|
||||
// get border specific style from FlatTableHeaderUI.
|
||||
if( header.getUI() instanceof FlatTableHeaderUI ) {
|
||||
FlatTableHeaderUI ui = (FlatTableHeaderUI) header.getUI();
|
||||
if( ui.separatorColor != null )
|
||||
separatorColor = ui.separatorColor;
|
||||
if( ui.bottomSeparatorColor != null )
|
||||
bottomSeparatorColor = ui.bottomSeparatorColor;
|
||||
}
|
||||
}
|
||||
|
||||
float lineWidth = UIScale.scale( 1f );
|
||||
@@ -110,6 +139,12 @@ public class FlatTableHeaderBorder
|
||||
}
|
||||
|
||||
protected boolean hideTrailingVerticalLine( JTableHeader header ) {
|
||||
if( header.getUI() instanceof FlatTableHeaderUI ) {
|
||||
FlatTableHeaderUI ui = (FlatTableHeaderUI) header.getUI();
|
||||
if( ui.showTrailingVerticalLine )
|
||||
return false;
|
||||
}
|
||||
|
||||
if( showTrailingVerticalLine )
|
||||
return false;
|
||||
|
||||
|
||||
@@ -26,7 +26,8 @@ import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.util.Objects;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Map;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLabel;
|
||||
@@ -40,6 +41,9 @@ import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicTableHeaderUI;
|
||||
import javax.swing.table.TableCellRenderer;
|
||||
import javax.swing.table.TableColumnModel;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
@@ -64,32 +68,52 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault TableHeader.bottomSeparatorColor Color
|
||||
* @uiDefault TableHeader.showTrailingVerticalLine boolean
|
||||
*
|
||||
* <!-- FlatAscendingSortIcon and FlatDescendingSortIcon -->
|
||||
*
|
||||
* @uiDefault Component.arrowType String chevron (default) or triangle
|
||||
* @uiDefault Table.sortIconColor Color
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatTableHeaderUI
|
||||
extends BasicTableHeaderUI
|
||||
implements StyleableUI
|
||||
{
|
||||
protected Color bottomSeparatorColor;
|
||||
protected int height;
|
||||
protected int sortIconPosition;
|
||||
@Styleable protected Color bottomSeparatorColor;
|
||||
@Styleable protected int height;
|
||||
@Styleable(type=String.class) protected int sortIconPosition;
|
||||
|
||||
// for FlatTableHeaderBorder
|
||||
@Styleable protected Insets cellMargins;
|
||||
@Styleable protected Color separatorColor;
|
||||
/** @since 2 */ @Styleable protected boolean showTrailingVerticalLine;
|
||||
|
||||
// for FlatAscendingSortIcon and FlatDescendingSortIcon
|
||||
// (needs to be public because icon classes are in another package)
|
||||
@Styleable public String arrowType;
|
||||
@Styleable public Color sortIconColor;
|
||||
|
||||
private PropertyChangeListener propertyChangeListener;
|
||||
private Map<String, Object> oldStyleValues;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatTableHeaderUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
installStyle();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
|
||||
bottomSeparatorColor = UIManager.getColor( "TableHeader.bottomSeparatorColor" );
|
||||
height = UIManager.getInt( "TableHeader.height" );
|
||||
switch( Objects.toString( UIManager.getString( "TableHeader.sortIconPosition" ), "right" ) ) {
|
||||
default:
|
||||
case "right": sortIconPosition = SwingConstants.RIGHT; break;
|
||||
case "left": sortIconPosition = SwingConstants.LEFT; break;
|
||||
case "top": sortIconPosition = SwingConstants.TOP; break;
|
||||
case "bottom": sortIconPosition = SwingConstants.BOTTOM; break;
|
||||
}
|
||||
sortIconPosition = parseSortIconPosition( UIManager.getString( "TableHeader.sortIconPosition" ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -97,6 +121,65 @@ public class FlatTableHeaderUI
|
||||
super.uninstallDefaults();
|
||||
|
||||
bottomSeparatorColor = null;
|
||||
|
||||
oldStyleValues = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installListeners() {
|
||||
super.installListeners();
|
||||
|
||||
propertyChangeListener = FlatStylingSupport.createPropertyChangeListener( header, this::installStyle, null );
|
||||
header.addPropertyChangeListener( propertyChangeListener );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void uninstallListeners() {
|
||||
super.uninstallListeners();
|
||||
|
||||
header.removePropertyChangeListener( propertyChangeListener );
|
||||
propertyChangeListener = null;
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void installStyle() {
|
||||
try {
|
||||
applyStyle( FlatStylingSupport.getResolvedStyle( header, "TableHeader" ) );
|
||||
} catch( RuntimeException ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void applyStyle( Object style ) {
|
||||
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected Object applyStyleProperty( String key, Object value ) {
|
||||
if( key.equals( "sortIconPosition" ) && value instanceof String )
|
||||
value = parseSortIconPosition( (String) value );
|
||||
|
||||
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, header, key, value );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
||||
}
|
||||
|
||||
private static int parseSortIconPosition( String str ) {
|
||||
if( str == null )
|
||||
str = "";
|
||||
|
||||
switch( str ) {
|
||||
default:
|
||||
case "right": return SwingConstants.RIGHT;
|
||||
case "left": return SwingConstants.LEFT;
|
||||
case "top": return SwingConstants.TOP;
|
||||
case "bottom": return SwingConstants.BOTTOM;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -265,9 +348,7 @@ public class FlatTableHeaderUI
|
||||
|
||||
//---- class FlatMouseInputHandler ----------------------------------------
|
||||
|
||||
/**
|
||||
* @since 1.6
|
||||
*/
|
||||
/** @since 1.6 */
|
||||
protected class FlatMouseInputHandler
|
||||
extends MouseInputHandler
|
||||
{
|
||||
|
||||
@@ -22,10 +22,12 @@ import java.awt.Dimension;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Map;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JViewport;
|
||||
@@ -36,7 +38,10 @@ import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicTableUI;
|
||||
import javax.swing.table.JTableHeader;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.Graphics2DProxy;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
@@ -90,27 +95,41 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
*/
|
||||
public class FlatTableUI
|
||||
extends BasicTableUI
|
||||
implements StyleableUI
|
||||
{
|
||||
protected boolean showHorizontalLines;
|
||||
protected boolean showVerticalLines;
|
||||
/** @since 1.6 */ protected boolean showTrailingVerticalLine;
|
||||
/** @since 1.6 */ @Styleable protected boolean showTrailingVerticalLine;
|
||||
protected Dimension intercellSpacing;
|
||||
|
||||
protected Color selectionBackground;
|
||||
protected Color selectionForeground;
|
||||
protected Color selectionInactiveBackground;
|
||||
protected Color selectionInactiveForeground;
|
||||
@Styleable protected Color selectionBackground;
|
||||
@Styleable protected Color selectionForeground;
|
||||
@Styleable protected Color selectionInactiveBackground;
|
||||
@Styleable protected Color selectionInactiveForeground;
|
||||
|
||||
// for FlatTableCellBorder
|
||||
@Styleable protected Insets cellMargins;
|
||||
@Styleable protected Color cellFocusColor;
|
||||
@Styleable protected boolean showCellFocusIndicator;
|
||||
|
||||
private boolean oldShowHorizontalLines;
|
||||
private boolean oldShowVerticalLines;
|
||||
private Dimension oldIntercellSpacing;
|
||||
|
||||
private PropertyChangeListener propertyChangeListener;
|
||||
private Map<String, Object> oldStyleValues;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatTableUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
installStyle();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
@@ -155,6 +174,8 @@ public class FlatTableUI
|
||||
selectionInactiveBackground = null;
|
||||
selectionInactiveForeground = null;
|
||||
|
||||
oldStyleValues = null;
|
||||
|
||||
// restore old show horizontal/vertical lines (if not modified)
|
||||
if( !showHorizontalLines && oldShowHorizontalLines && !table.getShowHorizontalLines() )
|
||||
table.setShowHorizontalLines( true );
|
||||
@@ -171,8 +192,18 @@ public class FlatTableUI
|
||||
super.installListeners();
|
||||
|
||||
propertyChangeListener = e -> {
|
||||
if( FlatClientProperties.COMPONENT_FOCUS_OWNER.equals( e.getPropertyName() ) )
|
||||
toggleSelectionColors();
|
||||
switch( e.getPropertyName() ) {
|
||||
case FlatClientProperties.COMPONENT_FOCUS_OWNER:
|
||||
toggleSelectionColors();
|
||||
break;
|
||||
|
||||
case FlatClientProperties.STYLE:
|
||||
case FlatClientProperties.STYLE_CLASS:
|
||||
installStyle();
|
||||
table.revalidate();
|
||||
table.repaint();
|
||||
break;
|
||||
}
|
||||
};
|
||||
table.addPropertyChangeListener( propertyChangeListener );
|
||||
}
|
||||
@@ -206,6 +237,54 @@ public class FlatTableUI
|
||||
};
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void installStyle() {
|
||||
try {
|
||||
applyStyle( FlatStylingSupport.getResolvedStyle( table, "Table" ) );
|
||||
} catch( RuntimeException ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void applyStyle( Object style ) {
|
||||
Color oldSelectionBackground = selectionBackground;
|
||||
Color oldSelectionForeground = selectionForeground;
|
||||
Color oldSelectionInactiveBackground = selectionInactiveBackground;
|
||||
Color oldSelectionInactiveForeground = selectionInactiveForeground;
|
||||
|
||||
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
|
||||
|
||||
// update selection background
|
||||
if( selectionBackground != oldSelectionBackground ) {
|
||||
Color selBg = table.getSelectionBackground();
|
||||
if( selBg == oldSelectionBackground )
|
||||
table.setSelectionBackground( selectionBackground );
|
||||
else if( selBg == oldSelectionInactiveBackground )
|
||||
table.setSelectionBackground( selectionInactiveBackground );
|
||||
}
|
||||
|
||||
// update selection foreground
|
||||
if( selectionForeground != oldSelectionForeground ) {
|
||||
Color selFg = table.getSelectionForeground();
|
||||
if( selFg == oldSelectionForeground )
|
||||
table.setSelectionForeground( selectionForeground );
|
||||
else if( selFg == oldSelectionInactiveForeground )
|
||||
table.setSelectionForeground( selectionInactiveForeground );
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected Object applyStyleProperty( String key, Object value ) {
|
||||
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, table, key, value );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle selection colors from focused to inactive and vice versa.
|
||||
*
|
||||
|
||||
@@ -23,14 +23,17 @@ import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.util.Map;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicTextAreaUI;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import javax.swing.text.Caret;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JTextArea}.
|
||||
@@ -60,17 +63,22 @@ import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
*/
|
||||
public class FlatTextAreaUI
|
||||
extends BasicTextAreaUI
|
||||
implements StyleableUI
|
||||
{
|
||||
protected int minimumWidth;
|
||||
@Styleable protected int minimumWidth;
|
||||
protected boolean isIntelliJTheme;
|
||||
protected Color background;
|
||||
protected Color disabledBackground;
|
||||
protected Color inactiveBackground;
|
||||
protected Color focusedBackground;
|
||||
private Color background;
|
||||
@Styleable protected Color disabledBackground;
|
||||
@Styleable protected Color inactiveBackground;
|
||||
@Styleable protected Color focusedBackground;
|
||||
|
||||
private Color oldDisabledBackground;
|
||||
private Color oldInactiveBackground;
|
||||
|
||||
private Insets defaultMargin;
|
||||
|
||||
private FocusListener focusListener;
|
||||
private Map<String, Object> oldStyleValues;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatTextAreaUI();
|
||||
@@ -80,7 +88,7 @@ public class FlatTextAreaUI
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
updateBackground();
|
||||
installStyle();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -105,6 +113,11 @@ public class FlatTextAreaUI
|
||||
disabledBackground = null;
|
||||
inactiveBackground = null;
|
||||
focusedBackground = null;
|
||||
|
||||
oldDisabledBackground = null;
|
||||
oldInactiveBackground = null;
|
||||
|
||||
oldStyleValues = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -125,39 +138,55 @@ public class FlatTextAreaUI
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void propertyChange( PropertyChangeEvent e ) {
|
||||
super.propertyChange( e );
|
||||
FlatEditorPaneUI.propertyChange( getComponent(), e );
|
||||
protected Caret createCaret() {
|
||||
return new FlatCaret( null, false );
|
||||
}
|
||||
|
||||
switch( e.getPropertyName() ) {
|
||||
case "editable":
|
||||
case "enabled":
|
||||
updateBackground();
|
||||
break;
|
||||
@Override
|
||||
protected void propertyChange( PropertyChangeEvent e ) {
|
||||
// invoke updateBackground() before super.propertyChange()
|
||||
String propertyName = e.getPropertyName();
|
||||
if( "editable".equals( propertyName ) || "enabled".equals( propertyName ) )
|
||||
updateBackground();
|
||||
|
||||
super.propertyChange( e );
|
||||
FlatEditorPaneUI.propertyChange( getComponent(), e, this::installStyle );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void installStyle() {
|
||||
try {
|
||||
applyStyle( FlatStylingSupport.getResolvedStyle( getComponent(), "TextArea" ) );
|
||||
} catch( RuntimeException ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void applyStyle( Object style ) {
|
||||
oldDisabledBackground = disabledBackground;
|
||||
oldInactiveBackground = inactiveBackground;
|
||||
|
||||
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
|
||||
|
||||
updateBackground();
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected Object applyStyleProperty( String key, Object value ) {
|
||||
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, getComponent(), key, value );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
||||
}
|
||||
|
||||
private void updateBackground() {
|
||||
JTextComponent c = getComponent();
|
||||
|
||||
Color background = c.getBackground();
|
||||
if( !(background instanceof UIResource) )
|
||||
return;
|
||||
|
||||
// do not update background if it currently has a unknown color (assigned from outside)
|
||||
if( background != this.background &&
|
||||
background != disabledBackground &&
|
||||
background != inactiveBackground )
|
||||
return;
|
||||
|
||||
Color newBackground = !c.isEnabled()
|
||||
? disabledBackground
|
||||
: (!c.isEditable()
|
||||
? inactiveBackground
|
||||
: this.background);
|
||||
|
||||
if( newBackground != background )
|
||||
c.setBackground( newBackground );
|
||||
FlatTextFieldUI.updateBackground( getComponent(), background,
|
||||
disabledBackground, inactiveBackground,
|
||||
oldDisabledBackground, oldInactiveBackground );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Component;
|
||||
import javax.swing.UIManager;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
|
||||
/**
|
||||
* Border for various text components (e.g. {@link javax.swing.JTextField}).
|
||||
@@ -29,7 +30,10 @@ import javax.swing.UIManager;
|
||||
public class FlatTextBorder
|
||||
extends FlatBorder
|
||||
{
|
||||
protected final int arc = UIManager.getInt( "TextComponent.arc" );
|
||||
@Styleable protected int arc = UIManager.getInt( "TextComponent.arc" );
|
||||
|
||||
// only used via styling (not in UI defaults, but has likewise client properties)
|
||||
/** @since 2 */ @Styleable protected Boolean roundRect;
|
||||
|
||||
@Override
|
||||
protected int getArc( Component c ) {
|
||||
@@ -37,6 +41,8 @@ public class FlatTextBorder
|
||||
return 0;
|
||||
|
||||
Boolean roundRect = FlatUIUtils.isRoundRect( c );
|
||||
if( roundRect == null )
|
||||
roundRect = this.roundRect;
|
||||
return roundRect != null ? (roundRect ? Short.MAX_VALUE : 0) : arc;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import static com.formdev.flatlaf.FlatClientProperties.*;
|
||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import java.awt.Color;
|
||||
import java.awt.Container;
|
||||
@@ -27,7 +28,10 @@ import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JSpinner;
|
||||
@@ -39,10 +43,11 @@ 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.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.JavaCompatibility;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JTextField}.
|
||||
@@ -68,6 +73,7 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault Component.isIntelliJTheme boolean
|
||||
* @uiDefault TextField.placeholderForeground Color
|
||||
* @uiDefault TextField.focusedBackground Color optional
|
||||
* @uiDefault TextField.iconTextGap int optional, default is 4
|
||||
* @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always
|
||||
* @uiDefault TextComponent.selectAllOnMouseClick boolean
|
||||
*
|
||||
@@ -75,20 +81,51 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
*/
|
||||
public class FlatTextFieldUI
|
||||
extends BasicTextFieldUI
|
||||
implements StyleableUI
|
||||
{
|
||||
protected int minimumWidth;
|
||||
@Styleable protected int minimumWidth;
|
||||
protected boolean isIntelliJTheme;
|
||||
protected Color placeholderForeground;
|
||||
protected Color focusedBackground;
|
||||
private Color background;
|
||||
@Styleable protected Color disabledBackground;
|
||||
@Styleable protected Color inactiveBackground;
|
||||
@Styleable protected Color placeholderForeground;
|
||||
@Styleable protected Color focusedBackground;
|
||||
/** @since 2 */ @Styleable protected int iconTextGap;
|
||||
|
||||
/** @since 2 */ @Styleable protected Icon leadingIcon;
|
||||
/** @since 2 */ @Styleable protected Icon trailingIcon;
|
||||
|
||||
private Color oldDisabledBackground;
|
||||
private Color oldInactiveBackground;
|
||||
|
||||
private Insets defaultMargin;
|
||||
|
||||
private FocusListener focusListener;
|
||||
private Map<String, Object> oldStyleValues;
|
||||
private AtomicBoolean borderShared;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatTextFieldUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
leadingIcon = clientProperty( c, TEXT_FIELD_LEADING_ICON, null, Icon.class );
|
||||
trailingIcon = clientProperty( c, TEXT_FIELD_TRAILING_ICON, null, Icon.class );
|
||||
|
||||
installStyle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uninstallUI( JComponent c ) {
|
||||
super.uninstallUI( c );
|
||||
|
||||
leadingIcon = null;
|
||||
trailingIcon = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
@@ -96,8 +133,12 @@ public class FlatTextFieldUI
|
||||
String prefix = getPropertyPrefix();
|
||||
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
||||
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
||||
background = UIManager.getColor( prefix + ".background" );
|
||||
disabledBackground = UIManager.getColor( prefix + ".disabledBackground" );
|
||||
inactiveBackground = UIManager.getColor( prefix + ".inactiveBackground" );
|
||||
placeholderForeground = UIManager.getColor( prefix + ".placeholderForeground" );
|
||||
focusedBackground = UIManager.getColor( prefix + ".focusedBackground" );
|
||||
iconTextGap = FlatUIUtils.getUIInt( prefix + ".iconTextGap", 4 );
|
||||
|
||||
defaultMargin = UIManager.getInsets( prefix + ".margin" );
|
||||
|
||||
@@ -110,9 +151,18 @@ public class FlatTextFieldUI
|
||||
protected void uninstallDefaults() {
|
||||
super.uninstallDefaults();
|
||||
|
||||
background = null;
|
||||
disabledBackground = null;
|
||||
inactiveBackground = null;
|
||||
placeholderForeground = null;
|
||||
focusedBackground = null;
|
||||
|
||||
oldDisabledBackground = null;
|
||||
oldInactiveBackground = null;
|
||||
|
||||
oldStyleValues = null;
|
||||
borderShared = null;
|
||||
|
||||
MigLayoutVisualPadding.uninstall( getComponent() );
|
||||
}
|
||||
|
||||
@@ -141,29 +191,127 @@ public class FlatTextFieldUI
|
||||
|
||||
@Override
|
||||
protected void propertyChange( PropertyChangeEvent e ) {
|
||||
super.propertyChange( e );
|
||||
propertyChange( getComponent(), e );
|
||||
}
|
||||
String propertyName = e.getPropertyName();
|
||||
if( "editable".equals( propertyName ) || "enabled".equals( propertyName ) )
|
||||
updateBackground();
|
||||
else
|
||||
super.propertyChange( e );
|
||||
|
||||
static void propertyChange( JTextComponent c, PropertyChangeEvent e ) {
|
||||
JTextComponent c = getComponent();
|
||||
switch( e.getPropertyName() ) {
|
||||
case FlatClientProperties.PLACEHOLDER_TEXT:
|
||||
case FlatClientProperties.COMPONENT_ROUND_RECT:
|
||||
case FlatClientProperties.TEXT_FIELD_PADDING:
|
||||
case PLACEHOLDER_TEXT:
|
||||
case COMPONENT_ROUND_RECT:
|
||||
case TEXT_FIELD_PADDING:
|
||||
c.repaint();
|
||||
break;
|
||||
|
||||
case FlatClientProperties.MINIMUM_WIDTH:
|
||||
case MINIMUM_WIDTH:
|
||||
c.revalidate();
|
||||
break;
|
||||
|
||||
case STYLE:
|
||||
case STYLE_CLASS:
|
||||
installStyle();
|
||||
c.revalidate();
|
||||
c.repaint();
|
||||
break;
|
||||
|
||||
case TEXT_FIELD_LEADING_ICON:
|
||||
leadingIcon = (e.getNewValue() instanceof Icon) ? (Icon) e.getNewValue() : null;
|
||||
c.repaint();
|
||||
break;
|
||||
|
||||
case TEXT_FIELD_TRAILING_ICON:
|
||||
trailingIcon = (e.getNewValue() instanceof Icon) ? (Icon) e.getNewValue() : null;
|
||||
c.repaint();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void installStyle() {
|
||||
try {
|
||||
applyStyle( FlatStylingSupport.getResolvedStyle( getComponent(), getStyleType() ) );
|
||||
} catch( RuntimeException ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
String getStyleType() {
|
||||
return "TextField";
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void applyStyle( Object style ) {
|
||||
oldDisabledBackground = disabledBackground;
|
||||
oldInactiveBackground = inactiveBackground;
|
||||
|
||||
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
|
||||
|
||||
updateBackground();
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected Object applyStyleProperty( String key, Object value ) {
|
||||
if( borderShared == null )
|
||||
borderShared = new AtomicBoolean( true );
|
||||
return FlatStylingSupport.applyToAnnotatedObjectOrBorder( this, key, value, getComponent(), borderShared );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this, getComponent().getBorder() );
|
||||
}
|
||||
|
||||
private void updateBackground() {
|
||||
updateBackground( getComponent(), background,
|
||||
disabledBackground, inactiveBackground,
|
||||
oldDisabledBackground, oldInactiveBackground );
|
||||
}
|
||||
|
||||
// same functionality as BasicTextUI.updateBackground()
|
||||
static void updateBackground( JTextComponent c, Color background,
|
||||
Color disabledBackground, Color inactiveBackground,
|
||||
Color oldDisabledBackground, Color oldInactiveBackground )
|
||||
{
|
||||
Color oldBackground = c.getBackground();
|
||||
if( !(oldBackground instanceof UIResource) )
|
||||
return;
|
||||
|
||||
// do not update background if it currently has a unknown color (assigned from outside)
|
||||
if( oldBackground != background &&
|
||||
oldBackground != disabledBackground &&
|
||||
oldBackground != inactiveBackground &&
|
||||
oldBackground != oldDisabledBackground &&
|
||||
oldBackground != oldInactiveBackground )
|
||||
return;
|
||||
|
||||
Color newBackground = !c.isEnabled()
|
||||
? disabledBackground
|
||||
: (!c.isEditable()
|
||||
? inactiveBackground
|
||||
: background);
|
||||
|
||||
if( newBackground != oldBackground )
|
||||
c.setBackground( newBackground );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintSafely( Graphics g ) {
|
||||
paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground );
|
||||
paintPlaceholder( g );
|
||||
|
||||
if( hasLeadingIcon() || hasTrailingIcon() )
|
||||
paintIcons( g, new Rectangle( getIconsRect() ) );
|
||||
|
||||
/*debug
|
||||
Rectangle r = getVisibleEditorRect();
|
||||
g.setColor( Color.red );
|
||||
g.drawRect( r.x, r.y, r.width - 1, r.height - 1 );
|
||||
debug*/
|
||||
|
||||
super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) );
|
||||
}
|
||||
|
||||
@@ -177,7 +325,7 @@ public class FlatTextFieldUI
|
||||
// - not opaque and
|
||||
// - border is not a flat border and
|
||||
// - opaque was explicitly set (to false)
|
||||
// (same behaviour as in AquaTextFieldUI)
|
||||
// (same behavior as in AquaTextFieldUI)
|
||||
if( !c.isOpaque() && FlatUIUtils.getOutsideFlatBorder( c ) == null && FlatUIUtils.hasOpaqueBeenExplicitlySet( c ) )
|
||||
return;
|
||||
|
||||
@@ -230,15 +378,15 @@ public class FlatTextFieldUI
|
||||
JComponent jc = (parent instanceof JComboBox) ? (JComboBox<?>) parent : c;
|
||||
|
||||
// get placeholder text
|
||||
Object placeholder = jc.getClientProperty( FlatClientProperties.PLACEHOLDER_TEXT );
|
||||
if( !(placeholder instanceof String) )
|
||||
String placeholder = clientProperty( jc, PLACEHOLDER_TEXT, null, String.class );
|
||||
if( placeholder == null )
|
||||
return;
|
||||
|
||||
// compute placeholder location
|
||||
Rectangle r = getVisibleEditorRect();
|
||||
FontMetrics fm = c.getFontMetrics( c.getFont() );
|
||||
String clippedPlaceholder = JavaCompatibility.getClippedString( c, fm, (String) placeholder, r.width );
|
||||
int x = r.x + (c.getComponentOrientation().isLeftToRight() ? 0 : r.width - fm.stringWidth( clippedPlaceholder ));
|
||||
String clippedPlaceholder = JavaCompatibility.getClippedString( c, fm, placeholder, r.width );
|
||||
int x = r.x + (isLeftToRight() ? 0 : r.width - fm.stringWidth( clippedPlaceholder ));
|
||||
int y = r.y + fm.getAscent() + ((r.height - fm.getHeight()) / 2);
|
||||
|
||||
// paint placeholder
|
||||
@@ -246,14 +394,57 @@ public class FlatTextFieldUI
|
||||
FlatUIUtils.drawString( c, g, clippedPlaceholder, x, y );
|
||||
}
|
||||
|
||||
/**
|
||||
* Paints the leading and trailing icons in the given rectangle.
|
||||
* The rectangle is updated by this method so that subclasses can use it
|
||||
* without painting over leading or trailing icons.
|
||||
*
|
||||
* @since 2
|
||||
*/
|
||||
protected void paintIcons( Graphics g, Rectangle r ) {
|
||||
boolean ltr = isLeftToRight();
|
||||
Icon leftIcon = ltr ? leadingIcon : trailingIcon;
|
||||
Icon rightIcon = ltr ? trailingIcon : leadingIcon;
|
||||
|
||||
// paint left icon
|
||||
if( leftIcon != null ) {
|
||||
int x = r.x;
|
||||
int y = r.y + Math.round( (r.height - leftIcon.getIconHeight()) / 2f );
|
||||
leftIcon.paintIcon( getComponent(), g, x, y );
|
||||
|
||||
// update rectangle so that subclasses can use it
|
||||
int w = leftIcon.getIconWidth() + scale( iconTextGap );
|
||||
r.x += w;
|
||||
r.width -= w;
|
||||
}
|
||||
|
||||
// paint right icon
|
||||
if( rightIcon != null ) {
|
||||
int iconWidth = rightIcon.getIconWidth();
|
||||
int x = r.x + r.width - iconWidth;
|
||||
int y = r.y + Math.round( (r.height - rightIcon.getIconHeight()) / 2f );
|
||||
rightIcon.paintIcon( getComponent(), g, x, y );
|
||||
|
||||
// update rectangle so that subclasses can use it
|
||||
r.width -= iconWidth + scale( iconTextGap );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize( JComponent c ) {
|
||||
return applyMinimumWidth( c, super.getPreferredSize( c ), minimumWidth );
|
||||
return applyMinimumWidth( c, applyExtraSize( super.getPreferredSize( c ) ), minimumWidth );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize( JComponent c ) {
|
||||
return applyMinimumWidth( c, super.getMinimumSize( c ), minimumWidth );
|
||||
return applyMinimumWidth( c, applyExtraSize( super.getMinimumSize( c ) ), minimumWidth );
|
||||
}
|
||||
|
||||
private Dimension applyExtraSize( Dimension size ) {
|
||||
// add width of leading and trailing icons
|
||||
size.width += getLeadingIconWidth() + getTrailingIconWidth();
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
private Dimension applyMinimumWidth( JComponent c, Dimension size, int minimumWidth ) {
|
||||
@@ -283,32 +474,105 @@ public class FlatTextFieldUI
|
||||
return margin instanceof UIResource && Objects.equals( margin, defaultMargin );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the rectangle used for the root view of the text.
|
||||
* This method is used to place the text.
|
||||
*/
|
||||
@Override
|
||||
protected Rectangle getVisibleEditorRect() {
|
||||
Rectangle r = super.getVisibleEditorRect();
|
||||
if( r != null ) {
|
||||
// remove padding
|
||||
Insets padding = getPadding();
|
||||
if( padding != null ) {
|
||||
r = FlatUIUtils.subtractInsets( r, padding );
|
||||
r.width = Math.max( r.width, 0 );
|
||||
r.height = Math.max( r.height, 0 );
|
||||
}
|
||||
Rectangle r = getIconsRect();
|
||||
if( r == null )
|
||||
return null;
|
||||
|
||||
// remove space needed for leading and trailing icons
|
||||
int leading = getLeadingIconWidth();
|
||||
int trailing = getTrailingIconWidth();
|
||||
if( leading != 0 || trailing != 0 ) {
|
||||
boolean ltr = isLeftToRight();
|
||||
int left = ltr ? leading : trailing;
|
||||
int right = ltr ? trailing : leading;
|
||||
r.x += left;
|
||||
r.width -= left + right;
|
||||
}
|
||||
|
||||
// remove padding
|
||||
Insets padding = getPadding();
|
||||
if( padding != null )
|
||||
r = FlatUIUtils.subtractInsets( r, padding );
|
||||
|
||||
// make sure that width and height are not negative
|
||||
r.width = Math.max( r.width, 0 );
|
||||
r.height = Math.max( r.height, 0 );
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.4
|
||||
* Returns the rectangle used to paint leading and trailing icons.
|
||||
* It invokes {@code super.getVisibleEditorRect()} and reduces left and/or
|
||||
* right margin if the text field has leading or trailing icons.
|
||||
*
|
||||
* @since 2
|
||||
*/
|
||||
protected Insets getPadding() {
|
||||
Object padding = getComponent().getClientProperty( FlatClientProperties.TEXT_FIELD_PADDING );
|
||||
return (padding instanceof Insets) ? UIScale.scale( (Insets) padding ) : null;
|
||||
protected Rectangle getIconsRect() {
|
||||
Rectangle r = super.getVisibleEditorRect();
|
||||
if( r == null )
|
||||
return null;
|
||||
|
||||
// if a leading/trailing icon is shown, then the left/right margin is reduced
|
||||
// to the top margin, which places the icon nicely centered on left/right side
|
||||
boolean ltr = isLeftToRight();
|
||||
if( ltr ? hasLeadingIcon() : hasTrailingIcon() ) {
|
||||
// reduce left margin
|
||||
Insets margin = getComponent().getMargin();
|
||||
int newLeftMargin = Math.min( margin.left, margin.top );
|
||||
if( newLeftMargin < margin.left ) {
|
||||
int diff = scale( margin.left - newLeftMargin );
|
||||
r.x -= diff;
|
||||
r.width += diff;
|
||||
}
|
||||
}
|
||||
if( ltr ? hasTrailingIcon() : hasLeadingIcon() ) {
|
||||
// reduce right margin
|
||||
Insets margin = getComponent().getMargin();
|
||||
int newRightMargin = Math.min( margin.right, margin.top );
|
||||
if( newRightMargin < margin.left )
|
||||
r.width += scale( margin.right - newRightMargin );
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.4
|
||||
*/
|
||||
/** @since 2 */
|
||||
protected boolean hasLeadingIcon() {
|
||||
return leadingIcon != null;
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected boolean hasTrailingIcon() {
|
||||
return trailingIcon != null;
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected int getLeadingIconWidth() {
|
||||
return (leadingIcon != null) ? leadingIcon.getIconWidth() + scale( iconTextGap ) : 0;
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected int getTrailingIconWidth() {
|
||||
return (trailingIcon != null) ? trailingIcon.getIconWidth() + scale( iconTextGap ) : 0;
|
||||
}
|
||||
|
||||
boolean isLeftToRight() {
|
||||
return getComponent().getComponentOrientation().isLeftToRight();
|
||||
}
|
||||
|
||||
/** @since 1.4 */
|
||||
protected Insets getPadding() {
|
||||
return scale( clientProperty( getComponent(), TEXT_FIELD_PADDING, null, Insets.class ) );
|
||||
}
|
||||
|
||||
/** @since 1.4 */
|
||||
protected void scrollCaretToVisible() {
|
||||
Caret caret = getComponent().getCaret();
|
||||
if( caret instanceof FlatCaret )
|
||||
|
||||
@@ -23,12 +23,17 @@ import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.util.Map;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JEditorPane;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicTextPaneUI;
|
||||
import javax.swing.text.Caret;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JTextPane}.
|
||||
@@ -58,20 +63,35 @@ import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
*/
|
||||
public class FlatTextPaneUI
|
||||
extends BasicTextPaneUI
|
||||
implements StyleableUI
|
||||
{
|
||||
protected int minimumWidth;
|
||||
@Styleable protected int minimumWidth;
|
||||
protected boolean isIntelliJTheme;
|
||||
protected Color focusedBackground;
|
||||
private Color background;
|
||||
@Styleable protected Color disabledBackground;
|
||||
@Styleable protected Color inactiveBackground;
|
||||
@Styleable protected Color focusedBackground;
|
||||
|
||||
private Color oldDisabledBackground;
|
||||
private Color oldInactiveBackground;
|
||||
|
||||
private Insets defaultMargin;
|
||||
|
||||
private Object oldHonorDisplayProperties;
|
||||
private FocusListener focusListener;
|
||||
private Map<String, Object> oldStyleValues;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatTextPaneUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
installStyle();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
@@ -79,6 +99,9 @@ public class FlatTextPaneUI
|
||||
String prefix = getPropertyPrefix();
|
||||
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
||||
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
||||
background = UIManager.getColor( prefix + ".background" );
|
||||
disabledBackground = UIManager.getColor( prefix + ".disabledBackground" );
|
||||
inactiveBackground = UIManager.getColor( prefix + ".inactiveBackground" );
|
||||
focusedBackground = UIManager.getColor( prefix + ".focusedBackground" );
|
||||
|
||||
defaultMargin = UIManager.getInsets( prefix + ".margin" );
|
||||
@@ -92,8 +115,16 @@ public class FlatTextPaneUI
|
||||
protected void uninstallDefaults() {
|
||||
super.uninstallDefaults();
|
||||
|
||||
background = null;
|
||||
disabledBackground = null;
|
||||
inactiveBackground = null;
|
||||
focusedBackground = null;
|
||||
|
||||
oldDisabledBackground = null;
|
||||
oldInactiveBackground = null;
|
||||
|
||||
oldStyleValues = null;
|
||||
|
||||
getComponent().putClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES, oldHonorDisplayProperties );
|
||||
}
|
||||
|
||||
@@ -114,10 +145,56 @@ public class FlatTextPaneUI
|
||||
focusListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Caret createCaret() {
|
||||
return new FlatCaret( null, false );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void propertyChange( PropertyChangeEvent e ) {
|
||||
// invoke updateBackground() before super.propertyChange()
|
||||
String propertyName = e.getPropertyName();
|
||||
if( "editable".equals( propertyName ) || "enabled".equals( propertyName ) )
|
||||
updateBackground();
|
||||
|
||||
super.propertyChange( e );
|
||||
FlatEditorPaneUI.propertyChange( getComponent(), e );
|
||||
FlatEditorPaneUI.propertyChange( getComponent(), e, this::installStyle );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void installStyle() {
|
||||
try {
|
||||
applyStyle( FlatStylingSupport.getResolvedStyle( getComponent(), "TextPane" ) );
|
||||
} catch( RuntimeException ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void applyStyle( Object style ) {
|
||||
oldDisabledBackground = disabledBackground;
|
||||
oldInactiveBackground = inactiveBackground;
|
||||
|
||||
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
|
||||
|
||||
updateBackground();
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected Object applyStyleProperty( String key, Object value ) {
|
||||
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, getComponent(), key, value );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
||||
}
|
||||
|
||||
private void updateBackground() {
|
||||
FlatTextFieldUI.updateBackground( getComponent(), background,
|
||||
disabledBackground, inactiveBackground,
|
||||
oldDisabledBackground, oldInactiveBackground );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -871,12 +871,14 @@ debug*/
|
||||
|
||||
//---- class FlatTitleLabelUI ---------------------------------------------
|
||||
|
||||
/**
|
||||
* @since 1.1
|
||||
*/
|
||||
/** @since 1.1 */
|
||||
protected class FlatTitleLabelUI
|
||||
extends FlatLabelUI
|
||||
{
|
||||
protected FlatTitleLabelUI() {
|
||||
super( false );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintEnabledText( JLabel l, Graphics g, String s, int textX, int textY ) {
|
||||
boolean hasEmbeddedMenuBar = hasVisibleEmbeddedMenuBar( rootPane.getJMenuBar() );
|
||||
|
||||
@@ -31,9 +31,7 @@ public class FlatTitlePaneIcon
|
||||
{
|
||||
private final List<Image> images;
|
||||
|
||||
/**
|
||||
* @since 1.2
|
||||
*/
|
||||
/** @since 1.2 */
|
||||
public FlatTitlePaneIcon( List<Image> images, Dimension size ) {
|
||||
super( null, size.width, size.height );
|
||||
this.images = images;
|
||||
|
||||
@@ -21,11 +21,15 @@ import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import javax.swing.AbstractButton;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JToggleButton;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
@@ -73,17 +77,28 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
public class FlatToggleButtonUI
|
||||
extends FlatButtonUI
|
||||
{
|
||||
protected int tabUnderlineHeight;
|
||||
protected Color tabUnderlineColor;
|
||||
protected Color tabDisabledUnderlineColor;
|
||||
protected Color tabSelectedBackground;
|
||||
protected Color tabHoverBackground;
|
||||
protected Color tabFocusBackground;
|
||||
@Styleable(dot=true) protected int tabUnderlineHeight;
|
||||
@Styleable(dot=true) protected Color tabUnderlineColor;
|
||||
@Styleable(dot=true) protected Color tabDisabledUnderlineColor;
|
||||
@Styleable(dot=true) protected Color tabSelectedBackground;
|
||||
@Styleable(dot=true) protected Color tabHoverBackground;
|
||||
@Styleable(dot=true) protected Color tabFocusBackground;
|
||||
|
||||
private boolean defaults_initialized = false;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return FlatUIUtils.createSharedUI( FlatToggleButtonUI.class, FlatToggleButtonUI::new );
|
||||
return FlatUIUtils.canUseSharedUI( c )
|
||||
? FlatUIUtils.createSharedUI( FlatToggleButtonUI.class, () -> new FlatToggleButtonUI( true ) )
|
||||
: new FlatToggleButtonUI( false );
|
||||
}
|
||||
|
||||
protected FlatToggleButtonUI( boolean shared ) {
|
||||
super( shared );
|
||||
}
|
||||
|
||||
@Override
|
||||
String getStyleType() {
|
||||
return "ToggleButton";
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -136,8 +151,29 @@ public class FlatToggleButtonUI
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
protected Object applyStyleProperty( AbstractButton b, String key, Object value ) {
|
||||
if( key.startsWith( "help." ) )
|
||||
throw new UnknownStyleException( key );
|
||||
|
||||
return super.applyStyleProperty( b, key, value );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||
Map<String, Class<?>> infos = super.getStyleableInfos( c );
|
||||
Iterator<String> it = infos.keySet().iterator();
|
||||
while( it.hasNext() ) {
|
||||
if( it.next().startsWith( "help." ) )
|
||||
it.remove();
|
||||
}
|
||||
return infos;
|
||||
}
|
||||
|
||||
static boolean isTabButton( Component c ) {
|
||||
return c instanceof JToggleButton && clientPropertyEquals( (JToggleButton) c, BUTTON_TYPE, BUTTON_TYPE_TAB );
|
||||
return c instanceof JToggleButton && BUTTON_TYPE_TAB.equals( getButtonTypeStr( (JToggleButton) c ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -22,9 +22,11 @@ import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import java.util.function.Function;
|
||||
import javax.swing.JToolBar;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ToolBarUI;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
@@ -42,7 +44,7 @@ public class FlatToolBarBorder
|
||||
private static final int DOT_SIZE = 2;
|
||||
private static final int GRIP_SIZE = DOT_SIZE * 3;
|
||||
|
||||
protected final Color gripColor = UIManager.getColor( "ToolBar.gripColor" );
|
||||
protected Color gripColor = UIManager.getColor( "ToolBar.gripColor" );
|
||||
|
||||
public FlatToolBarBorder() {
|
||||
super( UIManager.getInsets( "ToolBar.borderMargins" ) );
|
||||
@@ -56,7 +58,8 @@ public class FlatToolBarBorder
|
||||
try {
|
||||
FlatUIUtils.setRenderingHints( g2 );
|
||||
|
||||
g2.setColor( gripColor );
|
||||
Color color = getStyleFromToolBarUI( c, ui -> ui.gripColor );
|
||||
g2.setColor( (color != null) ? color : gripColor );
|
||||
paintGrip( c, g2, x, y, width, height );
|
||||
} finally {
|
||||
g2.dispose();
|
||||
@@ -90,7 +93,14 @@ public class FlatToolBarBorder
|
||||
|
||||
@Override
|
||||
public Insets getBorderInsets( Component c, Insets insets ) {
|
||||
insets = super.getBorderInsets( c, insets );
|
||||
Insets m = getStyleFromToolBarUI( c, ui -> ui.borderMargins );
|
||||
if( m != null ) {
|
||||
int t = top, l = left, b = bottom, r = right;
|
||||
top = m.top; left = m.left; bottom = m.bottom; right = m.right;
|
||||
insets = super.getBorderInsets( c, insets );
|
||||
top = t; left = l; bottom = b; right = r;
|
||||
} else
|
||||
insets = super.getBorderInsets( c, insets );
|
||||
|
||||
// add grip inset if floatable
|
||||
if( c instanceof JToolBar && ((JToolBar)c).isFloatable() ) {
|
||||
@@ -106,4 +116,17 @@ public class FlatToolBarBorder
|
||||
|
||||
return insets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Because this border is shared for all toolbars,
|
||||
* get border specific style from FlatToolBarUI.
|
||||
*/
|
||||
static <T> T getStyleFromToolBarUI( Component c, Function<FlatToolBarUI, T> f ) {
|
||||
if( c instanceof JToolBar ) {
|
||||
ToolBarUI ui = ((JToolBar)c).getUI();
|
||||
if( ui instanceof FlatToolBarUI )
|
||||
return f.apply( (FlatToolBarUI) ui );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Map;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JSeparator;
|
||||
import javax.swing.JToolBar;
|
||||
@@ -29,6 +31,9 @@ import javax.swing.SwingConstants;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicToolBarSeparatorUI;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JToolBar.Separator}.
|
||||
@@ -42,16 +47,34 @@ import javax.swing.plaf.basic.BasicToolBarSeparatorUI;
|
||||
*/
|
||||
public class FlatToolBarSeparatorUI
|
||||
extends BasicToolBarSeparatorUI
|
||||
implements StyleableUI
|
||||
{
|
||||
private static final int LINE_WIDTH = 1;
|
||||
|
||||
protected int separatorWidth;
|
||||
protected Color separatorColor;
|
||||
@Styleable protected int separatorWidth;
|
||||
@Styleable protected Color separatorColor;
|
||||
|
||||
private final boolean shared;
|
||||
private boolean defaults_initialized = false;
|
||||
private PropertyChangeListener propertyChangeListener;
|
||||
private Map<String, Object> oldStyleValues;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return FlatUIUtils.createSharedUI( FlatToolBarSeparatorUI.class, FlatToolBarSeparatorUI::new );
|
||||
return FlatUIUtils.canUseSharedUI( c )
|
||||
? FlatUIUtils.createSharedUI( FlatToolBarSeparatorUI.class, () -> new FlatToolBarSeparatorUI( true ) )
|
||||
: new FlatToolBarSeparatorUI( false );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected FlatToolBarSeparatorUI( boolean shared ) {
|
||||
this.shared = shared;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
installStyle( (JSeparator) c );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -73,7 +96,62 @@ public class FlatToolBarSeparatorUI
|
||||
@Override
|
||||
protected void uninstallDefaults( JSeparator s ) {
|
||||
super.uninstallDefaults( s );
|
||||
|
||||
defaults_initialized = false;
|
||||
oldStyleValues = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installListeners( JSeparator s ) {
|
||||
super.installListeners( s );
|
||||
|
||||
propertyChangeListener = FlatStylingSupport.createPropertyChangeListener(
|
||||
s, () -> stylePropertyChange( s ), null );
|
||||
s.addPropertyChangeListener( propertyChangeListener );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void uninstallListeners( JSeparator s ) {
|
||||
super.uninstallListeners( s );
|
||||
|
||||
s.removePropertyChangeListener( propertyChangeListener );
|
||||
propertyChangeListener = null;
|
||||
}
|
||||
|
||||
private void stylePropertyChange( JSeparator s ) {
|
||||
if( shared && FlatStylingSupport.hasStyleProperty( s ) ) {
|
||||
// unshare component UI if necessary
|
||||
// updateUI() invokes applyStyle() from installUI()
|
||||
s.updateUI();
|
||||
} else
|
||||
installStyle( s );
|
||||
s.revalidate();
|
||||
s.repaint();
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void installStyle( JSeparator s ) {
|
||||
try {
|
||||
applyStyle( FlatStylingSupport.getResolvedStyle( s, "ToolBarSeparator" ) );
|
||||
} catch( RuntimeException ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void applyStyle( Object style ) {
|
||||
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected Object applyStyleProperty( String key, Object value ) {
|
||||
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,16 +16,27 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.FocusTraversalPolicy;
|
||||
import java.awt.Insets;
|
||||
import java.awt.event.ContainerEvent;
|
||||
import java.awt.event.ContainerListener;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Map;
|
||||
import javax.swing.AbstractButton;
|
||||
import javax.swing.InputMap;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.LayoutFocusTraversalPolicy;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicToolBarUI;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JToolBar}.
|
||||
@@ -45,14 +56,30 @@ import javax.swing.plaf.basic.BasicToolBarUI;
|
||||
* <!-- FlatToolBarUI -->
|
||||
*
|
||||
* @uiDefault ToolBar.focusableButtons boolean
|
||||
* @uiDefault ToolBar.arrowKeysOnlyNavigation boolean
|
||||
* @uiDefault ToolBar.floatable boolean
|
||||
*
|
||||
* <!-- FlatToolBarBorder -->
|
||||
*
|
||||
* @uiDefault ToolBar.borderMargins Insets
|
||||
* @uiDefault ToolBar.gripColor Color
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatToolBarUI
|
||||
extends BasicToolBarUI
|
||||
implements StyleableUI
|
||||
{
|
||||
/** @since 1.4 */
|
||||
protected boolean focusableButtons;
|
||||
/** @since 1.4 */ @Styleable protected boolean focusableButtons;
|
||||
/** @since 2 */ @Styleable protected boolean arrowKeysOnlyNavigation;
|
||||
|
||||
// for FlatToolBarBorder
|
||||
@Styleable protected Insets borderMargins;
|
||||
@Styleable protected Color gripColor;
|
||||
|
||||
private FocusTraversalPolicy focusTraversalPolicy;
|
||||
private Boolean oldFloatable;
|
||||
private Map<String, Object> oldStyleValues;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatToolBarUI();
|
||||
@@ -62,7 +89,13 @@ public class FlatToolBarUI
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
installFocusTraversalPolicy();
|
||||
|
||||
installStyle();
|
||||
|
||||
// disable focusable state of buttons (when switching from another Laf)
|
||||
// do this after applying style to avoid disabling (here) and re-enabling
|
||||
// (in applyStyle()), which would transfer focus to next button
|
||||
if( !focusableButtons )
|
||||
setButtonsFocusable( false );
|
||||
}
|
||||
@@ -74,6 +107,10 @@ public class FlatToolBarUI
|
||||
// re-enable focusable state of buttons (when switching to another Laf)
|
||||
if( !focusableButtons )
|
||||
setButtonsFocusable( true );
|
||||
|
||||
uninstallFocusTraversalPolicy();
|
||||
|
||||
oldStyleValues = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -81,6 +118,24 @@ public class FlatToolBarUI
|
||||
super.installDefaults();
|
||||
|
||||
focusableButtons = UIManager.getBoolean( "ToolBar.focusableButtons" );
|
||||
arrowKeysOnlyNavigation = UIManager.getBoolean( "ToolBar.arrowKeysOnlyNavigation" );
|
||||
|
||||
// floatable
|
||||
if( !UIManager.getBoolean( "ToolBar.floatable" ) ) {
|
||||
oldFloatable = toolBar.isFloatable();
|
||||
toolBar.setFloatable( false );
|
||||
} else
|
||||
oldFloatable = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void uninstallDefaults() {
|
||||
super.uninstallDefaults();
|
||||
|
||||
if( oldFloatable != null ) {
|
||||
toolBar.setFloatable( oldFloatable );
|
||||
oldFloatable = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -90,36 +145,157 @@ public class FlatToolBarUI
|
||||
public void componentAdded( ContainerEvent e ) {
|
||||
super.componentAdded( e );
|
||||
|
||||
if( !focusableButtons ) {
|
||||
Component c = e.getChild();
|
||||
if( c instanceof AbstractButton )
|
||||
c.setFocusable( false );
|
||||
}
|
||||
if( !focusableButtons )
|
||||
setButtonFocusable( e.getChild(), false );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentRemoved( ContainerEvent e ) {
|
||||
super.componentRemoved( e );
|
||||
|
||||
if( !focusableButtons ) {
|
||||
Component c = e.getChild();
|
||||
if( c instanceof AbstractButton )
|
||||
c.setFocusable( true );
|
||||
}
|
||||
if( !focusableButtons )
|
||||
setButtonFocusable( e.getChild(), true );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.4
|
||||
*/
|
||||
protected void setButtonsFocusable( boolean focusable ) {
|
||||
for( Component c : toolBar.getComponents() ) {
|
||||
if( c instanceof AbstractButton )
|
||||
c.setFocusable( focusable );
|
||||
@Override
|
||||
protected PropertyChangeListener createPropertyListener() {
|
||||
return FlatStylingSupport.createPropertyChangeListener( toolBar, this::installStyle, super.createPropertyListener() );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void installStyle() {
|
||||
try {
|
||||
applyStyle( FlatStylingSupport.getResolvedStyle( toolBar, "ToolBar" ) );
|
||||
} catch( RuntimeException ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void applyStyle( Object style ) {
|
||||
boolean oldFocusableButtons = focusableButtons;
|
||||
boolean oldArrowKeysOnlyNavigation = arrowKeysOnlyNavigation;
|
||||
|
||||
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
|
||||
|
||||
if( focusableButtons != oldFocusableButtons )
|
||||
setButtonsFocusable( focusableButtons );
|
||||
if( arrowKeysOnlyNavigation != oldArrowKeysOnlyNavigation || focusableButtons != oldFocusableButtons ) {
|
||||
if( arrowKeysOnlyNavigation )
|
||||
installFocusTraversalPolicy();
|
||||
else
|
||||
uninstallFocusTraversalPolicy();
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected Object applyStyleProperty( String key, Object value ) {
|
||||
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, toolBar, key, value );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
||||
}
|
||||
|
||||
/** @since 1.4 */
|
||||
protected void setButtonsFocusable( boolean focusable ) {
|
||||
for( Component c : toolBar.getComponents() )
|
||||
setButtonFocusable( c, focusable );
|
||||
}
|
||||
|
||||
private void setButtonFocusable( Component c, boolean focusable ) {
|
||||
if( c instanceof AbstractButton && focusable != c.isFocusable() )
|
||||
c.setFocusable( focusable );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void installFocusTraversalPolicy() {
|
||||
if( !arrowKeysOnlyNavigation || !focusableButtons || toolBar.getFocusTraversalPolicy() != null )
|
||||
return;
|
||||
|
||||
focusTraversalPolicy = createFocusTraversalPolicy();
|
||||
if( focusTraversalPolicy != null ) {
|
||||
toolBar.setFocusTraversalPolicy( focusTraversalPolicy );
|
||||
toolBar.setFocusTraversalPolicyProvider( true );
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void uninstallFocusTraversalPolicy() {
|
||||
if( focusTraversalPolicy != null && toolBar.getFocusTraversalPolicy() == focusTraversalPolicy ) {
|
||||
toolBar.setFocusTraversalPolicy( null );
|
||||
toolBar.setFocusTraversalPolicyProvider( false );
|
||||
}
|
||||
focusTraversalPolicy = null;
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected FocusTraversalPolicy createFocusTraversalPolicy() {
|
||||
return new FlatToolBarFocusTraversalPolicy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the same as super.navigateFocusedComp() with the exception that components
|
||||
* with empty input map (e.g. JLabel) are skipped.
|
||||
*/
|
||||
@Override
|
||||
protected void navigateFocusedComp( int direction ) {
|
||||
int count = toolBar.getComponentCount();
|
||||
|
||||
if( focusedCompIndex < 0 || focusedCompIndex >= count )
|
||||
return;
|
||||
|
||||
int add;
|
||||
switch( direction ) {
|
||||
case EAST: case SOUTH: add = 1; break;
|
||||
case WEST: case NORTH: add = -1; break;
|
||||
default: return;
|
||||
}
|
||||
|
||||
for( int i = focusedCompIndex + add; i != focusedCompIndex; i += add ) {
|
||||
if( i < 0 )
|
||||
i = count - 1;
|
||||
else if( i >= count )
|
||||
i = 0;
|
||||
|
||||
Component c = toolBar.getComponentAtIndex( i );
|
||||
if( canBeFocusOwner( c ) ) {
|
||||
c.requestFocus();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean canBeFocusOwner( Component c ) {
|
||||
// see Component.canBeFocusOwner()
|
||||
if( c == null || !c.isEnabled() || !c.isVisible() || !c.isDisplayable() || !c.isFocusable() )
|
||||
return false;
|
||||
|
||||
// special handling for combo box
|
||||
// see LayoutFocusTraversalPolicy.accept()
|
||||
if( c instanceof JComboBox ) {
|
||||
JComboBox<?> comboBox = (JComboBox<?>) c;
|
||||
return comboBox.getUI().isFocusTraversable( comboBox );
|
||||
}
|
||||
|
||||
// check whether component has a empty input map to skip components that
|
||||
// are focusable, but do nothing when focused (e.g. JLabel)
|
||||
// see LayoutFocusTraversalPolicy.accept()
|
||||
if( c instanceof JComponent ) {
|
||||
InputMap inputMap = ((JComponent)c).getInputMap( JComponent.WHEN_FOCUSED );
|
||||
while( inputMap != null && inputMap.size() == 0 )
|
||||
inputMap = inputMap.getParent();
|
||||
if( inputMap == null )
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// disable rollover border
|
||||
@Override protected void setBorderToRollover( Component c ) {}
|
||||
@Override protected void setBorderToNonRollover( Component c ) {}
|
||||
@@ -142,4 +318,81 @@ public class FlatToolBarUI
|
||||
|
||||
super.setOrientation( orientation );
|
||||
}
|
||||
|
||||
//---- class FlatToolBarFocusTraversalPolicy ------------------------------
|
||||
|
||||
/**
|
||||
* Focus traversal policy used for toolbar to modify traversal behaviour:
|
||||
* <ul>
|
||||
* <li>Tab-key moves focus out of toolbar.</li>
|
||||
* <li>If moving focus into the toolbar, focus recently focused toolbar button.</li>
|
||||
* </ul>
|
||||
* If the toolbar contains non-button components (e.g. combobox), then the behavior
|
||||
* is slightly different. Non-button component are always included in Tab-key traversal.
|
||||
*
|
||||
* @since 2
|
||||
*/
|
||||
protected class FlatToolBarFocusTraversalPolicy
|
||||
extends LayoutFocusTraversalPolicy
|
||||
{
|
||||
@Override
|
||||
public Component getComponentAfter( Container aContainer, Component aComponent ) {
|
||||
// if currently focused component is not a button,
|
||||
// then move focus to next component/button in toolbar
|
||||
if( !(aComponent instanceof AbstractButton) )
|
||||
return super.getComponentAfter( aContainer, aComponent );
|
||||
|
||||
// if currently focused component is a button,
|
||||
// then either move focus to next non-button component in toolbar (and skip buttons)
|
||||
// or move it out of toolbar
|
||||
Component c = aComponent;
|
||||
while( (c = super.getComponentAfter( aContainer, c )) != null ) {
|
||||
if( !(c instanceof AbstractButton) )
|
||||
return c;
|
||||
}
|
||||
|
||||
// move focus out of toolbar
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getComponentBefore( Container aContainer, Component aComponent ) {
|
||||
// if currently focused component is not a button,
|
||||
// then move focus to previous component/button in toolbar
|
||||
if( !(aComponent instanceof AbstractButton) )
|
||||
return super.getComponentBefore( aContainer, aComponent );
|
||||
|
||||
// if currently focused component is a button,
|
||||
// then either move focus to previous non-button component in toolbar (and skip buttons)
|
||||
// or move it out of toolbar
|
||||
Component c = aComponent;
|
||||
while( (c = super.getComponentBefore( aContainer, c )) != null ) {
|
||||
if( !(c instanceof AbstractButton) )
|
||||
return c;
|
||||
}
|
||||
|
||||
// move focus out of toolbar
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getFirstComponent( Container aContainer ) {
|
||||
return getRecentComponent( aContainer, true );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getLastComponent( Container aContainer ) {
|
||||
return getRecentComponent( aContainer, false );
|
||||
}
|
||||
|
||||
private Component getRecentComponent( Container aContainer, boolean first ) {
|
||||
// if moving focus into the toolbar, focus recently focused toolbar button
|
||||
if( focusedCompIndex >= 0 && focusedCompIndex < toolBar.getComponentCount() )
|
||||
return toolBar.getComponent( focusedCompIndex );
|
||||
|
||||
return first
|
||||
? super.getFirstComponent( aContainer )
|
||||
: super.getLastComponent( aContainer );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import java.awt.Rectangle;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Map;
|
||||
import javax.swing.CellRendererPane;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComponent;
|
||||
@@ -39,6 +40,9 @@ import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicTreeUI;
|
||||
import javax.swing.tree.DefaultTreeCellRenderer;
|
||||
import javax.swing.tree.TreePath;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
@@ -94,25 +98,71 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault Tree.wideSelection boolean
|
||||
* @uiDefault Tree.showCellFocusIndicator boolean
|
||||
*
|
||||
* <!-- FlatTreeExpandedIcon -->
|
||||
*
|
||||
* @uiDefault Component.arrowType String chevron (default) or triangle
|
||||
* @uiDefault Tree.icon.expandedColor Color
|
||||
*
|
||||
* <!-- FlatTreeCollapsedIcon -->
|
||||
*
|
||||
* @uiDefault Component.arrowType String chevron (default) or triangle
|
||||
* @uiDefault Tree.icon.collapsedColor Color
|
||||
*
|
||||
* <!-- FlatTreeLeafIcon -->
|
||||
*
|
||||
* @uiDefault Tree.icon.leafColor Color
|
||||
*
|
||||
* <!-- FlatTreeClosedIcon -->
|
||||
*
|
||||
* @uiDefault Tree.icon.closedColor Color
|
||||
*
|
||||
* <!-- FlatTreeOpenIcon -->
|
||||
*
|
||||
* @uiDefault Tree.icon.openColor Color
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatTreeUI
|
||||
extends BasicTreeUI
|
||||
implements StyleableUI
|
||||
{
|
||||
protected Color selectionBackground;
|
||||
protected Color selectionForeground;
|
||||
protected Color selectionInactiveBackground;
|
||||
protected Color selectionInactiveForeground;
|
||||
protected Color selectionBorderColor;
|
||||
protected boolean wideSelection;
|
||||
protected boolean showCellFocusIndicator;
|
||||
@Styleable protected Color selectionBackground;
|
||||
@Styleable protected Color selectionForeground;
|
||||
@Styleable protected Color selectionInactiveBackground;
|
||||
@Styleable protected Color selectionInactiveForeground;
|
||||
@Styleable protected Color selectionBorderColor;
|
||||
@Styleable protected boolean wideSelection;
|
||||
@Styleable protected boolean showCellFocusIndicator;
|
||||
|
||||
// for icons
|
||||
// (needs to be public because icon classes are in another package)
|
||||
@Styleable(dot=true) public String iconArrowType;
|
||||
@Styleable(dot=true) public Color iconExpandedColor;
|
||||
@Styleable(dot=true) public Color iconCollapsedColor;
|
||||
@Styleable(dot=true) public Color iconLeafColor;
|
||||
@Styleable(dot=true) public Color iconClosedColor;
|
||||
@Styleable(dot=true) public Color iconOpenColor;
|
||||
|
||||
// only used via styling (not in UI defaults, but has likewise client properties)
|
||||
/** @since 2 */ @Styleable protected boolean paintSelection = true;
|
||||
|
||||
private Color defaultCellNonSelectionBackground;
|
||||
private Color defaultSelectionBackground;
|
||||
private Color defaultSelectionForeground;
|
||||
private Color defaultSelectionBorderColor;
|
||||
private Map<String, Object> oldStyleValues;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatTreeUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
installStyle();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
@@ -128,6 +178,9 @@ public class FlatTreeUI
|
||||
showCellFocusIndicator = UIManager.getBoolean( "Tree.showCellFocusIndicator" );
|
||||
|
||||
defaultCellNonSelectionBackground = UIManager.getColor( "Tree.textBackground" );
|
||||
defaultSelectionBackground = selectionBackground;
|
||||
defaultSelectionForeground = selectionForeground;
|
||||
defaultSelectionBorderColor = selectionBorderColor;
|
||||
|
||||
// scale
|
||||
int rowHeight = FlatUIUtils.getUIInt( "Tree.rowHeight", 16 );
|
||||
@@ -150,6 +203,10 @@ public class FlatTreeUI
|
||||
selectionBorderColor = null;
|
||||
|
||||
defaultCellNonSelectionBackground = null;
|
||||
defaultSelectionBackground = null;
|
||||
defaultSelectionForeground = null;
|
||||
defaultSelectionBorderColor = null;
|
||||
oldStyleValues = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -216,6 +273,13 @@ public class FlatTreeUI
|
||||
repaintWideDropLocation( tree.getDropLocation() );
|
||||
}
|
||||
break;
|
||||
|
||||
case STYLE:
|
||||
case STYLE_CLASS:
|
||||
installStyle();
|
||||
tree.revalidate();
|
||||
tree.repaint();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -250,6 +314,31 @@ public class FlatTreeUI
|
||||
return bounds;
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void installStyle() {
|
||||
try {
|
||||
applyStyle( FlatStylingSupport.getResolvedStyle( tree, "Tree" ) );
|
||||
} catch( RuntimeException ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected void applyStyle( Object style ) {
|
||||
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
protected Object applyStyleProperty( String key, Object value ) {
|
||||
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, tree, key, value );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as super.paintRow(), but supports wide selection and uses
|
||||
* inactive selection background/foreground if tree is not focused.
|
||||
@@ -263,9 +352,19 @@ public class FlatTreeUI
|
||||
boolean isDropRow = isDropRow( row );
|
||||
boolean needsSelectionPainting = (isSelected || isDropRow) && isPaintSelection();
|
||||
|
||||
// do not paint row if editing, except if selection needs painted
|
||||
if( isEditing && !needsSelectionPainting )
|
||||
// do not paint row if editing
|
||||
if( isEditing ) {
|
||||
// paint wide selection
|
||||
// (do not access cell renderer here to avoid side effect
|
||||
// if renderer component is also used as editor component)
|
||||
if( isSelected && isWideSelection() ) {
|
||||
Color oldColor = g.getColor();
|
||||
g.setColor( selectionInactiveBackground );
|
||||
paintWideSelection( g, clipBounds, insets, bounds, path, row, isExpanded, hasBeenExpanded, isLeaf );
|
||||
g.setColor( oldColor );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
boolean hasFocus = FlatUIUtils.isPermanentFocusOwner( tree );
|
||||
boolean cellHasFocus = hasFocus && (row == getLeadSelectionRow());
|
||||
@@ -279,35 +378,32 @@ public class FlatTreeUI
|
||||
Component rendererComponent = currentCellRenderer.getTreeCellRendererComponent( tree,
|
||||
path.getLastPathComponent(), isSelected, isExpanded, isLeaf, row, cellHasFocus );
|
||||
|
||||
// apply inactive selection background/foreground if tree is not focused
|
||||
// renderer background/foreground
|
||||
Color oldBackgroundSelectionColor = null;
|
||||
if( isSelected && !hasFocus && !isDropRow ) {
|
||||
if( rendererComponent instanceof DefaultTreeCellRenderer ) {
|
||||
DefaultTreeCellRenderer renderer = (DefaultTreeCellRenderer) rendererComponent;
|
||||
if( renderer.getBackgroundSelectionColor() == selectionBackground ) {
|
||||
oldBackgroundSelectionColor = renderer.getBackgroundSelectionColor();
|
||||
renderer.setBackgroundSelectionColor( selectionInactiveBackground );
|
||||
}
|
||||
} else {
|
||||
if( rendererComponent.getBackground() == selectionBackground )
|
||||
rendererComponent.setBackground( selectionInactiveBackground );
|
||||
}
|
||||
// apply inactive selection background/foreground if tree is not focused
|
||||
oldBackgroundSelectionColor = setRendererBackgroundSelectionColor( rendererComponent, selectionInactiveBackground );
|
||||
setRendererForeground( rendererComponent, selectionInactiveForeground );
|
||||
|
||||
if( rendererComponent.getForeground() == selectionForeground )
|
||||
rendererComponent.setForeground( selectionInactiveForeground );
|
||||
} else if( isSelected ) {
|
||||
// update background/foreground if set via style
|
||||
if( selectionBackground != defaultSelectionBackground )
|
||||
oldBackgroundSelectionColor = setRendererBackgroundSelectionColor( rendererComponent, selectionBackground );
|
||||
if( selectionForeground != defaultSelectionForeground )
|
||||
setRendererForeground( rendererComponent, selectionForeground );
|
||||
}
|
||||
|
||||
// remove focus selection border if exactly one item is selected
|
||||
// update focus selection border
|
||||
Color oldBorderSelectionColor = null;
|
||||
if( isSelected && hasFocus &&
|
||||
(!showCellFocusIndicator || tree.getMinSelectionRow() == tree.getMaxSelectionRow()) &&
|
||||
rendererComponent instanceof DefaultTreeCellRenderer )
|
||||
(!showCellFocusIndicator || tree.getMinSelectionRow() == tree.getMaxSelectionRow()) )
|
||||
{
|
||||
DefaultTreeCellRenderer renderer = (DefaultTreeCellRenderer) rendererComponent;
|
||||
if( renderer.getBorderSelectionColor() == selectionBorderColor ) {
|
||||
oldBorderSelectionColor = renderer.getBorderSelectionColor();
|
||||
renderer.setBorderSelectionColor( null );
|
||||
}
|
||||
// remove focus selection border if exactly one item is selected or if showCellFocusIndicator is false
|
||||
oldBorderSelectionColor = setRendererBorderSelectionColor( rendererComponent, null );
|
||||
|
||||
} else if( hasFocus && selectionBorderColor != defaultSelectionBorderColor ) {
|
||||
// update focus selection border if set via style
|
||||
oldBorderSelectionColor = setRendererBorderSelectionColor( rendererComponent, selectionBorderColor );
|
||||
}
|
||||
|
||||
// paint selection background
|
||||
@@ -322,14 +418,7 @@ public class FlatTreeUI
|
||||
|
||||
if( isWideSelection() ) {
|
||||
// wide selection
|
||||
g.fillRect( 0, bounds.y, tree.getWidth(), bounds.height );
|
||||
|
||||
// paint expand/collapse icon
|
||||
// (was already painted before, but painted over with wide selection)
|
||||
if( shouldPaintExpandControl( path, row, isExpanded, hasBeenExpanded, isLeaf ) ) {
|
||||
paintExpandControl( g, clipBounds, insets, bounds,
|
||||
path, row, isExpanded, hasBeenExpanded, isLeaf );
|
||||
}
|
||||
paintWideSelection( g, clipBounds, insets, bounds, path, row, isExpanded, hasBeenExpanded, isLeaf );
|
||||
} else {
|
||||
// non-wide selection
|
||||
paintCellBackground( g, rendererComponent, bounds );
|
||||
@@ -353,8 +442,7 @@ public class FlatTreeUI
|
||||
}
|
||||
|
||||
// paint renderer
|
||||
if( !isEditing )
|
||||
rendererPane.paintComponent( g, rendererComponent, tree, bounds.x, bounds.y, bounds.width, bounds.height, true );
|
||||
rendererPane.paintComponent( g, rendererComponent, tree, bounds.x, bounds.y, bounds.width, bounds.height, true );
|
||||
|
||||
// restore background selection color and border selection color
|
||||
if( oldBackgroundSelectionColor != null )
|
||||
@@ -363,6 +451,55 @@ public class FlatTreeUI
|
||||
((DefaultTreeCellRenderer)rendererComponent).setBorderSelectionColor( oldBorderSelectionColor );
|
||||
}
|
||||
|
||||
private Color setRendererBackgroundSelectionColor( Component rendererComponent, Color color ) {
|
||||
Color oldColor = null;
|
||||
|
||||
if( rendererComponent instanceof DefaultTreeCellRenderer ) {
|
||||
DefaultTreeCellRenderer renderer = (DefaultTreeCellRenderer) rendererComponent;
|
||||
if( renderer.getBackgroundSelectionColor() == defaultSelectionBackground ) {
|
||||
oldColor = renderer.getBackgroundSelectionColor();
|
||||
renderer.setBackgroundSelectionColor( color );
|
||||
}
|
||||
} else {
|
||||
if( rendererComponent.getBackground() == defaultSelectionBackground )
|
||||
rendererComponent.setBackground( color );
|
||||
}
|
||||
|
||||
return oldColor;
|
||||
}
|
||||
|
||||
private void setRendererForeground( Component rendererComponent, Color color ) {
|
||||
if( rendererComponent.getForeground() == defaultSelectionForeground )
|
||||
rendererComponent.setForeground( color );
|
||||
}
|
||||
|
||||
private Color setRendererBorderSelectionColor( Component rendererComponent, Color color ) {
|
||||
Color oldColor = null;
|
||||
|
||||
if( rendererComponent instanceof DefaultTreeCellRenderer ) {
|
||||
DefaultTreeCellRenderer renderer = (DefaultTreeCellRenderer) rendererComponent;
|
||||
if( renderer.getBorderSelectionColor() == defaultSelectionBorderColor ) {
|
||||
oldColor = renderer.getBorderSelectionColor();
|
||||
renderer.setBorderSelectionColor( color );
|
||||
}
|
||||
}
|
||||
|
||||
return oldColor;
|
||||
}
|
||||
|
||||
private void paintWideSelection( Graphics g, Rectangle clipBounds, Insets insets, Rectangle bounds,
|
||||
TreePath path, int row, boolean isExpanded, boolean hasBeenExpanded, boolean isLeaf )
|
||||
{
|
||||
g.fillRect( 0, bounds.y, tree.getWidth(), bounds.height );
|
||||
|
||||
// paint expand/collapse icon
|
||||
// (was already painted before, but painted over with wide selection)
|
||||
if( shouldPaintExpandControl( path, row, isExpanded, hasBeenExpanded, isLeaf ) ) {
|
||||
paintExpandControl( g, clipBounds, insets, bounds,
|
||||
path, row, isExpanded, hasBeenExpanded, isLeaf );
|
||||
}
|
||||
}
|
||||
|
||||
private void paintCellBackground( Graphics g, Component rendererComponent, Rectangle bounds ) {
|
||||
int xOffset = 0;
|
||||
int imageOffset = 0;
|
||||
@@ -401,6 +538,6 @@ public class FlatTreeUI
|
||||
}
|
||||
|
||||
protected boolean isPaintSelection() {
|
||||
return clientPropertyBoolean( tree, TREE_PAINT_SELECTION, true );
|
||||
return clientPropertyBoolean( tree, TREE_PAINT_SELECTION, paintSelection );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import java.awt.GraphicsConfiguration;
|
||||
import java.awt.GraphicsDevice;
|
||||
import java.awt.Insets;
|
||||
import java.awt.KeyboardFocusManager;
|
||||
import java.awt.Paint;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.Shape;
|
||||
@@ -129,9 +130,7 @@ public class FlatUIUtils
|
||||
return (color != null) ? color : UIManager.getColor( defaultKey );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.1
|
||||
*/
|
||||
/** @since 1.1 */
|
||||
public static boolean getUIBoolean( String key, boolean defaultValue ) {
|
||||
Object value = UIManager.get( key );
|
||||
return (value instanceof Boolean) ? (Boolean) value : defaultValue;
|
||||
@@ -147,9 +146,20 @@ public class FlatUIUtils
|
||||
return (value instanceof Number) ? ((Number)value).floatValue() : defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.1.2
|
||||
*/
|
||||
/** @since 2 */
|
||||
public static <T extends Enum<T>> T getUIEnum( String key, Class<T> enumType, T defaultValue ) {
|
||||
Object value = UIManager.get( key );
|
||||
if( value instanceof String ) {
|
||||
try {
|
||||
return Enum.valueOf( enumType, (String) value );
|
||||
} catch( IllegalArgumentException ex ) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/** @since 1.1.2 */
|
||||
public static boolean getBoolean( JComponent c, String systemPropertyKey,
|
||||
String clientPropertyKey, String uiKey, boolean defaultValue )
|
||||
{
|
||||
@@ -351,104 +361,6 @@ public class FlatUIUtils
|
||||
: color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Paints an outer border, which is usually a focus border.
|
||||
* <p>
|
||||
* The outside bounds of the painted border are {@code x,y,width,height}.
|
||||
* The line thickness of the painted border is {@code focusWidth + lineWidth}.
|
||||
* The given arc diameter refers to the inner rectangle ({@code x,y,width,height} minus {@code focusWidth}).
|
||||
*
|
||||
* @see #paintComponentBorder
|
||||
* @see #paintComponentBackground
|
||||
*/
|
||||
public static void paintComponentOuterBorder( Graphics2D g, int x, int y, int width, int height,
|
||||
float focusWidth, float lineWidth, float arc )
|
||||
{
|
||||
if( focusWidth + lineWidth == 0 )
|
||||
return; // nothing to paint
|
||||
|
||||
double systemScaleFactor = UIScale.getSystemScaleFactor( g );
|
||||
if( systemScaleFactor != 1 && systemScaleFactor != 2 ) {
|
||||
// paint at scale 1x to avoid clipping on right and bottom edges at 125%, 150% or 175%
|
||||
HiDPIUtils.paintAtScale1x( g, x, y, width, height,
|
||||
(g2d, x2, y2, width2, height2, scaleFactor) -> {
|
||||
paintComponentOuterBorderImpl( g2d, x2, y2, width2, height2,
|
||||
(float) (focusWidth * scaleFactor), (float) (lineWidth * scaleFactor), (float) (arc * scaleFactor) );
|
||||
} );
|
||||
return;
|
||||
}
|
||||
|
||||
paintComponentOuterBorderImpl( g, x, y, width, height, focusWidth, lineWidth, arc );
|
||||
}
|
||||
|
||||
private static void paintComponentOuterBorderImpl( Graphics2D g, int x, int y, int width, int height,
|
||||
float focusWidth, float lineWidth, float arc )
|
||||
{
|
||||
float ow = focusWidth + lineWidth;
|
||||
float outerArc = arc + (focusWidth * 2);
|
||||
float innerArc = arc - (lineWidth * 2);
|
||||
|
||||
// reduce outer arc slightly for small arcs to make the curve slightly wider
|
||||
if( focusWidth > 0 && arc > 0 && arc < UIScale.scale( 10 ) )
|
||||
outerArc -= UIScale.scale( 2f );
|
||||
|
||||
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
||||
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 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the border of a component as round rectangle.
|
||||
* <p>
|
||||
* The outside bounds of the painted border are
|
||||
* {@code x + focusWidth, y + focusWidth, width - (focusWidth * 2), height - (focusWidth * 2)}.
|
||||
* The line thickness of the painted border is {@code lineWidth}.
|
||||
* The given arc diameter refers to the painted rectangle (and not to {@code x,y,width,height}).
|
||||
*
|
||||
* @see #paintComponentOuterBorder
|
||||
* @see #paintComponentBackground
|
||||
*/
|
||||
public static void paintComponentBorder( Graphics2D g, int x, int y, int width, int height,
|
||||
float focusWidth, float lineWidth, float arc )
|
||||
{
|
||||
if( lineWidth == 0 )
|
||||
return; // nothing to paint
|
||||
|
||||
double systemScaleFactor = UIScale.getSystemScaleFactor( g );
|
||||
if( systemScaleFactor != 1 && systemScaleFactor != 2 ) {
|
||||
// paint at scale 1x to avoid clipping on right and bottom edges at 125%, 150% or 175%
|
||||
HiDPIUtils.paintAtScale1x( g, x, y, width, height,
|
||||
(g2d, x2, y2, width2, height2, scaleFactor) -> {
|
||||
paintComponentBorderImpl( g2d, x2, y2, width2, height2,
|
||||
(float) (focusWidth * scaleFactor), (float) (lineWidth * scaleFactor), (float) (arc * scaleFactor) );
|
||||
} );
|
||||
return;
|
||||
}
|
||||
|
||||
paintComponentBorderImpl( g, x, y, width, height, focusWidth, lineWidth, arc );
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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 );
|
||||
border.append( r2, false );
|
||||
g.fill( border );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the background of a component with a round rectangle.
|
||||
* <p>
|
||||
@@ -456,32 +368,203 @@ public class FlatUIUtils
|
||||
* {@code x + focusWidth, y + focusWidth, width - (focusWidth * 2), height - (focusWidth * 2)}.
|
||||
* The given arc diameter refers to the painted rectangle (and not to {@code x,y,width,height}).
|
||||
*
|
||||
* @see #paintComponentOuterBorder
|
||||
* @see #paintComponentBorder
|
||||
* @see #paintOutlinedComponent
|
||||
*/
|
||||
public static void paintComponentBackground( Graphics2D g, int x, int y, int width, int height,
|
||||
float focusWidth, float arc )
|
||||
{
|
||||
paintOutlinedComponent( g, x, y, width, height, focusWidth, 0, 0, 0, arc, null, null, g.getPaint() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Paints an outlined component with rounded corners, consisting of following parts:
|
||||
* <ul>
|
||||
* <li>an (optional) outer border, which is usually a focus indicator
|
||||
* <li>an (optional) component border
|
||||
* <li>the (optional) component background
|
||||
* </ul>
|
||||
* <p>
|
||||
*
|
||||
* Each part is painted only if the corresponding part color is not {@code null}.
|
||||
* The parts are painted in this order:
|
||||
* <ol>
|
||||
* <li>background
|
||||
* <li>focus border
|
||||
* <li>border
|
||||
* </ol>
|
||||
* <p>
|
||||
*
|
||||
* <strong>Background</strong>:
|
||||
* The bounds of the filled round rectangle are
|
||||
* {@code [x + focusWidth, y + focusWidth, width - (focusWidth * 2), height - (focusWidth * 2)]}.
|
||||
* The focus border and the border may paint over the background.
|
||||
* <p>
|
||||
*
|
||||
* <strong>Focus border</strong>:
|
||||
* The outside bounds of the painted focus border are {@code [x, y, width, height]}.
|
||||
* The thickness of the painted focus border is {@code (focusWidth * focusWidthFraction) + focusInnerWidth}.
|
||||
* The border may paint over the focus border if {@code focusInnerWidth > 0}.
|
||||
* <p>
|
||||
*
|
||||
* <strong>Border</strong>:
|
||||
* The outside bounds of the painted border are
|
||||
* {@code [x + focusWidth, y + focusWidth, width - (focusWidth * 2), height - (focusWidth * 2)]}.
|
||||
* The thickness of the painted border is {@code borderWidth}.
|
||||
*
|
||||
* @param g the graphics context used for painting
|
||||
* @param x the x coordinate of the component
|
||||
* @param y the y coordinate of the component
|
||||
* @param width the width of the component
|
||||
* @param height the height of the component
|
||||
* @param focusWidth the width of the focus border, or {@code 0}
|
||||
* @param focusWidthFraction specified how much of the focus border is painted (in range 0 - 1);
|
||||
* can be used for animation;
|
||||
* the painted thickness of the focus border is {@code (focusWidth * focusWidthFraction) + focusInnerWidth}
|
||||
* @param focusInnerWidth the inner width of the focus border, or {@code 0};
|
||||
* if a border is painted then {@code focusInnerWidth} needs to be larger
|
||||
* than {@code borderWidth} to be not hidden by the border
|
||||
* @param borderWidth the width of the border, or {@code 0}
|
||||
* @param arc the arc diameter used for the outside shape of the component border;
|
||||
* the other needed arc diameters are computed from this arc diameter
|
||||
* @param focusColor the color of the focus border, or {@code null}
|
||||
* @param borderColor the color of the border, or {@code null}
|
||||
* @param background the background color of the component, or {@code null}
|
||||
*
|
||||
* @since 2
|
||||
*/
|
||||
public static void paintOutlinedComponent( Graphics2D g, int x, int y, int width, int height,
|
||||
float focusWidth, float focusWidthFraction, float focusInnerWidth, float borderWidth, float arc,
|
||||
Paint focusColor, Paint borderColor, Paint background )
|
||||
{
|
||||
double systemScaleFactor = UIScale.getSystemScaleFactor( g );
|
||||
if( systemScaleFactor != 1 && systemScaleFactor != 2 ) {
|
||||
// paint at scale 1x to avoid clipping on right and bottom edges at 125%, 150% or 175%
|
||||
HiDPIUtils.paintAtScale1x( g, x, y, width, height,
|
||||
(g2d, x2, y2, width2, height2, scaleFactor) -> {
|
||||
paintComponentBackgroundImpl( g2d, x2, y2, width2, height2,
|
||||
(float) (focusWidth * scaleFactor), (float) (arc * scaleFactor) );
|
||||
paintOutlinedComponentImpl( g2d, x2, y2, width2, height2,
|
||||
(float) (focusWidth * scaleFactor), focusWidthFraction, (float) (focusInnerWidth * scaleFactor),
|
||||
(float) (borderWidth * scaleFactor), (float) (arc * scaleFactor),
|
||||
focusColor, borderColor, background );
|
||||
} );
|
||||
return;
|
||||
}
|
||||
|
||||
paintComponentBackgroundImpl( g, x, y, width, height, focusWidth, arc );
|
||||
paintOutlinedComponentImpl( g, x, y, width, height, focusWidth, focusWidthFraction, focusInnerWidth,
|
||||
borderWidth, arc, focusColor, borderColor, background );
|
||||
}
|
||||
|
||||
private static void paintComponentBackgroundImpl( Graphics2D g, int x, int y, int width, int height,
|
||||
float focusWidth, float arc )
|
||||
private static void paintOutlinedComponentImpl( Graphics2D g, int x, int y, int width, int height,
|
||||
float focusWidth, float focusWidthFraction, float focusInnerWidth, float borderWidth, float arc,
|
||||
Paint focusColor, Paint borderColor, Paint background )
|
||||
{
|
||||
g.fill( createComponentRectangle(
|
||||
x + focusWidth, y + focusWidth,
|
||||
width - focusWidth * 2, height - focusWidth * 2, arc ) );
|
||||
// outside bounds of the border and the background
|
||||
float x1 = x + focusWidth;
|
||||
float y1 = y + focusWidth;
|
||||
float w1 = width - focusWidth * 2;
|
||||
float h1 = height - focusWidth * 2;
|
||||
|
||||
// fill background
|
||||
// bounds: x + focusWidth, y + focusWidth, width - (focusWidth * 2), height - (focusWidth * 2)
|
||||
// arc diameter: arc
|
||||
if( background != null ) {
|
||||
g.setPaint( background );
|
||||
g.fill( createComponentRectangle( x1, y1, w1, h1, arc ) );
|
||||
}
|
||||
|
||||
// optimization: paint focus border and border in single operation if colors are equal
|
||||
if( borderColor != null && borderColor.equals( focusColor ) ) {
|
||||
borderColor = null;
|
||||
focusInnerWidth = Math.max( focusInnerWidth, borderWidth );
|
||||
}
|
||||
|
||||
// paint focus border
|
||||
// outer bounds: x, y, width, height
|
||||
// thickness: focusWidth + focusInnerWidth
|
||||
// outer arc diameter: arc + (focusWidth * 2)
|
||||
// inner arc diameter: arc - (focusInnerWidth * 2)
|
||||
float paintedFocusWidth = (focusWidth * focusWidthFraction) + focusInnerWidth;
|
||||
if( focusColor != null && paintedFocusWidth != 0 ) {
|
||||
// outside bounds of the focus border
|
||||
float inset = focusWidth - (focusWidth * focusWidthFraction);
|
||||
float x2 = x + inset;
|
||||
float y2 = y + inset;
|
||||
float w2 = width - (inset * 2);
|
||||
float h2 = height - (inset * 2);
|
||||
|
||||
float outerArc = arc + (focusWidth * 2);
|
||||
float innerArc = arc - (focusInnerWidth * 2);
|
||||
|
||||
// reduce outer arc slightly for small arcs to make the curve slightly wider
|
||||
if( focusWidth > 0 && arc > 0 && arc < UIScale.scale( 10 ) )
|
||||
outerArc -= UIScale.scale( 2f );
|
||||
|
||||
// consider focus width fraction
|
||||
if( focusWidthFraction != 1 )
|
||||
outerArc = arc + ((outerArc - arc) * focusWidthFraction);
|
||||
|
||||
g.setPaint( focusColor );
|
||||
paintOutline( g, x2, y2, w2, h2, paintedFocusWidth, outerArc, innerArc );
|
||||
}
|
||||
|
||||
// paint border
|
||||
// outer bounds: x + focusWidth, y + focusWidth, width - (focusWidth * 2), height - (focusWidth * 2)
|
||||
// thickness: borderWidth
|
||||
// outer arc diameter: arc
|
||||
// inner arc diameter: arc - (borderWidth * 2)
|
||||
if( borderColor != null && borderWidth != 0 ) {
|
||||
g.setPaint( borderColor );
|
||||
paintOutline( g, x1, y1, w1, h1, borderWidth, arc );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Paints an outline at the given bounds using the given line width.
|
||||
* Depending on the given arc, a rectangle, rounded rectangle or circle (if w == h) is painted.
|
||||
*
|
||||
* @param g the graphics context used for painting
|
||||
* @param x the x coordinate of the outline
|
||||
* @param y the y coordinate of the outline
|
||||
* @param w the width of the outline
|
||||
* @param h the height of the outline
|
||||
* @param lineWidth the width of the outline
|
||||
* @param arc the arc diameter used for the outside shape of the outline
|
||||
*
|
||||
* @since 2
|
||||
*/
|
||||
public static void paintOutline( Graphics2D g, float x, float y, float w, float h,
|
||||
float lineWidth, float arc )
|
||||
{
|
||||
paintOutline( g, x, y, w, h, lineWidth, arc, arc - (lineWidth * 2) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Paints an outline at the given bounds using the given line width.
|
||||
* Depending on the given arc, a rectangle, rounded rectangle or circle (if w == h) is painted.
|
||||
*
|
||||
* @param g the graphics context used for painting
|
||||
* @param x the x coordinate of the outline
|
||||
* @param y the y coordinate of the outline
|
||||
* @param w the width of the outline
|
||||
* @param h the height of the outline
|
||||
* @param lineWidth the width of the outline
|
||||
* @param arc the arc diameter used for the outside shape of the outline
|
||||
* @param innerArc the arc diameter used for the inside shape of the outline
|
||||
*
|
||||
* @since 2
|
||||
*/
|
||||
public static void paintOutline( Graphics2D g, float x, float y, float w, float h,
|
||||
float lineWidth, float arc, float innerArc )
|
||||
{
|
||||
if( lineWidth == 0 || w <= 0 || h <= 0 )
|
||||
return;
|
||||
|
||||
float t = lineWidth;
|
||||
float t2x = t * 2;
|
||||
|
||||
Path2D border = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
||||
border.append( createComponentRectangle( x, y, w, h, arc ), false );
|
||||
border.append( createComponentRectangle( x + t, y + t, w - t2x, h - t2x, innerArc ), false );
|
||||
g.fill( border );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -492,6 +575,9 @@ public class FlatUIUtils
|
||||
if( arc <= 0 )
|
||||
return new Rectangle2D.Float( x, y, w, h );
|
||||
|
||||
if( w == h && arc >= w )
|
||||
return new Ellipse2D.Float( x, y, w, h );
|
||||
|
||||
arc = Math.min( arc, Math.min( w, h ) );
|
||||
return new RoundRectangle2D.Float( x, y, w, h, arc, arc );
|
||||
}
|
||||
@@ -863,6 +949,14 @@ debug*/
|
||||
.computeIfAbsent( key, k -> newInstanceSupplier.get() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the component UI for the given component can be shared
|
||||
* with other components. This is only possible if it does not have styles.
|
||||
*/
|
||||
public static boolean canUseSharedUI( JComponent c ) {
|
||||
return !FlatStylingSupport.hasStyleProperty( c );
|
||||
}
|
||||
|
||||
//---- class RepaintFocusListener -----------------------------------------
|
||||
|
||||
public static class RepaintFocusListener
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.awt.Insets;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.function.Function;
|
||||
import javax.swing.JComponent;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
|
||||
/**
|
||||
* Support for MigLayout visual paddings.
|
||||
@@ -80,7 +81,7 @@ public class MigLayoutVisualPadding
|
||||
return new Insets( focusWidth, focusWidth, focusWidth, focusWidth );
|
||||
} else
|
||||
return null;
|
||||
}, "border" );
|
||||
}, "border", FlatClientProperties.STYLE, FlatClientProperties.STYLE_CLASS );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -99,7 +100,7 @@ public class MigLayoutVisualPadding
|
||||
c.addPropertyChangeListener( (FlatMigListener) e -> {
|
||||
String propertyName = e.getPropertyName();
|
||||
for( String name : propertyNames ) {
|
||||
if( name == propertyName ) {
|
||||
if( name.equals( propertyName ) ) {
|
||||
setVisualPadding( c, getPaddingFunction.apply( c ) );
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -25,30 +25,91 @@ import java.awt.Color;
|
||||
*/
|
||||
public class ColorFunctions
|
||||
{
|
||||
public static Color applyFunctions( Color color, ColorFunction... functions ) {
|
||||
/**
|
||||
* Increase the lightness of a color in HSL color space by an absolute amount.
|
||||
* <p>
|
||||
* Consider using {@link #tint(Color, float)} as alternative.
|
||||
*
|
||||
* @param color base color
|
||||
* @param amount the amount (in range 0-1) that is added to the lightness
|
||||
* @return new color
|
||||
* @since 2
|
||||
*/
|
||||
public static Color lighten( Color color, float amount ) {
|
||||
return hslIncreaseDecrease( color, amount, 2, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrease the lightness of a color in HSL color space by an absolute amount.
|
||||
* <p>
|
||||
* Consider using {@link #shade(Color, float)} as alternative.
|
||||
*
|
||||
* @param color base color
|
||||
* @param amount the amount (in range 0-1) that is subtracted from the lightness
|
||||
* @return new color
|
||||
* @since 2
|
||||
*/
|
||||
public static Color darken( Color color, float amount ) {
|
||||
return hslIncreaseDecrease( color, amount, 2, false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Increase the saturation of a color in HSL color space by an absolute amount.
|
||||
*
|
||||
* @param color base color
|
||||
* @param amount the amount (in range 0-1) that is added to the saturation
|
||||
* @return new color
|
||||
* @since 2
|
||||
*/
|
||||
public static Color saturate( Color color, float amount ) {
|
||||
return hslIncreaseDecrease( color, amount, 1, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrease the saturation of a color in HSL color space by an absolute amount.
|
||||
*
|
||||
* @param color base color
|
||||
* @param amount the amount (in range 0-1) that is subtracted from the saturation
|
||||
* @return new color
|
||||
* @since 2
|
||||
*/
|
||||
public static Color desaturate( Color color, float amount ) {
|
||||
return hslIncreaseDecrease( color, amount, 1, false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate the hue angle (0-360) of a color in HSL color space in either direction.
|
||||
*
|
||||
* @param color base color
|
||||
* @param angle the number of degrees to rotate (in range -360 - 360)
|
||||
* @return new color
|
||||
* @since 2
|
||||
*/
|
||||
public static Color spin( Color color, float angle ) {
|
||||
return hslIncreaseDecrease( color, angle, 0, true );
|
||||
}
|
||||
|
||||
private static Color hslIncreaseDecrease( Color color, float amount, int hslIndex, boolean increase ) {
|
||||
// convert RGB to HSL
|
||||
float[] hsl = HSLColor.fromRGB( color );
|
||||
float alpha = color.getAlpha() / 255f;
|
||||
float[] hsla = { hsl[0], hsl[1], hsl[2], alpha * 100 };
|
||||
|
||||
// apply color functions
|
||||
for( ColorFunction function : functions )
|
||||
function.apply( hsla );
|
||||
// apply HSL color change
|
||||
float amount2 = increase ? amount : -amount;
|
||||
if( hslIndex == 0 )
|
||||
hsl[0] = (hsl[0] + amount2) % 360;
|
||||
else
|
||||
hsl[hslIndex] = clamp( hsl[hslIndex] + (amount2 * 100) );
|
||||
|
||||
// convert HSL to RGB
|
||||
return HSLColor.toRGB( hsla[0], hsla[1], hsla[2], hsla[3] / 100 );
|
||||
}
|
||||
|
||||
public static float clamp( float value ) {
|
||||
return (value < 0)
|
||||
? 0
|
||||
: ((value > 100)
|
||||
? 100
|
||||
: value);
|
||||
return HSLColor.toRGB( hsl[0], hsl[1], hsl[2], alpha );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a color that is a mixture of two colors.
|
||||
* <p>
|
||||
* This can be used to animate a color change from {@code color1} to {@code color2}
|
||||
* by invoking this method multiple times with growing {@code weight} (from 0 to 1).
|
||||
*
|
||||
* @param color1 first color
|
||||
* @param color2 second color
|
||||
@@ -79,6 +140,95 @@ public class ColorFunctions
|
||||
Math.round( a2 + ((a1 - a2) * weight) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Mix color with white, which makes the color brighter.
|
||||
* This is the same as {@link #mix}{@code (Color.white, color, weight)}.
|
||||
*
|
||||
* @param color second color
|
||||
* @param weight the weight (in range 0-1) to mix the two colors.
|
||||
* Larger weight uses more of first color, smaller weight more of second color.
|
||||
* @return mixture of colors
|
||||
* @since 2
|
||||
*/
|
||||
public static Color tint( Color color, float weight ) {
|
||||
return mix( Color.white, color, weight );
|
||||
}
|
||||
|
||||
/**
|
||||
* Mix color with black, which makes the color darker.
|
||||
* This is the same as {@link #mix}{@code (Color.black, color, weight)}.
|
||||
*
|
||||
* @param color second color
|
||||
* @param weight the weight (in range 0-1) to mix the two colors.
|
||||
* Larger weight uses more of first color, smaller weight more of second color.
|
||||
* @return mixture of colors
|
||||
* @since 2
|
||||
*/
|
||||
public static Color shade( Color color, float weight ) {
|
||||
return mix( Color.black, color, weight );
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the luma (perceptual brightness) of the given color.
|
||||
* <p>
|
||||
* Uses SMPTE C / Rec. 709 coefficients, as recommended in
|
||||
* <a href="https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef">WCAG 2.0</a>.
|
||||
*
|
||||
* @param color a color
|
||||
* @return the luma (in range 0-1)
|
||||
*
|
||||
* @see <a href="https://en.wikipedia.org/wiki/Luma_(video)">https://en.wikipedia.org/wiki/Luma_(video)</a>
|
||||
* @since 2
|
||||
*/
|
||||
public static float luma( Color color ) {
|
||||
// see https://en.wikipedia.org/wiki/Luma_(video)
|
||||
// see https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
|
||||
// see https://github.com/less/less.js/blob/master/packages/less/src/less/tree/color.js
|
||||
float r = gammaCorrection( color.getRed() / 255f );
|
||||
float g = gammaCorrection( color.getGreen() / 255f );
|
||||
float b = gammaCorrection( color.getBlue() / 255f );
|
||||
return (0.2126f * r) + (0.7152f * g) + (0.0722f * b);
|
||||
}
|
||||
|
||||
private static float gammaCorrection( float value ) {
|
||||
return (value <= 0.03928f)
|
||||
? value / 12.92f
|
||||
: (float) Math.pow( (value + 0.055) / 1.055, 2.4 );
|
||||
}
|
||||
|
||||
public static Color applyFunctions( Color color, ColorFunction... functions ) {
|
||||
// if having only a single function of type Mix, then avoid four unnecessary conversions:
|
||||
// 1. RGB to HSL in this method
|
||||
// 2. HSL to RGB in Mix.apply()
|
||||
// mix
|
||||
// 3. RGB to HSL in Mix.apply()
|
||||
// 4. HSL to RGB in this method
|
||||
if( functions.length == 1 && functions[0] instanceof Mix ) {
|
||||
Mix mixFunction = (Mix) functions[0];
|
||||
return mix( color, mixFunction.color2, mixFunction.weight / 100 );
|
||||
}
|
||||
|
||||
// convert RGB to HSL
|
||||
float[] hsl = HSLColor.fromRGB( color );
|
||||
float alpha = color.getAlpha() / 255f;
|
||||
float[] hsla = { hsl[0], hsl[1], hsl[2], alpha * 100 };
|
||||
|
||||
// apply color functions
|
||||
for( ColorFunction function : functions )
|
||||
function.apply( hsla );
|
||||
|
||||
// convert HSL to RGB
|
||||
return HSLColor.toRGB( hsla[0], hsla[1], hsla[2], hsla[3] / 100 );
|
||||
}
|
||||
|
||||
public static float clamp( float value ) {
|
||||
return (value < 0)
|
||||
? 0
|
||||
: ((value > 100)
|
||||
? 100
|
||||
: value);
|
||||
}
|
||||
|
||||
//---- interface ColorFunction --------------------------------------------
|
||||
|
||||
public interface ColorFunction {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.formdev.flatlaf.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -46,16 +47,98 @@ public class StringUtils
|
||||
}
|
||||
|
||||
public static List<String> split( String str, char delim ) {
|
||||
ArrayList<String> strs = new ArrayList<>();
|
||||
return split( str, delim, false, false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits a string at the specified delimiter.
|
||||
* If trimming is enabled, then leading and trailing whitespace characters are removed.
|
||||
* If excludeEmpty is {@code true}, then only non-empty strings are returned.
|
||||
*
|
||||
* @since 2
|
||||
*/
|
||||
public static List<String> split( String str, char delim, boolean trim, boolean excludeEmpty ) {
|
||||
int delimIndex = str.indexOf( delim );
|
||||
if( delimIndex < 0 ) {
|
||||
if( trim )
|
||||
str = str.trim();
|
||||
return !excludeEmpty || !str.isEmpty()
|
||||
? Collections.singletonList( str )
|
||||
: Collections.emptyList();
|
||||
}
|
||||
|
||||
ArrayList<String> strs = new ArrayList<>();
|
||||
int index = 0;
|
||||
while( delimIndex >= 0 ) {
|
||||
strs.add( str.substring( index, delimIndex ) );
|
||||
add( strs, str, index, delimIndex, trim, excludeEmpty );
|
||||
index = delimIndex + 1;
|
||||
delimIndex = str.indexOf( delim, index );
|
||||
}
|
||||
strs.add( str.substring( index ) );
|
||||
add( strs, str, index, str.length(), trim, excludeEmpty );
|
||||
|
||||
return strs;
|
||||
}
|
||||
|
||||
private static void add( List<String> strs, String str, int beginIndex, int endIndex,
|
||||
boolean trim, boolean excludeEmpty )
|
||||
{
|
||||
if( trim ) {
|
||||
beginIndex = trimBegin( str, beginIndex, endIndex );
|
||||
endIndex = trimEnd( str, beginIndex, endIndex );
|
||||
}
|
||||
|
||||
if( !excludeEmpty || endIndex > beginIndex )
|
||||
strs.add( str.substring( beginIndex, endIndex ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* This is equal to {@code str.substring( beginIndex, endIndex ).trim()},
|
||||
* but avoids temporary untrimmed substring allocation.
|
||||
* If the trimmed string is empty, a shared empty string is returned.
|
||||
*
|
||||
* @since 2
|
||||
*/
|
||||
public static String substringTrimmed( String str, int beginIndex ) {
|
||||
return substringTrimmed( str, beginIndex, str.length() );
|
||||
}
|
||||
|
||||
/**
|
||||
* This is equal to {@code str.substring( beginIndex ).trim()},
|
||||
* but avoids temporary untrimmed substring allocation.
|
||||
* If the trimmed string is empty, a shared empty string is returned.
|
||||
*
|
||||
* @since 2
|
||||
*/
|
||||
public static String substringTrimmed( String str, int beginIndex, int endIndex ) {
|
||||
beginIndex = trimBegin( str, beginIndex, endIndex );
|
||||
endIndex = trimEnd( str, beginIndex, endIndex );
|
||||
return (endIndex > beginIndex) ? str.substring( beginIndex, endIndex ) : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* This is equal to {@code str.trim().isEmpty()},
|
||||
* but avoids temporary trimmed substring allocation.
|
||||
*
|
||||
* @since 2
|
||||
*/
|
||||
public static boolean isTrimmedEmpty( String str ) {
|
||||
int length = str.length();
|
||||
int beginIndex = trimBegin( str, 0, length );
|
||||
int endIndex = trimEnd( str, beginIndex, length );
|
||||
return beginIndex >= endIndex;
|
||||
}
|
||||
|
||||
private static int trimBegin( String str, int beginIndex, int endIndex ) {
|
||||
// skip leading whitespace
|
||||
while( beginIndex < endIndex && str.charAt( beginIndex ) <= ' ' )
|
||||
beginIndex++;
|
||||
return beginIndex;
|
||||
}
|
||||
|
||||
private static int trimEnd( String str, int beginIndex, int endIndex ) {
|
||||
// skip trailing whitespace
|
||||
while( beginIndex < endIndex && str.charAt( endIndex - 1 ) <= ' ' )
|
||||
endIndex--;
|
||||
return endIndex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,7 +192,15 @@ public class UIScale
|
||||
if( font == null )
|
||||
font = UIManager.getFont( "Label.font" );
|
||||
|
||||
float newScaleFactor;
|
||||
setUserScaleFactor( computeFontScaleFactor( font ), true );
|
||||
}
|
||||
|
||||
/**
|
||||
* For internal use only.
|
||||
*
|
||||
* @since 2
|
||||
*/
|
||||
public static float computeFontScaleFactor( Font font ) {
|
||||
if( SystemInfo.isWindows ) {
|
||||
// Special handling for Windows to be compatible with OS scaling,
|
||||
// which distinguish between "screen scaling" and "text scaling".
|
||||
@@ -204,33 +212,35 @@ public class UIScale
|
||||
// - Settings > Display > Scale and layout
|
||||
// - Settings > Ease of Access > Display > Make text bigger (100% - 225%)
|
||||
if( font instanceof UIResource ) {
|
||||
if( isSystemScalingEnabled() ) {
|
||||
// Do not apply own scaling if the JRE scales using Windows screen scale factor.
|
||||
// If user increases font size in Windows 10 settings, desktop property
|
||||
// "win.messagebox.font" is changed and FlatLaf uses the larger font.
|
||||
newScaleFactor = 1;
|
||||
} else {
|
||||
// If the JRE does not scale (Java 8), the size of the UI font
|
||||
// (usually from desktop property "win.messagebox.font")
|
||||
// combines the Windows screen and text scale factors.
|
||||
// But the font in desktop property "win.defaultGUI.font" is only
|
||||
// scaled with the Windows screen scale factor. So use it to compute
|
||||
// our scale factor that is equal to Windows screen scale factor.
|
||||
Font winFont = (Font) Toolkit.getDefaultToolkit().getDesktopProperty( "win.defaultGUI.font" );
|
||||
newScaleFactor = computeScaleFactor( (winFont != null) ? winFont : font );
|
||||
Font uiFont = (Font) Toolkit.getDefaultToolkit().getDesktopProperty( "win.messagebox.font" );
|
||||
if( uiFont == null || uiFont.getSize() == font.getSize() ) {
|
||||
if( isSystemScalingEnabled() ) {
|
||||
// Do not apply own scaling if the JRE scales using Windows screen scale factor.
|
||||
// If user increases font size in Windows 10 settings, desktop property
|
||||
// "win.messagebox.font" is changed and FlatLaf uses the larger font.
|
||||
return 1;
|
||||
} else {
|
||||
// If the JRE does not scale (Java 8), the size of the UI font
|
||||
// (usually from desktop property "win.messagebox.font")
|
||||
// combines the Windows screen and text scale factors.
|
||||
// But the font in desktop property "win.defaultGUI.font" is only
|
||||
// scaled with the Windows screen scale factor. So use it to compute
|
||||
// our scale factor that is equal to Windows screen scale factor.
|
||||
Font winFont = (Font) Toolkit.getDefaultToolkit().getDesktopProperty( "win.defaultGUI.font" );
|
||||
return computeScaleFactor( (winFont != null) ? winFont : font );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If font was explicitly set from outside (is not a UIResource)
|
||||
// use it to compute scale factor. This allows applications to
|
||||
// use custom fonts (e.g. that the user can change in UI) and
|
||||
// get scaling if a larger font size is used.
|
||||
// E.g. FlatLaf Demo supports increasing font size in "Font" menu and UI scales.
|
||||
newScaleFactor = computeScaleFactor( font );
|
||||
}
|
||||
} else
|
||||
newScaleFactor = computeScaleFactor( font );
|
||||
|
||||
setUserScaleFactor( newScaleFactor, true );
|
||||
// If font was explicitly set from outside (is not a UIResource),
|
||||
// or was set in FlatLaf properties files (is a UIResource),
|
||||
// use it to compute scale factor. This allows applications to
|
||||
// use custom fonts (e.g. that the user can change in UI) and
|
||||
// get scaling if a larger font size is used.
|
||||
// E.g. FlatLaf Demo supports increasing font size in "Font" menu and UI scales.
|
||||
}
|
||||
|
||||
return computeScaleFactor( font );
|
||||
}
|
||||
|
||||
private static float computeScaleFactor( Font font ) {
|
||||
|
||||
@@ -31,6 +31,12 @@
|
||||
# which is licensed under the Apache 2.0 license. Copyright 2000-2019 JetBrains s.r.o.
|
||||
# See: https://github.com/JetBrains/intellij-community/
|
||||
|
||||
#---- variables ----
|
||||
|
||||
# accent colors (blueish)
|
||||
@accentFocusColor = if(@accentColor, darken(@accentColor,20%), shade(spin(@accentBaseColor,-8),20%))
|
||||
|
||||
|
||||
#---- Button ----
|
||||
|
||||
Button.innerFocusWidth = 0
|
||||
@@ -40,6 +46,7 @@ Button.default.boldText = true
|
||||
|
||||
#---- CheckBox ----
|
||||
|
||||
CheckBox.icon.focusWidth = null
|
||||
CheckBox.icon.focusedBackground = null
|
||||
|
||||
|
||||
@@ -53,7 +60,7 @@ Component.arrowType = triangle
|
||||
|
||||
#---- ProgressBar ----
|
||||
|
||||
ProgressBar.foreground = #a0a0a0
|
||||
ProgressBar.foreground = darken(@foreground,10%)
|
||||
ProgressBar.selectionForeground = @background
|
||||
|
||||
|
||||
|
||||
@@ -32,24 +32,49 @@
|
||||
|
||||
#---- variables ----
|
||||
|
||||
# general background and foreground (text color)
|
||||
@background = #3c3f41
|
||||
@foreground = #bbb
|
||||
@selectionBackground = #4B6EAF
|
||||
@selectionForeground = @foreground
|
||||
@selectionInactiveBackground = #0D293E
|
||||
@selectionInactiveForeground = @foreground
|
||||
@disabledText = #888
|
||||
@textComponentBackground = #45494A
|
||||
@disabledBackground = @background
|
||||
@disabledForeground = shade(@foreground,25%)
|
||||
|
||||
# component background
|
||||
@buttonBackground = tint(@background,9%)
|
||||
@componentBackground = tint(@background,5%)
|
||||
@menuBackground = darken(@background,5%)
|
||||
|
||||
# selection
|
||||
@selectionBackground = @accentSelectionBackground
|
||||
@selectionForeground = contrast(@selectionBackground, @background, @foreground, 25%)
|
||||
@selectionInactiveBackground = spin(saturate(shade(@selectionBackground,70%),20%),-15)
|
||||
@selectionInactiveForeground = @foreground
|
||||
|
||||
# menu
|
||||
@menuHoverBackground = lighten(@menuBackground,10%,derived)
|
||||
@menuCheckBackground = darken(@selectionBackground,10%,derived noAutoInverse)
|
||||
@menuAcceleratorForeground = darken(@foreground,15%)
|
||||
@menuAcceleratorSelectionForeground = @selectionForeground
|
||||
|
||||
# misc
|
||||
@cellFocusColor = #000
|
||||
@icon = #adadad
|
||||
@icon = shade(@foreground,7%)
|
||||
|
||||
# accent colors (blueish)
|
||||
# set @accentColor to use single accent color or
|
||||
# modify @accentBaseColor to use variations of accent base color
|
||||
@accentColor = null
|
||||
@accentBaseColor = #4B6EAF
|
||||
@accentBase2Color = lighten(saturate(spin(@accentBaseColor,-8),13%),5%)
|
||||
# accent color variations
|
||||
@accentFocusColor = if(@accentColor, @accentColor, shade(spin(@accentBaseColor,-8),20%))
|
||||
@accentLinkColor = if(@accentColor, @accentColor, lighten(saturate(spin(@accentBaseColor,-5),50%),16%))
|
||||
@accentSelectionBackground = if(@accentColor, @accentColor, @accentBaseColor)
|
||||
@accentSliderColor = if(@accentColor, @accentColor, @accentBase2Color)
|
||||
@accentUnderlineColor = if(@accentColor, @accentColor, @accentBase2Color)
|
||||
@accentButtonDefaultBackground = if(@accentColor, @accentColor, darken(spin(@accentBaseColor,-8),13%))
|
||||
|
||||
# for buttons within components (e.g. combobox or spinner)
|
||||
@buttonArrowColor = #9A9DA1
|
||||
@buttonArrowColor = shade(@foreground,17%)
|
||||
@buttonDisabledArrowColor = darken(@buttonArrowColor,25%)
|
||||
@buttonHoverArrowColor = lighten(@buttonArrowColor,10%,derived noAutoInverse)
|
||||
@buttonPressedArrowColor = lighten(@buttonArrowColor,20%,derived noAutoInverse)
|
||||
@@ -72,28 +97,28 @@ controlDkShadow = lighten($controlShadow,10%)
|
||||
|
||||
#---- Button ----
|
||||
|
||||
Button.background = #4c5052
|
||||
Button.background = @buttonBackground
|
||||
Button.hoverBackground = lighten($Button.background,3%,derived)
|
||||
Button.pressedBackground = lighten($Button.background,6%,derived)
|
||||
Button.selectedBackground = lighten($Button.background,10%,derived)
|
||||
Button.selectedForeground = @foreground
|
||||
Button.selectedForeground = $Button.foreground
|
||||
Button.disabledSelectedBackground = lighten($Button.background,3%,derived)
|
||||
|
||||
Button.borderColor = #5e6060
|
||||
Button.borderColor = tint($Button.background,10%)
|
||||
Button.disabledBorderColor = $Button.borderColor
|
||||
Button.focusedBorderColor = $Component.focusedBorderColor
|
||||
Button.hoverBorderColor = $Button.focusedBorderColor
|
||||
|
||||
Button.innerFocusWidth = 1
|
||||
|
||||
Button.default.background = #365880
|
||||
Button.default.foreground = #bbb
|
||||
Button.default.background = @accentButtonDefaultBackground
|
||||
Button.default.foreground = contrast($Button.default.background, @background, $Button.foreground, 25%)
|
||||
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.borderColor = tint($Button.default.background,15%)
|
||||
Button.default.hoverBorderColor = tint($Button.default.background,18%)
|
||||
Button.default.focusedBorderColor = $Button.default.hoverBorderColor
|
||||
Button.default.focusColor = lighten($Component.focusColor,3%)
|
||||
Button.default.boldText = true
|
||||
|
||||
Button.toolbar.hoverBackground = lighten($Button.background,1%,derived)
|
||||
@@ -103,20 +128,22 @@ Button.toolbar.selectedBackground = lighten($Button.background,7%,derived)
|
||||
|
||||
#---- CheckBox ----
|
||||
|
||||
CheckBox.icon.focusWidth = 1
|
||||
|
||||
# enabled
|
||||
CheckBox.icon.borderColor = #6B6B6B
|
||||
CheckBox.icon.background = #43494A
|
||||
CheckBox.icon.selectedBorderColor = $CheckBox.icon.borderColor
|
||||
CheckBox.icon.borderColor = tint($Component.borderColor,5%)
|
||||
CheckBox.icon.background = tint(@background,5%)
|
||||
CheckBox.icon.selectedBorderColor = tint($CheckBox.icon.borderColor,20%)
|
||||
CheckBox.icon.selectedBackground = $CheckBox.icon.background
|
||||
CheckBox.icon.checkmarkColor = #A7A7A7
|
||||
CheckBox.icon.checkmarkColor = shade(@foreground,10%)
|
||||
|
||||
# disabled
|
||||
CheckBox.icon.disabledBorderColor = #545556
|
||||
CheckBox.icon.disabledBackground = @background
|
||||
CheckBox.icon.disabledCheckmarkColor = #606060
|
||||
CheckBox.icon.disabledBorderColor = shade($CheckBox.icon.borderColor,20%)
|
||||
CheckBox.icon.disabledBackground = @disabledBackground
|
||||
CheckBox.icon.disabledCheckmarkColor = darken($CheckBox.icon.checkmarkColor,25%)
|
||||
|
||||
# focused
|
||||
CheckBox.icon.focusedBorderColor = #466D94
|
||||
CheckBox.icon.focusedBorderColor = $Component.focusedBorderColor
|
||||
CheckBox.icon.focusedBackground = fade($CheckBox.icon.focusedBorderColor,30%)
|
||||
|
||||
# hover
|
||||
@@ -124,32 +151,35 @@ CheckBox.icon.hoverBorderColor = $CheckBox.icon.focusedBorderColor
|
||||
CheckBox.icon.hoverBackground = lighten($CheckBox.icon.background,3%,derived)
|
||||
|
||||
# pressed
|
||||
CheckBox.icon.pressedBorderColor = $CheckBox.icon.focusedBorderColor
|
||||
CheckBox.icon.pressedBackground = lighten($CheckBox.icon.background,6%,derived)
|
||||
|
||||
|
||||
# used if CheckBox.icon.style = filled
|
||||
# used if CheckBox.icon.style or RadioButton.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%,derived)
|
||||
CheckBox.icon[filled].hoverSelectedBackground = darken($CheckBox.icon[filled].selectedBackground,3%,derived)
|
||||
# pressed
|
||||
CheckBox.icon[filled].selectedPressedBackground = darken($CheckBox.icon[filled].selectedBackground,6%,derived)
|
||||
CheckBox.icon[filled].pressedSelectedBackground = darken($CheckBox.icon[filled].selectedBackground,6%,derived)
|
||||
|
||||
|
||||
#---- ComboBox ----
|
||||
#---- CheckBoxMenuItem ----
|
||||
|
||||
ComboBox.buttonEditableBackground = darken($ComboBox.background,2%)
|
||||
CheckBoxMenuItem.icon.checkmarkColor = @buttonArrowColor
|
||||
CheckBoxMenuItem.icon.disabledCheckmarkColor = @buttonDisabledArrowColor
|
||||
|
||||
|
||||
#---- Component ----
|
||||
|
||||
Component.borderColor = #646464
|
||||
Component.disabledBorderColor = #646464
|
||||
Component.focusedBorderColor = #466d94
|
||||
Component.focusColor = #3d6185
|
||||
Component.linkColor = #589df6
|
||||
Component.borderColor = tint(@background,19%)
|
||||
Component.disabledBorderColor = $Component.borderColor
|
||||
Component.focusedBorderColor = lighten($Component.focusColor,5%)
|
||||
Component.focusColor = @accentFocusColor
|
||||
Component.linkColor = @accentLinkColor
|
||||
Component.accentColor = if(@accentColor, @accentColor, @accentBaseColor)
|
||||
Component.grayFilter = -20,-70,100
|
||||
|
||||
Component.error.borderColor = desaturate($Component.error.focusedBorderColor,25%)
|
||||
@@ -169,12 +199,18 @@ Desktop.background = #3E434C
|
||||
DesktopIcon.background = lighten($Desktop.background,10%,derived)
|
||||
|
||||
|
||||
#---- HelpButton ----
|
||||
|
||||
HelpButton.questionMarkColor = shade(@foreground,10%)
|
||||
HelpButton.disabledQuestionMarkColor = tint(@background,30%)
|
||||
|
||||
|
||||
#---- InternalFrame ----
|
||||
|
||||
InternalFrame.activeTitleBackground = darken(@background,10%)
|
||||
InternalFrame.activeTitleForeground = @foreground
|
||||
InternalFrame.inactiveTitleBackground = darken(@background,5%)
|
||||
InternalFrame.inactiveTitleForeground = @disabledText
|
||||
InternalFrame.inactiveTitleBackground = lighten($InternalFrame.activeTitleBackground,5%)
|
||||
InternalFrame.inactiveTitleForeground = @disabledForeground
|
||||
|
||||
InternalFrame.activeBorderColor = darken(@background,7%)
|
||||
InternalFrame.inactiveBorderColor = darken(@background,3%)
|
||||
@@ -192,19 +228,13 @@ InternalFrame.inactiveDropShadowOpacity = 0.75
|
||||
|
||||
#---- Menu ----
|
||||
|
||||
Menu.icon.arrowColor = #A7A7A7
|
||||
Menu.icon.disabledArrowColor = #606060
|
||||
Menu.icon.arrowColor = @buttonArrowColor
|
||||
Menu.icon.disabledArrowColor = @buttonDisabledArrowColor
|
||||
|
||||
|
||||
#---- MenuBar ----
|
||||
|
||||
MenuBar.borderColor = #515151
|
||||
|
||||
|
||||
#---- MenuItemCheckBox ----
|
||||
|
||||
MenuItemCheckBox.icon.checkmarkColor = #A7A7A7
|
||||
MenuItemCheckBox.icon.disabledCheckmarkColor = #606060
|
||||
MenuBar.borderColor = $Separator.foreground
|
||||
|
||||
|
||||
#---- PasswordField ----
|
||||
@@ -220,15 +250,15 @@ Popup.dropShadowOpacity = 0.25
|
||||
|
||||
#---- PopupMenu ----
|
||||
|
||||
PopupMenu.borderColor = #5e5e5e
|
||||
PopupMenu.borderColor = tint(@background,17%)
|
||||
|
||||
|
||||
#---- ProgressBar ----
|
||||
|
||||
ProgressBar.background = #555
|
||||
ProgressBar.foreground = #4A88C7
|
||||
ProgressBar.selectionForeground = @foreground
|
||||
ProgressBar.background = lighten(@background,8%)
|
||||
ProgressBar.foreground = @accentSliderColor
|
||||
ProgressBar.selectionBackground = @foreground
|
||||
ProgressBar.selectionForeground = contrast($ProgressBar.foreground, @background, @foreground, 25%)
|
||||
|
||||
|
||||
#---- RootPane ----
|
||||
@@ -250,40 +280,40 @@ ScrollBar.pressedButtonBackground = lighten(@background,10%,derived noAutoInvers
|
||||
|
||||
#---- Separator ----
|
||||
|
||||
Separator.foreground = #515151
|
||||
Separator.foreground = tint(@background,10%)
|
||||
|
||||
|
||||
#---- Slider ----
|
||||
|
||||
Slider.trackValueColor = #4A88C7
|
||||
Slider.trackColor = #646464
|
||||
Slider.trackValueColor = @accentSliderColor
|
||||
Slider.trackColor = lighten(@background,15%)
|
||||
Slider.thumbColor = $Slider.trackValueColor
|
||||
Slider.tickColor = #888
|
||||
Slider.tickColor = @disabledForeground
|
||||
Slider.focusedColor = fade($Component.focusColor,70%,derived)
|
||||
Slider.hoverThumbColor = lighten($Slider.thumbColor,5%,derived)
|
||||
Slider.pressedThumbColor = lighten($Slider.thumbColor,8%,derived)
|
||||
Slider.disabledTrackColor = #4c5052
|
||||
Slider.disabledTrackColor = lighten(@background,10%)
|
||||
Slider.disabledThumbColor = $Slider.disabledTrackColor
|
||||
|
||||
|
||||
#---- SplitPane ----
|
||||
|
||||
SplitPaneDivider.draggingColor = #646464
|
||||
SplitPaneDivider.draggingColor = $Component.borderColor
|
||||
|
||||
|
||||
#---- TabbedPane ----
|
||||
|
||||
TabbedPane.underlineColor = #4A88C7
|
||||
TabbedPane.disabledUnderlineColor = #7a7a7a
|
||||
TabbedPane.underlineColor = @accentUnderlineColor
|
||||
TabbedPane.disabledUnderlineColor = lighten(@background,23%)
|
||||
TabbedPane.hoverColor = darken($TabbedPane.background,5%,derived noAutoInverse)
|
||||
TabbedPane.focusColor = #3d4b5c
|
||||
TabbedPane.contentAreaColor = #646464
|
||||
TabbedPane.focusColor = mix(@selectionBackground,$TabbedPane.background,25%)
|
||||
TabbedPane.contentAreaColor = $Component.borderColor
|
||||
|
||||
TabbedPane.buttonHoverBackground = darken($TabbedPane.background,5%,derived noAutoInverse)
|
||||
TabbedPane.buttonPressedBackground = darken($TabbedPane.background,8%,derived noAutoInverse)
|
||||
|
||||
TabbedPane.closeBackground = null
|
||||
TabbedPane.closeForeground = @disabledText
|
||||
TabbedPane.closeForeground = @disabledForeground
|
||||
TabbedPane.closeHoverBackground = lighten($TabbedPane.background,5%,derived)
|
||||
TabbedPane.closeHoverForeground = @foreground
|
||||
TabbedPane.closePressedBackground = lighten($TabbedPane.background,10%,derived)
|
||||
@@ -319,7 +349,7 @@ ToggleButton.toolbar.selectedBackground = lighten($ToggleButton.background,7%,de
|
||||
#---- ToolTip ----
|
||||
|
||||
ToolTip.border = 4,6,4,6
|
||||
ToolTip.background = #1e2123
|
||||
ToolTip.background = shade(@background,50%)
|
||||
|
||||
|
||||
#---- Tree ----
|
||||
|
||||
@@ -31,17 +31,22 @@
|
||||
# which is licensed under the Apache 2.0 license. Copyright 2000-2019 JetBrains s.r.o.
|
||||
# See: https://github.com/JetBrains/intellij-community/
|
||||
|
||||
#---- variables ----
|
||||
|
||||
# accent colors (blueish)
|
||||
@accentFocusColor = if(@accentColor, lighten(@accentColor,20%), lighten(@accentBaseColor,31%))
|
||||
@accentButtonDefaultBackground = if(@accentColor, @accentColor, tint(@accentBaseColor,15%))
|
||||
|
||||
#---- Button ----
|
||||
|
||||
Button.focusedBackground = null
|
||||
|
||||
Button.default.background = #4D8AC9
|
||||
Button.default.foreground = #fff
|
||||
Button.default.background = @accentButtonDefaultBackground
|
||||
Button.default.foreground = contrast($Button.default.background, tint($Button.foreground,50%), #fff, 50%)
|
||||
Button.default.focusedBackground = null
|
||||
Button.default.borderColor = #3D75B2
|
||||
Button.default.hoverBorderColor = #A9C9F5
|
||||
Button.default.focusedBorderColor = #A9C9F5
|
||||
Button.default.focusColor = #97c3f3
|
||||
Button.default.borderColor = shade($Button.default.background,15%)
|
||||
Button.default.hoverBorderColor = tint($Button.default.background,50%)
|
||||
Button.default.focusedBorderColor = $Button.default.hoverBorderColor
|
||||
Button.default.boldText = true
|
||||
Button.default.borderWidth = 1
|
||||
|
||||
@@ -49,6 +54,8 @@ Button.default.borderWidth = 1
|
||||
#---- CheckBox ----
|
||||
|
||||
CheckBox.icon.style = filled
|
||||
CheckBox.icon.focusWidth = null
|
||||
CheckBox.icon.focusedBackground = null
|
||||
|
||||
|
||||
#---- Component ----
|
||||
@@ -57,3 +64,8 @@ Component.focusWidth = 2
|
||||
Component.innerFocusWidth = 0
|
||||
Component.innerOutlineWidth = 0
|
||||
Component.arrowType = triangle
|
||||
|
||||
|
||||
#---- RadioButton ----
|
||||
|
||||
RadioButton.icon.style = filled
|
||||
|
||||
@@ -75,7 +75,7 @@ ViewportUI = com.formdev.flatlaf.ui.FlatViewportUI
|
||||
|
||||
#---- variables ----
|
||||
|
||||
@textComponentMargin = 2,6,2,6
|
||||
@componentMargin = 2,6,2,6
|
||||
@menuItemMargin = 3,6,3,6
|
||||
|
||||
|
||||
@@ -83,21 +83,21 @@ ViewportUI = com.formdev.flatlaf.ui.FlatViewportUI
|
||||
|
||||
*.background = @background
|
||||
*.foreground = @foreground
|
||||
*.caretForeground = @foreground
|
||||
*.inactiveBackground = @background
|
||||
*.inactiveForeground = @disabledText
|
||||
*.disabledBackground = @disabledBackground
|
||||
*.disabledForeground = @disabledForeground
|
||||
*.disabledText = @disabledForeground
|
||||
*.inactiveBackground = @disabledBackground
|
||||
*.inactiveForeground = @disabledForeground
|
||||
*.selectionBackground = @selectionBackground
|
||||
*.selectionForeground = @selectionForeground
|
||||
*.disabledBackground = @background
|
||||
*.disabledForeground = @disabledText
|
||||
*.disabledText = @disabledText
|
||||
*.caretForeground = @foreground
|
||||
*.acceleratorForeground = @menuAcceleratorForeground
|
||||
*.acceleratorSelectionForeground = @menuAcceleratorSelectionForeground
|
||||
|
||||
|
||||
#---- system colors ----
|
||||
|
||||
desktop = @textComponentBackground
|
||||
desktop = @componentBackground
|
||||
activeCaptionText = @foreground
|
||||
activeCaptionBorder = $activeCaption
|
||||
inactiveCaptionText = @foreground
|
||||
@@ -107,11 +107,11 @@ windowBorder = @foreground
|
||||
windowText = @foreground
|
||||
menu = @background
|
||||
menuText = @foreground
|
||||
text = @textComponentBackground
|
||||
text = @componentBackground
|
||||
textText = @foreground
|
||||
textHighlight = @selectionBackground
|
||||
textHighlightText = @selectionForeground
|
||||
textInactiveText = @disabledText
|
||||
textInactiveText = @disabledForeground
|
||||
control = @background
|
||||
controlText = @foreground
|
||||
controlShadow = $Component.borderColor
|
||||
@@ -205,15 +205,18 @@ ColorChooser.swatchesDefaultRecentColor = $control
|
||||
#---- ComboBox ----
|
||||
|
||||
ComboBox.border = com.formdev.flatlaf.ui.FlatRoundBorder
|
||||
ComboBox.padding = 2,6,2,6
|
||||
ComboBox.padding = @componentMargin
|
||||
ComboBox.minimumWidth = 72
|
||||
ComboBox.editorColumns = 0
|
||||
ComboBox.maximumRowCount = 15
|
||||
[mac]ComboBox.showPopupOnNavigation = true
|
||||
# allowed values: auto, button or none
|
||||
ComboBox.buttonStyle = auto
|
||||
ComboBox.background = @textComponentBackground
|
||||
ComboBox.buttonBackground = @textComponentBackground
|
||||
ComboBox.background = @componentBackground
|
||||
ComboBox.buttonBackground = $ComboBox.background
|
||||
ComboBox.buttonEditableBackground = darken($ComboBox.background,2%)
|
||||
ComboBox.buttonSeparatorColor = $Component.borderColor
|
||||
ComboBox.buttonDisabledSeparatorColor = $Component.disabledBorderColor
|
||||
ComboBox.buttonArrowColor = @buttonArrowColor
|
||||
ComboBox.buttonDisabledArrowColor = @buttonDisabledArrowColor
|
||||
ComboBox.buttonHoverArrowColor = @buttonHoverArrowColor
|
||||
@@ -223,8 +226,9 @@ ComboBox.buttonPressedArrowColor = @buttonPressedArrowColor
|
||||
#---- Component ----
|
||||
|
||||
Component.focusWidth = 0
|
||||
Component.innerFocusWidth = {float}0.5
|
||||
Component.innerOutlineWidth = {float}1
|
||||
Component.innerFocusWidth = 0.5
|
||||
Component.innerOutlineWidth = 1
|
||||
Component.borderWidth = 1
|
||||
Component.arc = 5
|
||||
Component.minimumWidth = 64
|
||||
# allowed values: chevron or triangle
|
||||
@@ -243,8 +247,8 @@ DesktopIcon.closeIcon = com.formdev.flatlaf.icons.FlatInternalFrameCloseIcon
|
||||
#---- EditorPane ----
|
||||
|
||||
EditorPane.border = com.formdev.flatlaf.ui.FlatMarginBorder
|
||||
EditorPane.margin = @textComponentMargin
|
||||
EditorPane.background = @textComponentBackground
|
||||
EditorPane.margin = @componentMargin
|
||||
EditorPane.background = @componentBackground
|
||||
|
||||
|
||||
#---- FileChooser ----
|
||||
@@ -270,25 +274,24 @@ FileView.floppyDriveIcon = com.formdev.flatlaf.icons.FlatFileViewFloppyDriveIcon
|
||||
#---- FormattedTextField ----
|
||||
|
||||
FormattedTextField.border = com.formdev.flatlaf.ui.FlatTextBorder
|
||||
FormattedTextField.margin = @textComponentMargin
|
||||
FormattedTextField.background = @textComponentBackground
|
||||
FormattedTextField.placeholderForeground = @disabledText
|
||||
FormattedTextField.margin = @componentMargin
|
||||
FormattedTextField.background = @componentBackground
|
||||
FormattedTextField.placeholderForeground = @disabledForeground
|
||||
FormattedTextField.iconTextGap = 4
|
||||
|
||||
|
||||
#---- HelpButton ----
|
||||
|
||||
HelpButton.icon = com.formdev.flatlaf.icons.FlatHelpButtonIcon
|
||||
HelpButton.borderColor = $CheckBox.icon.borderColor
|
||||
HelpButton.disabledBorderColor = $CheckBox.icon.disabledBorderColor
|
||||
HelpButton.focusedBorderColor = $CheckBox.icon.focusedBorderColor
|
||||
HelpButton.hoverBorderColor = $?CheckBox.icon.hoverBorderColor
|
||||
HelpButton.background = $CheckBox.icon.background
|
||||
HelpButton.disabledBackground = $CheckBox.icon.disabledBackground
|
||||
HelpButton.borderColor = $Button.borderColor
|
||||
HelpButton.disabledBorderColor = $Button.disabledBorderColor
|
||||
HelpButton.focusedBorderColor = $Button.focusedBorderColor
|
||||
HelpButton.hoverBorderColor = $?Button.hoverBorderColor
|
||||
HelpButton.background = $Button.background
|
||||
HelpButton.disabledBackground = $Button.disabledBackground
|
||||
HelpButton.focusedBackground = $?Button.focusedBackground
|
||||
HelpButton.hoverBackground = $?CheckBox.icon.hoverBackground
|
||||
HelpButton.pressedBackground = $?CheckBox.icon.pressedBackground
|
||||
HelpButton.questionMarkColor = $CheckBox.icon.checkmarkColor
|
||||
HelpButton.disabledQuestionMarkColor = $CheckBox.icon.disabledCheckmarkColor
|
||||
HelpButton.hoverBackground = $?Button.hoverBackground
|
||||
HelpButton.pressedBackground = $?Button.pressedBackground
|
||||
|
||||
HelpButton.borderWidth = $?Button.borderWidth
|
||||
HelpButton.innerFocusWidth = $?Button.innerFocusWidth
|
||||
@@ -327,7 +330,7 @@ List.cellFocusColor = @cellFocusColor
|
||||
List.cellNoFocusBorder = com.formdev.flatlaf.ui.FlatListCellBorder$Default
|
||||
List.focusCellHighlightBorder = com.formdev.flatlaf.ui.FlatListCellBorder$Focused
|
||||
List.focusSelectedCellHighlightBorder = com.formdev.flatlaf.ui.FlatListCellBorder$Selected
|
||||
List.background = @textComponentBackground
|
||||
List.background = @componentBackground
|
||||
List.selectionInactiveBackground = @selectionInactiveBackground
|
||||
List.selectionInactiveForeground = @selectionInactiveForeground
|
||||
List.dropCellBackground = @dropCellBackground
|
||||
@@ -380,7 +383,7 @@ MenuItem.acceleratorDelimiter = -
|
||||
# for MenuItem.selectionType = underline
|
||||
MenuItem.underlineSelectionBackground = @menuHoverBackground
|
||||
MenuItem.underlineSelectionCheckBackground = @menuCheckBackground
|
||||
MenuItem.underlineSelectionColor = $TabbedPane.underlineColor
|
||||
MenuItem.underlineSelectionColor = @accentUnderlineColor
|
||||
MenuItem.underlineSelectionHeight = 3
|
||||
|
||||
|
||||
@@ -410,9 +413,10 @@ OptionPane.warningIcon = com.formdev.flatlaf.icons.FlatOptionPaneWarningIcon
|
||||
#---- PasswordField ----
|
||||
|
||||
PasswordField.border = com.formdev.flatlaf.ui.FlatTextBorder
|
||||
PasswordField.margin = @textComponentMargin
|
||||
PasswordField.background = @textComponentBackground
|
||||
PasswordField.placeholderForeground = @disabledText
|
||||
PasswordField.margin = @componentMargin
|
||||
PasswordField.background = @componentBackground
|
||||
PasswordField.placeholderForeground = @disabledForeground
|
||||
PasswordField.iconTextGap = 4
|
||||
PasswordField.echoChar = \u2022
|
||||
PasswordField.showCapsLock = true
|
||||
PasswordField.capsLockIcon = com.formdev.flatlaf.icons.FlatCapsLockIcon
|
||||
@@ -446,6 +450,7 @@ ProgressBar.horizontalSize = 146,4
|
||||
ProgressBar.verticalSize = 4,146
|
||||
ProgressBar.cycleTime = 4000
|
||||
ProgressBar.repaintInterval = 15
|
||||
ProgressBar.font = -2
|
||||
|
||||
|
||||
#---- RadioButton ----
|
||||
@@ -543,13 +548,15 @@ Slider.focusWidth = 4
|
||||
#---- Spinner ----
|
||||
|
||||
Spinner.border = com.formdev.flatlaf.ui.FlatRoundBorder
|
||||
Spinner.background = @textComponentBackground
|
||||
Spinner.buttonBackground = $ComboBox.buttonEditableBackground
|
||||
Spinner.background = @componentBackground
|
||||
Spinner.buttonBackground = darken($Spinner.background,2%)
|
||||
Spinner.buttonSeparatorColor = $Component.borderColor
|
||||
Spinner.buttonDisabledSeparatorColor = $Component.disabledBorderColor
|
||||
Spinner.buttonArrowColor = @buttonArrowColor
|
||||
Spinner.buttonDisabledArrowColor = @buttonDisabledArrowColor
|
||||
Spinner.buttonHoverArrowColor = @buttonHoverArrowColor
|
||||
Spinner.buttonPressedArrowColor = @buttonPressedArrowColor
|
||||
Spinner.padding = @textComponentMargin
|
||||
Spinner.padding = @componentMargin
|
||||
Spinner.editorBorderPainted = false
|
||||
# allowed values: button or none
|
||||
Spinner.buttonStyle = button
|
||||
@@ -557,7 +564,7 @@ Spinner.buttonStyle = button
|
||||
|
||||
#---- SplitPane ----
|
||||
|
||||
SplitPane.dividerSize = {integer}5
|
||||
SplitPane.dividerSize = 5
|
||||
SplitPane.continuousLayout = true
|
||||
SplitPane.border = null
|
||||
SplitPane.centerOneTouchButtons = true
|
||||
@@ -572,7 +579,7 @@ SplitPaneDivider.oneTouchPressedArrowColor = @buttonPressedArrowColor
|
||||
SplitPaneDivider.style = grip
|
||||
SplitPaneDivider.gripColor = @icon
|
||||
SplitPaneDivider.gripDotCount = 3
|
||||
SplitPaneDivider.gripDotSize = {integer}3
|
||||
SplitPaneDivider.gripDotSize = 3
|
||||
SplitPaneDivider.gripGap = 2
|
||||
|
||||
|
||||
@@ -589,7 +596,7 @@ TabbedPane.tabAreaInsets = 0,0,0,0
|
||||
TabbedPane.selectedTabPadInsets = 0,0,0,0
|
||||
TabbedPane.tabRunOverlay = 0
|
||||
TabbedPane.tabsOverlapBorder = false
|
||||
TabbedPane.disabledForeground = @disabledText
|
||||
TabbedPane.disabledForeground = @disabledForeground
|
||||
TabbedPane.shadow = @background
|
||||
TabbedPane.contentBorderInsets = null
|
||||
# allowed values: moreTabsButton or arrowButtons
|
||||
@@ -618,9 +625,9 @@ TabbedPane.scrollButtonsPlacement = both
|
||||
TabbedPane.closeIcon = com.formdev.flatlaf.icons.FlatTabbedPaneCloseIcon
|
||||
TabbedPane.closeSize = 16,16
|
||||
TabbedPane.closeArc = 4
|
||||
TabbedPane.closeCrossPlainSize = {float}7.5
|
||||
TabbedPane.closeCrossPlainSize = 7.5
|
||||
TabbedPane.closeCrossFilledSize = $TabbedPane.closeCrossPlainSize
|
||||
TabbedPane.closeCrossLineWidth = {float}1
|
||||
TabbedPane.closeCrossLineWidth = 1
|
||||
|
||||
|
||||
#---- Table ----
|
||||
@@ -630,7 +637,7 @@ Table.showHorizontalLines = false
|
||||
Table.showVerticalLines = false
|
||||
Table.showTrailingVerticalLine = false
|
||||
Table.consistentHomeEndKeyBehavior = true
|
||||
Table.intercellSpacing = {dimension}0,0
|
||||
Table.intercellSpacing = 0,0
|
||||
Table.scrollPaneBorder = com.formdev.flatlaf.ui.FlatBorder
|
||||
Table.ascendingSortIcon = com.formdev.flatlaf.icons.FlatAscendingSortIcon
|
||||
Table.descendingSortIcon = com.formdev.flatlaf.icons.FlatDescendingSortIcon
|
||||
@@ -640,9 +647,9 @@ Table.cellFocusColor = @cellFocusColor
|
||||
Table.cellNoFocusBorder = com.formdev.flatlaf.ui.FlatTableCellBorder$Default
|
||||
Table.focusCellHighlightBorder = com.formdev.flatlaf.ui.FlatTableCellBorder$Focused
|
||||
Table.focusSelectedCellHighlightBorder = com.formdev.flatlaf.ui.FlatTableCellBorder$Selected
|
||||
Table.focusCellBackground = @textComponentBackground
|
||||
Table.focusCellForeground = @foreground
|
||||
Table.background = @textComponentBackground
|
||||
Table.focusCellBackground = $Table.background
|
||||
Table.focusCellForeground = $Table.foreground
|
||||
Table.background = @componentBackground
|
||||
Table.selectionInactiveBackground = @selectionInactiveBackground
|
||||
Table.selectionInactiveForeground = @selectionInactiveForeground
|
||||
Table.dropCellBackground = @dropCellBackground
|
||||
@@ -657,14 +664,15 @@ TableHeader.height = 25
|
||||
TableHeader.cellBorder = com.formdev.flatlaf.ui.FlatTableHeaderBorder
|
||||
TableHeader.cellMargins = 2,3,2,3
|
||||
TableHeader.focusCellBackground = $TableHeader.background
|
||||
TableHeader.background = @textComponentBackground
|
||||
TableHeader.background = @componentBackground
|
||||
TableHeader.showTrailingVerticalLine = false
|
||||
|
||||
|
||||
#---- TextArea ----
|
||||
|
||||
TextArea.border = com.formdev.flatlaf.ui.FlatMarginBorder
|
||||
TextArea.margin = @textComponentMargin
|
||||
TextArea.background = @textComponentBackground
|
||||
TextArea.margin = @componentMargin
|
||||
TextArea.background = @componentBackground
|
||||
|
||||
|
||||
#---- TextComponent ----
|
||||
@@ -678,16 +686,17 @@ TextComponent.arc = 0
|
||||
#---- TextField ----
|
||||
|
||||
TextField.border = com.formdev.flatlaf.ui.FlatTextBorder
|
||||
TextField.margin = @textComponentMargin
|
||||
TextField.background = @textComponentBackground
|
||||
TextField.placeholderForeground = @disabledText
|
||||
TextField.margin = @componentMargin
|
||||
TextField.background = @componentBackground
|
||||
TextField.placeholderForeground = @disabledForeground
|
||||
TextField.iconTextGap = 4
|
||||
|
||||
|
||||
#---- TextPane ----
|
||||
|
||||
TextPane.border = com.formdev.flatlaf.ui.FlatMarginBorder
|
||||
TextPane.margin = @textComponentMargin
|
||||
TextPane.background = @textComponentBackground
|
||||
TextPane.margin = @componentMargin
|
||||
TextPane.background = @componentBackground
|
||||
|
||||
|
||||
#---- TitledBorder ----
|
||||
@@ -717,7 +726,7 @@ TitlePane.restoreIcon = com.formdev.flatlaf.icons.FlatWindowRestoreIcon
|
||||
TitlePane.background = $MenuBar.background
|
||||
TitlePane.inactiveBackground = $TitlePane.background
|
||||
TitlePane.foreground = @foreground
|
||||
TitlePane.inactiveForeground = @disabledText
|
||||
TitlePane.inactiveForeground = @disabledForeground
|
||||
|
||||
TitlePane.closeHoverBackground = #e81123
|
||||
TitlePane.closePressedBackground = fade($TitlePane.closeHoverBackground,60%)
|
||||
@@ -727,14 +736,14 @@ TitlePane.closePressedForeground = #fff
|
||||
|
||||
#---- ToggleButton ----
|
||||
|
||||
ToggleButton.border = com.formdev.flatlaf.ui.FlatButtonBorder
|
||||
ToggleButton.margin = 2,14,2,14
|
||||
ToggleButton.iconTextGap = 4
|
||||
ToggleButton.rollover = true
|
||||
ToggleButton.border = $Button.border
|
||||
ToggleButton.margin = $Button.margin
|
||||
ToggleButton.iconTextGap = $Button.iconTextGap
|
||||
ToggleButton.rollover = $Button.rollover
|
||||
|
||||
ToggleButton.background = $Button.background
|
||||
ToggleButton.pressedBackground = $Button.pressedBackground
|
||||
ToggleButton.selectedForeground = @foreground
|
||||
ToggleButton.selectedForeground = $ToggleButton.foreground
|
||||
|
||||
ToggleButton.toolbar.hoverBackground = $Button.toolbar.hoverBackground
|
||||
ToggleButton.toolbar.pressedBackground = $Button.toolbar.pressedBackground
|
||||
@@ -753,18 +762,22 @@ ToggleButton.tab.focusBackground = $TabbedPane.focusColor
|
||||
ToolBar.border = com.formdev.flatlaf.ui.FlatToolBarBorder
|
||||
ToolBar.borderMargins = 2,2,2,2
|
||||
ToolBar.isRollover = true
|
||||
ToolBar.focusableButtons = false
|
||||
ToolBar.arrowKeysOnlyNavigation = true
|
||||
ToolBar.floatable = false
|
||||
ToolBar.gripColor = @icon
|
||||
ToolBar.dockingBackground = @background
|
||||
ToolBar.dockingForeground = @foreground
|
||||
ToolBar.floatingBackground = @background
|
||||
ToolBar.floatingForeground = @disabledText
|
||||
ToolBar.dockingBackground = darken($ToolBar.background,5%)
|
||||
ToolBar.dockingForeground = $Component.borderColor
|
||||
ToolBar.floatingBackground = $ToolBar.background
|
||||
ToolBar.floatingForeground = $Component.borderColor
|
||||
|
||||
ToolBar.separatorSize = null
|
||||
ToolBar.separatorWidth = 7
|
||||
ToolBar.separatorColor = $Separator.foreground
|
||||
|
||||
# not used in FlatLaf; intended for custom components in toolbar
|
||||
# https://github.com/JFormDesigner/FlatLaf/issues/56#issuecomment-586297814
|
||||
ToolBar.spacingBorder = $Button.toolbar.spacingInsets
|
||||
ToolBar.focusableButtons = false
|
||||
|
||||
|
||||
#---- ToolTipManager ----
|
||||
@@ -776,7 +789,7 @@ ToolTipManager.enableToolTipMode = activeApplication
|
||||
|
||||
Tree.border = 1,1,1,1
|
||||
Tree.editorBorder = 1,1,1,1,@cellFocusColor
|
||||
Tree.background = @textComponentBackground
|
||||
Tree.background = @componentBackground
|
||||
Tree.selectionInactiveBackground = @selectionInactiveBackground
|
||||
Tree.selectionInactiveForeground = @selectionInactiveForeground
|
||||
Tree.textBackground = $Tree.background
|
||||
|
||||
@@ -32,24 +32,50 @@
|
||||
|
||||
#---- variables ----
|
||||
|
||||
# general background and foreground (text color)
|
||||
@background = #f2f2f2
|
||||
@foreground = #000
|
||||
@selectionBackground = #2675BF
|
||||
@selectionForeground = #fff
|
||||
@selectionInactiveBackground = #d4d4d4
|
||||
@disabledBackground = @background
|
||||
@disabledForeground = tint(@foreground,55%)
|
||||
|
||||
# component background
|
||||
@buttonBackground = lighten(@background,5%)
|
||||
@componentBackground = lighten(@background,5%)
|
||||
@menuBackground = lighten(@background,5%)
|
||||
|
||||
# selection
|
||||
@selectionBackground = @accentSelectionBackground
|
||||
@selectionForeground = contrast(@selectionBackground, @foreground, #fff)
|
||||
@selectionInactiveBackground = shade(@background,13%)
|
||||
@selectionInactiveForeground = @foreground
|
||||
@disabledText = #8C8C8C
|
||||
@textComponentBackground = #fff
|
||||
@menuBackground = #fff
|
||||
|
||||
# menu
|
||||
@menuHoverBackground = darken(@menuBackground,10%,derived)
|
||||
@menuCheckBackground = lighten(@selectionBackground,40%,derived noAutoInverse)
|
||||
@menuAcceleratorForeground = lighten(@foreground,30%)
|
||||
@menuAcceleratorSelectionForeground = @selectionForeground
|
||||
|
||||
# misc
|
||||
@cellFocusColor = #000
|
||||
@icon = #afafaf
|
||||
@icon = shade(@background,27%)
|
||||
|
||||
# accent colors (blueish)
|
||||
# set @accentColor to use single accent color or
|
||||
# modify @accentBaseColor to use variations of accent base color
|
||||
@accentColor = null
|
||||
@accentBaseColor = #2675BF
|
||||
@accentBase2Color = lighten(saturate(@accentBaseColor,10%),6%)
|
||||
# accent color variations
|
||||
@accentCheckmarkColor = if(@accentColor, @accentColor, tint(@accentBase2Color,20%))
|
||||
@accentFocusColor = if(@accentColor, @accentColor, lighten(@accentBaseColor,31%))
|
||||
@accentLinkColor = if(@accentColor, @accentColor, darken(@accentBaseColor,3%))
|
||||
@accentSelectionBackground = if(@accentColor, @accentColor, @accentBaseColor)
|
||||
@accentSliderColor = if(@accentColor, @accentColor, @accentBase2Color)
|
||||
@accentUnderlineColor = if(@accentColor, @accentColor, tint(@accentBaseColor,10%))
|
||||
@accentButtonDefaultBorderColor = if(@accentColor, @accentColor, tint(@accentBase2Color,20%))
|
||||
|
||||
# for buttons within components (e.g. combobox or spinner)
|
||||
@buttonArrowColor = #666
|
||||
@buttonArrowColor = tint(@foreground,40%)
|
||||
@buttonDisabledArrowColor = lighten(@buttonArrowColor,25%)
|
||||
@buttonHoverArrowColor = lighten(@buttonArrowColor,20%,derived noAutoInverse)
|
||||
@buttonPressedArrowColor = lighten(@buttonArrowColor,30%,derived noAutoInverse)
|
||||
@@ -72,12 +98,12 @@ controlDkShadow = darken($controlShadow,15%)
|
||||
|
||||
#---- Button ----
|
||||
|
||||
Button.background = #fff
|
||||
Button.focusedBackground = #e3f1fa
|
||||
Button.background = @buttonBackground
|
||||
Button.focusedBackground = changeLightness($Component.focusColor,95%)
|
||||
Button.hoverBackground = darken($Button.background,3%,derived)
|
||||
Button.pressedBackground = darken($Button.background,10%,derived)
|
||||
Button.selectedBackground = darken($Button.background,20%,derived)
|
||||
Button.selectedForeground = @foreground
|
||||
Button.selectedForeground = $Button.foreground
|
||||
Button.disabledSelectedBackground = darken($Button.background,13%,derived)
|
||||
|
||||
Button.borderColor = $Component.borderColor
|
||||
@@ -88,11 +114,11 @@ Button.hoverBorderColor = $Button.focusedBorderColor
|
||||
Button.innerFocusWidth = 0
|
||||
|
||||
Button.default.background = $Button.background
|
||||
Button.default.foreground = @foreground
|
||||
Button.default.foreground = $Button.foreground
|
||||
Button.default.focusedBackground = $Button.focusedBackground
|
||||
Button.default.hoverBackground = darken($Button.default.background,3%,derived)
|
||||
Button.default.pressedBackground = darken($Button.default.background,10%,derived)
|
||||
Button.default.borderColor = #4F9EE3
|
||||
Button.default.borderColor = @accentButtonDefaultBorderColor
|
||||
Button.default.hoverBorderColor = $Button.hoverBorderColor
|
||||
Button.default.focusedBorderColor = $Button.focusedBorderColor
|
||||
Button.default.focusColor = $Component.focusColor
|
||||
@@ -105,57 +131,62 @@ Button.toolbar.selectedBackground = $Button.selectedBackground
|
||||
|
||||
#---- CheckBox ----
|
||||
|
||||
CheckBox.icon.focusWidth = 1
|
||||
|
||||
# enabled
|
||||
CheckBox.icon.borderColor = #b0b0b0
|
||||
CheckBox.icon.background = #fff
|
||||
CheckBox.icon.selectedBorderColor = $CheckBox.icon.borderColor
|
||||
CheckBox.icon.borderColor = shade($Component.borderColor,10%)
|
||||
CheckBox.icon.background = @buttonBackground
|
||||
CheckBox.icon.selectedBorderColor = $CheckBox.icon.checkmarkColor
|
||||
CheckBox.icon.selectedBackground = $CheckBox.icon.background
|
||||
CheckBox.icon.checkmarkColor = #4F9EE3
|
||||
CheckBox.icon.checkmarkColor = @accentCheckmarkColor
|
||||
|
||||
# disabled
|
||||
CheckBox.icon.disabledBorderColor = #BDBDBD
|
||||
CheckBox.icon.disabledBackground = @background
|
||||
CheckBox.icon.disabledCheckmarkColor = #ABABAB
|
||||
CheckBox.icon.disabledBorderColor = tint($CheckBox.icon.borderColor,20%)
|
||||
CheckBox.icon.disabledBackground = @disabledBackground
|
||||
CheckBox.icon.disabledCheckmarkColor = lighten(changeSaturation($CheckBox.icon.checkmarkColor,0%),5%)
|
||||
|
||||
# focused
|
||||
CheckBox.icon.focusedBorderColor = #7B9FC7
|
||||
CheckBox.icon.focusedBackground = $Button.focusedBackground
|
||||
CheckBox.icon.focusedBorderColor = shade($Component.focusedBorderColor,10%)
|
||||
CheckBox.icon.focusedBackground = changeLightness($Component.focusColor,95%)
|
||||
|
||||
# hover
|
||||
CheckBox.icon.hoverBorderColor = $CheckBox.icon.focusedBorderColor
|
||||
CheckBox.icon.hoverBackground = $Button.hoverBackground
|
||||
CheckBox.icon.hoverBackground = darken($CheckBox.icon.background,3%,derived)
|
||||
|
||||
# pressed
|
||||
CheckBox.icon.pressedBackground = $Button.pressedBackground
|
||||
CheckBox.icon.pressedBorderColor = $CheckBox.icon.focusedBorderColor
|
||||
CheckBox.icon.pressedBackground = darken($CheckBox.icon.background,10%,derived)
|
||||
|
||||
|
||||
# used if CheckBox.icon.style = filled
|
||||
# used if CheckBox.icon.style or RadioButton.icon.style = filled
|
||||
# enabled
|
||||
CheckBox.icon[filled].selectedBorderColor = #4B97D9
|
||||
CheckBox.icon[filled].selectedBackground = #4F9EE3
|
||||
CheckBox.icon[filled].checkmarkColor = #fff
|
||||
CheckBox.icon[filled].selectedBorderColor = shade($CheckBox.icon[filled].selectedBackground,5%)
|
||||
CheckBox.icon[filled].selectedBackground = @accentCheckmarkColor
|
||||
CheckBox.icon[filled].checkmarkColor = @buttonBackground
|
||||
# focused
|
||||
CheckBox.icon[filled].selectedFocusedBorderColor = #ACCFF7
|
||||
CheckBox.icon[filled].selectedFocusedBackground = $CheckBox.icon[filled].selectedBackground
|
||||
CheckBox.icon[filled].selectedFocusedCheckmarkColor = $CheckBox.icon.focusedBackground
|
||||
CheckBox.icon[filled].focusedSelectedBorderColor = tint($CheckBox.icon[filled].selectedBackground,50%)
|
||||
CheckBox.icon[filled].focusedSelectedBackground = $CheckBox.icon[filled].selectedBackground
|
||||
CheckBox.icon[filled].focusedCheckmarkColor = $CheckBox.icon.focusedBackground
|
||||
# hover
|
||||
CheckBox.icon[filled].selectedHoverBackground = darken($CheckBox.icon[filled].selectedBackground,5%,derived)
|
||||
CheckBox.icon[filled].hoverSelectedBackground = darken($CheckBox.icon[filled].selectedBackground,5%,derived)
|
||||
# pressed
|
||||
CheckBox.icon[filled].selectedPressedBackground = darken($CheckBox.icon[filled].selectedBackground,10%,derived)
|
||||
CheckBox.icon[filled].pressedSelectedBackground = darken($CheckBox.icon[filled].selectedBackground,10%,derived)
|
||||
|
||||
|
||||
#---- ComboBox ----
|
||||
#---- CheckBoxMenuItem ----
|
||||
|
||||
ComboBox.buttonEditableBackground = darken($ComboBox.background,2%)
|
||||
CheckBoxMenuItem.icon.checkmarkColor = @accentCheckmarkColor
|
||||
CheckBoxMenuItem.icon.disabledCheckmarkColor = @buttonDisabledArrowColor
|
||||
|
||||
|
||||
#---- Component ----
|
||||
|
||||
Component.borderColor = #c4c4c4
|
||||
Component.disabledBorderColor = #cfcfcf
|
||||
Component.focusedBorderColor = #87afda
|
||||
Component.focusColor = #97c3f3
|
||||
Component.linkColor = #2470B3
|
||||
Component.borderColor = shade(@background,20%)
|
||||
Component.disabledBorderColor = tint($Component.borderColor,20%)
|
||||
Component.focusedBorderColor = shade($Component.focusColor,10%)
|
||||
Component.focusColor = @accentFocusColor
|
||||
Component.linkColor = @accentLinkColor
|
||||
Component.accentColor = if(@accentColor, @accentColor, @accentBaseColor)
|
||||
Component.grayFilter = 25,-25,100
|
||||
|
||||
Component.error.borderColor = lighten(desaturate($Component.error.focusedBorderColor,20%),25%)
|
||||
@@ -177,18 +208,19 @@ DesktopIcon.background = darken($Desktop.background,10%,derived)
|
||||
|
||||
#---- HelpButton ----
|
||||
|
||||
HelpButton.questionMarkColor = #4F9EE3
|
||||
HelpButton.questionMarkColor = @accentCheckmarkColor
|
||||
HelpButton.disabledQuestionMarkColor = shade(@background,30%)
|
||||
|
||||
|
||||
#---- InternalFrame ----
|
||||
|
||||
InternalFrame.activeTitleBackground = #fff
|
||||
InternalFrame.activeTitleForeground = @foreground
|
||||
InternalFrame.inactiveTitleBackground = #fafafa
|
||||
InternalFrame.inactiveTitleForeground = @disabledText
|
||||
InternalFrame.inactiveTitleBackground = darken($InternalFrame.activeTitleBackground,2%)
|
||||
InternalFrame.inactiveTitleForeground = @disabledForeground
|
||||
|
||||
InternalFrame.activeBorderColor = darken($Component.borderColor,20%)
|
||||
InternalFrame.inactiveBorderColor = $Component.borderColor
|
||||
InternalFrame.activeBorderColor = shade(@background,40%)
|
||||
InternalFrame.inactiveBorderColor = shade(@background,20%)
|
||||
|
||||
InternalFrame.buttonHoverBackground = darken($InternalFrame.activeTitleBackground,10%,derived)
|
||||
InternalFrame.buttonPressedBackground = darken($InternalFrame.activeTitleBackground,20%,derived)
|
||||
@@ -203,19 +235,13 @@ InternalFrame.inactiveDropShadowOpacity = 0.5
|
||||
|
||||
#---- Menu ----
|
||||
|
||||
Menu.icon.arrowColor = #666
|
||||
Menu.icon.disabledArrowColor = #ABABAB
|
||||
Menu.icon.arrowColor = @buttonArrowColor
|
||||
Menu.icon.disabledArrowColor = @buttonDisabledArrowColor
|
||||
|
||||
|
||||
#---- MenuBar ----
|
||||
|
||||
MenuBar.borderColor = #cdcdcd
|
||||
|
||||
|
||||
#---- MenuItemCheckBox ----
|
||||
|
||||
MenuItemCheckBox.icon.checkmarkColor = #4F9EE3
|
||||
MenuItemCheckBox.icon.disabledCheckmarkColor = #ABABAB
|
||||
MenuBar.borderColor = $Separator.foreground
|
||||
|
||||
|
||||
#---- PasswordField ----
|
||||
@@ -231,15 +257,15 @@ Popup.dropShadowOpacity = 0.15
|
||||
|
||||
#---- PopupMenu ----
|
||||
|
||||
PopupMenu.borderColor = #adadad
|
||||
PopupMenu.borderColor = shade(@background,28%)
|
||||
|
||||
|
||||
#---- ProgressBar ----
|
||||
|
||||
ProgressBar.background = #D1D1D1
|
||||
ProgressBar.foreground = #1E82E6
|
||||
ProgressBar.selectionForeground = @textComponentBackground
|
||||
ProgressBar.background = darken(@background,13%)
|
||||
ProgressBar.foreground = @accentSliderColor
|
||||
ProgressBar.selectionBackground = @foreground
|
||||
ProgressBar.selectionForeground = contrast($ProgressBar.foreground, @foreground, @componentBackground)
|
||||
|
||||
|
||||
#---- RootPane ----
|
||||
@@ -261,40 +287,40 @@ ScrollBar.pressedButtonBackground = darken(@background,10%,derived noAutoInverse
|
||||
|
||||
#---- Separator ----
|
||||
|
||||
Separator.foreground = #d1d1d1
|
||||
Separator.foreground = shade(@background,15%)
|
||||
|
||||
|
||||
#---- Slider ----
|
||||
|
||||
Slider.trackValueColor = #1E82E6
|
||||
Slider.trackColor = #c4c4c4
|
||||
Slider.trackValueColor = @accentSliderColor
|
||||
Slider.trackColor = darken(@background,18%)
|
||||
Slider.thumbColor = $Slider.trackValueColor
|
||||
Slider.tickColor = #888
|
||||
Slider.tickColor = @disabledForeground
|
||||
Slider.focusedColor = fade($Component.focusColor,50%,derived)
|
||||
Slider.hoverThumbColor = darken($Slider.thumbColor,5%,derived)
|
||||
Slider.pressedThumbColor = darken($Slider.thumbColor,8%,derived)
|
||||
Slider.disabledTrackColor = #c0c0c0
|
||||
Slider.disabledTrackColor = darken(@background,13%)
|
||||
Slider.disabledThumbColor = $Slider.disabledTrackColor
|
||||
|
||||
|
||||
#---- SplitPane ----
|
||||
|
||||
SplitPaneDivider.draggingColor = #c4c4c4
|
||||
SplitPaneDivider.draggingColor = $Component.borderColor
|
||||
|
||||
|
||||
#---- TabbedPane ----
|
||||
|
||||
TabbedPane.underlineColor = #4083C9
|
||||
TabbedPane.disabledUnderlineColor = #ababab
|
||||
TabbedPane.underlineColor = @accentUnderlineColor
|
||||
TabbedPane.disabledUnderlineColor = darken(@background,28%)
|
||||
TabbedPane.hoverColor = darken($TabbedPane.background,7%,derived)
|
||||
TabbedPane.focusColor = #dae4ed
|
||||
TabbedPane.contentAreaColor = #bfbfbf
|
||||
TabbedPane.focusColor = mix(@selectionBackground,$TabbedPane.background,10%)
|
||||
TabbedPane.contentAreaColor = $Component.borderColor
|
||||
|
||||
TabbedPane.buttonHoverBackground = darken($TabbedPane.background,7%,derived)
|
||||
TabbedPane.buttonPressedBackground = darken($TabbedPane.background,10%,derived)
|
||||
|
||||
TabbedPane.closeBackground = null
|
||||
TabbedPane.closeForeground = @disabledText
|
||||
TabbedPane.closeForeground = @disabledForeground
|
||||
TabbedPane.closeHoverBackground = darken($TabbedPane.background,20%,derived)
|
||||
TabbedPane.closeHoverForeground = @foreground
|
||||
TabbedPane.closePressedBackground = darken($TabbedPane.background,25%,derived)
|
||||
@@ -329,8 +355,8 @@ ToggleButton.toolbar.selectedBackground = $ToggleButton.selectedBackground
|
||||
|
||||
#---- ToolTip ----
|
||||
|
||||
ToolTip.border = 4,6,4,6,$InternalFrame.activeBorderColor
|
||||
ToolTip.background = #fafafa
|
||||
ToolTip.border = 4,6,4,6,shade(@background,40%)
|
||||
ToolTip.background = lighten(@background,3%)
|
||||
|
||||
|
||||
#---- Tree ----
|
||||
|
||||
@@ -60,18 +60,18 @@ Button.hoverBorderColor = null
|
||||
Button.default.hoverBorderColor = null
|
||||
|
||||
|
||||
#---- CheckBoxMenuItem ----
|
||||
|
||||
# colors from intellij/checkmark.svg and darcula/checkmark.svg
|
||||
[light]CheckBoxMenuItem.icon.checkmarkColor=#3E3E3C
|
||||
[dark]CheckBoxMenuItem.icon.checkmarkColor=#fff9
|
||||
|
||||
|
||||
#---- HelpButton ----
|
||||
|
||||
HelpButton.hoverBorderColor = null
|
||||
|
||||
|
||||
#---- MenuItemCheckBox ----
|
||||
|
||||
# colors from intellij/checkmark.svg and darcula/checkmark.svg
|
||||
[light]MenuItemCheckBox.icon.checkmarkColor=#3E3E3C
|
||||
[dark]MenuItemCheckBox.icon.checkmarkColor=#fff9
|
||||
|
||||
|
||||
#---- Slider ----
|
||||
|
||||
Slider.focusedColor = fade($Component.focusColor,40%,derived)
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 2021 FormDev Software GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.Insets;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.UIDefaults.ActiveValue;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class TestUIDefaultsLoader
|
||||
{
|
||||
@Test
|
||||
void parseValue() {
|
||||
assertEquals( null, UIDefaultsLoader.parseValue( "dummy", "null", null ) );
|
||||
assertEquals( false, UIDefaultsLoader.parseValue( "dummy", "false", null ) );
|
||||
assertEquals( true, UIDefaultsLoader.parseValue( "dummy", "true", null ) );
|
||||
|
||||
assertEquals( "hello", UIDefaultsLoader.parseValue( "dummy", "hello", null ) );
|
||||
assertEquals( "hello", UIDefaultsLoader.parseValue( "dummy", "\"hello\"", null ) );
|
||||
assertEquals( "null", UIDefaultsLoader.parseValue( "dummy", "\"null\"", null ) );
|
||||
|
||||
assertEquals( 'a', UIDefaultsLoader.parseValue( "dummyChar", "a", null ) );
|
||||
assertEquals( 123, UIDefaultsLoader.parseValue( "dummy", "123", null ) );
|
||||
assertEquals( 123, UIDefaultsLoader.parseValue( "dummyWidth", "123", null ) );
|
||||
assertEquals( 1.23f, UIDefaultsLoader.parseValue( "dummy", "1.23", null ) );
|
||||
assertEquals( 1.23f, UIDefaultsLoader.parseValue( "dummyWidth", "1.23", null ) );
|
||||
|
||||
assertEquals( new Insets( 2,2,2,2 ), UIDefaultsLoader.parseValue( "dummyInsets", "2,2,2,2", null ) );
|
||||
assertEquals( new Dimension( 2,2 ), UIDefaultsLoader.parseValue( "dummySize", "2,2", null ) );
|
||||
assertEquals( new Color( 0xff0000 ), UIDefaultsLoader.parseValue( "dummy", "#f00", null ) );
|
||||
assertEquals( new Color( 0xff0000 ), UIDefaultsLoader.parseValue( "dummyColor", "#f00", null ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
void parseValueWithJavaType() {
|
||||
assertEquals( null, UIDefaultsLoader.parseValue( "dummy", "null", String.class ) );
|
||||
assertEquals( false, UIDefaultsLoader.parseValue( "dummy", "false", boolean.class ) );
|
||||
assertEquals( true, UIDefaultsLoader.parseValue( "dummy", "true", Boolean.class ) );
|
||||
|
||||
assertEquals( "hello", UIDefaultsLoader.parseValue( "dummy", "hello", String.class ) );
|
||||
assertEquals( "hello", UIDefaultsLoader.parseValue( "dummy", "\"hello\"", String.class ) );
|
||||
assertEquals( "null", UIDefaultsLoader.parseValue( "dummy", "\"null\"", String.class ) );
|
||||
assertEquals( null, UIDefaultsLoader.parseValue( "dummy", "null", String.class ) );
|
||||
|
||||
assertEquals( 'a', UIDefaultsLoader.parseValue( "dummy", "a", char.class ) );
|
||||
assertEquals( 'a', UIDefaultsLoader.parseValue( "dummy", "a", Character.class ) );
|
||||
assertEquals( 123, UIDefaultsLoader.parseValue( "dummy", "123", int.class ) );
|
||||
assertEquals( 123, UIDefaultsLoader.parseValue( "dummy", "123", Integer.class ) );
|
||||
assertEquals( 1.23f, UIDefaultsLoader.parseValue( "dummy", "1.23", float.class ) );
|
||||
assertEquals( 1.23f, UIDefaultsLoader.parseValue( "dummy", "1.23", Float.class ) );
|
||||
|
||||
assertEquals( new Insets( 2,2,2,2 ), UIDefaultsLoader.parseValue( "dummy", "2,2,2,2", Insets.class ) );
|
||||
assertEquals( new Dimension( 2,2 ), UIDefaultsLoader.parseValue( "dummy", "2,2", Dimension.class ) );
|
||||
assertEquals( new Color( 0xff0000 ), UIDefaultsLoader.parseValue( "dummy", "#f00", Color.class ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
void parseFonts() {
|
||||
// style
|
||||
UIManager.put( "defaultFont", new Font( Font.DIALOG, Font.PLAIN, 10 ) );
|
||||
assertFontEquals( Font.DIALOG, Font.PLAIN, 10, "normal" );
|
||||
assertFontEquals( Font.DIALOG, Font.BOLD, 10, "bold" );
|
||||
assertFontEquals( Font.DIALOG, Font.ITALIC, 10, "italic" );
|
||||
assertFontEquals( Font.DIALOG, Font.BOLD|Font.ITALIC, 10, "bold italic" );
|
||||
|
||||
// derived style
|
||||
assertFontEquals( Font.DIALOG, Font.BOLD, 10, "+bold" );
|
||||
assertFontEquals( Font.DIALOG, Font.ITALIC, 10, "+italic" );
|
||||
assertFontEquals( Font.DIALOG, Font.BOLD|Font.ITALIC, 10, "+bold +italic" );
|
||||
UIManager.put( "defaultFont", new Font( Font.DIALOG, Font.BOLD|Font.ITALIC, 10 ) );
|
||||
assertFontEquals( Font.DIALOG, Font.ITALIC, 10, "-bold" );
|
||||
assertFontEquals( Font.DIALOG, Font.BOLD, 10, "-italic" );
|
||||
assertFontEquals( Font.DIALOG, Font.PLAIN, 10, "-bold -italic" );
|
||||
UIManager.put( "defaultFont", new Font( Font.DIALOG, Font.BOLD, 10 ) );
|
||||
assertFontEquals( Font.DIALOG, Font.ITALIC, 10, "-bold +italic" );
|
||||
|
||||
// size
|
||||
UIManager.put( "defaultFont", new Font( Font.DIALOG, Font.PLAIN, 10 ) );
|
||||
assertFontEquals( Font.DIALOG, Font.PLAIN, 12, "12" );
|
||||
assertFontEquals( Font.DIALOG, Font.PLAIN, 13, "+3" );
|
||||
assertFontEquals( Font.DIALOG, Font.PLAIN, 6, "-4" );
|
||||
assertFontEquals( Font.DIALOG, Font.PLAIN, 15, "150%" );
|
||||
|
||||
// family
|
||||
assertFontEquals( Font.MONOSPACED, Font.PLAIN, 10, "Monospaced" );
|
||||
assertFontEquals( Font.MONOSPACED, Font.PLAIN, 10, "Monospaced, Dialog" );
|
||||
assertFontEquals( Font.DIALOG, Font.PLAIN, 10, "Dialog, Monospaced" );
|
||||
|
||||
// unknown family
|
||||
assertFontEquals( Font.MONOSPACED, Font.PLAIN, 12, "normal 12 UnknownFamily, Monospaced" );
|
||||
assertFontEquals( Font.DIALOG, Font.PLAIN, 12, "normal 12 UnknownFamily, Dialog" );
|
||||
assertFontEquals( Font.DIALOG, Font.PLAIN, 12, "normal 12 UnknownFamily, 'Another unknown family'" );
|
||||
|
||||
// all
|
||||
assertFontEquals( Font.MONOSPACED, Font.BOLD, 13, "bold 13 Monospaced" );
|
||||
assertFontEquals( Font.DIALOG, Font.ITALIC, 14, "italic 14 Dialog" );
|
||||
assertFontEquals( Font.DIALOG, Font.BOLD|Font.ITALIC, 15, "bold italic 15 Dialog" );
|
||||
|
||||
UIManager.put( "defaultFont", null );
|
||||
}
|
||||
|
||||
private void assertFontEquals( String name, int style, int size, String actualStyle ) {
|
||||
assertEquals(
|
||||
new Font( name, style, size ),
|
||||
((ActiveValue)UIDefaultsLoader.parseValue( "dummyFont", actualStyle, null )).createValue( null ) );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,464 @@
|
||||
/*
|
||||
* Copyright 2021 FormDev Software GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.util.Arrays;
|
||||
import javax.swing.*;
|
||||
import javax.swing.table.JTableHeader;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.FlatSystemProperties;
|
||||
|
||||
/**
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class TestFlatStyleClasses
|
||||
{
|
||||
private static final String BUTTON_PRIMARY = "borderColor: #08f; background: #08f; foreground: #fff";
|
||||
private static final String SECONDARY = "borderColor: #0f8; background: #0f8";
|
||||
private static final String TOGGLE_BUTTON_SECONDARY = "selectedBackground: #f00";
|
||||
private static final String BACKGROUND = "background: #f0f";
|
||||
|
||||
@BeforeAll
|
||||
static void setup() {
|
||||
System.setProperty( FlatSystemProperties.UI_SCALE_ENABLED, "false" );
|
||||
TestUtils.setup( false );
|
||||
|
||||
UIManager.put( "[style]Button.primary", BUTTON_PRIMARY );
|
||||
UIManager.put( "[style].secondary", SECONDARY );
|
||||
UIManager.put( "[style]ToggleButton.secondary", TOGGLE_BUTTON_SECONDARY );
|
||||
UIManager.put( "[style].test", BACKGROUND );
|
||||
|
||||
UIManager.put( "[style]Button.test", "foreground: #000001" );
|
||||
UIManager.put( "[style]CheckBox.test", "foreground: #000002" );
|
||||
UIManager.put( "[style]ComboBox.test", "foreground: #000003" );
|
||||
UIManager.put( "[style]EditorPane.test", "foreground: #000004" );
|
||||
UIManager.put( "[style]FormattedTextField.test", "foreground: #000005" );
|
||||
UIManager.put( "[style]InternalFrame.test", "foreground: #000006" );
|
||||
UIManager.put( "[style]Label.test", "foreground: #000007" );
|
||||
UIManager.put( "[style]List.test", "foreground: #000008" );
|
||||
UIManager.put( "[style]MenuBar.test", "foreground: #000009" );
|
||||
UIManager.put( "[style]Menu.test", "foreground: #000010" );
|
||||
UIManager.put( "[style]MenuItem.test", "foreground: #000011" );
|
||||
UIManager.put( "[style]CheckBoxMenuItem.test", "foreground: #000012" );
|
||||
UIManager.put( "[style]RadioButtonMenuItem.test", "foreground: #000013" );
|
||||
UIManager.put( "[style]PasswordField.test", "foreground: #000014" );
|
||||
UIManager.put( "[style]PopupMenu.test", "foreground: #000015" );
|
||||
UIManager.put( "[style]PopupMenuSeparator.test", "foreground: #000016" );
|
||||
UIManager.put( "[style]ProgressBar.test", "foreground: #000017" );
|
||||
UIManager.put( "[style]RadioButton.test", "foreground: #000018" );
|
||||
UIManager.put( "[style]ScrollBar.test", "foreground: #000019" );
|
||||
UIManager.put( "[style]ScrollPane.test", "foreground: #000020" );
|
||||
UIManager.put( "[style]Separator.test", "foreground: #000021" );
|
||||
UIManager.put( "[style]Slider.test", "foreground: #000022" );
|
||||
UIManager.put( "[style]Spinner.test", "foreground: #000023" );
|
||||
UIManager.put( "[style]SplitPane.test", "foreground: #000024" );
|
||||
UIManager.put( "[style]TabbedPane.test", "foreground: #000025" );
|
||||
UIManager.put( "[style]Table.test", "foreground: #000026" );
|
||||
UIManager.put( "[style]TableHeader.test", "foreground: #000027" );
|
||||
UIManager.put( "[style]TextArea.test", "foreground: #000028" );
|
||||
UIManager.put( "[style]TextField.test", "foreground: #000029" );
|
||||
UIManager.put( "[style]TextPane.test", "foreground: #000030" );
|
||||
UIManager.put( "[style]ToggleButton.test", "foreground: #000031" );
|
||||
UIManager.put( "[style]ToolBar.test", "foreground: #000032" );
|
||||
UIManager.put( "[style]Tree.test", "foreground: #000033" );
|
||||
|
||||
// for shared UIs
|
||||
UIManager.put( "[style]Button.test2", "foreground: #000100" );
|
||||
UIManager.put( "[style]CheckBox.test2", "foreground: #000200" );
|
||||
UIManager.put( "[style]Label.test2", "foreground: #000700" );
|
||||
UIManager.put( "[style]PopupMenuSeparator.test2", "foreground: #001600" );
|
||||
UIManager.put( "[style]RadioButton.test2", "foreground: #001800" );
|
||||
UIManager.put( "[style]Separator.test2", "foreground: #002100" );
|
||||
UIManager.put( "[style]ToggleButton.test2", "foreground: #003100" );
|
||||
|
||||
// JToolBar.Separator
|
||||
UIManager.put( "[style]ToolBarSeparator.toolbar-separator-test", "separatorWidth: 21" );
|
||||
UIManager.put( "[style]ToolBarSeparator.toolbar-separator-test2", "separatorWidth: 31" );
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void cleanup() {
|
||||
TestUtils.cleanup();
|
||||
System.clearProperty( FlatSystemProperties.UI_SCALE_ENABLED );
|
||||
}
|
||||
|
||||
@Test
|
||||
void styleForClass() {
|
||||
assertEquals( null, FlatStylingSupport.getStyleForClasses( "foo", "Button" ) );
|
||||
|
||||
assertEquals( BUTTON_PRIMARY, FlatStylingSupport.getStyleForClasses( "primary", "Button" ) );
|
||||
assertEquals( SECONDARY, FlatStylingSupport.getStyleForClasses( "secondary", "Button" ) );
|
||||
|
||||
assertEquals(
|
||||
FlatStylingSupport.concatStyles( SECONDARY, TOGGLE_BUTTON_SECONDARY ),
|
||||
FlatStylingSupport.getStyleForClasses( "secondary", "ToggleButton" ) );
|
||||
|
||||
assertEquals(
|
||||
FlatStylingSupport.concatStyles( BUTTON_PRIMARY, SECONDARY ),
|
||||
FlatStylingSupport.getStyleForClasses( "primary secondary", "Button" ) );
|
||||
assertEquals(
|
||||
FlatStylingSupport.concatStyles( SECONDARY, BUTTON_PRIMARY ),
|
||||
FlatStylingSupport.getStyleForClasses( "secondary primary", "Button" ) );
|
||||
|
||||
// String
|
||||
assertEquals(
|
||||
FlatStylingSupport.concatStyles( SECONDARY, BUTTON_PRIMARY ),
|
||||
FlatStylingSupport.getStyleForClasses( " secondary primary bla blu ", "Button" ) );
|
||||
|
||||
// String[]
|
||||
assertEquals(
|
||||
FlatStylingSupport.concatStyles( SECONDARY, BUTTON_PRIMARY ),
|
||||
FlatStylingSupport.getStyleForClasses( new String[] { "secondary", "primary" }, "Button" ) );
|
||||
|
||||
// List<String>
|
||||
assertEquals(
|
||||
FlatStylingSupport.concatStyles( SECONDARY, BUTTON_PRIMARY ),
|
||||
FlatStylingSupport.getStyleForClasses( Arrays.asList( "secondary", "primary" ), "Button" ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
void apply1() {
|
||||
JButton c = new JButton();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "primary" );
|
||||
|
||||
assertEquals( new Color( 0x0088ff ), c.getBackground() );
|
||||
assertEquals( Color.white, c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void apply2() {
|
||||
JButton c = new JButton();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "primary secondary" );
|
||||
|
||||
assertEquals( new Color( 0x00ff88 ), c.getBackground() );
|
||||
assertEquals( Color.white, c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void apply3() {
|
||||
JButton c = new JButton();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "secondary primary" );
|
||||
|
||||
assertEquals( new Color( 0x0088ff ), c.getBackground() );
|
||||
assertEquals( Color.white, c.getForeground() );
|
||||
}
|
||||
|
||||
//---- components ---------------------------------------------------------
|
||||
|
||||
@Test
|
||||
void button() {
|
||||
JButton c = new JButton();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" );
|
||||
assertEquals( Color.magenta, c.getBackground() );
|
||||
assertEquals( new Color( 0x000001 ), c.getForeground() );
|
||||
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test2" );
|
||||
assertEquals( new Color( 0x000100 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void checkBox() {
|
||||
JCheckBox c = new JCheckBox();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" );
|
||||
assertEquals( Color.magenta, c.getBackground() );
|
||||
assertEquals( new Color( 0x000002 ), c.getForeground() );
|
||||
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test2" );
|
||||
assertEquals( new Color( 0x000200 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void comboBox() {
|
||||
JComboBox<Object> c = new JComboBox<>();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" );
|
||||
assertEquals( Color.magenta, c.getBackground() );
|
||||
assertEquals( new Color( 0x000003 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void editorPane() {
|
||||
JEditorPane c = new JEditorPane();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" );
|
||||
assertEquals( Color.magenta, c.getBackground() );
|
||||
assertEquals( new Color( 0x000004 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void formattedTextField() {
|
||||
JFormattedTextField c = new JFormattedTextField();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" );
|
||||
assertEquals( Color.magenta, c.getBackground() );
|
||||
assertEquals( new Color( 0x000005 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void internalFrame() {
|
||||
JInternalFrame c = new JInternalFrame();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" );
|
||||
assertEquals( Color.magenta, c.getBackground() );
|
||||
assertEquals( new Color( 0x000006 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void label() {
|
||||
JLabel c = new JLabel();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" );
|
||||
assertEquals( Color.magenta, c.getBackground() );
|
||||
assertEquals( new Color( 0x000007 ), c.getForeground() );
|
||||
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test2" );
|
||||
assertEquals( new Color( 0x000700 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void list() {
|
||||
JList<Object> c = new JList<>();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" );
|
||||
assertEquals( Color.magenta, c.getBackground() );
|
||||
assertEquals( new Color( 0x000008 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void menuBar() {
|
||||
JMenuBar c = new JMenuBar();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" );
|
||||
assertEquals( Color.magenta, c.getBackground() );
|
||||
assertEquals( new Color( 0x000009 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void menu() {
|
||||
JMenu c = new JMenu();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" );
|
||||
assertEquals( Color.magenta, c.getBackground() );
|
||||
assertEquals( new Color( 0x000010 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void menuItem() {
|
||||
JMenuItem c = new JMenuItem();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" );
|
||||
assertEquals( Color.magenta, c.getBackground() );
|
||||
assertEquals( new Color( 0x000011 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void checkBoxMenuItem() {
|
||||
JCheckBoxMenuItem c = new JCheckBoxMenuItem();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" );
|
||||
assertEquals( Color.magenta, c.getBackground() );
|
||||
assertEquals( new Color( 0x000012 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void radioButtonMenuItem() {
|
||||
JRadioButtonMenuItem c = new JRadioButtonMenuItem();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" );
|
||||
assertEquals( Color.magenta, c.getBackground() );
|
||||
assertEquals( new Color( 0x000013 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void passwordField() {
|
||||
JPasswordField c = new JPasswordField();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" );
|
||||
assertEquals( Color.magenta, c.getBackground() );
|
||||
assertEquals( new Color( 0x000014 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void popupMenu() {
|
||||
JPopupMenu c = new JPopupMenu();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" );
|
||||
assertEquals( Color.magenta, c.getBackground() );
|
||||
assertEquals( new Color( 0x000015 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void popupMenuSeparator() {
|
||||
JPopupMenu.Separator c = new JPopupMenu.Separator();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" );
|
||||
assertEquals( Color.magenta, c.getBackground() );
|
||||
assertEquals( new Color( 0x000016 ), c.getForeground() );
|
||||
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test2" );
|
||||
assertEquals( new Color( 0x001600 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void progressBar() {
|
||||
JProgressBar c = new JProgressBar();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" );
|
||||
assertEquals( Color.magenta, c.getBackground() );
|
||||
assertEquals( new Color( 0x000017 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void radioButton() {
|
||||
JRadioButton c = new JRadioButton();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" );
|
||||
assertEquals( Color.magenta, c.getBackground() );
|
||||
assertEquals( new Color( 0x000018 ), c.getForeground() );
|
||||
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test2" );
|
||||
assertEquals( new Color( 0x001800 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void scrollBar() {
|
||||
JScrollBar c = new JScrollBar();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" );
|
||||
assertEquals( Color.magenta, c.getBackground() );
|
||||
assertEquals( new Color( 0x000019 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void scrollPane() {
|
||||
JScrollPane c = new JScrollPane();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" );
|
||||
assertEquals( Color.magenta, c.getBackground() );
|
||||
assertEquals( new Color( 0x000020 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void separator() {
|
||||
JSeparator c = new JSeparator();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" );
|
||||
assertEquals( Color.magenta, c.getBackground() );
|
||||
assertEquals( new Color( 0x000021 ), c.getForeground() );
|
||||
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test2" );
|
||||
assertEquals( new Color( 0x002100 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void slider() {
|
||||
JSlider c = new JSlider();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" );
|
||||
assertEquals( Color.magenta, c.getBackground() );
|
||||
assertEquals( new Color( 0x000022 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void spinner() {
|
||||
JSpinner c = new JSpinner();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" );
|
||||
assertEquals( Color.magenta, c.getBackground() );
|
||||
assertEquals( new Color( 0x000023 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void splitPane() {
|
||||
JSplitPane c = new JSplitPane();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" );
|
||||
assertEquals( Color.magenta, c.getBackground() );
|
||||
assertEquals( new Color( 0x000024 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void tabbedPane() {
|
||||
JTabbedPane c = new JTabbedPane();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" );
|
||||
assertEquals( Color.magenta, c.getBackground() );
|
||||
assertEquals( new Color( 0x000025 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void table() {
|
||||
JTable c = new JTable();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" );
|
||||
assertEquals( Color.magenta, c.getBackground() );
|
||||
assertEquals( new Color( 0x000026 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void tableHeader() {
|
||||
JTableHeader c = new JTableHeader();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" );
|
||||
assertEquals( Color.magenta, c.getBackground() );
|
||||
assertEquals( new Color( 0x000027 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void textArea() {
|
||||
JTextArea c = new JTextArea();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" );
|
||||
assertEquals( Color.magenta, c.getBackground() );
|
||||
assertEquals( new Color( 0x000028 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void textField() {
|
||||
JTextField c = new JTextField();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" );
|
||||
assertEquals( Color.magenta, c.getBackground() );
|
||||
assertEquals( new Color( 0x000029 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void textPane() {
|
||||
JTextPane c = new JTextPane();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" );
|
||||
assertEquals( Color.magenta, c.getBackground() );
|
||||
assertEquals( new Color( 0x000030 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void toggleButton() {
|
||||
JToggleButton c = new JToggleButton();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" );
|
||||
assertEquals( Color.magenta, c.getBackground() );
|
||||
assertEquals( new Color( 0x000031 ), c.getForeground() );
|
||||
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test2" );
|
||||
assertEquals( new Color( 0x003100 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void toolBar() {
|
||||
JToolBar c = new JToolBar();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" );
|
||||
assertEquals( Color.magenta, c.getBackground() );
|
||||
assertEquals( new Color( 0x000032 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void toolBarSeparator() {
|
||||
JToolBar.Separator c = new JToolBar.Separator();
|
||||
assertEquals( new Dimension( 0, 7 ), c.getPreferredSize() );
|
||||
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "toolbar-separator-test" );
|
||||
assertEquals( new Dimension( 0, 21 ), c.getPreferredSize() );
|
||||
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "toolbar-separator-test2" );
|
||||
assertEquals( new Dimension( 0, 31 ), c.getPreferredSize() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void tree() {
|
||||
JTree c = new JTree();
|
||||
c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" );
|
||||
assertEquals( Color.magenta, c.getBackground() );
|
||||
assertEquals( new Color( 0x000033 ), c.getForeground() );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
* Copyright 2021 FormDev Software GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import javax.swing.*;
|
||||
import javax.swing.table.JTableHeader;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import com.formdev.flatlaf.FlatSystemProperties;
|
||||
|
||||
/**
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class TestFlatStyleType
|
||||
{
|
||||
@BeforeAll
|
||||
static void setup() {
|
||||
System.setProperty( FlatSystemProperties.UI_SCALE_ENABLED, "false" );
|
||||
TestUtils.setup( false );
|
||||
|
||||
UIManager.put( "[style]Button", "foreground: #000001" );
|
||||
UIManager.put( "[style]CheckBox", "foreground: #000002" );
|
||||
UIManager.put( "[style]ComboBox", "foreground: #000003" );
|
||||
UIManager.put( "[style]EditorPane", "foreground: #000004" );
|
||||
UIManager.put( "[style]FormattedTextField", "foreground: #000005" );
|
||||
UIManager.put( "[style]InternalFrame", "foreground: #000006" );
|
||||
UIManager.put( "[style]Label", "foreground: #000007" );
|
||||
UIManager.put( "[style]List", "foreground: #000008" );
|
||||
UIManager.put( "[style]MenuBar", "foreground: #000009" );
|
||||
UIManager.put( "[style]Menu", "foreground: #000010" );
|
||||
UIManager.put( "[style]MenuItem", "foreground: #000011" );
|
||||
UIManager.put( "[style]CheckBoxMenuItem", "foreground: #000012" );
|
||||
UIManager.put( "[style]RadioButtonMenuItem", "foreground: #000013" );
|
||||
UIManager.put( "[style]PasswordField", "foreground: #000014" );
|
||||
UIManager.put( "[style]PopupMenu", "foreground: #000015" );
|
||||
UIManager.put( "[style]PopupMenuSeparator", "foreground: #000016" );
|
||||
UIManager.put( "[style]ProgressBar", "foreground: #000017" );
|
||||
UIManager.put( "[style]RadioButton", "foreground: #000018" );
|
||||
UIManager.put( "[style]ScrollBar", "foreground: #000019" );
|
||||
UIManager.put( "[style]ScrollPane", "foreground: #000020" );
|
||||
UIManager.put( "[style]Separator", "foreground: #000021" );
|
||||
UIManager.put( "[style]Slider", "foreground: #000022" );
|
||||
UIManager.put( "[style]Spinner", "foreground: #000023" );
|
||||
UIManager.put( "[style]SplitPane", "foreground: #000024" );
|
||||
UIManager.put( "[style]TabbedPane", "foreground: #000025" );
|
||||
UIManager.put( "[style]Table", "foreground: #000026" );
|
||||
UIManager.put( "[style]TableHeader", "foreground: #000027" );
|
||||
UIManager.put( "[style]TextArea", "foreground: #000028" );
|
||||
UIManager.put( "[style]TextField", "foreground: #000029" );
|
||||
UIManager.put( "[style]TextPane", "foreground: #000030" );
|
||||
UIManager.put( "[style]ToggleButton", "foreground: #000031" );
|
||||
UIManager.put( "[style]ToolBar", "foreground: #000032" );
|
||||
UIManager.put( "[style]Tree", "foreground: #000033" );
|
||||
|
||||
// JToolBar.Separator
|
||||
UIManager.put( "[style]ToolBarSeparator", "separatorWidth: 21" );
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void cleanup() {
|
||||
TestUtils.cleanup();
|
||||
System.clearProperty( FlatSystemProperties.UI_SCALE_ENABLED );
|
||||
}
|
||||
|
||||
@Test
|
||||
void styleForType() {
|
||||
assertEquals( "foreground: #000001", FlatStylingSupport.getStyleForType( "Button" ) );
|
||||
}
|
||||
|
||||
//---- components ---------------------------------------------------------
|
||||
|
||||
@Test
|
||||
void button() {
|
||||
JButton c = new JButton();
|
||||
assertEquals( new Color( 0x000001 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void checkBox() {
|
||||
JCheckBox c = new JCheckBox();
|
||||
assertEquals( new Color( 0x000002 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void comboBox() {
|
||||
JComboBox<Object> c = new JComboBox<>();
|
||||
assertEquals( new Color( 0x000003 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void editorPane() {
|
||||
JEditorPane c = new JEditorPane();
|
||||
assertEquals( new Color( 0x000004 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void formattedTextField() {
|
||||
JFormattedTextField c = new JFormattedTextField();
|
||||
assertEquals( new Color( 0x000005 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void internalFrame() {
|
||||
JInternalFrame c = new JInternalFrame();
|
||||
assertEquals( new Color( 0x000006 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void label() {
|
||||
JLabel c = new JLabel();
|
||||
assertEquals( new Color( 0x000007 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void list() {
|
||||
JList<Object> c = new JList<>();
|
||||
assertEquals( new Color( 0x000008 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void menuBar() {
|
||||
JMenuBar c = new JMenuBar();
|
||||
assertEquals( new Color( 0x000009 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void menu() {
|
||||
JMenu c = new JMenu();
|
||||
assertEquals( new Color( 0x000010 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void menuItem() {
|
||||
JMenuItem c = new JMenuItem();
|
||||
assertEquals( new Color( 0x000011 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void checkBoxMenuItem() {
|
||||
JCheckBoxMenuItem c = new JCheckBoxMenuItem();
|
||||
assertEquals( new Color( 0x000012 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void radioButtonMenuItem() {
|
||||
JRadioButtonMenuItem c = new JRadioButtonMenuItem();
|
||||
assertEquals( new Color( 0x000013 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void passwordField() {
|
||||
JPasswordField c = new JPasswordField();
|
||||
assertEquals( new Color( 0x000014 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void popupMenu() {
|
||||
JPopupMenu c = new JPopupMenu();
|
||||
assertEquals( new Color( 0x000015 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void popupMenuSeparator() {
|
||||
JPopupMenu.Separator c = new JPopupMenu.Separator();
|
||||
assertEquals( new Color( 0x000016 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void progressBar() {
|
||||
JProgressBar c = new JProgressBar();
|
||||
assertEquals( new Color( 0x000017 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void radioButton() {
|
||||
JRadioButton c = new JRadioButton();
|
||||
assertEquals( new Color( 0x000018 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void scrollBar() {
|
||||
JScrollBar c = new JScrollBar();
|
||||
assertEquals( new Color( 0x000019 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void scrollPane() {
|
||||
JScrollPane c = new JScrollPane();
|
||||
assertEquals( new Color( 0x000020 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void separator() {
|
||||
JSeparator c = new JSeparator();
|
||||
assertEquals( new Color( 0x000021 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void slider() {
|
||||
JSlider c = new JSlider();
|
||||
assertEquals( new Color( 0x000022 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void slider2() {
|
||||
JSlider c = new JSlider();
|
||||
|
||||
// when slider labels are painted, then a Java private subclass of JLabel
|
||||
// is used that overrides getForeground(), which is not accessible via reflection
|
||||
// see class JSlider.SmartHashtable.LabelUIResource
|
||||
c.setPaintLabels( true );
|
||||
c.setMajorTickSpacing( 50 );
|
||||
|
||||
assertEquals( new Color( 0x000022 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void spinner() {
|
||||
JSpinner c = new JSpinner();
|
||||
assertEquals( new Color( 0x000023 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void splitPane() {
|
||||
JSplitPane c = new JSplitPane();
|
||||
assertEquals( new Color( 0x000024 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void tabbedPane() {
|
||||
JTabbedPane c = new JTabbedPane();
|
||||
assertEquals( new Color( 0x000025 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void table() {
|
||||
JTable c = new JTable();
|
||||
assertEquals( new Color( 0x000026 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void tableHeader() {
|
||||
JTableHeader c = new JTableHeader();
|
||||
assertEquals( new Color( 0x000027 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void textArea() {
|
||||
JTextArea c = new JTextArea();
|
||||
assertEquals( new Color( 0x000028 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void textField() {
|
||||
JTextField c = new JTextField();
|
||||
assertEquals( new Color( 0x000029 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void textPane() {
|
||||
JTextPane c = new JTextPane();
|
||||
assertEquals( new Color( 0x000030 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void toggleButton() {
|
||||
JToggleButton c = new JToggleButton();
|
||||
assertEquals( new Color( 0x000031 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void toolBar() {
|
||||
JToolBar c = new JToolBar();
|
||||
assertEquals( new Color( 0x000032 ), c.getForeground() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void toolBarSeparator() {
|
||||
JToolBar.Separator c = new JToolBar.Separator();
|
||||
assertEquals( new Dimension( 0, 21 ), c.getPreferredSize() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void tree() {
|
||||
JTree c = new JTree();
|
||||
assertEquals( new Color( 0x000033 ), c.getForeground() );
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright 2021 FormDev Software GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static com.formdev.flatlaf.FlatClientProperties.STYLE;
|
||||
import java.util.function.Supplier;
|
||||
import javax.swing.JEditorPane;
|
||||
import javax.swing.JFormattedTextField;
|
||||
import javax.swing.JPasswordField;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.JTextPane;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ColorUIResource;
|
||||
import javax.swing.plaf.basic.BasicTextFieldUI;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class TestFlatTextComponents
|
||||
{
|
||||
@BeforeAll
|
||||
static void setup() {
|
||||
TestUtils.setup( false );
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void cleanup() {
|
||||
TestUtils.cleanup();
|
||||
}
|
||||
|
||||
@Test
|
||||
void editorPane_updateBackground() {
|
||||
textComponent_updateBackground( "EditorPane", JEditorPane::new );
|
||||
}
|
||||
|
||||
@Test
|
||||
void formattedTextField_updateBackground() {
|
||||
textComponent_updateBackground( "FormattedTextField", JFormattedTextField::new );
|
||||
}
|
||||
|
||||
@Test
|
||||
void passwordField_updateBackground() {
|
||||
textComponent_updateBackground( "PasswordField", JPasswordField::new );
|
||||
}
|
||||
|
||||
@Test
|
||||
void textArea_updateBackground() {
|
||||
textComponent_updateBackground( "TextArea", JTextArea::new );
|
||||
}
|
||||
|
||||
@Test
|
||||
void textField_updateBackground() {
|
||||
textComponent_updateBackground( "TextField", JTextField::new );
|
||||
}
|
||||
|
||||
@Test
|
||||
void textPane_updateBackground() {
|
||||
textComponent_updateBackground( "TextPane", JTextPane::new );
|
||||
}
|
||||
|
||||
@Test
|
||||
void basicTextField_updateBackground() {
|
||||
textComponent_updateBackground( "TextField", () -> {
|
||||
JTextField c = new JTextField();
|
||||
c.setUI( new BasicTextFieldUI() );
|
||||
return c;
|
||||
} );
|
||||
}
|
||||
|
||||
private void textComponent_updateBackground( String prefix, Supplier<JTextComponent> createTextComponent ) {
|
||||
ColorUIResource background = new ColorUIResource( 0xff0000 );
|
||||
ColorUIResource inactiveBackground = new ColorUIResource( 0x00ff00 );
|
||||
ColorUIResource disabledBackground = new ColorUIResource( 0x0000ff );
|
||||
|
||||
UIManager.put( prefix + ".background", background );
|
||||
UIManager.put( prefix + ".inactiveBackground", inactiveBackground );
|
||||
UIManager.put( prefix + ".disabledBackground", disabledBackground );
|
||||
|
||||
JTextComponent c = createTextComponent.get();
|
||||
|
||||
// without styling
|
||||
assertEquals( background, c.getBackground() );
|
||||
c.setEditable( false ); assertEquals( inactiveBackground, c.getBackground() );
|
||||
c.setEnabled( false ); assertEquals( disabledBackground, c.getBackground() );
|
||||
c.setEditable( true ); assertEquals( disabledBackground, c.getBackground() );
|
||||
c.setEnabled( true ); assertEquals( background, c.getBackground() );
|
||||
|
||||
|
||||
if( !c.getUI().getClass().getSimpleName().startsWith( "Flat" ) )
|
||||
return;
|
||||
|
||||
|
||||
// with styling
|
||||
|
||||
ColorUIResource inactiveBackground1 = new ColorUIResource( 0x00ee00 );
|
||||
ColorUIResource disabledBackground1 = new ColorUIResource( 0x0000ee );
|
||||
ColorUIResource inactiveBackground2 = new ColorUIResource( 0x00dd00 );
|
||||
ColorUIResource disabledBackground2 = new ColorUIResource( 0x0000dd );
|
||||
String style1 = "inactiveBackground: #00ee00; disabledBackground: #0000ee";
|
||||
String style2 = "inactiveBackground: #00dd00; disabledBackground: #0000dd";
|
||||
|
||||
c.putClientProperty( STYLE, style1 );
|
||||
|
||||
assertEquals( background, c.getBackground() );
|
||||
c.setEditable( false ); assertEquals( inactiveBackground1, c.getBackground() );
|
||||
c.setEnabled( false ); assertEquals( disabledBackground1, c.getBackground() );
|
||||
c.setEditable( true ); assertEquals( disabledBackground1, c.getBackground() );
|
||||
c.setEnabled( true ); assertEquals( background, c.getBackground() );
|
||||
|
||||
c.putClientProperty( STYLE, null );
|
||||
assertEquals( background, c.getBackground() );
|
||||
|
||||
c.setEditable( false );
|
||||
c.putClientProperty( STYLE, style1 );
|
||||
assertEquals( inactiveBackground1, c.getBackground() );
|
||||
|
||||
c.putClientProperty( STYLE, null );
|
||||
assertEquals( inactiveBackground, c.getBackground() );
|
||||
|
||||
c.setEnabled( false );
|
||||
c.putClientProperty( STYLE, style1 );
|
||||
assertEquals( disabledBackground1, c.getBackground() );
|
||||
|
||||
|
||||
// change from style1 to style2
|
||||
c.putClientProperty( STYLE, style2 );
|
||||
assertEquals( disabledBackground2, c.getBackground() );
|
||||
|
||||
c.setEnabled( true );
|
||||
assertEquals( inactiveBackground2, c.getBackground() );
|
||||
|
||||
|
||||
// remove style
|
||||
c.putClientProperty( STYLE, null );
|
||||
assertEquals( inactiveBackground, c.getBackground() );
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,11 @@
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import javax.swing.UIManager;
|
||||
import org.opentest4j.AssertionFailedError;
|
||||
import com.formdev.flatlaf.FlatIntelliJLaf;
|
||||
import com.formdev.flatlaf.FlatLightLaf;
|
||||
import com.formdev.flatlaf.FlatSystemProperties;
|
||||
@@ -39,7 +43,12 @@ public class TestUtils
|
||||
}
|
||||
|
||||
public static void cleanup() {
|
||||
UIManager.put( "defaultFont", null );
|
||||
// remove all properties added by UIManager.put()
|
||||
Iterator<Object> it = UIManager.getDefaults().keySet().iterator();
|
||||
while( it.hasNext() ) {
|
||||
it.next();
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
public static void scaleFont( float factor ) {
|
||||
@@ -50,4 +59,15 @@ public class TestUtils
|
||||
public static void resetFont() {
|
||||
UIManager.put( "defaultFont", null );
|
||||
}
|
||||
|
||||
public static void assertMapEquals( Map<?, ?> expected, Map<?, ?> actual ) {
|
||||
if( !Objects.equals( expected, actual ) ) {
|
||||
String expectedStr = String.valueOf( expected ).replace( ", ", ",\n" );
|
||||
String actualStr = String.valueOf( actual ).replace( ", ", ",\n" );
|
||||
String msg = String.format( "expected: <%s> but was: <%s>", expectedStr, actualStr );
|
||||
|
||||
// pass expected/actual strings to exception for nice diff in IDE
|
||||
throw new AssertionFailedError( msg, expectedStr, actualStr );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user