mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2026-02-11 22:47:13 -06:00
Compare commits
128 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b0997fb5d2 | ||
|
|
37dab9fb22 | ||
|
|
fb44c8fbe4 | ||
|
|
94375b7d36 | ||
|
|
8b585deb78 | ||
|
|
4d8b544aed | ||
|
|
548d651d29 | ||
|
|
0b342acec9 | ||
|
|
cc6d3c1b1a | ||
|
|
74a748d92e | ||
|
|
1de81d0af5 | ||
|
|
ff9ef21f67 | ||
|
|
266a546478 | ||
|
|
87407ca832 | ||
|
|
90282d4436 | ||
|
|
abbe6d6c1f | ||
|
|
a28f701e6f | ||
|
|
4cdc995a7f | ||
|
|
c708205593 | ||
|
|
a22c6c8013 | ||
|
|
b576f473e5 | ||
|
|
0b127caa83 | ||
|
|
4507ce359d | ||
|
|
3e14f28dc2 | ||
|
|
a9dcf09d13 | ||
|
|
c8998c2bcf | ||
|
|
10bf1295bc | ||
|
|
1e869973d4 | ||
|
|
731c8962c9 | ||
|
|
294b8bb789 | ||
|
|
4f9b819f48 | ||
|
|
5318d5fa8e | ||
|
|
98b156bdde | ||
|
|
511dd02107 | ||
|
|
f1f7a2e7b6 | ||
|
|
d557cf5427 | ||
|
|
39d2941099 | ||
|
|
2a732306a1 | ||
|
|
8a72b30cbc | ||
|
|
ed9cb0f918 | ||
|
|
7e0915cb9c | ||
|
|
a51294d570 | ||
|
|
d962f218a1 | ||
|
|
7b248427f0 | ||
|
|
b99fb8b11f | ||
|
|
26250e790f | ||
|
|
b26dbe81f4 | ||
|
|
903212345b | ||
|
|
025f6564dc | ||
|
|
35f97368fa | ||
|
|
09e5c86488 | ||
|
|
8998371cae | ||
|
|
29e1dc6b55 | ||
|
|
439e63b52f | ||
|
|
eea341fb33 | ||
|
|
359eedf773 | ||
|
|
866751ffc1 | ||
|
|
38a3a0768d | ||
|
|
03b42749cd | ||
|
|
60fd78e082 | ||
|
|
9edaf58929 | ||
|
|
5000186f85 | ||
|
|
cacf0ea987 | ||
|
|
067501cbe7 | ||
|
|
9fe0cf496b | ||
|
|
9d0823038e | ||
|
|
5a05efefdd | ||
|
|
988d171bdd | ||
|
|
e6f72bf343 | ||
|
|
89c5a0c57b | ||
|
|
d97146393c | ||
|
|
1c52f1f76c | ||
|
|
9bd3a68115 | ||
|
|
f58780d36b | ||
|
|
6eb15ab437 | ||
|
|
00dc7004f5 | ||
|
|
8ec0e57235 | ||
|
|
d75dc9e70c | ||
|
|
ec2fccbb0e | ||
|
|
34861166e8 | ||
|
|
584fa0a26e | ||
|
|
6c48489d89 | ||
|
|
ba9c884a0c | ||
|
|
360f0bafe0 | ||
|
|
4327c13dca | ||
|
|
4f2256f713 | ||
|
|
5167cd368f | ||
|
|
ef7289d11a | ||
|
|
cb11d98bf7 | ||
|
|
992349da8c | ||
|
|
2e7637f274 | ||
|
|
1f8eaf4a64 | ||
|
|
46ac7a9dc7 | ||
|
|
0d86d39217 | ||
|
|
1f591f3d1b | ||
|
|
30c6ddba37 | ||
|
|
406eeaec96 | ||
|
|
2fe5652bc6 | ||
|
|
39bf68a6bd | ||
|
|
a7a4a19824 | ||
|
|
7f906ba0ea | ||
|
|
07bf6e4506 | ||
|
|
a331760321 | ||
|
|
d9c240d729 | ||
|
|
d9526c19e7 | ||
|
|
1798ccd284 | ||
|
|
ab1ce7fab1 | ||
|
|
e9b2f17171 | ||
|
|
d3bf4433b7 | ||
|
|
ba0f43455b | ||
|
|
638af4bcd7 | ||
|
|
5eab843d97 | ||
|
|
c55f0e239e | ||
|
|
32d9381745 | ||
|
|
77fc564e70 | ||
|
|
3b84314c45 | ||
|
|
6db39d1860 | ||
|
|
1762ead89f | ||
|
|
98a3c4b0f5 | ||
|
|
6e990a7e31 | ||
|
|
8e49904f8d | ||
|
|
69f52c8abd | ||
|
|
d7b0754327 | ||
|
|
2a00de11f1 | ||
|
|
923cc51f3e | ||
|
|
c8f7478170 | ||
|
|
bffac60bf8 | ||
|
|
ae8323e2f8 |
8
.gitbugtraq
Normal file
8
.gitbugtraq
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# links issue numbers in git commit messages to issue tracker
|
||||||
|
# https://github.com/mstrap/bugtraq
|
||||||
|
# for SmartGit - https://www.syntevo.com/smartgit/
|
||||||
|
|
||||||
|
[bugtraq]
|
||||||
|
url = "https://github.com/JFormDesigner/FlatLaf/issues/%BUGID%"
|
||||||
|
loglinkregex = "#[0-9]{1,5}"
|
||||||
|
logregex = "[0-9]{1,5}"
|
||||||
135
CHANGELOG.md
135
CHANGELOG.md
@@ -1,6 +1,139 @@
|
|||||||
FlatLaf Change Log
|
FlatLaf Change Log
|
||||||
==================
|
==================
|
||||||
|
|
||||||
|
## 1.4
|
||||||
|
|
||||||
|
#### New features and improvements
|
||||||
|
|
||||||
|
- TextField, FormattedTextField and PasswordField: Support adding extra padding.
|
||||||
|
(set client property `JTextField.padding` to `Insets`).
|
||||||
|
- PasswordField: UI delegate `FlatPasswordFieldUI` now extends `FlatTextFieldUI`
|
||||||
|
(instead of `BasicPasswordFieldUI`) to avoid duplicate code and for easier
|
||||||
|
extensibility.
|
||||||
|
- Table and PopupFactory: Use `StackWalker` in Java 9+ for better performance.
|
||||||
|
(issue #334)
|
||||||
|
- ToolBar: Paint focus indicator for focused button in toolbar. (issue #346)
|
||||||
|
- ToolBar: Support focusable buttons in toolbar (set UI values
|
||||||
|
`ToolBar.focusableButtons` to `true`). (issue #346)
|
||||||
|
|
||||||
|
#### Fixed bugs
|
||||||
|
|
||||||
|
- ComboBox (editable) and Spinner: Increased size of internal text field to the
|
||||||
|
component border so that it behaves like plain text field (mouse click to left
|
||||||
|
of text now positions caret to first character instead of opening ComboBox
|
||||||
|
popup; mouse cursor is now of type "text" within the whole component, except
|
||||||
|
for arrow buttons). (issue #330)
|
||||||
|
- ComboBox (not editable): Increased size of internal renderer pane to the
|
||||||
|
component border so that it can paint within the whole component. Also
|
||||||
|
increase combo box size if a custom renderer uses a border with insets that
|
||||||
|
are larger than the default combo box padding (`2,6,2,6`).
|
||||||
|
- Fixed component heights at `1.25x`, `1.75x` and `2.25x` scaling factors (Java
|
||||||
|
8 only) so that Button, ComboBox, Spinner and TextField components (including
|
||||||
|
subclasses) have same heights. This increases heights of Button and TextField
|
||||||
|
components by:
|
||||||
|
- `2px` at `1.75x` in **Light** and **Dark** themes
|
||||||
|
- `2px` at `1.25x` and `2.25x` in **IntelliJ** and **Darcula** themes
|
||||||
|
- OptionPane: Do not make child components, which are derived from `JPanel`,
|
||||||
|
non-opaque. (issue #349)
|
||||||
|
- OptionPane: Align wrapped lines to the right if component orientation is
|
||||||
|
right-to-left. (issue #350)
|
||||||
|
- PasswordField: Caps lock icon no longer painted over long text. (issue #172)
|
||||||
|
- PasswordField: Paint caps lock icon on left side in right-to-left component
|
||||||
|
orientation.
|
||||||
|
- Window decorations: Window title bar width is no longer considered when
|
||||||
|
calculating preferred/minimum width of window. (issue #351)
|
||||||
|
|
||||||
|
|
||||||
|
## 1.3
|
||||||
|
|
||||||
|
#### New features and improvements
|
||||||
|
|
||||||
|
- TextComponents, ComboBox and Spinner: Support different background color when
|
||||||
|
component is focused (use UI values `TextField.focusedBackground`,
|
||||||
|
`PasswordField.focusedBackground`, `FormattedTextField.focusedBackground`,
|
||||||
|
`TextArea.focusedBackground`, `TextPane.focusedBackground`,
|
||||||
|
`EditorPane.focusedBackground`, `ComboBox.focusedBackground`,
|
||||||
|
`ComboBox.buttonFocusedBackground`, `ComboBox.popupBackground` and
|
||||||
|
`Spinner.focusedBackground`). (issue #335)
|
||||||
|
|
||||||
|
#### Fixed bugs
|
||||||
|
|
||||||
|
- Fixed white lines at bottom and right side of window (in dark themes on HiDPI
|
||||||
|
screens with scaling enabled).
|
||||||
|
- ScrollBar: Fixed left/top arrow icon location (if visible). (issue #329)
|
||||||
|
- Spinner: Fixed up/down arrow icon location.
|
||||||
|
- ToolTip: Fixed positioning of huge tooltips. (issue #333)
|
||||||
|
|
||||||
|
|
||||||
|
## 1.2
|
||||||
|
|
||||||
|
#### New features and improvements
|
||||||
|
|
||||||
|
- Renamed `Flat*Laf.install()` methods to `Flat*Laf.setup()` to avoid confusion
|
||||||
|
with `UIManager.installLookAndFeel(LookAndFeelInfo info)`. The old
|
||||||
|
`Flat*Laf.install()` methods are still there, but marked as deprecated. They
|
||||||
|
will be removed in a future version.
|
||||||
|
- Button and ToggleButton: Support borderless button style (set client property
|
||||||
|
`JButton.buttonType` to `borderless`). (PR #276)
|
||||||
|
- ComboBox: Support using as cell renderer (e.g. in `JTable`).
|
||||||
|
- DesktopPane: Improved layout of iconified internal frames in dock:
|
||||||
|
- Always placed at bottom-left in desktop pane.
|
||||||
|
- Newly iconified frames are added to the right side of the dock.
|
||||||
|
- If frame is deiconified, dock is compacted (icons move to the left).
|
||||||
|
- If dock is wider than desktop width, additional rows are used.
|
||||||
|
- If desktop pane is resized, layout of dock is updated.
|
||||||
|
- TableHeader: Moved table header column border painting from
|
||||||
|
`FlatTableHeaderUI` to new border `FlatTableHeaderBorder` to improve
|
||||||
|
compatibility with custom table header implementations. (issue #228)
|
||||||
|
- Linux: Enable text anti-aliasing if no Gnome or KDE Desktop properties are
|
||||||
|
available. (issue #218)
|
||||||
|
- IntelliJ Themes: Added "Material Theme UI Lite / GitHub Dark" theme.
|
||||||
|
- JIDE Common Layer: Improved support for `JideTabbedPane`. (PR #306)
|
||||||
|
- Extras: `FlatSVGIcon` improvements:
|
||||||
|
- Each icon can now have its own color filter. (PR #303)
|
||||||
|
- Use mapper function in color filter to dynamically map colors. (PR #303)
|
||||||
|
- Color filter supports light and dark themes.
|
||||||
|
- Getters for icon name, classloader, etc.
|
||||||
|
- Extras: UI Inspector: Show class hierarchies when pressing <kbd>Alt</kbd> key
|
||||||
|
and prettified class names (dimmed package name).
|
||||||
|
- Extras: `FlatSVGUtils.createWindowIconImages()` now returns a single
|
||||||
|
multi-resolution image that creates requested image sizes on demand from SVG
|
||||||
|
(only on Windows with Java 9+).
|
||||||
|
|
||||||
|
#### Fixed bugs
|
||||||
|
|
||||||
|
- CheckBox and RadioButton: Do not fill background if used as cell renderer,
|
||||||
|
except if cell is selected or has different background color. (issue #311)
|
||||||
|
- DesktopPane:
|
||||||
|
- Fixed missing preview of iconified internal frames in dock when using a
|
||||||
|
custom desktop manager. (PR #294)
|
||||||
|
- Fixed incomplete preview of iconified internal frames in dock when switching
|
||||||
|
LaF.
|
||||||
|
- On HiDPI screens, use high-resolution images for preview of iconified
|
||||||
|
internal frames in dock.
|
||||||
|
- PopupFactory: Fixed occasional `NullPointerException` in
|
||||||
|
`FlatPopupFactory.fixToolTipLocation()`. (issue #305)
|
||||||
|
- Tree: Fill cell background if
|
||||||
|
`DefaultTreeCellRenderer.setBackgroundNonSelectionColor(Color)` was used.
|
||||||
|
(issue #322)
|
||||||
|
- IntelliJ Themes: Fixed background colors of DesktopPane and DesktopIcon in all
|
||||||
|
themes.
|
||||||
|
- Native window decorations:
|
||||||
|
- Fixed slow application startup under particular conditions. (e.g. incomplete
|
||||||
|
custom JRE) (issue #319)
|
||||||
|
- Fixed occasional double window title bar when creating many frames or
|
||||||
|
dialogs. (issue #315)
|
||||||
|
- Fixed broken maximizing window (under special conditions) when restoring
|
||||||
|
frame state at startup.
|
||||||
|
- Title icon: For multi-resolution images now use `getResolutionVariant(width,
|
||||||
|
height)` (instead of `getResolutionVariants()`) to allow creation of
|
||||||
|
requested size on demand. This also avoids creation of all resolution
|
||||||
|
variants.
|
||||||
|
- Double-click at upper-left corner of maximized frame did not close window.
|
||||||
|
(issue #326)
|
||||||
|
- Linux: Fixed/improved detection of user font settings. (issue #309)
|
||||||
|
|
||||||
|
|
||||||
## 1.1.2
|
## 1.1.2
|
||||||
|
|
||||||
#### New features and improvements
|
#### New features and improvements
|
||||||
@@ -164,7 +297,7 @@ FlatLaf Change Log
|
|||||||
- CheckBox and RadioButton: Fill component background as soon as background
|
- CheckBox and RadioButton: Fill component background as soon as background
|
||||||
color is different to default background color, even if component is not
|
color is different to default background color, even if component is not
|
||||||
opaque (which is the default). This paints selection if using the component as
|
opaque (which is the default). This paints selection if using the component as
|
||||||
cell renderer a Table, Tree or List.
|
cell renderer in Table, Tree or List.
|
||||||
- TextComponents: Border of focused non-editable text components had wrong
|
- TextComponents: Border of focused non-editable text components had wrong
|
||||||
color.
|
color.
|
||||||
- Custom window decorations: Fixed top window border in dark themes when running
|
- Custom window decorations: Fixed top window border in dark themes when running
|
||||||
|
|||||||
@@ -76,11 +76,11 @@ Addons
|
|||||||
Getting started
|
Getting started
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
To enable FlatLaf, add following code to your main method before you create any
|
To use FlatLaf, add following code to your main method before you create any
|
||||||
Swing component:
|
Swing component:
|
||||||
|
|
||||||
~~~java
|
~~~java
|
||||||
FlatLightLaf.install();
|
FlatLightLaf.setup();
|
||||||
|
|
||||||
// create UI here...
|
// create UI here...
|
||||||
~~~
|
~~~
|
||||||
|
|||||||
@@ -14,8 +14,8 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
val releaseVersion = "1.1.2"
|
val releaseVersion = "1.4"
|
||||||
val developmentVersion = "1.2-SNAPSHOT"
|
val developmentVersion = "1.5-SNAPSHOT"
|
||||||
|
|
||||||
version = if( java.lang.Boolean.getBoolean( "release" ) ) releaseVersion else developmentVersion
|
version = if( java.lang.Boolean.getBoolean( "release" ) ) releaseVersion else developmentVersion
|
||||||
|
|
||||||
@@ -47,19 +47,35 @@ allprojects {
|
|||||||
targetCompatibility = "1.8"
|
targetCompatibility = "1.8"
|
||||||
|
|
||||||
options.encoding = "ISO-8859-1"
|
options.encoding = "ISO-8859-1"
|
||||||
|
options.isDeprecation = false
|
||||||
}
|
}
|
||||||
|
|
||||||
withType<Jar>().configureEach {
|
withType<Jar>().configureEach {
|
||||||
// manifest for all created JARs
|
// manifest for all created JARs
|
||||||
manifest.attributes(mapOf(
|
manifest.attributes(
|
||||||
"Implementation-Vendor" to "FormDev Software GmbH",
|
"Implementation-Vendor" to "FormDev Software GmbH",
|
||||||
"Implementation-Copyright" to "Copyright (C) 2019-${java.time.LocalDate.now().year} FormDev Software GmbH. All rights reserved.",
|
"Implementation-Copyright" to "Copyright (C) 2019-${java.time.LocalDate.now().year} FormDev Software GmbH. All rights reserved.",
|
||||||
"Implementation-Version" to project.version))
|
"Implementation-Version" to project.version
|
||||||
|
)
|
||||||
|
|
||||||
// add META-INF/LICENSE to all created JARs
|
// add META-INF/LICENSE to all created JARs
|
||||||
from("${rootDir}/LICENSE") {
|
from( "${rootDir}/LICENSE" ) {
|
||||||
into("META-INF")
|
into( "META-INF" )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
withType<Javadoc>().configureEach {
|
||||||
|
options {
|
||||||
|
this as StandardJavadocDocletOptions
|
||||||
|
|
||||||
|
title = "${project.name} $version"
|
||||||
|
header = title
|
||||||
|
isUse = true
|
||||||
|
tags = listOf( "uiDefault", "clientProperty" )
|
||||||
|
addStringOption( "Xdoclint:all,-missing", "-Xdoclint:all,-missing" )
|
||||||
|
links( "https://docs.oracle.com/en/java/javase/11/docs/api/" )
|
||||||
|
}
|
||||||
|
isFailOnError = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,12 @@ plugins {
|
|||||||
`flatlaf-publish`
|
`flatlaf-publish`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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" )
|
||||||
|
}
|
||||||
|
|
||||||
java {
|
java {
|
||||||
withSourcesJar()
|
withSourcesJar()
|
||||||
withJavadocJar()
|
withJavadocJar()
|
||||||
@@ -45,23 +51,18 @@ tasks {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
javadoc {
|
named<Jar>( "sourcesJar" ) {
|
||||||
options {
|
|
||||||
this as StandardJavadocDocletOptions
|
|
||||||
use( true )
|
|
||||||
tags = listOf( "uiDefault", "clientProperty" )
|
|
||||||
addStringOption( "Xdoclint:all,-missing", "-Xdoclint:all,-missing" )
|
|
||||||
}
|
|
||||||
isFailOnError = false
|
|
||||||
}
|
|
||||||
|
|
||||||
named<Jar>("sourcesJar" ) {
|
|
||||||
archiveBaseName.set( "flatlaf" )
|
archiveBaseName.set( "flatlaf" )
|
||||||
}
|
}
|
||||||
|
|
||||||
named<Jar>("javadocJar" ) {
|
named<Jar>( "javadocJar" ) {
|
||||||
archiveBaseName.set( "flatlaf" )
|
archiveBaseName.set( "flatlaf" )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test {
|
||||||
|
useJUnitPlatform()
|
||||||
|
testLogging.exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
flatlafPublish {
|
flatlafPublish {
|
||||||
|
|||||||
@@ -39,8 +39,9 @@ public interface FlatClientProperties
|
|||||||
* {@link #BUTTON_TYPE_SQUARE},
|
* {@link #BUTTON_TYPE_SQUARE},
|
||||||
* {@link #BUTTON_TYPE_ROUND_RECT},
|
* {@link #BUTTON_TYPE_ROUND_RECT},
|
||||||
* {@link #BUTTON_TYPE_TAB},
|
* {@link #BUTTON_TYPE_TAB},
|
||||||
* {@link #BUTTON_TYPE_HELP} or
|
* {@link #BUTTON_TYPE_HELP},
|
||||||
* {@link BUTTON_TYPE_TOOLBAR_BUTTON}
|
* {@link #BUTTON_TYPE_TOOLBAR_BUTTON} or
|
||||||
|
* {@link #BUTTON_TYPE_BORDERLESS}
|
||||||
*/
|
*/
|
||||||
String BUTTON_TYPE = "JButton.buttonType";
|
String BUTTON_TYPE = "JButton.buttonType";
|
||||||
|
|
||||||
@@ -89,6 +90,16 @@ public interface FlatClientProperties
|
|||||||
*/
|
*/
|
||||||
String BUTTON_TYPE_TOOLBAR_BUTTON = "toolBarButton";
|
String BUTTON_TYPE_TOOLBAR_BUTTON = "toolBarButton";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Paint the button without a border in the unfocused state.
|
||||||
|
* <p>
|
||||||
|
* <strong>Components</strong> {@link javax.swing.JButton} and {@link javax.swing.JToggleButton}
|
||||||
|
*
|
||||||
|
* @see #BUTTON_TYPE
|
||||||
|
* @since 1.2
|
||||||
|
*/
|
||||||
|
String BUTTON_TYPE_BORDERLESS = "borderless";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies selected state of a checkbox.
|
* Specifies selected state of a checkbox.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -272,6 +283,8 @@ public interface FlatClientProperties
|
|||||||
/**
|
/**
|
||||||
* Background color of window title bar (requires enabled window decorations).
|
* Background color of window title bar (requires enabled window decorations).
|
||||||
* <p>
|
* <p>
|
||||||
|
* (requires Window 10)
|
||||||
|
* <p>
|
||||||
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||||
* <strong>Value type</strong> {@link java.awt.Color}
|
* <strong>Value type</strong> {@link java.awt.Color}
|
||||||
*
|
*
|
||||||
@@ -282,6 +295,8 @@ public interface FlatClientProperties
|
|||||||
/**
|
/**
|
||||||
* Foreground color of window title bar (requires enabled window decorations).
|
* Foreground color of window title bar (requires enabled window decorations).
|
||||||
* <p>
|
* <p>
|
||||||
|
* (requires Window 10)
|
||||||
|
* <p>
|
||||||
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||||
* <strong>Value type</strong> {@link java.awt.Color}
|
* <strong>Value type</strong> {@link java.awt.Color}
|
||||||
*
|
*
|
||||||
@@ -718,6 +733,18 @@ public interface FlatClientProperties
|
|||||||
*/
|
*/
|
||||||
String PLACEHOLDER_TEXT = "JTextField.placeholderText";
|
String PLACEHOLDER_TEXT = "JTextField.placeholderText";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the padding of the text.
|
||||||
|
* This changes the location and size of the text view within the component bounds,
|
||||||
|
* but does not affect the size of the component.
|
||||||
|
* <p>
|
||||||
|
* <strong>Component</strong> {@link javax.swing.JTextField} (and subclasses)<br>
|
||||||
|
* <strong>Value type</strong> {@link java.awt.Insets}
|
||||||
|
*
|
||||||
|
* @since 1.4
|
||||||
|
*/
|
||||||
|
String TEXT_FIELD_PADDING = "JTextField.padding";
|
||||||
|
|
||||||
//---- JToggleButton ------------------------------------------------------
|
//---- JToggleButton ------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package com.formdev.flatlaf;
|
package com.formdev.flatlaf;
|
||||||
|
|
||||||
|
import javax.swing.UIManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Flat LaF that has a dark color scheme and looks like Darcula LaF.
|
* A Flat LaF that has a dark color scheme and looks like Darcula LaF.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -29,10 +31,28 @@ public class FlatDarculaLaf
|
|||||||
{
|
{
|
||||||
public static final String NAME = "FlatLaf Darcula";
|
public static final String NAME = "FlatLaf Darcula";
|
||||||
|
|
||||||
public static boolean install() {
|
/**
|
||||||
return install( new FlatDarculaLaf() );
|
* Sets the application look and feel to this LaF
|
||||||
|
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
|
||||||
|
*/
|
||||||
|
public static boolean setup() {
|
||||||
|
return setup( new FlatDarculaLaf() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public static boolean install() {
|
||||||
|
return setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds this look and feel to the set of available look and feels.
|
||||||
|
* <p>
|
||||||
|
* Useful if your application uses {@link UIManager#getInstalledLookAndFeels()}
|
||||||
|
* to query available LaFs and display them to the user in a combobox.
|
||||||
|
*/
|
||||||
public static void installLafInfo() {
|
public static void installLafInfo() {
|
||||||
installLafInfo( NAME, FlatDarculaLaf.class );
|
installLafInfo( NAME, FlatDarculaLaf.class );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,8 +34,16 @@ public class FlatDarkLaf
|
|||||||
* Sets the application look and feel to this LaF
|
* Sets the application look and feel to this LaF
|
||||||
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
|
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
|
||||||
*/
|
*/
|
||||||
|
public static boolean setup() {
|
||||||
|
return setup( new FlatDarkLaf() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public static boolean install() {
|
public static boolean install() {
|
||||||
return install( new FlatDarkLaf() );
|
return setup();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package com.formdev.flatlaf;
|
package com.formdev.flatlaf;
|
||||||
|
|
||||||
|
import javax.swing.UIManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Flat LaF that has a light color scheme and looks like IntelliJ LaF.
|
* A Flat LaF that has a light color scheme and looks like IntelliJ LaF.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -29,10 +31,28 @@ public class FlatIntelliJLaf
|
|||||||
{
|
{
|
||||||
public static final String NAME = "FlatLaf IntelliJ";
|
public static final String NAME = "FlatLaf IntelliJ";
|
||||||
|
|
||||||
public static boolean install() {
|
/**
|
||||||
return install( new FlatIntelliJLaf() );
|
* Sets the application look and feel to this LaF
|
||||||
|
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
|
||||||
|
*/
|
||||||
|
public static boolean setup() {
|
||||||
|
return setup( new FlatIntelliJLaf() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public static boolean install() {
|
||||||
|
return setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds this look and feel to the set of available look and feels.
|
||||||
|
* <p>
|
||||||
|
* Useful if your application uses {@link UIManager#getInstalledLookAndFeels()}
|
||||||
|
* to query available LaFs and display them to the user in a combobox.
|
||||||
|
*/
|
||||||
public static void installLafInfo() {
|
public static void installLafInfo() {
|
||||||
installLafInfo( NAME, FlatIntelliJLaf.class );
|
installLafInfo( NAME, FlatIntelliJLaf.class );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import java.beans.PropertyChangeListener;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
@@ -54,6 +55,7 @@ import javax.swing.UIManager;
|
|||||||
import javax.swing.UnsupportedLookAndFeelException;
|
import javax.swing.UnsupportedLookAndFeelException;
|
||||||
import javax.swing.plaf.ColorUIResource;
|
import javax.swing.plaf.ColorUIResource;
|
||||||
import javax.swing.plaf.FontUIResource;
|
import javax.swing.plaf.FontUIResource;
|
||||||
|
import javax.swing.plaf.IconUIResource;
|
||||||
import javax.swing.plaf.UIResource;
|
import javax.swing.plaf.UIResource;
|
||||||
import javax.swing.plaf.basic.BasicLookAndFeel;
|
import javax.swing.plaf.basic.BasicLookAndFeel;
|
||||||
import javax.swing.text.StyleContext;
|
import javax.swing.text.StyleContext;
|
||||||
@@ -95,16 +97,24 @@ public abstract class FlatLaf
|
|||||||
* Sets the application look and feel to the given LaF
|
* Sets the application look and feel to the given LaF
|
||||||
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
|
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
|
||||||
*/
|
*/
|
||||||
public static boolean install( LookAndFeel newLookAndFeel ) {
|
public static boolean setup( LookAndFeel newLookAndFeel ) {
|
||||||
try {
|
try {
|
||||||
UIManager.setLookAndFeel( newLookAndFeel );
|
UIManager.setLookAndFeel( newLookAndFeel );
|
||||||
return true;
|
return true;
|
||||||
} catch( Exception ex ) {
|
} catch( Exception ex ) {
|
||||||
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to initialize look and feel '" + newLookAndFeel.getClass().getName() + "'.", ex );
|
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to setup look and feel '" + newLookAndFeel.getClass().getName() + "'.", ex );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link #setup(LookAndFeel)} instead; this method will be removed in a future version
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public static boolean install( LookAndFeel newLookAndFeel ) {
|
||||||
|
return setup( newLookAndFeel );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the given look and feel to the set of available look and feels.
|
* Adds the given look and feel to the set of available look and feels.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -181,8 +191,10 @@ public abstract class FlatLaf
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Icon getDisabledIcon( JComponent component, Icon icon ) {
|
public Icon getDisabledIcon( JComponent component, Icon icon ) {
|
||||||
if( icon instanceof DisabledIconProvider )
|
if( icon instanceof DisabledIconProvider ) {
|
||||||
return ((DisabledIconProvider)icon).getDisabledIcon();
|
Icon disabledIcon = ((DisabledIconProvider)icon).getDisabledIcon();
|
||||||
|
return !(disabledIcon instanceof UIResource) ? new IconUIResource( disabledIcon ) : disabledIcon;
|
||||||
|
}
|
||||||
|
|
||||||
if( icon instanceof ImageIcon ) {
|
if( icon instanceof ImageIcon ) {
|
||||||
Object grayFilter = UIManager.get( "Component.grayFilter" );
|
Object grayFilter = UIManager.get( "Component.grayFilter" );
|
||||||
@@ -318,7 +330,7 @@ public abstract class FlatLaf
|
|||||||
Method m = UIManager.class.getMethod( "createLookAndFeel", String.class );
|
Method m = UIManager.class.getMethod( "createLookAndFeel", String.class );
|
||||||
aquaLaf = (BasicLookAndFeel) m.invoke( null, "Mac OS X" );
|
aquaLaf = (BasicLookAndFeel) m.invoke( null, "Mac OS X" );
|
||||||
} else
|
} else
|
||||||
aquaLaf = (BasicLookAndFeel) Class.forName( aquaLafClassName ).newInstance();
|
aquaLaf = (BasicLookAndFeel) Class.forName( aquaLafClassName ).getDeclaredConstructor().newInstance();
|
||||||
} catch( Exception ex ) {
|
} catch( Exception ex ) {
|
||||||
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to initialize Aqua look and feel '" + aquaLafClassName + "'.", ex );
|
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to initialize Aqua look and feel '" + aquaLafClassName + "'.", ex );
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
@@ -553,6 +565,8 @@ public abstract class FlatLaf
|
|||||||
defaults.put( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON );
|
defaults.put( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON );
|
||||||
} else if( SystemInfo.isJava_9_orLater ) {
|
} else if( SystemInfo.isJava_9_orLater ) {
|
||||||
Object desktopHints = Toolkit.getDefaultToolkit().getDesktopProperty( DESKTOPFONTHINTS );
|
Object desktopHints = Toolkit.getDefaultToolkit().getDesktopProperty( DESKTOPFONTHINTS );
|
||||||
|
if( desktopHints == null )
|
||||||
|
desktopHints = fallbackAATextInfo();
|
||||||
if( desktopHints instanceof Map ) {
|
if( desktopHints instanceof Map ) {
|
||||||
@SuppressWarnings( "unchecked" )
|
@SuppressWarnings( "unchecked" )
|
||||||
Map<Object, Object> hints = (Map<Object, Object>) desktopHints;
|
Map<Object, Object> hints = (Map<Object, Object>) desktopHints;
|
||||||
@@ -575,6 +589,8 @@ public abstract class FlatLaf
|
|||||||
Object value = Class.forName( "sun.swing.SwingUtilities2$AATextInfo" )
|
Object value = Class.forName( "sun.swing.SwingUtilities2$AATextInfo" )
|
||||||
.getMethod( "getAATextInfo", boolean.class )
|
.getMethod( "getAATextInfo", boolean.class )
|
||||||
.invoke( null, true );
|
.invoke( null, true );
|
||||||
|
if( value == null )
|
||||||
|
value = fallbackAATextInfo();
|
||||||
defaults.put( key, value );
|
defaults.put( key, value );
|
||||||
} catch( Exception ex ) {
|
} catch( Exception ex ) {
|
||||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||||
@@ -583,6 +599,47 @@ public abstract class FlatLaf
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Object fallbackAATextInfo() {
|
||||||
|
// do nothing if explicitly overridden
|
||||||
|
if( System.getProperty( "awt.useSystemAAFontSettings" ) != null )
|
||||||
|
return null;
|
||||||
|
|
||||||
|
Object aaHint = null;
|
||||||
|
Integer lcdContrastHint = null;
|
||||||
|
|
||||||
|
if( SystemInfo.isLinux ) {
|
||||||
|
// see sun.awt.UNIXToolkit.getDesktopAAHints()
|
||||||
|
Toolkit toolkit = Toolkit.getDefaultToolkit();
|
||||||
|
if( toolkit.getDesktopProperty( "gnome.Xft/Antialias" ) == null &&
|
||||||
|
toolkit.getDesktopProperty( "fontconfig/Antialias" ) == null )
|
||||||
|
{
|
||||||
|
// no Gnome or KDE Desktop properties available
|
||||||
|
// --> enable antialiasing
|
||||||
|
aaHint = RenderingHints.VALUE_TEXT_ANTIALIAS_ON;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( aaHint == null )
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if( SystemInfo.isJava_9_orLater ) {
|
||||||
|
Map<Object, Object> hints = new HashMap<>();
|
||||||
|
hints.put( RenderingHints.KEY_TEXT_ANTIALIASING, aaHint );
|
||||||
|
hints.put( RenderingHints.KEY_TEXT_LCD_CONTRAST, lcdContrastHint );
|
||||||
|
return hints;
|
||||||
|
} else {
|
||||||
|
// Java 8
|
||||||
|
try {
|
||||||
|
return Class.forName( "sun.swing.SwingUtilities2$AATextInfo" )
|
||||||
|
.getConstructor( Object.class, Integer.class )
|
||||||
|
.newInstance( aaHint, lcdContrastHint );
|
||||||
|
} catch( Exception ex ) {
|
||||||
|
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||||
|
throw new RuntimeException( ex );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void putDefaults( UIDefaults defaults, Object value, String... keys ) {
|
private void putDefaults( UIDefaults defaults, Object value, String... keys ) {
|
||||||
for( String key : keys )
|
for( String key : keys )
|
||||||
defaults.put( key, value );
|
defaults.put( key, value );
|
||||||
|
|||||||
@@ -34,8 +34,16 @@ public class FlatLightLaf
|
|||||||
* Sets the application look and feel to this LaF
|
* Sets the application look and feel to this LaF
|
||||||
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
|
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
|
||||||
*/
|
*/
|
||||||
|
public static boolean setup() {
|
||||||
|
return setup( new FlatLightLaf() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public static boolean install() {
|
public static boolean install() {
|
||||||
return install( new FlatLightLaf() );
|
return setup();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ public interface FlatSystemProperties
|
|||||||
* (requires Window 10)
|
* (requires Window 10)
|
||||||
* <p>
|
* <p>
|
||||||
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
||||||
* <strong>Default</strong> true
|
* <strong>Default</strong> {@code true}
|
||||||
*/
|
*/
|
||||||
String USE_JETBRAINS_CUSTOM_DECORATIONS = "flatlaf.useJetBrainsCustomDecorations";
|
String USE_JETBRAINS_CUSTOM_DECORATIONS = "flatlaf.useJetBrainsCustomDecorations";
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import javax.swing.UIDefaults;
|
|||||||
import javax.swing.plaf.ColorUIResource;
|
import javax.swing.plaf.ColorUIResource;
|
||||||
import com.formdev.flatlaf.json.Json;
|
import com.formdev.flatlaf.json.Json;
|
||||||
import com.formdev.flatlaf.json.ParseException;
|
import com.formdev.flatlaf.json.ParseException;
|
||||||
|
import com.formdev.flatlaf.util.ColorFunctions;
|
||||||
import com.formdev.flatlaf.util.LoggingFacade;
|
import com.formdev.flatlaf.util.LoggingFacade;
|
||||||
import com.formdev.flatlaf.util.StringUtils;
|
import com.formdev.flatlaf.util.StringUtils;
|
||||||
|
|
||||||
@@ -67,20 +68,28 @@ public class IntelliJTheme
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a IntelliJ .theme.json file from the given input stream,
|
* Loads a IntelliJ .theme.json file from the given input stream,
|
||||||
* creates a Laf instance for it and installs it.
|
* creates a Laf instance for it and sets it up.
|
||||||
*
|
*
|
||||||
* The input stream is automatically closed.
|
* The input stream is automatically closed.
|
||||||
* Using a buffered input stream is not necessary.
|
* Using a buffered input stream is not necessary.
|
||||||
*/
|
*/
|
||||||
public static boolean install( InputStream in ) {
|
public static boolean setup( InputStream in ) {
|
||||||
try {
|
try {
|
||||||
return FlatLaf.install( createLaf( in ) );
|
return FlatLaf.setup( createLaf( in ) );
|
||||||
} catch( Exception ex ) {
|
} catch( Exception ex ) {
|
||||||
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to load IntelliJ theme", ex );
|
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to load IntelliJ theme", ex );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link #setup(InputStream)} instead; this method will be removed in a future version
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public static boolean install( InputStream in ) {
|
||||||
|
return setup( in );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a IntelliJ .theme.json file from the given input stream and
|
* Loads a IntelliJ .theme.json file from the given input stream and
|
||||||
* creates a Laf instance for it.
|
* creates a Laf instance for it.
|
||||||
@@ -215,6 +224,12 @@ public class IntelliJTheme
|
|||||||
if( !uiKeys.contains( "ToggleButton.foreground" ) && uiKeys.contains( "Button.foreground" ) )
|
if( !uiKeys.contains( "ToggleButton.foreground" ) && uiKeys.contains( "Button.foreground" ) )
|
||||||
defaults.put( "ToggleButton.foreground", defaults.get( "Button.foreground" ) );
|
defaults.put( "ToggleButton.foreground", defaults.get( "Button.foreground" ) );
|
||||||
|
|
||||||
|
// fix DesktopPane background (use Panel.background and make it 5% darker/lighter)
|
||||||
|
Color desktopBackgroundBase = defaults.getColor( "Panel.background" );
|
||||||
|
Color desktopBackground = ColorFunctions.applyFunctions( desktopBackgroundBase,
|
||||||
|
new ColorFunctions.HSLIncreaseDecrease( 2, dark, 5, false, true ) );
|
||||||
|
defaults.put( "Desktop.background", new ColorUIResource( desktopBackground ) );
|
||||||
|
|
||||||
// fix List and Table background colors in Material UI Lite themes
|
// fix List and Table background colors in Material UI Lite themes
|
||||||
if( isMaterialUILite ) {
|
if( isMaterialUILite ) {
|
||||||
defaults.put( "List.background", defaults.get( "Tree.background" ) );
|
defaults.put( "List.background", defaults.get( "Tree.background" ) );
|
||||||
@@ -241,9 +256,10 @@ public class IntelliJTheme
|
|||||||
// remove theme specific UI defaults and remember only those for current theme
|
// remove theme specific UI defaults and remember only those for current theme
|
||||||
Map<Object, Object> themeSpecificDefaults = new HashMap<>();
|
Map<Object, Object> themeSpecificDefaults = new HashMap<>();
|
||||||
String currentThemePrefix = '[' + name.replace( ' ', '_' ) + ']';
|
String currentThemePrefix = '[' + name.replace( ' ', '_' ) + ']';
|
||||||
|
String currentThemeAndAuthorPrefix = '[' + name.replace( ' ', '_' ) + "---" + author.replace( ' ', '_' ) + ']';
|
||||||
String currentAuthorPrefix = "[author-" + author.replace( ' ', '_' ) + ']';
|
String currentAuthorPrefix = "[author-" + author.replace( ' ', '_' ) + ']';
|
||||||
String allThemesPrefix = "[*]";
|
String allThemesPrefix = "[*]";
|
||||||
String[] prefixes = { currentThemePrefix, currentAuthorPrefix, allThemesPrefix };
|
String[] prefixes = { currentThemePrefix, currentThemeAndAuthorPrefix, currentAuthorPrefix, allThemesPrefix };
|
||||||
for( String key : themeSpecificKeys ) {
|
for( String key : themeSpecificKeys ) {
|
||||||
Object value = defaults.remove( key );
|
Object value = defaults.remove( key );
|
||||||
for( String prefix : prefixes ) {
|
for( String prefix : prefixes ) {
|
||||||
@@ -344,6 +360,10 @@ public class IntelliJTheme
|
|||||||
|
|
||||||
// replace all values in UI defaults that match the wildcard key
|
// replace all values in UI defaults that match the wildcard key
|
||||||
for( Object k : defaultsKeysCache ) {
|
for( Object k : defaultsKeysCache ) {
|
||||||
|
if( k.equals( "Desktop.background" ) ||
|
||||||
|
k.equals( "DesktopIcon.background" ) )
|
||||||
|
continue;
|
||||||
|
|
||||||
if( k instanceof String ) {
|
if( k instanceof String ) {
|
||||||
// support replacing of mapped keys
|
// support replacing of mapped keys
|
||||||
// (e.g. set ComboBox.buttonEditableBackground to *.background
|
// (e.g. set ComboBox.buttonEditableBackground to *.background
|
||||||
|
|||||||
@@ -55,24 +55,38 @@ class LinuxFontPolicy
|
|||||||
|
|
||||||
String family = "";
|
String family = "";
|
||||||
int style = Font.PLAIN;
|
int style = Font.PLAIN;
|
||||||
int size = 10;
|
double dsize = 10;
|
||||||
|
|
||||||
|
// parse pango font description
|
||||||
|
// see https://developer.gnome.org/pango/1.46/pango-Fonts.html#pango-font-description-from-string
|
||||||
StringTokenizer st = new StringTokenizer( (String) fontName );
|
StringTokenizer st = new StringTokenizer( (String) fontName );
|
||||||
while( st.hasMoreTokens() ) {
|
while( st.hasMoreTokens() ) {
|
||||||
String word = st.nextToken();
|
String word = st.nextToken();
|
||||||
|
|
||||||
if( word.equalsIgnoreCase( "italic" ) )
|
// remove trailing ',' (e.g. in "Ubuntu Condensed, 11" or "Ubuntu Condensed, Bold 11")
|
||||||
|
if( word.endsWith( "," ) )
|
||||||
|
word = word.substring( 0, word.length() - 1 ).trim();
|
||||||
|
|
||||||
|
String lword = word.toLowerCase();
|
||||||
|
if( lword.equals( "italic" ) || lword.equals( "oblique" ) )
|
||||||
style |= Font.ITALIC;
|
style |= Font.ITALIC;
|
||||||
else if( word.equalsIgnoreCase( "bold" ) )
|
else if( lword.equals( "bold" ) )
|
||||||
style |= Font.BOLD;
|
style |= Font.BOLD;
|
||||||
else if( Character.isDigit( word.charAt( 0 ) ) ) {
|
else if( Character.isDigit( word.charAt( 0 ) ) ) {
|
||||||
try {
|
try {
|
||||||
size = Integer.parseInt( word );
|
dsize = Double.parseDouble( word );
|
||||||
} catch( NumberFormatException ex ) {
|
} catch( NumberFormatException ex ) {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
|
// remove '-' from "Semi-Bold", "Extra-Light", etc
|
||||||
|
if( lword.startsWith( "semi-" ) || lword.startsWith( "demi-" ) )
|
||||||
|
word = word.substring( 0, 4 ) + word.substring( 5 );
|
||||||
|
else if( lword.startsWith( "extra-" ) || lword.startsWith( "ultra-" ) )
|
||||||
|
word = word.substring( 0, 5 ) + word.substring( 6 );
|
||||||
|
|
||||||
family = family.isEmpty() ? word : (family + ' ' + word);
|
family = family.isEmpty() ? word : (family + ' ' + word);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ubuntu font is rendered poorly (except if running in JetBrains VM)
|
// Ubuntu font is rendered poorly (except if running in JetBrains VM)
|
||||||
@@ -83,8 +97,8 @@ class LinuxFontPolicy
|
|||||||
family = "Liberation Sans";
|
family = "Liberation Sans";
|
||||||
|
|
||||||
// scale font size
|
// scale font size
|
||||||
double dsize = size * getGnomeFontScale();
|
dsize *= getGnomeFontScale();
|
||||||
size = (int) (dsize + 0.5);
|
int size = (int) (dsize + 0.5);
|
||||||
if( size < 1 )
|
if( size < 1 )
|
||||||
size = 1;
|
size = 1;
|
||||||
|
|
||||||
@@ -93,7 +107,37 @@ class LinuxFontPolicy
|
|||||||
if( logicalFamily != null )
|
if( logicalFamily != null )
|
||||||
family = logicalFamily;
|
family = logicalFamily;
|
||||||
|
|
||||||
return createFont( family, style, size, dsize );
|
return createFontEx( family, style, size, dsize );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a font for the given family, style and size.
|
||||||
|
* If the font family does not match any font on the system,
|
||||||
|
* then the last word (usually a font weight) from the family name is removed and tried again.
|
||||||
|
* E.g. family 'URW Bookman Light' is not found, but 'URW Bookman' is found.
|
||||||
|
* If still not found, then font of family 'Dialog' is returned.
|
||||||
|
*/
|
||||||
|
private static Font createFontEx( String family, int style, int size, double dsize ) {
|
||||||
|
for(;;) {
|
||||||
|
Font font = createFont( family, style, size, dsize );
|
||||||
|
|
||||||
|
// if the font family does not match any font on the system, "Dialog" family is returned
|
||||||
|
if( !"Dialog".equals( font.getFamily() ) || "Dialog".equals( family ) )
|
||||||
|
return font;
|
||||||
|
|
||||||
|
// find last word in family
|
||||||
|
int index = family.lastIndexOf( ' ' );
|
||||||
|
if( index < 0 )
|
||||||
|
return createFont( "Dialog", style, size, dsize );
|
||||||
|
|
||||||
|
// check whether last work contains some font weight (e.g. Ultra-Bold or Heavy)
|
||||||
|
String lastWord = family.substring( index + 1 ).toLowerCase();
|
||||||
|
if( lastWord.contains( "bold" ) || lastWord.contains( "heavy" ) || lastWord.contains( "black" ) )
|
||||||
|
style |= Font.BOLD;
|
||||||
|
|
||||||
|
// remove last word from family and try again
|
||||||
|
family = family.substring( 0, index );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Font createFont( String family, int style, int size, double dsize ) {
|
private static Font createFont( String family, int style, int size, double dsize ) {
|
||||||
@@ -265,6 +309,9 @@ class LinuxFontPolicy
|
|||||||
* - running on JetBrains Runtime 11 or later and scaling is enabled in system Settings
|
* - running on JetBrains Runtime 11 or later and scaling is enabled in system Settings
|
||||||
*/
|
*/
|
||||||
private static boolean isSystemScaling() {
|
private static boolean isSystemScaling() {
|
||||||
|
if( GraphicsEnvironment.isHeadless() )
|
||||||
|
return true;
|
||||||
|
|
||||||
GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment()
|
GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment()
|
||||||
.getDefaultScreenDevice().getDefaultConfiguration();
|
.getDefaultScreenDevice().getDefaultConfiguration();
|
||||||
return UIScale.getSystemScaleFactor( gc ) > 1;
|
return UIScale.getSystemScaleFactor( gc ) > 1;
|
||||||
|
|||||||
@@ -442,8 +442,8 @@ class UIDefaultsLoader
|
|||||||
private static Object parseInstance( String value, List<ClassLoader> addonClassLoaders ) {
|
private static Object parseInstance( String value, List<ClassLoader> addonClassLoaders ) {
|
||||||
return (LazyValue) t -> {
|
return (LazyValue) t -> {
|
||||||
try {
|
try {
|
||||||
return findClass( value, addonClassLoaders ).newInstance();
|
return findClass( value, addonClassLoaders ).getDeclaredConstructor().newInstance();
|
||||||
} catch( InstantiationException | IllegalAccessException | ClassNotFoundException ex ) {
|
} catch( Exception ex ) {
|
||||||
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to instantiate '" + value + "'.", ex );
|
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to instantiate '" + value + "'.", ex );
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ public class FlatCapsLockIcon
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||||
<g fill="none" fill-rule="evenodd">
|
<g fill="none" fill-rule="evenodd">
|
||||||
<rect width="16" height="16" fill="#6E6E6E" rx="3"/>
|
<rect width="16" height="16" fill="#6E6E6E" rx="3"/>
|
||||||
<rect width="6" height="2" x="5" y="12" fill="#FFF"/>
|
<rect width="6" height="2" x="5" y="11.5" fill="#FFF"/>
|
||||||
<path fill="#FFF" d="M2,8 L8,2 L14,8 L11,8 L11,10 L5,10 L5,8 L2,8 Z"/>
|
<path fill="#FFF" d="M2,8 L8,2 L14,8 L11,8 L11,10 L5,10 L5,8 L2,8 Z"/>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
@@ -52,7 +52,7 @@ public class FlatCapsLockIcon
|
|||||||
|
|
||||||
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
||||||
path.append( new RoundRectangle2D.Float( 0, 0, 16, 16, 6, 6 ), false );
|
path.append( new RoundRectangle2D.Float( 0, 0, 16, 16, 6, 6 ), false );
|
||||||
path.append( new Rectangle2D.Float( 5, 12, 6, 2 ), false );
|
path.append( new Rectangle2D.Float( 5, 11.5f, 6, 2 ), false );
|
||||||
path.append( FlatUIUtils.createPath( 2,8, 8,2, 14,8, 11,8, 11,10, 5,10, 5,8 ), false );
|
path.append( FlatUIUtils.createPath( 2,8, 8,2, 14,8, 11,8, 11,10, 5,10, 5,8 ), false );
|
||||||
g.fill( path );
|
g.fill( path );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,8 +48,8 @@ public class FlatArrowButton
|
|||||||
protected final Color pressedBackground;
|
protected final Color pressedBackground;
|
||||||
|
|
||||||
private int arrowWidth = DEFAULT_ARROW_WIDTH;
|
private int arrowWidth = DEFAULT_ARROW_WIDTH;
|
||||||
private int xOffset = 0;
|
private float xOffset = 0;
|
||||||
private int yOffset = 0;
|
private float yOffset = 0;
|
||||||
|
|
||||||
private boolean hover;
|
private boolean hover;
|
||||||
private boolean pressed;
|
private boolean pressed;
|
||||||
@@ -117,19 +117,19 @@ public class FlatArrowButton
|
|||||||
return pressed;
|
return pressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getXOffset() {
|
public float getXOffset() {
|
||||||
return xOffset;
|
return xOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setXOffset( int xOffset ) {
|
public void setXOffset( float xOffset ) {
|
||||||
this.xOffset = xOffset;
|
this.xOffset = xOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getYOffset() {
|
public float getYOffset() {
|
||||||
return yOffset;
|
return yOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setYOffset( int yOffset ) {
|
public void setYOffset( float yOffset ) {
|
||||||
this.yOffset = yOffset;
|
this.yOffset = yOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,6 +141,21 @@ public class FlatArrowButton
|
|||||||
return FlatUIUtils.deriveColor( foreground, this.foreground );
|
return FlatUIUtils.deriveColor( foreground, this.foreground );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the color used to paint the arrow.
|
||||||
|
*
|
||||||
|
* @since 1.2
|
||||||
|
*/
|
||||||
|
protected Color getArrowColor() {
|
||||||
|
return isEnabled()
|
||||||
|
? (pressedForeground != null && isPressed()
|
||||||
|
? pressedForeground
|
||||||
|
: (hoverForeground != null && isHover()
|
||||||
|
? hoverForeground
|
||||||
|
: foreground))
|
||||||
|
: disabledForeground;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Dimension getPreferredSize() {
|
public Dimension getPreferredSize() {
|
||||||
return scale( super.getPreferredSize() );
|
return scale( super.getPreferredSize() );
|
||||||
@@ -170,13 +185,7 @@ public class FlatArrowButton
|
|||||||
}
|
}
|
||||||
|
|
||||||
// paint arrow
|
// paint arrow
|
||||||
g.setColor( deriveForeground( isEnabled()
|
g.setColor( deriveForeground( getArrowColor() ) );
|
||||||
? (pressedForeground != null && isPressed()
|
|
||||||
? pressedForeground
|
|
||||||
: (hoverForeground != null && isHover()
|
|
||||||
? hoverForeground
|
|
||||||
: foreground))
|
|
||||||
: disabledForeground ) );
|
|
||||||
paintArrow( (Graphics2D) g );
|
paintArrow( (Graphics2D) g );
|
||||||
|
|
||||||
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
|
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
|
||||||
|
|||||||
@@ -22,17 +22,12 @@ import java.awt.Component;
|
|||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.Insets;
|
import java.awt.Insets;
|
||||||
import java.awt.KeyboardFocusManager;
|
|
||||||
import java.awt.Paint;
|
import java.awt.Paint;
|
||||||
import javax.swing.JComboBox;
|
import javax.swing.JComboBox;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JScrollPane;
|
import javax.swing.JScrollPane;
|
||||||
import javax.swing.JSpinner;
|
import javax.swing.JSpinner;
|
||||||
import javax.swing.JTable;
|
|
||||||
import javax.swing.JTextField;
|
|
||||||
import javax.swing.JTree;
|
|
||||||
import javax.swing.JViewport;
|
import javax.swing.JViewport;
|
||||||
import javax.swing.SwingUtilities;
|
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.plaf.basic.BasicBorders;
|
import javax.swing.plaf.basic.BasicBorders;
|
||||||
import com.formdev.flatlaf.FlatClientProperties;
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
@@ -164,37 +159,13 @@ public class FlatBorder
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isFocused( Component c ) {
|
protected boolean isFocused( Component c ) {
|
||||||
if( c instanceof JScrollPane ) {
|
if( c instanceof JScrollPane )
|
||||||
JViewport viewport = ((JScrollPane)c).getViewport();
|
return FlatScrollPaneUI.isPermanentFocusOwner( (JScrollPane) c );
|
||||||
Component view = (viewport != null) ? viewport.getView() : null;
|
else if( c instanceof JComboBox )
|
||||||
if( view != null ) {
|
return FlatComboBoxUI.isPermanentFocusOwner( (JComboBox<?>) c );
|
||||||
if( FlatUIUtils.isPermanentFocusOwner( view ) )
|
else if( c instanceof JSpinner )
|
||||||
return true;
|
return FlatSpinnerUI.isPermanentFocusOwner( (JSpinner) c );
|
||||||
|
else
|
||||||
if( (view instanceof JTable && ((JTable)view).isEditing()) ||
|
|
||||||
(view instanceof JTree && ((JTree)view).isEditing()) )
|
|
||||||
{
|
|
||||||
Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
|
|
||||||
if( focusOwner != null )
|
|
||||||
return SwingUtilities.isDescendingFrom( focusOwner, view );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
} else if( c instanceof JComboBox && ((JComboBox<?>)c).isEditable() ) {
|
|
||||||
Component editorComponent = ((JComboBox<?>)c).getEditor().getEditorComponent();
|
|
||||||
return (editorComponent != null) ? FlatUIUtils.isPermanentFocusOwner( editorComponent ) : false;
|
|
||||||
} else if( c instanceof JSpinner ) {
|
|
||||||
if( FlatUIUtils.isPermanentFocusOwner( c ) )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
JComponent editor = ((JSpinner)c).getEditor();
|
|
||||||
if( editor instanceof JSpinner.DefaultEditor ) {
|
|
||||||
JTextField textField = ((JSpinner.DefaultEditor)editor).getTextField();
|
|
||||||
if( textField != null )
|
|
||||||
return FlatUIUtils.isPermanentFocusOwner( textField );
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
} else
|
|
||||||
return FlatUIUtils.isPermanentFocusOwner( c );
|
return FlatUIUtils.isPermanentFocusOwner( c );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,13 +176,14 @@ public class FlatBorder
|
|||||||
@Override
|
@Override
|
||||||
public Insets getBorderInsets( Component c, Insets insets ) {
|
public Insets getBorderInsets( Component c, Insets insets ) {
|
||||||
float focusWidth = scale( (float) getFocusWidth( c ) );
|
float focusWidth = scale( (float) getFocusWidth( c ) );
|
||||||
float ow = focusWidth + scale( (float) getLineWidth( c ) );
|
int ow = Math.round( focusWidth + scale( (float) getLineWidth( c ) ) );
|
||||||
|
|
||||||
insets = super.getBorderInsets( c, insets );
|
insets = super.getBorderInsets( c, insets );
|
||||||
insets.top = Math.round( scale( (float) insets.top ) + ow );
|
|
||||||
insets.left = Math.round( scale( (float) insets.left ) + ow );
|
insets.top = scale( insets.top ) + ow;
|
||||||
insets.bottom = Math.round( scale( (float) insets.bottom ) + ow );
|
insets.left = scale( insets.left ) + ow;
|
||||||
insets.right = Math.round( scale( (float) insets.right ) + ow );
|
insets.bottom = scale( insets.bottom ) + ow;
|
||||||
|
insets.right = scale( insets.right ) + ow;
|
||||||
|
|
||||||
if( isCellEditor( c ) ) {
|
if( isCellEditor( c ) ) {
|
||||||
// remove top and bottom insets if used as cell editor
|
// remove top and bottom insets if used as cell editor
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import java.awt.Color;
|
|||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.GradientPaint;
|
import java.awt.GradientPaint;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
|
import java.awt.Graphics2D;
|
||||||
import java.awt.Insets;
|
import java.awt.Insets;
|
||||||
import java.awt.Paint;
|
import java.awt.Paint;
|
||||||
import javax.swing.AbstractButton;
|
import javax.swing.AbstractButton;
|
||||||
@@ -42,11 +43,13 @@ import com.formdev.flatlaf.util.UIScale;
|
|||||||
* @uiDefault Button.default.hoverBorderColor Color optional
|
* @uiDefault Button.default.hoverBorderColor Color optional
|
||||||
* @uiDefault Button.default.focusedBorderColor Color
|
* @uiDefault Button.default.focusedBorderColor Color
|
||||||
* @uiDefault Button.default.focusColor Color
|
* @uiDefault Button.default.focusColor Color
|
||||||
|
* @uiDefault Button.toolbar.focusColor Color optional; defaults to Component.focusColor
|
||||||
* @uiDefault Button.borderWidth int
|
* @uiDefault Button.borderWidth int
|
||||||
* @uiDefault Button.default.borderWidth int
|
* @uiDefault Button.default.borderWidth int
|
||||||
* @uiDefault Button.innerFocusWidth int or float optional; defaults to Component.innerFocusWidth
|
* @uiDefault Button.innerFocusWidth int or float optional; defaults to Component.innerFocusWidth
|
||||||
* @uiDefault Button.toolbar.margin Insets
|
* @uiDefault Button.toolbar.margin Insets
|
||||||
* @uiDefault Button.toolbar.spacingInsets Insets
|
* @uiDefault Button.toolbar.spacingInsets Insets
|
||||||
|
* @uiDefault Button.toolbar.focusWidth int or float optional; default is 1
|
||||||
* @uiDefault Button.arc int
|
* @uiDefault Button.arc int
|
||||||
*
|
*
|
||||||
* @author Karl Tauber
|
* @author Karl Tauber
|
||||||
@@ -64,25 +67,60 @@ public class FlatButtonBorder
|
|||||||
protected final Color defaultHoverBorderColor = UIManager.getColor( "Button.default.hoverBorderColor" );
|
protected final Color defaultHoverBorderColor = UIManager.getColor( "Button.default.hoverBorderColor" );
|
||||||
protected final Color defaultFocusedBorderColor = UIManager.getColor( "Button.default.focusedBorderColor" );
|
protected final Color defaultFocusedBorderColor = UIManager.getColor( "Button.default.focusedBorderColor" );
|
||||||
protected final Color defaultFocusColor = UIManager.getColor( "Button.default.focusColor" );
|
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 borderWidth = UIManager.getInt( "Button.borderWidth" );
|
||||||
protected final int defaultBorderWidth = UIManager.getInt( "Button.default.borderWidth" );
|
protected final int defaultBorderWidth = UIManager.getInt( "Button.default.borderWidth" );
|
||||||
protected final float buttonInnerFocusWidth = FlatUIUtils.getUIFloat( "Button.innerFocusWidth", innerFocusWidth );
|
protected final float buttonInnerFocusWidth = FlatUIUtils.getUIFloat( "Button.innerFocusWidth", innerFocusWidth );
|
||||||
protected final Insets toolbarMargin = UIManager.getInsets( "Button.toolbar.margin" );
|
protected final Insets toolbarMargin = UIManager.getInsets( "Button.toolbar.margin" );
|
||||||
protected final Insets toolbarSpacingInsets = UIManager.getInsets( "Button.toolbar.spacingInsets" );
|
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" );
|
protected final int arc = UIManager.getInt( "Button.arc" );
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||||
if( FlatButtonUI.isContentAreaFilled( c ) &&
|
if( FlatButtonUI.isContentAreaFilled( c ) &&
|
||||||
!FlatButtonUI.isToolBarButton( c ) &&
|
!FlatButtonUI.isToolBarButton( c ) &&
|
||||||
|
(!FlatButtonUI.isBorderlessButton( c ) || FlatUIUtils.isPermanentFocusOwner( c )) &&
|
||||||
!FlatButtonUI.isHelpButton( c ) &&
|
!FlatButtonUI.isHelpButton( c ) &&
|
||||||
!FlatToggleButtonUI.isTabButton( c ) )
|
!FlatToggleButtonUI.isTabButton( c ) )
|
||||||
super.paintBorder( c, g, x, y, width, height );
|
super.paintBorder( c, g, x, y, width, height );
|
||||||
|
else if( FlatButtonUI.isToolBarButton( c ) && isFocused( c ) )
|
||||||
|
paintToolBarFocus( c, g, x, y, width, height );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 1.4
|
||||||
|
*/
|
||||||
|
protected void paintToolBarFocus( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||||
|
Graphics2D g2 = (Graphics2D) g.create();
|
||||||
|
try {
|
||||||
|
FlatUIUtils.setRenderingHints( g2 );
|
||||||
|
|
||||||
|
float focusWidth = UIScale.scale( toolbarFocusWidth );
|
||||||
|
float arc = UIScale.scale( (float) getArc( c ) );
|
||||||
|
Color outlineColor = getOutlineColor( c );
|
||||||
|
|
||||||
|
Insets spacing = UIScale.scale( toolbarSpacingInsets );
|
||||||
|
x += spacing.left;
|
||||||
|
y += spacing.top;
|
||||||
|
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 );
|
||||||
|
} finally {
|
||||||
|
g2.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Color getFocusColor( Component c ) {
|
protected Color getFocusColor( Component c ) {
|
||||||
return FlatButtonUI.isDefaultButton( c ) ? defaultFocusColor : super.getFocusColor( c );
|
return (toolbarFocusColor != null && FlatButtonUI.isToolBarButton( c ))
|
||||||
|
? toolbarFocusColor
|
||||||
|
: (FlatButtonUI.isDefaultButton( c ) ? defaultFocusColor : super.getFocusColor( c ));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -285,6 +285,10 @@ public class FlatButtonUI
|
|||||||
(c instanceof AbstractButton && clientPropertyEquals( (AbstractButton) c, BUTTON_TYPE, BUTTON_TYPE_TOOLBAR_BUTTON ));
|
(c instanceof AbstractButton && clientPropertyEquals( (AbstractButton) c, BUTTON_TYPE, BUTTON_TYPE_TOOLBAR_BUTTON ));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static boolean isBorderlessButton( Component c ) {
|
||||||
|
return c instanceof AbstractButton && clientPropertyEquals( (AbstractButton) c, BUTTON_TYPE, BUTTON_TYPE_BORDERLESS );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update( Graphics g, JComponent c ) {
|
public void update( Graphics g, JComponent c ) {
|
||||||
// fill background if opaque to avoid garbage if user sets opaque to true
|
// fill background if opaque to avoid garbage if user sets opaque to true
|
||||||
@@ -332,8 +336,9 @@ public class FlatButtonUI
|
|||||||
|
|
||||||
// paint shadow
|
// paint shadow
|
||||||
Color shadowColor = def ? defaultShadowColor : this.shadowColor;
|
Color shadowColor = def ? defaultShadowColor : this.shadowColor;
|
||||||
if( !isToolBarButton && shadowColor != null && shadowWidth > 0 && focusWidth > 0 &&
|
if( shadowColor != null && shadowWidth > 0 && focusWidth > 0 && c.isEnabled() &&
|
||||||
!(isFocusPainted( c ) && FlatUIUtils.isPermanentFocusOwner( c )) && c.isEnabled() )
|
!isToolBarButton && !isBorderlessButton( c ) &&
|
||||||
|
!(isFocusPainted( c ) && FlatUIUtils.isPermanentFocusOwner( c )) )
|
||||||
{
|
{
|
||||||
g2.setColor( shadowColor );
|
g2.setColor( shadowColor );
|
||||||
g2.fill( new RoundRectangle2D.Float( focusWidth, focusWidth + UIScale.scale( (float) shadowWidth ),
|
g2.fill( new RoundRectangle2D.Float( focusWidth, focusWidth + UIScale.scale( (float) shadowWidth ),
|
||||||
@@ -388,7 +393,7 @@ public class FlatButtonUI
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected Color getBackground( JComponent c ) {
|
protected Color getBackground( JComponent c ) {
|
||||||
boolean toolBarButton = isToolBarButton( c );
|
boolean toolBarButton = isToolBarButton( c ) || isBorderlessButton( c );
|
||||||
|
|
||||||
// selected state
|
// selected state
|
||||||
if( ((AbstractButton)c).isSelected() ) {
|
if( ((AbstractButton)c).isSelected() ) {
|
||||||
@@ -461,7 +466,7 @@ public class FlatButtonUI
|
|||||||
if( !c.isEnabled() )
|
if( !c.isEnabled() )
|
||||||
return disabledText;
|
return disabledText;
|
||||||
|
|
||||||
if( ((AbstractButton)c).isSelected() && !isToolBarButton( c ) )
|
if( ((AbstractButton)c).isSelected() && !(isToolBarButton( c ) || isBorderlessButton( c )) )
|
||||||
return selectedForeground;
|
return selectedForeground;
|
||||||
|
|
||||||
// use component foreground if explicitly set
|
// use component foreground if explicitly set
|
||||||
@@ -496,9 +501,9 @@ public class FlatButtonUI
|
|||||||
prefSize.width = Math.max( prefSize.width, prefSize.height );
|
prefSize.width = Math.max( prefSize.width, prefSize.height );
|
||||||
} else if( !isIconOnlyOrSingleCharacter && !isToolBarButton( c ) && c.getBorder() instanceof FlatButtonBorder ) {
|
} else if( !isIconOnlyOrSingleCharacter && !isToolBarButton( c ) && c.getBorder() instanceof FlatButtonBorder ) {
|
||||||
// apply minimum width/height
|
// apply minimum width/height
|
||||||
float focusWidth = FlatUIUtils.getBorderFocusWidth( c );
|
int fw = Math.round( FlatUIUtils.getBorderFocusWidth( c ) * 2 );
|
||||||
prefSize.width = Math.max( prefSize.width, scale( FlatUIUtils.minimumWidth( c, minimumWidth ) ) + Math.round( focusWidth * 2 ) );
|
prefSize.width = Math.max( prefSize.width, scale( FlatUIUtils.minimumWidth( c, minimumWidth ) ) + fw );
|
||||||
prefSize.height = Math.max( prefSize.height, scale( FlatUIUtils.minimumHeight( c, 0 ) ) + Math.round( focusWidth * 2 ) );
|
prefSize.height = Math.max( prefSize.height, scale( FlatUIUtils.minimumHeight( c, 0 ) ) + fw );
|
||||||
}
|
}
|
||||||
|
|
||||||
return prefSize;
|
return prefSize;
|
||||||
|
|||||||
@@ -18,10 +18,13 @@ package com.formdev.flatlaf.ui;
|
|||||||
|
|
||||||
import static com.formdev.flatlaf.FlatClientProperties.*;
|
import static com.formdev.flatlaf.FlatClientProperties.*;
|
||||||
import java.awt.EventQueue;
|
import java.awt.EventQueue;
|
||||||
|
import java.awt.Insets;
|
||||||
|
import java.awt.Rectangle;
|
||||||
import java.awt.event.FocusEvent;
|
import java.awt.event.FocusEvent;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import javax.swing.JFormattedTextField;
|
import javax.swing.JFormattedTextField;
|
||||||
import javax.swing.plaf.UIResource;
|
import javax.swing.plaf.UIResource;
|
||||||
|
import javax.swing.text.BadLocationException;
|
||||||
import javax.swing.text.DefaultCaret;
|
import javax.swing.text.DefaultCaret;
|
||||||
import javax.swing.text.Document;
|
import javax.swing.text.Document;
|
||||||
import javax.swing.text.JTextComponent;
|
import javax.swing.text.JTextComponent;
|
||||||
@@ -61,6 +64,19 @@ public class FlatCaret
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.adjustVisibility( nloc );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void focusGained( FocusEvent e ) {
|
public void focusGained( FocusEvent e ) {
|
||||||
if( !wasTemporaryLost && (!isMousePressed || selectAllOnMouseClick) )
|
if( !wasTemporaryLost && (!isMousePressed || selectAllOnMouseClick) )
|
||||||
@@ -127,4 +143,23 @@ public class FlatCaret
|
|||||||
moveDot( doc.getLength() );
|
moveDot( doc.getLength() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 1.4
|
||||||
|
*/
|
||||||
|
public void scrollCaretToVisible() {
|
||||||
|
JTextComponent c = getComponent();
|
||||||
|
if( c == null || c.getUI() == null )
|
||||||
|
return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
Rectangle loc = c.getUI().modelToView( c, getDot(), getDotBias() );
|
||||||
|
if( loc != null ) {
|
||||||
|
adjustVisibility( loc );
|
||||||
|
damage( loc );
|
||||||
|
}
|
||||||
|
} catch( BadLocationException ex ) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package com.formdev.flatlaf.ui;
|
package com.formdev.flatlaf.ui;
|
||||||
|
|
||||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||||
|
import static com.formdev.flatlaf.util.UIScale.unscale;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.ComponentOrientation;
|
import java.awt.ComponentOrientation;
|
||||||
@@ -39,9 +40,9 @@ import java.awt.event.MouseEvent;
|
|||||||
import java.awt.event.MouseListener;
|
import java.awt.event.MouseListener;
|
||||||
import java.awt.geom.Rectangle2D;
|
import java.awt.geom.Rectangle2D;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
import javax.swing.AbstractAction;
|
import javax.swing.AbstractAction;
|
||||||
import javax.swing.BorderFactory;
|
import javax.swing.BorderFactory;
|
||||||
|
import javax.swing.CellRendererPane;
|
||||||
import javax.swing.ComboBoxEditor;
|
import javax.swing.ComboBoxEditor;
|
||||||
import javax.swing.DefaultListCellRenderer;
|
import javax.swing.DefaultListCellRenderer;
|
||||||
import javax.swing.InputMap;
|
import javax.swing.InputMap;
|
||||||
@@ -60,13 +61,13 @@ import javax.swing.UIManager;
|
|||||||
import javax.swing.border.AbstractBorder;
|
import javax.swing.border.AbstractBorder;
|
||||||
import javax.swing.border.Border;
|
import javax.swing.border.Border;
|
||||||
import javax.swing.plaf.ComponentUI;
|
import javax.swing.plaf.ComponentUI;
|
||||||
|
import javax.swing.plaf.UIResource;
|
||||||
import javax.swing.plaf.basic.BasicComboBoxUI;
|
import javax.swing.plaf.basic.BasicComboBoxUI;
|
||||||
import javax.swing.plaf.basic.BasicComboPopup;
|
import javax.swing.plaf.basic.BasicComboPopup;
|
||||||
import javax.swing.plaf.basic.ComboPopup;
|
import javax.swing.plaf.basic.ComboPopup;
|
||||||
import javax.swing.text.JTextComponent;
|
import javax.swing.text.JTextComponent;
|
||||||
import com.formdev.flatlaf.FlatClientProperties;
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
import com.formdev.flatlaf.util.SystemInfo;
|
import com.formdev.flatlaf.util.SystemInfo;
|
||||||
import com.formdev.flatlaf.util.UIScale;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JComboBox}.
|
* Provides the Flat LaF UI delegate for {@link javax.swing.JComboBox}.
|
||||||
@@ -91,14 +92,17 @@ import com.formdev.flatlaf.util.UIScale;
|
|||||||
* @uiDefault Component.borderColor Color
|
* @uiDefault Component.borderColor Color
|
||||||
* @uiDefault Component.disabledBorderColor Color
|
* @uiDefault Component.disabledBorderColor Color
|
||||||
* @uiDefault ComboBox.editableBackground Color optional; defaults to ComboBox.background
|
* @uiDefault ComboBox.editableBackground Color optional; defaults to ComboBox.background
|
||||||
|
* @uiDefault ComboBox.focusedBackground Color optional
|
||||||
* @uiDefault ComboBox.disabledBackground Color
|
* @uiDefault ComboBox.disabledBackground Color
|
||||||
* @uiDefault ComboBox.disabledForeground Color
|
* @uiDefault ComboBox.disabledForeground Color
|
||||||
* @uiDefault ComboBox.buttonBackground Color
|
* @uiDefault ComboBox.buttonBackground Color
|
||||||
* @uiDefault ComboBox.buttonEditableBackground Color
|
* @uiDefault ComboBox.buttonEditableBackground Color
|
||||||
|
* @uiDefault ComboBox.buttonFocusedBackground Color optional; defaults to ComboBox.focusedBackground
|
||||||
* @uiDefault ComboBox.buttonArrowColor Color
|
* @uiDefault ComboBox.buttonArrowColor Color
|
||||||
* @uiDefault ComboBox.buttonDisabledArrowColor Color
|
* @uiDefault ComboBox.buttonDisabledArrowColor Color
|
||||||
* @uiDefault ComboBox.buttonHoverArrowColor Color
|
* @uiDefault ComboBox.buttonHoverArrowColor Color
|
||||||
* @uiDefault ComboBox.buttonPressedArrowColor Color
|
* @uiDefault ComboBox.buttonPressedArrowColor Color
|
||||||
|
* @uiDefault ComboBox.popupBackground Color optional
|
||||||
*
|
*
|
||||||
* @author Karl Tauber
|
* @author Karl Tauber
|
||||||
*/
|
*/
|
||||||
@@ -114,21 +118,25 @@ public class FlatComboBoxUI
|
|||||||
protected Color disabledBorderColor;
|
protected Color disabledBorderColor;
|
||||||
|
|
||||||
protected Color editableBackground;
|
protected Color editableBackground;
|
||||||
|
protected Color focusedBackground;
|
||||||
protected Color disabledBackground;
|
protected Color disabledBackground;
|
||||||
protected Color disabledForeground;
|
protected Color disabledForeground;
|
||||||
|
|
||||||
protected Color buttonBackground;
|
protected Color buttonBackground;
|
||||||
protected Color buttonEditableBackground;
|
protected Color buttonEditableBackground;
|
||||||
|
protected Color buttonFocusedBackground;
|
||||||
protected Color buttonArrowColor;
|
protected Color buttonArrowColor;
|
||||||
protected Color buttonDisabledArrowColor;
|
protected Color buttonDisabledArrowColor;
|
||||||
protected Color buttonHoverArrowColor;
|
protected Color buttonHoverArrowColor;
|
||||||
protected Color buttonPressedArrowColor;
|
protected Color buttonPressedArrowColor;
|
||||||
|
|
||||||
|
protected Color popupBackground;
|
||||||
|
|
||||||
private MouseListener hoverListener;
|
private MouseListener hoverListener;
|
||||||
protected boolean hover;
|
protected boolean hover;
|
||||||
protected boolean pressed;
|
protected boolean pressed;
|
||||||
|
|
||||||
private WeakReference<Component> lastRendererComponent;
|
private CellPaddingBorder paddingBorder;
|
||||||
|
|
||||||
public static ComponentUI createUI( JComponent c ) {
|
public static ComponentUI createUI( JComponent c ) {
|
||||||
return new FlatComboBoxUI();
|
return new FlatComboBoxUI();
|
||||||
@@ -194,23 +202,26 @@ public class FlatComboBoxUI
|
|||||||
disabledBorderColor = UIManager.getColor( "Component.disabledBorderColor" );
|
disabledBorderColor = UIManager.getColor( "Component.disabledBorderColor" );
|
||||||
|
|
||||||
editableBackground = UIManager.getColor( "ComboBox.editableBackground" );
|
editableBackground = UIManager.getColor( "ComboBox.editableBackground" );
|
||||||
|
focusedBackground = UIManager.getColor( "ComboBox.focusedBackground" );
|
||||||
disabledBackground = UIManager.getColor( "ComboBox.disabledBackground" );
|
disabledBackground = UIManager.getColor( "ComboBox.disabledBackground" );
|
||||||
disabledForeground = UIManager.getColor( "ComboBox.disabledForeground" );
|
disabledForeground = UIManager.getColor( "ComboBox.disabledForeground" );
|
||||||
|
|
||||||
buttonBackground = UIManager.getColor( "ComboBox.buttonBackground" );
|
buttonBackground = UIManager.getColor( "ComboBox.buttonBackground" );
|
||||||
|
buttonFocusedBackground = UIManager.getColor( "ComboBox.buttonFocusedBackground" );
|
||||||
buttonEditableBackground = UIManager.getColor( "ComboBox.buttonEditableBackground" );
|
buttonEditableBackground = UIManager.getColor( "ComboBox.buttonEditableBackground" );
|
||||||
buttonArrowColor = UIManager.getColor( "ComboBox.buttonArrowColor" );
|
buttonArrowColor = UIManager.getColor( "ComboBox.buttonArrowColor" );
|
||||||
buttonDisabledArrowColor = UIManager.getColor( "ComboBox.buttonDisabledArrowColor" );
|
buttonDisabledArrowColor = UIManager.getColor( "ComboBox.buttonDisabledArrowColor" );
|
||||||
buttonHoverArrowColor = UIManager.getColor( "ComboBox.buttonHoverArrowColor" );
|
buttonHoverArrowColor = UIManager.getColor( "ComboBox.buttonHoverArrowColor" );
|
||||||
buttonPressedArrowColor = UIManager.getColor( "ComboBox.buttonPressedArrowColor" );
|
buttonPressedArrowColor = UIManager.getColor( "ComboBox.buttonPressedArrowColor" );
|
||||||
|
|
||||||
|
popupBackground = UIManager.getColor( "ComboBox.popupBackground" );
|
||||||
|
|
||||||
// set maximumRowCount
|
// set maximumRowCount
|
||||||
int maximumRowCount = UIManager.getInt( "ComboBox.maximumRowCount" );
|
int maximumRowCount = UIManager.getInt( "ComboBox.maximumRowCount" );
|
||||||
if( maximumRowCount > 0 && maximumRowCount != 8 && comboBox.getMaximumRowCount() == 8 )
|
if( maximumRowCount > 0 && maximumRowCount != 8 && comboBox.getMaximumRowCount() == 8 )
|
||||||
comboBox.setMaximumRowCount( maximumRowCount );
|
comboBox.setMaximumRowCount( maximumRowCount );
|
||||||
|
|
||||||
// scale
|
paddingBorder = new CellPaddingBorder( padding );
|
||||||
padding = UIScale.scale( padding );
|
|
||||||
|
|
||||||
MigLayoutVisualPadding.install( comboBox );
|
MigLayoutVisualPadding.install( comboBox );
|
||||||
}
|
}
|
||||||
@@ -223,16 +234,22 @@ public class FlatComboBoxUI
|
|||||||
disabledBorderColor = null;
|
disabledBorderColor = null;
|
||||||
|
|
||||||
editableBackground = null;
|
editableBackground = null;
|
||||||
|
focusedBackground = null;
|
||||||
disabledBackground = null;
|
disabledBackground = null;
|
||||||
disabledForeground = null;
|
disabledForeground = null;
|
||||||
|
|
||||||
buttonBackground = null;
|
buttonBackground = null;
|
||||||
buttonEditableBackground = null;
|
buttonEditableBackground = null;
|
||||||
|
buttonFocusedBackground = null;
|
||||||
buttonArrowColor = null;
|
buttonArrowColor = null;
|
||||||
buttonDisabledArrowColor = null;
|
buttonDisabledArrowColor = null;
|
||||||
buttonHoverArrowColor = null;
|
buttonHoverArrowColor = null;
|
||||||
buttonPressedArrowColor = null;
|
buttonPressedArrowColor = null;
|
||||||
|
|
||||||
|
popupBackground = null;
|
||||||
|
|
||||||
|
paddingBorder.uninstall();
|
||||||
|
|
||||||
MigLayoutVisualPadding.uninstall( comboBox );
|
MigLayoutVisualPadding.uninstall( comboBox );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,11 +276,6 @@ public class FlatComboBoxUI
|
|||||||
editor.setBounds( rectangleForCurrentValue() );
|
editor.setBounds( rectangleForCurrentValue() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( editor != null && padding != null ) {
|
|
||||||
// fix editor bounds by subtracting padding
|
|
||||||
editor.setBounds( FlatUIUtils.subtractInsets( editor.getBounds(), padding ) );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -354,6 +366,7 @@ public class FlatComboBoxUI
|
|||||||
|
|
||||||
editor.applyComponentOrientation( comboBox.getComponentOrientation() );
|
editor.applyComponentOrientation( comboBox.getComponentOrientation() );
|
||||||
|
|
||||||
|
updateEditorPadding();
|
||||||
updateEditorColors();
|
updateEditorColors();
|
||||||
|
|
||||||
// macOS
|
// macOS
|
||||||
@@ -370,6 +383,25 @@ public class FlatComboBoxUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateEditorPadding() {
|
||||||
|
if( !(editor instanceof JTextField) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
JTextField textField = (JTextField) editor;
|
||||||
|
Insets insets = textField.getInsets();
|
||||||
|
Insets pad = padding;
|
||||||
|
if( insets.top != 0 || insets.left != 0 || insets.bottom != 0 || insets.right != 0 ) {
|
||||||
|
// if text field has custom border, subtract text field insets from padding
|
||||||
|
pad = new Insets(
|
||||||
|
unscale( Math.max( scale( padding.top ) - insets.top, 0 ) ),
|
||||||
|
unscale( Math.max( scale( padding.left ) - insets.left, 0 ) ),
|
||||||
|
unscale( Math.max( scale( padding.bottom ) - insets.bottom, 0 ) ),
|
||||||
|
unscale( Math.max( scale( padding.right ) - insets.right, 0 ) )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
textField.putClientProperty( FlatClientProperties.TEXT_FIELD_PADDING, pad );
|
||||||
|
}
|
||||||
|
|
||||||
private void updateEditorColors() {
|
private void updateEditorColors() {
|
||||||
// use non-UIResource colors because when SwingUtilities.updateComponentTreeUI()
|
// use non-UIResource colors because when SwingUtilities.updateComponentTreeUI()
|
||||||
// is used, then the editor is updated after the combobox and the
|
// is used, then the editor is updated after the combobox and the
|
||||||
@@ -390,6 +422,15 @@ public class FlatComboBoxUI
|
|||||||
public void update( Graphics g, JComponent c ) {
|
public void update( Graphics g, JComponent c ) {
|
||||||
float focusWidth = FlatUIUtils.getBorderFocusWidth( c );
|
float focusWidth = FlatUIUtils.getBorderFocusWidth( c );
|
||||||
float arc = FlatUIUtils.getBorderArc( c );
|
float arc = FlatUIUtils.getBorderArc( c );
|
||||||
|
boolean paintBackground = true;
|
||||||
|
|
||||||
|
// check whether used as cell renderer
|
||||||
|
boolean isCellRenderer = c.getParent() instanceof CellRendererPane;
|
||||||
|
if( isCellRenderer ) {
|
||||||
|
focusWidth = 0;
|
||||||
|
arc = 0;
|
||||||
|
paintBackground = isCellRendererBackgroundChanged();
|
||||||
|
}
|
||||||
|
|
||||||
// fill background if opaque to avoid garbage if user sets opaque to true
|
// fill background if opaque to avoid garbage if user sets opaque to true
|
||||||
if( c.isOpaque() && (focusWidth > 0 || arc > 0) )
|
if( c.isOpaque() && (focusWidth > 0 || arc > 0) )
|
||||||
@@ -407,27 +448,33 @@ public class FlatComboBoxUI
|
|||||||
boolean isLeftToRight = comboBox.getComponentOrientation().isLeftToRight();
|
boolean isLeftToRight = comboBox.getComponentOrientation().isLeftToRight();
|
||||||
|
|
||||||
// paint background
|
// paint background
|
||||||
g2.setColor( getBackground( enabled ) );
|
if( paintBackground || c.isOpaque() ) {
|
||||||
FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc );
|
g2.setColor( getBackground( enabled ) );
|
||||||
|
|
||||||
// paint arrow button background
|
|
||||||
if( enabled ) {
|
|
||||||
g2.setColor( paintButton ? buttonEditableBackground : buttonBackground );
|
|
||||||
Shape oldClip = g2.getClip();
|
|
||||||
if( isLeftToRight )
|
|
||||||
g2.clipRect( arrowX, 0, width - arrowX, height );
|
|
||||||
else
|
|
||||||
g2.clipRect( 0, 0, arrowX + arrowWidth, height );
|
|
||||||
FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc );
|
FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc );
|
||||||
g2.setClip( oldClip );
|
|
||||||
}
|
|
||||||
|
|
||||||
// paint vertical line between value and arrow button
|
// paint arrow button background
|
||||||
if( paintButton ) {
|
if( enabled && !isCellRenderer ) {
|
||||||
g2.setColor( enabled ? borderColor : disabledBorderColor );
|
g2.setColor( paintButton
|
||||||
float lw = scale( 1f );
|
? buttonEditableBackground
|
||||||
float lx = isLeftToRight ? arrowX : arrowX + arrowWidth - lw;
|
: (buttonFocusedBackground != null || focusedBackground != null) && isPermanentFocusOwner( comboBox )
|
||||||
g2.fill( new Rectangle2D.Float( lx, focusWidth, lw, height - 1 - (focusWidth * 2)) );
|
? (buttonFocusedBackground != null ? buttonFocusedBackground : focusedBackground)
|
||||||
|
: buttonBackground );
|
||||||
|
Shape oldClip = g2.getClip();
|
||||||
|
if( isLeftToRight )
|
||||||
|
g2.clipRect( arrowX, 0, width - arrowX, height );
|
||||||
|
else
|
||||||
|
g2.clipRect( 0, 0, arrowX + arrowWidth, height );
|
||||||
|
FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc );
|
||||||
|
g2.setClip( oldClip );
|
||||||
|
}
|
||||||
|
|
||||||
|
// paint vertical line between value and arrow 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)) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// avoid that the "current value" renderer is invoked with enabled antialiasing
|
// avoid that the "current value" renderer is invoked with enabled antialiasing
|
||||||
@@ -439,30 +486,24 @@ public class FlatComboBoxUI
|
|||||||
@Override
|
@Override
|
||||||
@SuppressWarnings( "unchecked" )
|
@SuppressWarnings( "unchecked" )
|
||||||
public void paintCurrentValue( Graphics g, Rectangle bounds, boolean hasFocus ) {
|
public void paintCurrentValue( Graphics g, Rectangle bounds, boolean hasFocus ) {
|
||||||
|
paddingBorder.uninstall();
|
||||||
|
|
||||||
ListCellRenderer<Object> renderer = comboBox.getRenderer();
|
ListCellRenderer<Object> renderer = comboBox.getRenderer();
|
||||||
uninstallCellPaddingBorder( renderer );
|
|
||||||
if( renderer == null )
|
if( renderer == null )
|
||||||
renderer = new DefaultListCellRenderer();
|
renderer = new DefaultListCellRenderer();
|
||||||
Component c = renderer.getListCellRendererComponent( listBox, comboBox.getSelectedItem(), -1, false, false );
|
Component c = renderer.getListCellRendererComponent( listBox, comboBox.getSelectedItem(), -1, false, false );
|
||||||
c.setFont( comboBox.getFont() );
|
c.setFont( comboBox.getFont() );
|
||||||
c.applyComponentOrientation( comboBox.getComponentOrientation() );
|
c.applyComponentOrientation( comboBox.getComponentOrientation() );
|
||||||
uninstallCellPaddingBorder( c );
|
|
||||||
|
|
||||||
boolean enabled = comboBox.isEnabled();
|
boolean enabled = comboBox.isEnabled();
|
||||||
c.setBackground( getBackground( enabled ) );
|
c.setBackground( getBackground( enabled ) );
|
||||||
c.setForeground( getForeground( enabled ) );
|
c.setForeground( getForeground( enabled ) );
|
||||||
|
|
||||||
boolean shouldValidate = (c instanceof JPanel);
|
boolean shouldValidate = (c instanceof JPanel);
|
||||||
if( padding != null )
|
|
||||||
bounds = FlatUIUtils.subtractInsets( bounds, padding );
|
|
||||||
|
|
||||||
// increase the size of the rendering area to make sure that the text
|
|
||||||
// is vertically aligned with other component types (e.g. JTextField)
|
|
||||||
Insets rendererInsets = getRendererComponentInsets( c );
|
|
||||||
if( rendererInsets != null )
|
|
||||||
bounds = FlatUIUtils.addInsets( bounds, rendererInsets );
|
|
||||||
|
|
||||||
|
paddingBorder.install( c );
|
||||||
currentValuePane.paintComponent( g, c, comboBox, bounds.x, bounds.y, bounds.width, bounds.height, shouldValidate );
|
currentValuePane.paintComponent( g, c, comboBox, bounds.x, bounds.y, bounds.width, bounds.height, shouldValidate );
|
||||||
|
paddingBorder.uninstall();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -471,9 +512,20 @@ public class FlatComboBoxUI
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected Color getBackground( boolean enabled ) {
|
protected Color getBackground( boolean enabled ) {
|
||||||
return enabled
|
if( enabled ) {
|
||||||
? (editableBackground != null && comboBox.isEditable() ? editableBackground : comboBox.getBackground())
|
Color background = comboBox.getBackground();
|
||||||
: (isIntelliJTheme ? FlatUIUtils.getParentBackground( comboBox ) : disabledBackground);
|
|
||||||
|
// always use explicitly set color
|
||||||
|
if( !(background instanceof UIResource) )
|
||||||
|
return background;
|
||||||
|
|
||||||
|
// focused
|
||||||
|
if( focusedBackground != null && isPermanentFocusOwner( comboBox ) )
|
||||||
|
return focusedBackground;
|
||||||
|
|
||||||
|
return (editableBackground != null && comboBox.isEditable()) ? editableBackground : background;
|
||||||
|
} else
|
||||||
|
return isIntelliJTheme ? FlatUIUtils.getParentBackground( comboBox ) : disabledBackground;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Color getForeground( boolean enabled ) {
|
protected Color getForeground( boolean enabled ) {
|
||||||
@@ -483,75 +535,68 @@ public class FlatComboBoxUI
|
|||||||
@Override
|
@Override
|
||||||
public Dimension getMinimumSize( JComponent c ) {
|
public Dimension getMinimumSize( JComponent c ) {
|
||||||
Dimension minimumSize = super.getMinimumSize( c );
|
Dimension minimumSize = super.getMinimumSize( c );
|
||||||
minimumSize.width = Math.max( minimumSize.width, scale( FlatUIUtils.minimumWidth( c, minimumWidth ) ) );
|
int fw = Math.round( FlatUIUtils.getBorderFocusWidth( c ) * 2 );
|
||||||
|
minimumSize.width = Math.max( minimumSize.width, scale( FlatUIUtils.minimumWidth( c, minimumWidth ) ) + fw );
|
||||||
return minimumSize;
|
return minimumSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Dimension getDefaultSize() {
|
protected Dimension getDefaultSize() {
|
||||||
@SuppressWarnings( "unchecked" )
|
paddingBorder.uninstall();
|
||||||
ListCellRenderer<Object> renderer = comboBox.getRenderer();
|
|
||||||
uninstallCellPaddingBorder( renderer );
|
|
||||||
|
|
||||||
Dimension size = super.getDefaultSize();
|
Dimension size = super.getDefaultSize();
|
||||||
|
paddingBorder.uninstall();
|
||||||
uninstallCellPaddingBorder( renderer );
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Dimension getDisplaySize() {
|
protected Dimension getDisplaySize() {
|
||||||
@SuppressWarnings( "unchecked" )
|
paddingBorder.uninstall();
|
||||||
ListCellRenderer<Object> renderer = comboBox.getRenderer();
|
|
||||||
uninstallCellPaddingBorder( renderer );
|
|
||||||
|
|
||||||
Dimension displaySize = super.getDisplaySize();
|
Dimension displaySize = super.getDisplaySize();
|
||||||
|
paddingBorder.uninstall();
|
||||||
|
|
||||||
|
// remove padding added in super.getDisplaySize()
|
||||||
|
int displayWidth = displaySize.width - padding.left - padding.right;
|
||||||
|
int displayHeight = displaySize.height - padding.top - padding.bottom;
|
||||||
|
|
||||||
// recalculate width without hardcoded 100 under special conditions
|
// recalculate width without hardcoded 100 under special conditions
|
||||||
if( displaySize.width == 100 + padding.left + padding.right &&
|
if( displayWidth == 100 &&
|
||||||
comboBox.isEditable() &&
|
comboBox.isEditable() &&
|
||||||
comboBox.getItemCount() == 0 &&
|
comboBox.getItemCount() == 0 &&
|
||||||
comboBox.getPrototypeDisplayValue() == null )
|
comboBox.getPrototypeDisplayValue() == null )
|
||||||
{
|
{
|
||||||
int width = getDefaultSize().width;
|
displayWidth = Math.max( getDefaultSize().width, editor.getPreferredSize().width );
|
||||||
width = Math.max( width, editor.getPreferredSize().width );
|
|
||||||
width += padding.left + padding.right;
|
|
||||||
displaySize = new Dimension( width, displaySize.height );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uninstallCellPaddingBorder( renderer );
|
return new Dimension( displayWidth, displayHeight );
|
||||||
return displaySize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Dimension getSizeForComponent( Component comp ) {
|
protected Dimension getSizeForComponent( Component comp ) {
|
||||||
|
paddingBorder.install( comp );
|
||||||
Dimension size = super.getSizeForComponent( comp );
|
Dimension size = super.getSizeForComponent( comp );
|
||||||
|
paddingBorder.uninstall();
|
||||||
// remove the renderer border top/bottom insets from the size to make sure that
|
|
||||||
// the combobox gets the same height as other component types (e.g. JTextField)
|
|
||||||
Insets rendererInsets = getRendererComponentInsets( comp );
|
|
||||||
if( rendererInsets != null )
|
|
||||||
size = new Dimension( size.width, size.height - rendererInsets.top - rendererInsets.bottom );
|
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Insets getRendererComponentInsets( Component rendererComponent ) {
|
private boolean isCellRenderer() {
|
||||||
if( rendererComponent instanceof JComponent ) {
|
return comboBox.getParent() instanceof CellRendererPane;
|
||||||
Border rendererBorder = ((JComponent)rendererComponent).getBorder();
|
|
||||||
if( rendererBorder != null )
|
|
||||||
return rendererBorder.getBorderInsets( rendererComponent );
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void uninstallCellPaddingBorder( Object o ) {
|
private boolean isCellRendererBackgroundChanged() {
|
||||||
CellPaddingBorder.uninstall( o );
|
// parent is a CellRendererPane, parentParent is e.g. a JTable
|
||||||
if( lastRendererComponent != null ) {
|
Container parentParent = comboBox.getParent().getParent();
|
||||||
CellPaddingBorder.uninstall( lastRendererComponent );
|
return parentParent != null && !comboBox.getBackground().equals( parentParent.getBackground() );
|
||||||
lastRendererComponent = null;
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
|
* @since 1.3
|
||||||
|
*/
|
||||||
|
public static boolean isPermanentFocusOwner( JComboBox<?> comboBox ) {
|
||||||
|
if( comboBox.isEditable() ) {
|
||||||
|
Component editorComponent = comboBox.getEditor().getEditorComponent();
|
||||||
|
return (editorComponent != null) ? FlatUIUtils.isPermanentFocusOwner( editorComponent ) : false;
|
||||||
|
} else
|
||||||
|
return FlatUIUtils.isPermanentFocusOwner( comboBox );
|
||||||
}
|
}
|
||||||
|
|
||||||
//---- class FlatComboBoxButton -------------------------------------------
|
//---- class FlatComboBoxButton -------------------------------------------
|
||||||
@@ -580,6 +625,14 @@ public class FlatComboBoxUI
|
|||||||
protected boolean isPressed() {
|
protected boolean isPressed() {
|
||||||
return super.isPressed() || (!comboBox.isEditable() ? pressed : false);
|
return super.isPressed() || (!comboBox.isEditable() ? pressed : false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Color getArrowColor() {
|
||||||
|
if( isCellRenderer() && isCellRendererBackgroundChanged() )
|
||||||
|
return comboBox.getForeground();
|
||||||
|
|
||||||
|
return super.getArrowColor();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//---- class FlatComboPopup -----------------------------------------------
|
//---- class FlatComboPopup -----------------------------------------------
|
||||||
@@ -588,13 +641,11 @@ public class FlatComboBoxUI
|
|||||||
protected class FlatComboPopup
|
protected class FlatComboPopup
|
||||||
extends BasicComboPopup
|
extends BasicComboPopup
|
||||||
{
|
{
|
||||||
private CellPaddingBorder paddingBorder;
|
|
||||||
|
|
||||||
protected FlatComboPopup( JComboBox combo ) {
|
protected FlatComboPopup( JComboBox combo ) {
|
||||||
super( combo );
|
super( combo );
|
||||||
|
|
||||||
// BasicComboPopup listens to JComboBox.componentOrientation and updates
|
// BasicComboPopup listens to JComboBox.componentOrientation and updates
|
||||||
// the component orientation of the list, scroller and popup, but when
|
// the component orientation of the list, scroll pane and popup, but when
|
||||||
// switching the LaF and a new combo popup is created, the component
|
// switching the LaF and a new combo popup is created, the component
|
||||||
// orientation is not applied.
|
// orientation is not applied.
|
||||||
ComponentOrientation o = comboBox.getComponentOrientation();
|
ComponentOrientation o = comboBox.getComponentOrientation();
|
||||||
@@ -658,6 +709,8 @@ public class FlatComboBoxUI
|
|||||||
super.configureList();
|
super.configureList();
|
||||||
|
|
||||||
list.setCellRenderer( new PopupListCellRenderer() );
|
list.setCellRenderer( new PopupListCellRenderer() );
|
||||||
|
if( popupBackground != null )
|
||||||
|
list.setBackground( popupBackground );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -671,6 +724,19 @@ public class FlatComboBoxUI
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getPopupHeightForRowCount( int maxRowCount ) {
|
||||||
|
int height = super.getPopupHeightForRowCount( maxRowCount );
|
||||||
|
paddingBorder.uninstall();
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void paintChildren( Graphics g ) {
|
||||||
|
super.paintChildren( g );
|
||||||
|
paddingBorder.uninstall();
|
||||||
|
}
|
||||||
|
|
||||||
//---- class PopupListCellRenderer -----
|
//---- class PopupListCellRenderer -----
|
||||||
|
|
||||||
private class PopupListCellRenderer
|
private class PopupListCellRenderer
|
||||||
@@ -680,22 +746,15 @@ public class FlatComboBoxUI
|
|||||||
public Component getListCellRendererComponent( JList list, Object value,
|
public Component getListCellRendererComponent( JList list, Object value,
|
||||||
int index, boolean isSelected, boolean cellHasFocus )
|
int index, boolean isSelected, boolean cellHasFocus )
|
||||||
{
|
{
|
||||||
ListCellRenderer renderer = comboBox.getRenderer();
|
paddingBorder.uninstall();
|
||||||
CellPaddingBorder.uninstall( renderer );
|
|
||||||
CellPaddingBorder.uninstall( lastRendererComponent );
|
|
||||||
|
|
||||||
|
ListCellRenderer renderer = comboBox.getRenderer();
|
||||||
if( renderer == null )
|
if( renderer == null )
|
||||||
renderer = new DefaultListCellRenderer();
|
renderer = new DefaultListCellRenderer();
|
||||||
Component c = renderer.getListCellRendererComponent( list, value, index, isSelected, cellHasFocus );
|
Component c = renderer.getListCellRendererComponent( list, value, index, isSelected, cellHasFocus );
|
||||||
c.applyComponentOrientation( comboBox.getComponentOrientation() );
|
c.applyComponentOrientation( comboBox.getComponentOrientation() );
|
||||||
|
|
||||||
if( c instanceof JComponent ) {
|
paddingBorder.install( c );
|
||||||
if( paddingBorder == null )
|
|
||||||
paddingBorder = new CellPaddingBorder( padding );
|
|
||||||
paddingBorder.install( (JComponent) c );
|
|
||||||
}
|
|
||||||
|
|
||||||
lastRendererComponent = (c != renderer) ? new WeakReference<>( c ) : null;
|
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
@@ -705,49 +764,69 @@ public class FlatComboBoxUI
|
|||||||
//---- class CellPaddingBorder --------------------------------------------
|
//---- class CellPaddingBorder --------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cell padding border used only in popup list.
|
* Cell padding border used in popup list and for current value if not editable.
|
||||||
*
|
* <p>
|
||||||
* The insets are the union of the cell padding and the renderer border insets,
|
* The insets are the union of the cell padding and the renderer border insets,
|
||||||
* which vertically aligns text in popup list with text in combobox.
|
* which vertically aligns text in popup list with text in combobox.
|
||||||
*
|
* <p>
|
||||||
* The renderer border is painted on the outside of this border.
|
* The renderer border is painted on the outer side of this border.
|
||||||
*/
|
*/
|
||||||
private static class CellPaddingBorder
|
private static class CellPaddingBorder
|
||||||
extends AbstractBorder
|
extends AbstractBorder
|
||||||
{
|
{
|
||||||
private final Insets padding;
|
private final Insets padding;
|
||||||
|
private JComponent rendererComponent;
|
||||||
private Border rendererBorder;
|
private Border rendererBorder;
|
||||||
|
|
||||||
CellPaddingBorder( Insets padding ) {
|
CellPaddingBorder( Insets padding ) {
|
||||||
this.padding = padding;
|
this.padding = padding;
|
||||||
}
|
}
|
||||||
|
|
||||||
void install( JComponent rendererComponent ) {
|
void install( Component c ) {
|
||||||
Border oldBorder = rendererComponent.getBorder();
|
if( !(c instanceof JComponent) )
|
||||||
if( !(oldBorder instanceof CellPaddingBorder) ) {
|
|
||||||
rendererBorder = oldBorder;
|
|
||||||
rendererComponent.setBorder( this );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void uninstall( Object o ) {
|
|
||||||
if( o instanceof WeakReference )
|
|
||||||
o = ((WeakReference<?>)o).get();
|
|
||||||
|
|
||||||
if( !(o instanceof JComponent) )
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
JComponent rendererComponent = (JComponent) o;
|
JComponent jc = (JComponent) c;
|
||||||
Border border = rendererComponent.getBorder();
|
Border oldBorder = jc.getBorder();
|
||||||
if( border instanceof CellPaddingBorder ) {
|
if( oldBorder == this )
|
||||||
CellPaddingBorder paddingBorder = (CellPaddingBorder) border;
|
return; // already installed
|
||||||
rendererComponent.setBorder( paddingBorder.rendererBorder );
|
|
||||||
paddingBorder.rendererBorder = null;
|
// component already has a padding border --> uninstall it
|
||||||
}
|
// (may happen if single renderer instance is used in multiple comboboxes)
|
||||||
|
if( oldBorder instanceof CellPaddingBorder )
|
||||||
|
((CellPaddingBorder)oldBorder).uninstall();
|
||||||
|
|
||||||
|
// this border can be installed only at one component
|
||||||
|
// (may happen if a renderer returns varying components)
|
||||||
|
uninstall();
|
||||||
|
|
||||||
|
// remember component where this border was installed for uninstall
|
||||||
|
rendererComponent = jc;
|
||||||
|
|
||||||
|
// remember old border and replace it
|
||||||
|
rendererBorder = jc.getBorder();
|
||||||
|
rendererComponent.setBorder( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uninstall border from previously installed component.
|
||||||
|
* Because this border is installed in PopupListCellRenderer.getListCellRendererComponent(),
|
||||||
|
* there is no single place to uninstall it.
|
||||||
|
* This is the reason why this method is called from various places.
|
||||||
|
*/
|
||||||
|
void uninstall() {
|
||||||
|
if( rendererComponent == null )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( rendererComponent.getBorder() == this )
|
||||||
|
rendererComponent.setBorder( rendererBorder );
|
||||||
|
rendererComponent = null;
|
||||||
|
rendererBorder = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Insets getBorderInsets( Component c, Insets insets ) {
|
public Insets getBorderInsets( Component c, Insets insets ) {
|
||||||
|
Insets padding = scale( this.padding );
|
||||||
if( rendererBorder != null ) {
|
if( rendererBorder != null ) {
|
||||||
Insets insideInsets = rendererBorder.getBorderInsets( c );
|
Insets insideInsets = rendererBorder.getBorderInsets( c );
|
||||||
insets.top = Math.max( padding.top, insideInsets.top );
|
insets.top = Math.max( padding.top, insideInsets.top );
|
||||||
|
|||||||
@@ -16,10 +16,12 @@
|
|||||||
|
|
||||||
package com.formdev.flatlaf.ui;
|
package com.formdev.flatlaf.ui;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Container;
|
import java.awt.Container;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.EventQueue;
|
import java.awt.EventQueue;
|
||||||
|
import java.awt.Graphics;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.Image;
|
import java.awt.Image;
|
||||||
import java.awt.Insets;
|
import java.awt.Insets;
|
||||||
@@ -28,11 +30,13 @@ import java.awt.Point;
|
|||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.beans.PropertyChangeListener;
|
||||||
import java.beans.PropertyVetoException;
|
import java.beans.PropertyVetoException;
|
||||||
import javax.swing.BorderFactory;
|
import javax.swing.BorderFactory;
|
||||||
import javax.swing.ImageIcon;
|
import javax.swing.ImageIcon;
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
|
import javax.swing.JDesktopPane;
|
||||||
import javax.swing.event.MouseInputAdapter;
|
import javax.swing.event.MouseInputAdapter;
|
||||||
import javax.swing.event.MouseInputListener;
|
import javax.swing.event.MouseInputListener;
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
@@ -45,6 +49,7 @@ import javax.swing.SwingUtilities;
|
|||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.plaf.ComponentUI;
|
import javax.swing.plaf.ComponentUI;
|
||||||
import javax.swing.plaf.basic.BasicDesktopIconUI;
|
import javax.swing.plaf.basic.BasicDesktopIconUI;
|
||||||
|
import com.formdev.flatlaf.util.MultiResolutionImageSupport;
|
||||||
import com.formdev.flatlaf.util.UIScale;
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -75,11 +80,21 @@ public class FlatDesktopIconUI
|
|||||||
private JToolTip titleTip;
|
private JToolTip titleTip;
|
||||||
private ActionListener closeListener;
|
private ActionListener closeListener;
|
||||||
private MouseInputListener mouseInputListener;
|
private MouseInputListener mouseInputListener;
|
||||||
|
private PropertyChangeListener ancestorListener;
|
||||||
|
|
||||||
public static ComponentUI createUI( JComponent c ) {
|
public static ComponentUI createUI( JComponent c ) {
|
||||||
return new FlatDesktopIconUI();
|
return new FlatDesktopIconUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void installUI( JComponent c ) {
|
||||||
|
super.installUI( c );
|
||||||
|
|
||||||
|
// update dock icon preview if already iconified
|
||||||
|
if( c.isDisplayable() )
|
||||||
|
updateDockIconPreviewLater();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void uninstallUI( JComponent c ) {
|
public void uninstallUI( JComponent c ) {
|
||||||
super.uninstallUI( c );
|
super.uninstallUI( c );
|
||||||
@@ -136,6 +151,17 @@ public class FlatDesktopIconUI
|
|||||||
};
|
};
|
||||||
closeButton.addActionListener( closeListener );
|
closeButton.addActionListener( closeListener );
|
||||||
closeButton.addMouseListener( mouseInputListener );
|
closeButton.addMouseListener( mouseInputListener );
|
||||||
|
|
||||||
|
ancestorListener = e -> {
|
||||||
|
if( e.getNewValue() != null ) {
|
||||||
|
// update dock icon preview if desktopIcon is added to desktop (internal frame was iconified)
|
||||||
|
updateDockIconPreviewLater();
|
||||||
|
} else {
|
||||||
|
// remove preview icon to release memory
|
||||||
|
dockIcon.setIcon( null );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
desktopIcon.addPropertyChangeListener( "ancestor", ancestorListener );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -146,6 +172,9 @@ public class FlatDesktopIconUI
|
|||||||
closeButton.removeMouseListener( mouseInputListener );
|
closeButton.removeMouseListener( mouseInputListener );
|
||||||
closeListener = null;
|
closeListener = null;
|
||||||
mouseInputListener = null;
|
mouseInputListener = null;
|
||||||
|
|
||||||
|
desktopIcon.removePropertyChangeListener( "ancestor", ancestorListener );
|
||||||
|
ancestorListener = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -228,15 +257,30 @@ public class FlatDesktopIconUI
|
|||||||
return getPreferredSize( c );
|
return getPreferredSize( c );
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateDockIcon() {
|
@Override
|
||||||
|
public void update( Graphics g, JComponent c ) {
|
||||||
|
if( c.isOpaque() ) {
|
||||||
|
// fill background with color derived from desktop pane
|
||||||
|
Color background = c.getBackground();
|
||||||
|
JDesktopPane desktopPane = desktopIcon.getDesktopPane();
|
||||||
|
g.setColor( (desktopPane != null)
|
||||||
|
? FlatUIUtils.deriveColor( background, desktopPane.getBackground() )
|
||||||
|
: background );
|
||||||
|
g.fillRect( 0, 0, c.getWidth(), c.getHeight() );
|
||||||
|
}
|
||||||
|
|
||||||
|
paint( g, c );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateDockIconPreviewLater() {
|
||||||
// use invoke later to make sure that components are updated when switching LaF
|
// use invoke later to make sure that components are updated when switching LaF
|
||||||
EventQueue.invokeLater( () -> {
|
EventQueue.invokeLater( () -> {
|
||||||
if( dockIcon != null )
|
if( dockIcon != null )
|
||||||
updateDockIconLater();
|
updateDockIconPreview();
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateDockIconLater() {
|
protected void updateDockIconPreview() {
|
||||||
// make sure that frame is not selected
|
// make sure that frame is not selected
|
||||||
if( frame.isSelected() ) {
|
if( frame.isSelected() ) {
|
||||||
try {
|
try {
|
||||||
@@ -246,13 +290,22 @@ public class FlatDesktopIconUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// layout internal frame title pane, which was recreated when switching Laf
|
||||||
|
// (directly invoke doLayout() because frame.validate() does not work here
|
||||||
|
// because frame is not displayable)
|
||||||
|
if( !frame.isValid() )
|
||||||
|
frame.doLayout();
|
||||||
|
for( Component c : frame.getComponents() ) {
|
||||||
|
if( !c.isValid() )
|
||||||
|
c.doLayout();
|
||||||
|
}
|
||||||
|
|
||||||
// paint internal frame to buffered image
|
// paint internal frame to buffered image
|
||||||
int frameWidth = Math.max( frame.getWidth(), 1 );
|
int frameWidth = Math.max( frame.getWidth(), 1 );
|
||||||
int frameHeight = Math.max( frame.getHeight(), 1 );
|
int frameHeight = Math.max( frame.getHeight(), 1 );
|
||||||
BufferedImage frameImage = new BufferedImage( frameWidth, frameHeight, BufferedImage.TYPE_INT_ARGB );
|
BufferedImage frameImage = new BufferedImage( frameWidth, frameHeight, BufferedImage.TYPE_INT_ARGB );
|
||||||
Graphics2D g = frameImage.createGraphics();
|
Graphics2D g = frameImage.createGraphics();
|
||||||
try {
|
try {
|
||||||
//TODO fix missing internal frame header when switching LaF
|
|
||||||
frame.paint( g );
|
frame.paint( g );
|
||||||
} finally {
|
} finally {
|
||||||
g.dispose();
|
g.dispose();
|
||||||
@@ -270,6 +323,27 @@ public class FlatDesktopIconUI
|
|||||||
|
|
||||||
// scale preview
|
// scale preview
|
||||||
Image previewImage = frameImage.getScaledInstance( previewWidth, previewHeight, Image.SCALE_SMOOTH );
|
Image previewImage = frameImage.getScaledInstance( previewWidth, previewHeight, Image.SCALE_SMOOTH );
|
||||||
|
if( MultiResolutionImageSupport.isAvailable() ) {
|
||||||
|
// On HiDPI screens, create preview images for 1x, 2x and current scale factor.
|
||||||
|
// The icon then chooses the best resolution for painting, which is usually
|
||||||
|
// the one for the current scale factor. But if changing scale factor or
|
||||||
|
// moving window to another screen with different scale factor, then another
|
||||||
|
// resolution may be used because the preview icon is not updated.
|
||||||
|
Image previewImage2x = frameImage.getScaledInstance( previewWidth * 2, previewHeight * 2, Image.SCALE_SMOOTH );
|
||||||
|
double scaleFactor = UIScale.getSystemScaleFactor( desktopIcon.getGraphicsConfiguration() );
|
||||||
|
if( scaleFactor != 1 && scaleFactor != 2 ) {
|
||||||
|
Image previewImageCurrent = frameImage.getScaledInstance(
|
||||||
|
(int) Math.round( previewWidth * scaleFactor ),
|
||||||
|
(int) Math.round( previewHeight * scaleFactor ),
|
||||||
|
Image.SCALE_SMOOTH );
|
||||||
|
|
||||||
|
// the images must be ordered by resolution
|
||||||
|
previewImage = (scaleFactor < 2)
|
||||||
|
? MultiResolutionImageSupport.create( 0, previewImage, previewImageCurrent, previewImage2x )
|
||||||
|
: MultiResolutionImageSupport.create( 0, previewImage, previewImage2x, previewImageCurrent );
|
||||||
|
} else
|
||||||
|
previewImage = MultiResolutionImageSupport.create( 0, previewImage, previewImage2x );
|
||||||
|
}
|
||||||
dockIcon.setIcon( new ImageIcon( previewImage ) );
|
dockIcon.setIcon( new ImageIcon( previewImage ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,11 +16,16 @@
|
|||||||
|
|
||||||
package com.formdev.flatlaf.ui;
|
package com.formdev.flatlaf.ui;
|
||||||
|
|
||||||
import javax.swing.DefaultDesktopManager;
|
import java.awt.Component;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.EventQueue;
|
||||||
|
import java.awt.event.ComponentAdapter;
|
||||||
|
import java.awt.event.ComponentEvent;
|
||||||
|
import java.awt.event.ContainerEvent;
|
||||||
|
import java.awt.event.ContainerListener;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JInternalFrame;
|
import javax.swing.JInternalFrame.JDesktopIcon;
|
||||||
import javax.swing.plaf.ComponentUI;
|
import javax.swing.plaf.ComponentUI;
|
||||||
import javax.swing.plaf.UIResource;
|
|
||||||
import javax.swing.plaf.basic.BasicDesktopPaneUI;
|
import javax.swing.plaf.basic.BasicDesktopPaneUI;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -36,30 +41,96 @@ import javax.swing.plaf.basic.BasicDesktopPaneUI;
|
|||||||
public class FlatDesktopPaneUI
|
public class FlatDesktopPaneUI
|
||||||
extends BasicDesktopPaneUI
|
extends BasicDesktopPaneUI
|
||||||
{
|
{
|
||||||
|
private LayoutDockListener layoutDockListener;
|
||||||
|
private boolean layoutDockPending;
|
||||||
|
|
||||||
public static ComponentUI createUI( JComponent c ) {
|
public static ComponentUI createUI( JComponent c ) {
|
||||||
return new FlatDesktopPaneUI();
|
return new FlatDesktopPaneUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void installDesktopManager() {
|
public void installUI( JComponent c ) {
|
||||||
desktopManager = desktop.getDesktopManager();
|
super.installUI( c );
|
||||||
if( desktopManager == null ) {
|
|
||||||
desktopManager = new FlatDesktopManager();
|
layoutDockLaterOnce();
|
||||||
desktop.setDesktopManager( desktopManager );
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void installListeners() {
|
||||||
|
super.installListeners();
|
||||||
|
|
||||||
|
layoutDockListener = new LayoutDockListener();
|
||||||
|
desktop.addContainerListener( layoutDockListener );
|
||||||
|
desktop.addComponentListener( layoutDockListener );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void uninstallListeners() {
|
||||||
|
super.uninstallListeners();
|
||||||
|
|
||||||
|
desktop.removeContainerListener( layoutDockListener );
|
||||||
|
desktop.removeComponentListener( layoutDockListener );
|
||||||
|
layoutDockListener = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void layoutDockLaterOnce() {
|
||||||
|
if( layoutDockPending )
|
||||||
|
return;
|
||||||
|
layoutDockPending = true;
|
||||||
|
|
||||||
|
EventQueue.invokeLater( () -> {
|
||||||
|
layoutDockPending = false;
|
||||||
|
if( desktop != null )
|
||||||
|
layoutDock();
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void layoutDock() {
|
||||||
|
Dimension desktopSize = desktop.getSize();
|
||||||
|
int x = 0;
|
||||||
|
int y = desktopSize.height;
|
||||||
|
int rowHeight = 0;
|
||||||
|
|
||||||
|
for( Component c : desktop.getComponents() ) {
|
||||||
|
if( !(c instanceof JDesktopIcon) )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
JDesktopIcon icon = (JDesktopIcon) c;
|
||||||
|
Dimension iconSize = icon.getPreferredSize();
|
||||||
|
|
||||||
|
if( x + iconSize.width > desktopSize.width ) {
|
||||||
|
// new row
|
||||||
|
x = 0;
|
||||||
|
y -= rowHeight;
|
||||||
|
rowHeight = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
icon.setLocation( x, y - iconSize.height );
|
||||||
|
|
||||||
|
x += iconSize.width;
|
||||||
|
rowHeight = Math.max( iconSize.height, rowHeight );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//---- class FlatDesktopManager -------------------------------------------
|
//---- class LayoutDockListener -------------------------------------------
|
||||||
|
|
||||||
private class FlatDesktopManager
|
private class LayoutDockListener
|
||||||
extends DefaultDesktopManager
|
extends ComponentAdapter
|
||||||
implements UIResource
|
implements ContainerListener
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public void iconifyFrame( JInternalFrame f ) {
|
public void componentAdded( ContainerEvent e ) {
|
||||||
super.iconifyFrame( f );
|
layoutDockLaterOnce();
|
||||||
|
}
|
||||||
|
|
||||||
((FlatDesktopIconUI)f.getDesktopIcon().getUI()).updateDockIcon();
|
@Override
|
||||||
|
public void componentRemoved( ContainerEvent e ) {
|
||||||
|
layoutDockLaterOnce();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void componentResized( ComponentEvent e ) {
|
||||||
|
layoutDockLaterOnce();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,15 +17,16 @@
|
|||||||
package com.formdev.flatlaf.ui;
|
package com.formdev.flatlaf.ui;
|
||||||
|
|
||||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||||
|
import java.awt.Color;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.event.FocusListener;
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JEditorPane;
|
import javax.swing.JEditorPane;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.plaf.ComponentUI;
|
import javax.swing.plaf.ComponentUI;
|
||||||
import javax.swing.plaf.UIResource;
|
|
||||||
import javax.swing.plaf.basic.BasicEditorPaneUI;
|
import javax.swing.plaf.basic.BasicEditorPaneUI;
|
||||||
import javax.swing.text.JTextComponent;
|
import javax.swing.text.JTextComponent;
|
||||||
import com.formdev.flatlaf.FlatClientProperties;
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
@@ -53,6 +54,7 @@ import com.formdev.flatlaf.util.HiDPIUtils;
|
|||||||
*
|
*
|
||||||
* @uiDefault Component.minimumWidth int
|
* @uiDefault Component.minimumWidth int
|
||||||
* @uiDefault Component.isIntelliJTheme boolean
|
* @uiDefault Component.isIntelliJTheme boolean
|
||||||
|
* @uiDefault EditorPane.focusedBackground Color optional
|
||||||
*
|
*
|
||||||
* @author Karl Tauber
|
* @author Karl Tauber
|
||||||
*/
|
*/
|
||||||
@@ -61,8 +63,10 @@ public class FlatEditorPaneUI
|
|||||||
{
|
{
|
||||||
protected int minimumWidth;
|
protected int minimumWidth;
|
||||||
protected boolean isIntelliJTheme;
|
protected boolean isIntelliJTheme;
|
||||||
|
protected Color focusedBackground;
|
||||||
|
|
||||||
private Object oldHonorDisplayProperties;
|
private Object oldHonorDisplayProperties;
|
||||||
|
private FocusListener focusListener;
|
||||||
|
|
||||||
public static ComponentUI createUI( JComponent c ) {
|
public static ComponentUI createUI( JComponent c ) {
|
||||||
return new FlatEditorPaneUI();
|
return new FlatEditorPaneUI();
|
||||||
@@ -72,8 +76,10 @@ public class FlatEditorPaneUI
|
|||||||
protected void installDefaults() {
|
protected void installDefaults() {
|
||||||
super.installDefaults();
|
super.installDefaults();
|
||||||
|
|
||||||
|
String prefix = getPropertyPrefix();
|
||||||
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
||||||
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
||||||
|
focusedBackground = UIManager.getColor( prefix + ".focusedBackground" );
|
||||||
|
|
||||||
// use component font and foreground for HTML text
|
// use component font and foreground for HTML text
|
||||||
oldHonorDisplayProperties = getComponent().getClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES );
|
oldHonorDisplayProperties = getComponent().getClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES );
|
||||||
@@ -84,9 +90,28 @@ public class FlatEditorPaneUI
|
|||||||
protected void uninstallDefaults() {
|
protected void uninstallDefaults() {
|
||||||
super.uninstallDefaults();
|
super.uninstallDefaults();
|
||||||
|
|
||||||
|
focusedBackground = null;
|
||||||
|
|
||||||
getComponent().putClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES, oldHonorDisplayProperties );
|
getComponent().putClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES, oldHonorDisplayProperties );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void installListeners() {
|
||||||
|
super.installListeners();
|
||||||
|
|
||||||
|
// necessary to update focus background
|
||||||
|
focusListener = new FlatUIUtils.RepaintFocusListener( getComponent(), c -> focusedBackground != null );
|
||||||
|
getComponent().addFocusListener( focusListener );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void uninstallListeners() {
|
||||||
|
super.uninstallListeners();
|
||||||
|
|
||||||
|
getComponent().removeFocusListener( focusListener );
|
||||||
|
focusListener = null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void propertyChange( PropertyChangeEvent e ) {
|
protected void propertyChange( PropertyChangeEvent e ) {
|
||||||
super.propertyChange( e );
|
super.propertyChange( e );
|
||||||
@@ -128,14 +153,11 @@ public class FlatEditorPaneUI
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void paintBackground( Graphics g ) {
|
protected void paintBackground( Graphics g ) {
|
||||||
JTextComponent c = getComponent();
|
paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground );
|
||||||
|
}
|
||||||
|
|
||||||
// for compatibility with IntelliJ themes
|
static void paintBackground( Graphics g, JTextComponent c, boolean isIntelliJTheme, Color focusedBackground ) {
|
||||||
if( isIntelliJTheme && (!c.isEnabled() || !c.isEditable()) && (c.getBackground() instanceof UIResource) ) {
|
g.setColor( FlatTextFieldUI.getBackground( c, isIntelliJTheme, focusedBackground ) );
|
||||||
FlatUIUtils.paintParentBackground( g, c );
|
g.fillRect( 0, 0, c.getWidth(), c.getHeight() );
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
super.paintBackground( g );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,11 +39,10 @@ import javax.swing.plaf.ComponentUI;
|
|||||||
*
|
*
|
||||||
* <!-- FlatTextFieldUI -->
|
* <!-- FlatTextFieldUI -->
|
||||||
*
|
*
|
||||||
* @uiDefault TextComponent.arc int
|
|
||||||
* @uiDefault Component.focusWidth int
|
|
||||||
* @uiDefault Component.minimumWidth int
|
* @uiDefault Component.minimumWidth int
|
||||||
* @uiDefault Component.isIntelliJTheme boolean
|
* @uiDefault Component.isIntelliJTheme boolean
|
||||||
* @uiDefault FormattedTextField.placeholderForeground Color
|
* @uiDefault FormattedTextField.placeholderForeground Color
|
||||||
|
* @uiDefault FormattedTextField.focusedBackground Color optional
|
||||||
* @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always
|
* @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always
|
||||||
* @uiDefault TextComponent.selectAllOnMouseClick boolean
|
* @uiDefault TextComponent.selectAllOnMouseClick boolean
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -125,6 +125,10 @@ public class FlatNativeWindowBorder
|
|||||||
// enable native window border for window
|
// enable native window border for window
|
||||||
setHasCustomDecoration( frame, true );
|
setHasCustomDecoration( frame, true );
|
||||||
|
|
||||||
|
// avoid double window title bar if enabling native window border failed
|
||||||
|
if( !hasCustomDecoration( frame ) )
|
||||||
|
return;
|
||||||
|
|
||||||
// enable Swing window decoration
|
// enable Swing window decoration
|
||||||
rootPane.setWindowDecorationStyle( JRootPane.FRAME );
|
rootPane.setWindowDecorationStyle( JRootPane.FRAME );
|
||||||
|
|
||||||
@@ -143,6 +147,10 @@ public class FlatNativeWindowBorder
|
|||||||
// enable native window border for window
|
// enable native window border for window
|
||||||
setHasCustomDecoration( dialog, true );
|
setHasCustomDecoration( dialog, true );
|
||||||
|
|
||||||
|
// avoid double window title bar if enabling native window border failed
|
||||||
|
if( !hasCustomDecoration( dialog ) )
|
||||||
|
return;
|
||||||
|
|
||||||
// enable Swing window decoration
|
// enable Swing window decoration
|
||||||
rootPane.setWindowDecorationStyle( JRootPane.PLAIN_DIALOG );
|
rootPane.setWindowDecorationStyle( JRootPane.PLAIN_DIALOG );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,10 @@ import java.awt.Dimension;
|
|||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.GridBagConstraints;
|
import java.awt.GridBagConstraints;
|
||||||
import java.awt.Insets;
|
import java.awt.Insets;
|
||||||
|
import javax.swing.Box;
|
||||||
|
import javax.swing.BoxLayout;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
|
import javax.swing.JLabel;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.border.Border;
|
import javax.swing.border.Border;
|
||||||
@@ -160,12 +163,30 @@ public class FlatOptionPaneUI
|
|||||||
if( msg instanceof String && BasicHTML.isHTMLString( (String) msg ) )
|
if( msg instanceof String && BasicHTML.isHTMLString( (String) msg ) )
|
||||||
maxll = Integer.MAX_VALUE;
|
maxll = Integer.MAX_VALUE;
|
||||||
|
|
||||||
|
// fix right-to-left alignment if super.addMessageComponents() breaks longer lines
|
||||||
|
// into multiple labels and puts them into a box that aligns them to the left
|
||||||
|
if( msg instanceof Box ) {
|
||||||
|
Box box = (Box) msg;
|
||||||
|
if( "OptionPane.verticalBox".equals( box.getName() ) &&
|
||||||
|
box.getLayout() instanceof BoxLayout &&
|
||||||
|
((BoxLayout)box.getLayout()).getAxis() == BoxLayout.Y_AXIS )
|
||||||
|
{
|
||||||
|
box.addPropertyChangeListener( "componentOrientation", e -> {
|
||||||
|
float alignX = box.getComponentOrientation().isLeftToRight() ? 0 : 1;
|
||||||
|
for( Component c : box.getComponents() ) {
|
||||||
|
if( c instanceof JLabel && "OptionPane.label".equals( c.getName() ) )
|
||||||
|
((JLabel)c).setAlignmentX( alignX );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
super.addMessageComponents( container, cons, msg, maxll, internallyCreated );
|
super.addMessageComponents( container, cons, msg, maxll, internallyCreated );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateChildPanels( Container c ) {
|
private void updateChildPanels( Container c ) {
|
||||||
for( Component child : c.getComponents() ) {
|
for( Component child : c.getComponents() ) {
|
||||||
if( child instanceof JPanel ) {
|
if( child.getClass() == JPanel.class ) {
|
||||||
JPanel panel = (JPanel)child;
|
JPanel panel = (JPanel)child;
|
||||||
|
|
||||||
// make sub-panel non-opaque for OptionPane.background
|
// make sub-panel non-opaque for OptionPane.background
|
||||||
@@ -177,9 +198,8 @@ public class FlatOptionPaneUI
|
|||||||
panel.setBorder( new NonUIResourceBorder( border ) );
|
panel.setBorder( new NonUIResourceBorder( border ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( child instanceof Container ) {
|
if( child instanceof Container )
|
||||||
updateChildPanels( (Container) child );
|
updateChildPanels( (Container) child );
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,30 +16,31 @@
|
|||||||
|
|
||||||
package com.formdev.flatlaf.ui;
|
package com.formdev.flatlaf.ui;
|
||||||
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Dimension;
|
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Insets;
|
||||||
|
import java.awt.Shape;
|
||||||
import java.awt.Toolkit;
|
import java.awt.Toolkit;
|
||||||
import java.awt.event.FocusListener;
|
|
||||||
import java.awt.event.KeyAdapter;
|
import java.awt.event.KeyAdapter;
|
||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
import java.awt.event.KeyListener;
|
import java.awt.event.KeyListener;
|
||||||
import java.beans.PropertyChangeEvent;
|
import javax.swing.Action;
|
||||||
|
import javax.swing.ActionMap;
|
||||||
import javax.swing.Icon;
|
import javax.swing.Icon;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.LookAndFeel;
|
import javax.swing.LookAndFeel;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.plaf.ComponentUI;
|
import javax.swing.plaf.ComponentUI;
|
||||||
import javax.swing.plaf.basic.BasicPasswordFieldUI;
|
import javax.swing.text.DefaultEditorKit;
|
||||||
import javax.swing.text.Caret;
|
import javax.swing.text.Element;
|
||||||
import javax.swing.text.JTextComponent;
|
import javax.swing.text.JTextComponent;
|
||||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
import javax.swing.text.PasswordView;
|
||||||
|
import javax.swing.text.View;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JPasswordField}.
|
* Provides the Flat LaF UI delegate for {@link javax.swing.JPasswordField}.
|
||||||
*
|
*
|
||||||
* <!-- BasicPasswordFieldUI -->
|
* <!-- BasicTextFieldUI -->
|
||||||
*
|
*
|
||||||
* @uiDefault PasswordField.font Font
|
* @uiDefault PasswordField.font Font
|
||||||
* @uiDefault PasswordField.background Color
|
* @uiDefault PasswordField.background Color
|
||||||
@@ -52,68 +53,67 @@ import com.formdev.flatlaf.util.HiDPIUtils;
|
|||||||
* @uiDefault PasswordField.inactiveForeground Color used if not enabled (yes, this is confusing; this should be named disabledForeground)
|
* @uiDefault PasswordField.inactiveForeground Color used if not enabled (yes, this is confusing; this should be named disabledForeground)
|
||||||
* @uiDefault PasswordField.border Border
|
* @uiDefault PasswordField.border Border
|
||||||
* @uiDefault PasswordField.margin Insets
|
* @uiDefault PasswordField.margin Insets
|
||||||
* @uiDefault PasswordField.echoChar character
|
|
||||||
* @uiDefault PasswordField.caretBlinkRate int default is 500 milliseconds
|
* @uiDefault PasswordField.caretBlinkRate int default is 500 milliseconds
|
||||||
*
|
*
|
||||||
* <!-- FlatPasswordFieldUI -->
|
* <!-- FlatTextFieldUI -->
|
||||||
*
|
*
|
||||||
* @uiDefault Component.minimumWidth int
|
* @uiDefault Component.minimumWidth int
|
||||||
* @uiDefault Component.isIntelliJTheme boolean
|
* @uiDefault Component.isIntelliJTheme boolean
|
||||||
* @uiDefault PasswordField.placeholderForeground Color
|
* @uiDefault PasswordField.placeholderForeground Color
|
||||||
* @uiDefault PasswordField.showCapsLock boolean
|
* @uiDefault PasswordField.focusedBackground Color optional
|
||||||
* @uiDefault PasswordField.capsLockIcon Icon
|
|
||||||
* @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always
|
* @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always
|
||||||
* @uiDefault TextComponent.selectAllOnMouseClick boolean
|
* @uiDefault TextComponent.selectAllOnMouseClick boolean
|
||||||
*
|
*
|
||||||
|
* <!-- FlatPasswordFieldUI -->
|
||||||
|
*
|
||||||
|
* @uiDefault PasswordField.echoChar character
|
||||||
|
* @uiDefault PasswordField.showCapsLock boolean
|
||||||
|
* @uiDefault PasswordField.capsLockIcon Icon
|
||||||
|
*
|
||||||
* @author Karl Tauber
|
* @author Karl Tauber
|
||||||
*/
|
*/
|
||||||
public class FlatPasswordFieldUI
|
public class FlatPasswordFieldUI
|
||||||
extends BasicPasswordFieldUI
|
extends FlatTextFieldUI
|
||||||
{
|
{
|
||||||
protected int minimumWidth;
|
|
||||||
protected boolean isIntelliJTheme;
|
|
||||||
protected Color placeholderForeground;
|
|
||||||
protected boolean showCapsLock;
|
protected boolean showCapsLock;
|
||||||
protected Icon capsLockIcon;
|
protected Icon capsLockIcon;
|
||||||
|
|
||||||
private FocusListener focusListener;
|
|
||||||
private KeyListener capsLockListener;
|
private KeyListener capsLockListener;
|
||||||
|
|
||||||
public static ComponentUI createUI( JComponent c ) {
|
public static ComponentUI createUI( JComponent c ) {
|
||||||
return new FlatPasswordFieldUI();
|
return new FlatPasswordFieldUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getPropertyPrefix() {
|
||||||
|
return "PasswordField";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void installDefaults() {
|
protected void installDefaults() {
|
||||||
super.installDefaults();
|
super.installDefaults();
|
||||||
|
|
||||||
String prefix = getPropertyPrefix();
|
String prefix = getPropertyPrefix();
|
||||||
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
Character echoChar = (Character) UIManager.get( prefix + ".echoChar" );
|
||||||
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
if( echoChar != null )
|
||||||
placeholderForeground = UIManager.getColor( prefix + ".placeholderForeground" );
|
LookAndFeel.installProperty( getComponent(), "echoChar", echoChar );
|
||||||
|
|
||||||
showCapsLock = UIManager.getBoolean( "PasswordField.showCapsLock" );
|
showCapsLock = UIManager.getBoolean( "PasswordField.showCapsLock" );
|
||||||
capsLockIcon = UIManager.getIcon( "PasswordField.capsLockIcon" );
|
capsLockIcon = UIManager.getIcon( "PasswordField.capsLockIcon" );
|
||||||
|
|
||||||
LookAndFeel.installProperty( getComponent(), "opaque", false );
|
|
||||||
|
|
||||||
MigLayoutVisualPadding.install( getComponent() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void uninstallDefaults() {
|
protected void uninstallDefaults() {
|
||||||
super.uninstallDefaults();
|
super.uninstallDefaults();
|
||||||
|
|
||||||
placeholderForeground = null;
|
|
||||||
capsLockIcon = null;
|
capsLockIcon = null;
|
||||||
|
|
||||||
MigLayoutVisualPadding.uninstall( getComponent() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void installListeners() {
|
protected void installListeners() {
|
||||||
super.installListeners();
|
super.installListeners();
|
||||||
|
|
||||||
focusListener = new FlatUIUtils.RepaintFocusListener( getComponent() );
|
// update caps lock indicator
|
||||||
capsLockListener = new KeyAdapter() {
|
capsLockListener = new KeyAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void keyPressed( KeyEvent e ) {
|
public void keyPressed( KeyEvent e ) {
|
||||||
@@ -124,12 +124,13 @@ public class FlatPasswordFieldUI
|
|||||||
repaint( e );
|
repaint( e );
|
||||||
}
|
}
|
||||||
private void repaint( KeyEvent e ) {
|
private void repaint( KeyEvent e ) {
|
||||||
if( e.getKeyCode() == KeyEvent.VK_CAPS_LOCK )
|
if( e.getKeyCode() == KeyEvent.VK_CAPS_LOCK ) {
|
||||||
e.getComponent().repaint();
|
e.getComponent().repaint();
|
||||||
|
scrollCaretToVisible();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
getComponent().addFocusListener( focusListener );
|
|
||||||
getComponent().addKeyListener( capsLockListener );
|
getComponent().addKeyListener( capsLockListener );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,59 +138,74 @@ public class FlatPasswordFieldUI
|
|||||||
protected void uninstallListeners() {
|
protected void uninstallListeners() {
|
||||||
super.uninstallListeners();
|
super.uninstallListeners();
|
||||||
|
|
||||||
getComponent().removeFocusListener( focusListener );
|
|
||||||
getComponent().removeKeyListener( capsLockListener );
|
getComponent().removeKeyListener( capsLockListener );
|
||||||
focusListener = null;
|
|
||||||
capsLockListener = null;
|
capsLockListener = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Caret createCaret() {
|
protected void installKeyboardActions() {
|
||||||
return new FlatCaret( UIManager.getString( "TextComponent.selectAllOnFocusPolicy" ),
|
super.installKeyboardActions();
|
||||||
UIManager.getBoolean( "TextComponent.selectAllOnMouseClick" ) );
|
|
||||||
|
// map "select-word" action (double-click) to "select-line" action
|
||||||
|
ActionMap map = SwingUtilities.getUIActionMap( getComponent() );
|
||||||
|
if( map != null && map.get( DefaultEditorKit.selectWordAction ) != null ) {
|
||||||
|
Action selectLineAction = map.get( DefaultEditorKit.selectLineAction );
|
||||||
|
if( selectLineAction != null )
|
||||||
|
map.put( DefaultEditorKit.selectWordAction, selectLineAction );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void propertyChange( PropertyChangeEvent e ) {
|
public View create( Element elem ) {
|
||||||
super.propertyChange( e );
|
return new PasswordView( elem );
|
||||||
FlatTextFieldUI.propertyChange( getComponent(), e );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void paintSafely( Graphics g ) {
|
protected void paintSafely( Graphics g ) {
|
||||||
FlatTextFieldUI.paintBackground( g, getComponent(), isIntelliJTheme );
|
// safe and restore clipping area because super.paintSafely() modifies it
|
||||||
FlatTextFieldUI.paintPlaceholder( g, getComponent(), placeholderForeground );
|
// and the caps lock icon would be truncated
|
||||||
paintCapsLock( g );
|
Shape oldClip = g.getClip();
|
||||||
|
super.paintSafely( g );
|
||||||
|
g.setClip( oldClip );
|
||||||
|
|
||||||
super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) );
|
paintCapsLock( g );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void paintCapsLock( Graphics g ) {
|
protected void paintCapsLock( Graphics g ) {
|
||||||
if( !showCapsLock )
|
if( !isCapsLockVisible() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
JTextComponent c = getComponent();
|
JTextComponent c = getComponent();
|
||||||
if( !FlatUIUtils.isPermanentFocusOwner( c ) ||
|
|
||||||
!Toolkit.getDefaultToolkit().getLockingKeyState( KeyEvent.VK_CAPS_LOCK ) )
|
|
||||||
return;
|
|
||||||
|
|
||||||
int y = (c.getHeight() - capsLockIcon.getIconHeight()) / 2;
|
int y = (c.getHeight() - capsLockIcon.getIconHeight()) / 2;
|
||||||
int x = c.getWidth() - capsLockIcon.getIconWidth() - y;
|
int x = c.getComponentOrientation().isLeftToRight()
|
||||||
|
? c.getWidth() - capsLockIcon.getIconWidth() - y
|
||||||
|
: y;
|
||||||
capsLockIcon.paintIcon( c, g, x, y );
|
capsLockIcon.paintIcon( c, g, x, y );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
protected void paintBackground( Graphics g ) {
|
* @since 1.4
|
||||||
// background is painted elsewhere
|
*/
|
||||||
|
protected boolean isCapsLockVisible() {
|
||||||
|
if( !showCapsLock )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
JTextComponent c = getComponent();
|
||||||
|
return FlatUIUtils.isPermanentFocusOwner( c ) &&
|
||||||
|
Toolkit.getDefaultToolkit().getLockingKeyState( KeyEvent.VK_CAPS_LOCK );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 1.4
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Dimension getPreferredSize( JComponent c ) {
|
protected Insets getPadding() {
|
||||||
return FlatTextFieldUI.applyMinimumWidth( c, super.getPreferredSize( c ), minimumWidth );
|
Insets padding = super.getPadding();
|
||||||
}
|
if( !isCapsLockVisible() )
|
||||||
|
return padding;
|
||||||
|
|
||||||
@Override
|
boolean ltr = getComponent().getComponentOrientation().isLeftToRight();
|
||||||
public Dimension getMinimumSize( JComponent c ) {
|
int iconWidth = capsLockIcon.getIconWidth();
|
||||||
return FlatTextFieldUI.applyMinimumWidth( c, super.getMinimumSize( c ), minimumWidth );
|
return FlatUIUtils.addInsets( padding, new Insets( 0, ltr ? 0 : iconWidth, 0, ltr ? iconWidth : 0 ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,11 +20,16 @@ import java.awt.Color;
|
|||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Container;
|
import java.awt.Container;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
|
import java.awt.GraphicsConfiguration;
|
||||||
|
import java.awt.GraphicsDevice;
|
||||||
|
import java.awt.GraphicsEnvironment;
|
||||||
import java.awt.Insets;
|
import java.awt.Insets;
|
||||||
import java.awt.MouseInfo;
|
import java.awt.MouseInfo;
|
||||||
import java.awt.Panel;
|
import java.awt.Panel;
|
||||||
import java.awt.Point;
|
import java.awt.Point;
|
||||||
|
import java.awt.PointerInfo;
|
||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
|
import java.awt.Toolkit;
|
||||||
import java.awt.Window;
|
import java.awt.Window;
|
||||||
import java.awt.event.ComponentEvent;
|
import java.awt.event.ComponentEvent;
|
||||||
import java.awt.event.ComponentListener;
|
import java.awt.event.ComponentListener;
|
||||||
@@ -39,6 +44,7 @@ import javax.swing.Popup;
|
|||||||
import javax.swing.PopupFactory;
|
import javax.swing.PopupFactory;
|
||||||
import javax.swing.RootPaneContainer;
|
import javax.swing.RootPaneContainer;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
|
import javax.swing.ToolTipManager;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.border.Border;
|
import javax.swing.border.Border;
|
||||||
import com.formdev.flatlaf.FlatClientProperties;
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
@@ -62,7 +68,7 @@ public class FlatPopupFactory
|
|||||||
public Popup getPopup( Component owner, Component contents, int x, int y )
|
public Popup getPopup( Component owner, Component contents, int x, int y )
|
||||||
throws IllegalArgumentException
|
throws IllegalArgumentException
|
||||||
{
|
{
|
||||||
Point pt = fixToolTipLocation( contents, x, y );
|
Point pt = fixToolTipLocation( owner, contents, x, y );
|
||||||
if( pt != null ) {
|
if( pt != null ) {
|
||||||
x = pt.x;
|
x = pt.x;
|
||||||
y = pt.y;
|
y = pt.y;
|
||||||
@@ -206,17 +212,21 @@ public class FlatPopupFactory
|
|||||||
/**
|
/**
|
||||||
* Usually ToolTipManager places a tooltip at (mouseLocation.x, mouseLocation.y + 20).
|
* Usually ToolTipManager places a tooltip at (mouseLocation.x, mouseLocation.y + 20).
|
||||||
* In case that the tooltip would be partly outside of the screen,
|
* In case that the tooltip would be partly outside of the screen,
|
||||||
* ToolTipManagerthe changes the location so that the entire tooltip fits on screen.
|
* the ToolTipManager changes the location so that the entire tooltip fits on screen.
|
||||||
* But this can place the tooltip under the mouse location and hide the owner component.
|
* But this can place the tooltip under the mouse location and hide the owner component.
|
||||||
* <p>
|
* <p>
|
||||||
* This method checks whether the current mouse location is within tooltip bounds
|
* This method checks whether the current mouse location is within tooltip bounds
|
||||||
* and corrects the y-location so that the tooltip is placed above the mouse location.
|
* and corrects the y-location so that the tooltip is placed above the mouse location.
|
||||||
*/
|
*/
|
||||||
private Point fixToolTipLocation( Component contents, int x, int y ) {
|
private Point fixToolTipLocation( Component owner, Component contents, int x, int y ) {
|
||||||
if( !(contents instanceof JToolTip) || !wasInvokedFromToolTipManager() )
|
if( !(contents instanceof JToolTip) || !wasInvokedFromToolTipManager() )
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
Point mouseLocation = MouseInfo.getPointerInfo().getLocation();
|
PointerInfo pointerInfo = MouseInfo.getPointerInfo();
|
||||||
|
if( pointerInfo == null )
|
||||||
|
return null;
|
||||||
|
|
||||||
|
Point mouseLocation = pointerInfo.getLocation();
|
||||||
Dimension tipSize = contents.getPreferredSize();
|
Dimension tipSize = contents.getPreferredSize();
|
||||||
|
|
||||||
// check whether mouse location is within tooltip bounds
|
// check whether mouse location is within tooltip bounds
|
||||||
@@ -224,18 +234,34 @@ public class FlatPopupFactory
|
|||||||
if( !tipBounds.contains( mouseLocation ) )
|
if( !tipBounds.contains( mouseLocation ) )
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
// place tooltip above mouse location
|
// find GraphicsConfiguration at mouse location (similar to ToolTipManager.getDrawingGC())
|
||||||
return new Point( x, mouseLocation.y - tipSize.height - UIScale.scale( 20 ) );
|
GraphicsConfiguration gc = null;
|
||||||
|
for( GraphicsDevice device : GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices() ) {
|
||||||
|
GraphicsConfiguration dgc = device.getDefaultConfiguration();
|
||||||
|
if( dgc.getBounds().contains( mouseLocation ) ) {
|
||||||
|
gc = dgc;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( gc == null )
|
||||||
|
gc = owner.getGraphicsConfiguration();
|
||||||
|
if( gc == null )
|
||||||
|
return null;
|
||||||
|
|
||||||
|
Rectangle screenBounds = gc.getBounds();
|
||||||
|
Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets( gc );
|
||||||
|
int screenTop = screenBounds.y + screenInsets.top;
|
||||||
|
|
||||||
|
// place tooltip above mouse location if there is enough space
|
||||||
|
int newY = mouseLocation.y - tipSize.height - UIScale.scale( 20 );
|
||||||
|
if( newY < screenTop )
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return new Point( x, newY );
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean wasInvokedFromToolTipManager() {
|
private boolean wasInvokedFromToolTipManager() {
|
||||||
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
|
return StackUtils.wasInvokedFrom( ToolTipManager.class.getName(), "showTipWindow", 8 );
|
||||||
for( StackTraceElement stackTraceElement : stackTrace ) {
|
|
||||||
if( "javax.swing.ToolTipManager".equals( stackTraceElement.getClassName() ) &&
|
|
||||||
"showTipWindow".equals( stackTraceElement.getMethodName() ) )
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//---- class NonFlashingPopup ---------------------------------------------
|
//---- class NonFlashingPopup ---------------------------------------------
|
||||||
|
|||||||
@@ -18,11 +18,14 @@ package com.formdev.flatlaf.ui;
|
|||||||
|
|
||||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
import java.awt.Container;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.Insets;
|
import java.awt.Insets;
|
||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
|
import java.util.Objects;
|
||||||
import javax.swing.AbstractButton;
|
import javax.swing.AbstractButton;
|
||||||
|
import javax.swing.CellRendererPane;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.LookAndFeel;
|
import javax.swing.LookAndFeel;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
@@ -120,10 +123,11 @@ public class FlatRadioButtonUI
|
|||||||
public void paint( Graphics g, JComponent c ) {
|
public void paint( Graphics g, JComponent c ) {
|
||||||
// fill background even if not opaque if
|
// fill background even if not opaque if
|
||||||
// - contentAreaFilled is true and
|
// - contentAreaFilled is true and
|
||||||
// - if background was explicitly set to a non-UIResource color
|
// - if background color is different to default background color
|
||||||
|
// (this paints selection if using the component as cell renderer)
|
||||||
if( !c.isOpaque() &&
|
if( !c.isOpaque() &&
|
||||||
((AbstractButton)c).isContentAreaFilled() &&
|
((AbstractButton)c).isContentAreaFilled() &&
|
||||||
!defaultBackground.equals( c.getBackground() ) )
|
!Objects.equals( c.getBackground(), getDefaultBackground( c ) ) )
|
||||||
{
|
{
|
||||||
g.setColor( c.getBackground() );
|
g.setColor( c.getBackground() );
|
||||||
g.fillRect( 0, 0, c.getWidth(), c.getHeight() );
|
g.fillRect( 0, 0, c.getWidth(), c.getHeight() );
|
||||||
@@ -160,6 +164,18 @@ public class FlatRadioButtonUI
|
|||||||
FlatButtonUI.paintText( g, b, textRect, text, b.isEnabled() ? b.getForeground() : disabledText );
|
FlatButtonUI.paintText( g, b, textRect, text, b.isEnabled() ? b.getForeground() : disabledText );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the default background color of the component.
|
||||||
|
* If the component is used as cell renderer (e.g. in JTable),
|
||||||
|
* then the background color of the renderer container is returned.
|
||||||
|
*/
|
||||||
|
private Color getDefaultBackground( JComponent c ) {
|
||||||
|
Container parent = c.getParent();
|
||||||
|
return (parent instanceof CellRendererPane && parent.getParent() != null)
|
||||||
|
? parent.getParent().getBackground()
|
||||||
|
: defaultBackground;
|
||||||
|
}
|
||||||
|
|
||||||
private int getIconFocusWidth( JComponent c ) {
|
private int getIconFocusWidth( JComponent c ) {
|
||||||
AbstractButton b = (AbstractButton) c;
|
AbstractButton b = (AbstractButton) c;
|
||||||
return (b.getIcon() == null && getDefaultIcon() instanceof FlatCheckBoxIcon)
|
return (b.getIcon() == null && getDefaultIcon() instanceof FlatCheckBoxIcon)
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ import java.awt.Insets;
|
|||||||
import java.awt.LayoutManager;
|
import java.awt.LayoutManager;
|
||||||
import java.awt.LayoutManager2;
|
import java.awt.LayoutManager2;
|
||||||
import java.awt.Window;
|
import java.awt.Window;
|
||||||
|
import java.awt.event.HierarchyEvent;
|
||||||
|
import java.awt.event.HierarchyListener;
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
@@ -79,6 +81,7 @@ public class FlatRootPaneUI
|
|||||||
|
|
||||||
private Object nativeWindowBorderData;
|
private Object nativeWindowBorderData;
|
||||||
private LayoutManager oldLayout;
|
private LayoutManager oldLayout;
|
||||||
|
private HierarchyListener hierarchyListener;
|
||||||
|
|
||||||
public static ComponentUI createUI( JComponent c ) {
|
public static ComponentUI createUI( JComponent c ) {
|
||||||
return new FlatRootPaneUI();
|
return new FlatRootPaneUI();
|
||||||
@@ -136,6 +139,39 @@ public class FlatRootPaneUI
|
|||||||
c.putClientProperty( "jetbrains.awt.windowDarkAppearance", FlatLaf.isLafDark() );
|
c.putClientProperty( "jetbrains.awt.windowDarkAppearance", FlatLaf.isLafDark() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void installListeners( JRootPane root ) {
|
||||||
|
super.installListeners( root );
|
||||||
|
|
||||||
|
if( SystemInfo.isJava_9_orLater ) {
|
||||||
|
// On HiDPI screens, where scaling is used, there may be white lines at the
|
||||||
|
// bottom and at the right side of the window when it is initially shown.
|
||||||
|
// This is very disturbing in dark themes, but hard to notice in light themes.
|
||||||
|
// Seems to be a rounding issue when Swing adds dirty region of window
|
||||||
|
// using RepaintManager.nativeAddDirtyRegion().
|
||||||
|
hierarchyListener = e -> {
|
||||||
|
if( (e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0 &&
|
||||||
|
rootPane.getParent() instanceof Window )
|
||||||
|
{
|
||||||
|
// add whole root pane to dirty regions when window is initially shown
|
||||||
|
rootPane.getParent().repaint( rootPane.getX(), rootPane.getY(),
|
||||||
|
rootPane.getWidth(), rootPane.getHeight() );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
root.addHierarchyListener( hierarchyListener );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void uninstallListeners( JRootPane root ) {
|
||||||
|
super.uninstallListeners( root );
|
||||||
|
|
||||||
|
if( SystemInfo.isJava_9_orLater ) {
|
||||||
|
root.removeHierarchyListener( hierarchyListener );
|
||||||
|
hierarchyListener = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @since 1.1.2
|
* @since 1.1.2
|
||||||
*/
|
*/
|
||||||
@@ -306,7 +342,7 @@ public class FlatRootPaneUI
|
|||||||
? getSizeFunc.apply( rootPane.getContentPane() )
|
? getSizeFunc.apply( rootPane.getContentPane() )
|
||||||
: rootPane.getSize();
|
: rootPane.getSize();
|
||||||
|
|
||||||
int width = Math.max( titlePaneSize.width, contentSize.width );
|
int width = contentSize.width; // title pane width is not considered here
|
||||||
int height = titlePaneSize.height + contentSize.height;
|
int height = titlePaneSize.height + contentSize.height;
|
||||||
if( titlePane == null || !titlePane.isMenuBarEmbedded() ) {
|
if( titlePane == null || !titlePane.isMenuBarEmbedded() ) {
|
||||||
JMenuBar menuBar = rootPane.getJMenuBar();
|
JMenuBar menuBar = rootPane.getJMenuBar();
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package com.formdev.flatlaf.ui;
|
|||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.Insets;
|
import java.awt.Insets;
|
||||||
|
import java.awt.KeyboardFocusManager;
|
||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
import java.awt.event.ContainerEvent;
|
import java.awt.event.ContainerEvent;
|
||||||
import java.awt.event.ContainerListener;
|
import java.awt.event.ContainerListener;
|
||||||
@@ -34,11 +35,13 @@ import javax.swing.JComponent;
|
|||||||
import javax.swing.JScrollBar;
|
import javax.swing.JScrollBar;
|
||||||
import javax.swing.JScrollPane;
|
import javax.swing.JScrollPane;
|
||||||
import javax.swing.JTable;
|
import javax.swing.JTable;
|
||||||
|
import javax.swing.JTree;
|
||||||
import javax.swing.JViewport;
|
import javax.swing.JViewport;
|
||||||
import javax.swing.LookAndFeel;
|
import javax.swing.LookAndFeel;
|
||||||
import javax.swing.ScrollPaneConstants;
|
import javax.swing.ScrollPaneConstants;
|
||||||
import javax.swing.Scrollable;
|
import javax.swing.Scrollable;
|
||||||
import javax.swing.SwingConstants;
|
import javax.swing.SwingConstants;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.plaf.ComponentUI;
|
import javax.swing.plaf.ComponentUI;
|
||||||
import javax.swing.plaf.basic.BasicScrollPaneUI;
|
import javax.swing.plaf.basic.BasicScrollPaneUI;
|
||||||
@@ -329,6 +332,31 @@ public class FlatScrollPaneUI
|
|||||||
paint( g, c );
|
paint( g, c );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 1.3
|
||||||
|
*/
|
||||||
|
public static boolean isPermanentFocusOwner( JScrollPane scrollPane ) {
|
||||||
|
JViewport viewport = scrollPane.getViewport();
|
||||||
|
Component view = (viewport != null) ? viewport.getView() : null;
|
||||||
|
if( view == null )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// check whether view is focus owner
|
||||||
|
if( FlatUIUtils.isPermanentFocusOwner( view ) )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// check whether editor component in JTable or JTree is focus owner
|
||||||
|
if( (view instanceof JTable && ((JTable)view).isEditing()) ||
|
||||||
|
(view instanceof JTree && ((JTree)view).isEditing()) )
|
||||||
|
{
|
||||||
|
Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
|
||||||
|
if( focusOwner != null )
|
||||||
|
return SwingUtilities.isDescendingFrom( focusOwner, view );
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//---- class Handler ------------------------------------------------------
|
//---- class Handler ------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -350,11 +378,13 @@ public class FlatScrollPaneUI
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void focusGained( FocusEvent e ) {
|
public void focusGained( FocusEvent e ) {
|
||||||
|
// necessary to update focus border
|
||||||
scrollpane.repaint();
|
scrollpane.repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void focusLost( FocusEvent e ) {
|
public void focusLost( FocusEvent e ) {
|
||||||
|
// necessary to update focus border
|
||||||
scrollpane.repaint();
|
scrollpane.repaint();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import javax.swing.LookAndFeel;
|
|||||||
import javax.swing.SwingConstants;
|
import javax.swing.SwingConstants;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.plaf.ComponentUI;
|
import javax.swing.plaf.ComponentUI;
|
||||||
|
import javax.swing.plaf.UIResource;
|
||||||
import javax.swing.plaf.basic.BasicSpinnerUI;
|
import javax.swing.plaf.basic.BasicSpinnerUI;
|
||||||
import com.formdev.flatlaf.FlatClientProperties;
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
|
|
||||||
@@ -65,6 +66,7 @@ import com.formdev.flatlaf.FlatClientProperties;
|
|||||||
* @uiDefault Component.disabledBorderColor Color
|
* @uiDefault Component.disabledBorderColor Color
|
||||||
* @uiDefault Spinner.disabledBackground Color
|
* @uiDefault Spinner.disabledBackground Color
|
||||||
* @uiDefault Spinner.disabledForeground Color
|
* @uiDefault Spinner.disabledForeground Color
|
||||||
|
* @uiDefault Spinner.focusedBackground Color optional
|
||||||
* @uiDefault Spinner.buttonBackground Color
|
* @uiDefault Spinner.buttonBackground Color
|
||||||
* @uiDefault Spinner.buttonArrowColor Color
|
* @uiDefault Spinner.buttonArrowColor Color
|
||||||
* @uiDefault Spinner.buttonDisabledArrowColor Color
|
* @uiDefault Spinner.buttonDisabledArrowColor Color
|
||||||
@@ -87,6 +89,7 @@ public class FlatSpinnerUI
|
|||||||
protected Color disabledBorderColor;
|
protected Color disabledBorderColor;
|
||||||
protected Color disabledBackground;
|
protected Color disabledBackground;
|
||||||
protected Color disabledForeground;
|
protected Color disabledForeground;
|
||||||
|
protected Color focusedBackground;
|
||||||
protected Color buttonBackground;
|
protected Color buttonBackground;
|
||||||
protected Color buttonArrowColor;
|
protected Color buttonArrowColor;
|
||||||
protected Color buttonDisabledArrowColor;
|
protected Color buttonDisabledArrowColor;
|
||||||
@@ -112,6 +115,7 @@ public class FlatSpinnerUI
|
|||||||
disabledBorderColor = UIManager.getColor( "Component.disabledBorderColor" );
|
disabledBorderColor = UIManager.getColor( "Component.disabledBorderColor" );
|
||||||
disabledBackground = UIManager.getColor( "Spinner.disabledBackground" );
|
disabledBackground = UIManager.getColor( "Spinner.disabledBackground" );
|
||||||
disabledForeground = UIManager.getColor( "Spinner.disabledForeground" );
|
disabledForeground = UIManager.getColor( "Spinner.disabledForeground" );
|
||||||
|
focusedBackground = UIManager.getColor( "Spinner.focusedBackground" );
|
||||||
buttonBackground = UIManager.getColor( "Spinner.buttonBackground" );
|
buttonBackground = UIManager.getColor( "Spinner.buttonBackground" );
|
||||||
buttonArrowColor = UIManager.getColor( "Spinner.buttonArrowColor" );
|
buttonArrowColor = UIManager.getColor( "Spinner.buttonArrowColor" );
|
||||||
buttonDisabledArrowColor = UIManager.getColor( "Spinner.buttonDisabledArrowColor" );
|
buttonDisabledArrowColor = UIManager.getColor( "Spinner.buttonDisabledArrowColor" );
|
||||||
@@ -119,9 +123,6 @@ public class FlatSpinnerUI
|
|||||||
buttonPressedArrowColor = UIManager.getColor( "Spinner.buttonPressedArrowColor" );
|
buttonPressedArrowColor = UIManager.getColor( "Spinner.buttonPressedArrowColor" );
|
||||||
padding = UIManager.getInsets( "Spinner.padding" );
|
padding = UIManager.getInsets( "Spinner.padding" );
|
||||||
|
|
||||||
// scale
|
|
||||||
padding = scale( padding );
|
|
||||||
|
|
||||||
MigLayoutVisualPadding.install( spinner );
|
MigLayoutVisualPadding.install( spinner );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,6 +134,7 @@ public class FlatSpinnerUI
|
|||||||
disabledBorderColor = null;
|
disabledBorderColor = null;
|
||||||
disabledBackground = null;
|
disabledBackground = null;
|
||||||
disabledForeground = null;
|
disabledForeground = null;
|
||||||
|
focusedBackground = null;
|
||||||
buttonBackground = null;
|
buttonBackground = null;
|
||||||
buttonArrowColor = null;
|
buttonArrowColor = null;
|
||||||
buttonDisabledArrowColor = null;
|
buttonDisabledArrowColor = null;
|
||||||
@@ -179,6 +181,7 @@ public class FlatSpinnerUI
|
|||||||
if( textField != null )
|
if( textField != null )
|
||||||
textField.setOpaque( false );
|
textField.setOpaque( false );
|
||||||
|
|
||||||
|
updateEditorPadding();
|
||||||
updateEditorColors();
|
updateEditorColors();
|
||||||
return editor;
|
return editor;
|
||||||
}
|
}
|
||||||
@@ -189,6 +192,8 @@ public class FlatSpinnerUI
|
|||||||
|
|
||||||
removeEditorFocusListener( oldEditor );
|
removeEditorFocusListener( oldEditor );
|
||||||
addEditorFocusListener( newEditor );
|
addEditorFocusListener( newEditor );
|
||||||
|
|
||||||
|
updateEditorPadding();
|
||||||
updateEditorColors();
|
updateEditorColors();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,6 +209,12 @@ public class FlatSpinnerUI
|
|||||||
textField.removeFocusListener( getHandler() );
|
textField.removeFocusListener( getHandler() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateEditorPadding() {
|
||||||
|
JTextField textField = getEditorTextField( spinner.getEditor() );
|
||||||
|
if( textField != null )
|
||||||
|
textField.putClientProperty( FlatClientProperties.TEXT_FIELD_PADDING, padding );
|
||||||
|
}
|
||||||
|
|
||||||
private void updateEditorColors() {
|
private void updateEditorColors() {
|
||||||
JTextField textField = getEditorTextField( spinner.getEditor() );
|
JTextField textField = getEditorTextField( spinner.getEditor() );
|
||||||
if( textField != null ) {
|
if( textField != null ) {
|
||||||
@@ -221,10 +232,34 @@ public class FlatSpinnerUI
|
|||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 1.3
|
||||||
|
*/
|
||||||
|
public static boolean isPermanentFocusOwner( JSpinner spinner ) {
|
||||||
|
if( FlatUIUtils.isPermanentFocusOwner( spinner ) )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
JTextField textField = getEditorTextField( spinner.getEditor() );
|
||||||
|
return (textField != null)
|
||||||
|
? FlatUIUtils.isPermanentFocusOwner( textField )
|
||||||
|
: false;
|
||||||
|
}
|
||||||
|
|
||||||
protected Color getBackground( boolean enabled ) {
|
protected Color getBackground( boolean enabled ) {
|
||||||
return enabled
|
if( enabled ) {
|
||||||
? spinner.getBackground()
|
Color background = spinner.getBackground();
|
||||||
: (isIntelliJTheme ? FlatUIUtils.getParentBackground( spinner ) : disabledBackground);
|
|
||||||
|
// always use explicitly set color
|
||||||
|
if( !(background instanceof UIResource) )
|
||||||
|
return background;
|
||||||
|
|
||||||
|
// focused
|
||||||
|
if( focusedBackground != null && isPermanentFocusOwner( spinner ) )
|
||||||
|
return focusedBackground;
|
||||||
|
|
||||||
|
return background;
|
||||||
|
} else
|
||||||
|
return isIntelliJTheme ? FlatUIUtils.getParentBackground( spinner ) : disabledBackground;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Color getForeground( boolean enabled ) {
|
protected Color getForeground( boolean enabled ) {
|
||||||
@@ -250,7 +285,7 @@ public class FlatSpinnerUI
|
|||||||
FlatArrowButton button = new FlatArrowButton( direction, arrowType, buttonArrowColor,
|
FlatArrowButton button = new FlatArrowButton( direction, arrowType, buttonArrowColor,
|
||||||
buttonDisabledArrowColor, buttonHoverArrowColor, null, buttonPressedArrowColor, null );
|
buttonDisabledArrowColor, buttonHoverArrowColor, null, buttonPressedArrowColor, null );
|
||||||
button.setName( name );
|
button.setName( name );
|
||||||
button.setYOffset( (direction == SwingConstants.NORTH) ? 1 : -1 );
|
button.setYOffset( (direction == SwingConstants.NORTH) ? 1.25f : -1.25f );
|
||||||
if( direction == SwingConstants.NORTH )
|
if( direction == SwingConstants.NORTH )
|
||||||
installNextButtonListeners( button );
|
installNextButtonListeners( button );
|
||||||
else
|
else
|
||||||
@@ -344,6 +379,7 @@ public class FlatSpinnerUI
|
|||||||
@Override
|
@Override
|
||||||
public Dimension preferredLayoutSize( Container parent ) {
|
public Dimension preferredLayoutSize( Container parent ) {
|
||||||
Insets insets = parent.getInsets();
|
Insets insets = parent.getInsets();
|
||||||
|
Insets padding = scale( FlatSpinnerUI.this.padding );
|
||||||
Dimension editorSize = (editor != null) ? editor.getPreferredSize() : new Dimension( 0, 0 );
|
Dimension editorSize = (editor != null) ? editor.getPreferredSize() : new Dimension( 0, 0 );
|
||||||
|
|
||||||
// the arrows width is the same as the inner height so that the arrows area is square
|
// the arrows width is the same as the inner height so that the arrows area is square
|
||||||
@@ -368,7 +404,7 @@ public class FlatSpinnerUI
|
|||||||
|
|
||||||
if( nextButton == null && previousButton == null ) {
|
if( nextButton == null && previousButton == null ) {
|
||||||
if( editor != null )
|
if( editor != null )
|
||||||
editor.setBounds( FlatUIUtils.subtractInsets( r, padding ) );
|
editor.setBounds( r );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -388,7 +424,7 @@ public class FlatSpinnerUI
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( editor != null )
|
if( editor != null )
|
||||||
editor.setBounds( FlatUIUtils.subtractInsets( editorRect, padding ) );
|
editor.setBounds( editorRect );
|
||||||
|
|
||||||
int nextHeight = (buttonsRect.height / 2) + (buttonsRect.height % 2); // round up
|
int nextHeight = (buttonsRect.height / 2) + (buttonsRect.height % 2); // round up
|
||||||
if( nextButton != null )
|
if( nextButton != null )
|
||||||
@@ -405,6 +441,7 @@ public class FlatSpinnerUI
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void focusGained( FocusEvent e ) {
|
public void focusGained( FocusEvent e ) {
|
||||||
|
// necessary to update focus border
|
||||||
spinner.repaint();
|
spinner.repaint();
|
||||||
|
|
||||||
// if spinner gained focus, transfer it to the editor text field
|
// if spinner gained focus, transfer it to the editor text field
|
||||||
@@ -417,6 +454,7 @@ public class FlatSpinnerUI
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void focusLost( FocusEvent e ) {
|
public void focusLost( FocusEvent e ) {
|
||||||
|
// necessary to update focus border
|
||||||
spinner.repaint();
|
spinner.repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -58,6 +58,8 @@ import java.util.function.BiConsumer;
|
|||||||
import java.util.function.IntConsumer;
|
import java.util.function.IntConsumer;
|
||||||
import javax.accessibility.Accessible;
|
import javax.accessibility.Accessible;
|
||||||
import javax.accessibility.AccessibleContext;
|
import javax.accessibility.AccessibleContext;
|
||||||
|
import javax.swing.Action;
|
||||||
|
import javax.swing.ActionMap;
|
||||||
import javax.swing.ButtonModel;
|
import javax.swing.ButtonModel;
|
||||||
import javax.swing.Icon;
|
import javax.swing.Icon;
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
@@ -325,7 +327,7 @@ public class FlatTabbedPaneUI
|
|||||||
// the default also includes Ctrl+TAB/Ctrl+Shift+TAB, which we need to switch tabs
|
// the default also includes Ctrl+TAB/Ctrl+Shift+TAB, which we need to switch tabs
|
||||||
if( focusForwardTraversalKeys == null ) {
|
if( focusForwardTraversalKeys == null ) {
|
||||||
focusForwardTraversalKeys = Collections.singleton( KeyStroke.getKeyStroke( KeyEvent.VK_TAB, 0 ) );
|
focusForwardTraversalKeys = Collections.singleton( KeyStroke.getKeyStroke( KeyEvent.VK_TAB, 0 ) );
|
||||||
focusBackwardTraversalKeys = Collections.singleton( KeyStroke.getKeyStroke( KeyEvent.VK_TAB, InputEvent.SHIFT_MASK ) );
|
focusBackwardTraversalKeys = Collections.singleton( KeyStroke.getKeyStroke( KeyEvent.VK_TAB, InputEvent.SHIFT_DOWN_MASK ) );
|
||||||
}
|
}
|
||||||
// Ideally we should use `LookAndFeel.installProperty( tabPane, "focusTraversalKeysForward", keys )` here
|
// Ideally we should use `LookAndFeel.installProperty( tabPane, "focusTraversalKeysForward", keys )` here
|
||||||
// instead of `tabPane.setFocusTraversalKeys()`, but WindowsTabbedPaneUI also uses later method
|
// instead of `tabPane.setFocusTraversalKeys()`, but WindowsTabbedPaneUI also uses later method
|
||||||
@@ -490,6 +492,20 @@ public class FlatTabbedPaneUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void installKeyboardActions() {
|
||||||
|
super.installKeyboardActions();
|
||||||
|
|
||||||
|
// get shared action map, used for all tabbed panes
|
||||||
|
ActionMap map = SwingUtilities.getUIActionMap( tabPane );
|
||||||
|
if( map != null ) {
|
||||||
|
// this is required for the case that those actions are used from outside
|
||||||
|
// (e.g. wheel tab scroller in NetBeans)
|
||||||
|
RunWithOriginalLayoutManagerDelegateAction.install( map, "scrollTabsForwardAction" );
|
||||||
|
RunWithOriginalLayoutManagerDelegateAction.install( map, "scrollTabsBackwardAction" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Handler getHandler() {
|
private Handler getHandler() {
|
||||||
if( handler == null )
|
if( handler == null )
|
||||||
handler = new Handler();
|
handler = new Handler();
|
||||||
@@ -826,6 +842,17 @@ public class FlatTabbedPaneUI
|
|||||||
paintTabArea( g, tabPlacement, selectedIndex );
|
paintTabArea( g, tabPlacement, selectedIndex );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void paintTabArea( Graphics g, int tabPlacement, int selectedIndex ) {
|
||||||
|
// need to set rendering hints here too because this method is also invoked
|
||||||
|
// from BasicTabbedPaneUI.ScrollableTabPanel.paintComponent()
|
||||||
|
Object[] oldHints = FlatUIUtils.setRenderingHints( g );
|
||||||
|
|
||||||
|
super.paintTabArea( g, tabPlacement, selectedIndex );
|
||||||
|
|
||||||
|
FlatUIUtils.resetRenderingHints( g, oldHints );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void paintTab( Graphics g, int tabPlacement, Rectangle[] rects,
|
protected void paintTab( Graphics g, int tabPlacement, Rectangle[] rects,
|
||||||
int tabIndex, Rectangle iconRect, Rectangle textRect )
|
int tabIndex, Rectangle iconRect, Rectangle textRect )
|
||||||
@@ -2959,4 +2986,51 @@ public class FlatTabbedPaneUI
|
|||||||
scrollBackwardButtonPrefSize = backwardButton.getPreferredSize();
|
scrollBackwardButtonPrefSize = backwardButton.getPreferredSize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---- class RunWithOriginalLayoutManagerDelegateAction -------------------
|
||||||
|
|
||||||
|
private static class RunWithOriginalLayoutManagerDelegateAction
|
||||||
|
implements Action
|
||||||
|
{
|
||||||
|
private final Action delegate;
|
||||||
|
|
||||||
|
static void install( ActionMap map, String key ) {
|
||||||
|
Action oldAction = map.get( key );
|
||||||
|
if( oldAction == null || oldAction instanceof RunWithOriginalLayoutManagerDelegateAction )
|
||||||
|
return; // not found or already installed
|
||||||
|
|
||||||
|
map.put( key, new RunWithOriginalLayoutManagerDelegateAction( oldAction ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private RunWithOriginalLayoutManagerDelegateAction( Action delegate ) {
|
||||||
|
this.delegate = delegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getValue( String key ) {
|
||||||
|
return delegate.getValue( key );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return delegate.isEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void putValue( String key, Object value ) {}
|
||||||
|
@Override public void setEnabled( boolean b ) {}
|
||||||
|
@Override public void addPropertyChangeListener( PropertyChangeListener listener ) {}
|
||||||
|
@Override public void removePropertyChangeListener( PropertyChangeListener listener ) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed( ActionEvent e ) {
|
||||||
|
JTabbedPane tabbedPane = (JTabbedPane) e.getSource();
|
||||||
|
ComponentUI ui = tabbedPane.getUI();
|
||||||
|
if( ui instanceof FlatTabbedPaneUI ) {
|
||||||
|
((FlatTabbedPaneUI)ui).runWithOriginalLayoutManager( () -> {
|
||||||
|
delegate.actionPerformed( e );
|
||||||
|
} );
|
||||||
|
} else
|
||||||
|
delegate.actionPerformed( e );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,124 @@
|
|||||||
|
/*
|
||||||
|
* 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.awt.Color;
|
||||||
|
import java.awt.Component;
|
||||||
|
import java.awt.Container;
|
||||||
|
import java.awt.Graphics;
|
||||||
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.geom.Rectangle2D;
|
||||||
|
import javax.swing.JScrollBar;
|
||||||
|
import javax.swing.JScrollPane;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
|
import javax.swing.UIManager;
|
||||||
|
import javax.swing.table.JTableHeader;
|
||||||
|
import javax.swing.table.TableColumn;
|
||||||
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cell border for {@code sun.swing.table.DefaultTableCellHeaderRenderer}
|
||||||
|
* (used by {@link javax.swing.table.JTableHeader}).
|
||||||
|
* <p>
|
||||||
|
* Uses separate cell margins from UI defaults to allow easy customizing.
|
||||||
|
*
|
||||||
|
* @author Karl Tauber
|
||||||
|
* @since 1.2
|
||||||
|
*/
|
||||||
|
public class FlatTableHeaderBorder
|
||||||
|
extends FlatEmptyBorder
|
||||||
|
{
|
||||||
|
protected Color separatorColor = UIManager.getColor( "TableHeader.separatorColor" );
|
||||||
|
protected Color bottomSeparatorColor = UIManager.getColor( "TableHeader.bottomSeparatorColor" );
|
||||||
|
|
||||||
|
public FlatTableHeaderBorder() {
|
||||||
|
super( UIManager.getInsets( "TableHeader.cellMargins" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@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;
|
||||||
|
|
||||||
|
if( header != null ) {
|
||||||
|
int hx = SwingUtilities.convertPoint( c, x, y, header ).x;
|
||||||
|
if( isDraggedColumn( header, hx ) )
|
||||||
|
paintLeft = paintRight = true;
|
||||||
|
else {
|
||||||
|
if( hx <= 0 && !leftToRight && hideTrailingVerticalLine( header ) )
|
||||||
|
paintLeft = false;
|
||||||
|
if( hx + width >= header.getWidth() && leftToRight && hideTrailingVerticalLine( header ) )
|
||||||
|
paintRight = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float lineWidth = UIScale.scale( 1f );
|
||||||
|
|
||||||
|
Graphics2D g2 = (Graphics2D) g.create();
|
||||||
|
try {
|
||||||
|
FlatUIUtils.setRenderingHints( g2 );
|
||||||
|
|
||||||
|
// paint column separator lines
|
||||||
|
g2.setColor( separatorColor );
|
||||||
|
if( paintLeft )
|
||||||
|
g2.fill( new Rectangle2D.Float( x, y, lineWidth, height - lineWidth ) );
|
||||||
|
if( paintRight )
|
||||||
|
g2.fill( new Rectangle2D.Float( x + width - lineWidth, y, lineWidth, height - lineWidth ) );
|
||||||
|
|
||||||
|
// paint bottom line
|
||||||
|
g2.setColor( bottomSeparatorColor );
|
||||||
|
g2.fill( new Rectangle2D.Float( x, y + height - lineWidth, width, lineWidth ) );
|
||||||
|
} finally {
|
||||||
|
g2.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isDraggedColumn( JTableHeader header, int x ) {
|
||||||
|
TableColumn draggedColumn = header.getDraggedColumn();
|
||||||
|
if( draggedColumn == null )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int draggedDistance = header.getDraggedDistance();
|
||||||
|
if( draggedDistance == 0 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int columnCount = header.getColumnModel().getColumnCount();
|
||||||
|
for( int i = 0; i < columnCount; i++ ) {
|
||||||
|
if( header.getHeaderRect( i ).x + draggedDistance == x )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean hideTrailingVerticalLine( JTableHeader header ) {
|
||||||
|
Container viewport = header.getParent();
|
||||||
|
Container viewportParent = (viewport != null) ? viewport.getParent() : null;
|
||||||
|
if( !(viewportParent instanceof JScrollPane) )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
JScrollBar vsb = ((JScrollPane)viewportParent).getVerticalScrollBar();
|
||||||
|
if( vsb == null || !vsb.isVisible() )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// if "ScrollPane.fillUpperCorner" is true, then javax.swing.ScrollPaneLayout
|
||||||
|
// extends the vertical scrollbar into the upper right/left corner
|
||||||
|
return vsb.getY() == viewport.getY();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,20 +18,16 @@ package com.formdev.flatlaf.ui;
|
|||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Container;
|
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.Insets;
|
import java.awt.Insets;
|
||||||
import java.awt.Rectangle;
|
|
||||||
import java.awt.geom.Rectangle2D;
|
import java.awt.geom.Rectangle2D;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import javax.swing.Icon;
|
import javax.swing.Icon;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import javax.swing.JScrollPane;
|
|
||||||
import javax.swing.JTable;
|
import javax.swing.JTable;
|
||||||
import javax.swing.ScrollPaneConstants;
|
|
||||||
import javax.swing.SwingConstants;
|
import javax.swing.SwingConstants;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.border.Border;
|
import javax.swing.border.Border;
|
||||||
@@ -39,7 +35,6 @@ import javax.swing.plaf.ComponentUI;
|
|||||||
import javax.swing.plaf.UIResource;
|
import javax.swing.plaf.UIResource;
|
||||||
import javax.swing.plaf.basic.BasicTableHeaderUI;
|
import javax.swing.plaf.basic.BasicTableHeaderUI;
|
||||||
import javax.swing.table.TableCellRenderer;
|
import javax.swing.table.TableCellRenderer;
|
||||||
import javax.swing.table.TableColumn;
|
|
||||||
import javax.swing.table.TableColumnModel;
|
import javax.swing.table.TableColumnModel;
|
||||||
import com.formdev.flatlaf.util.UIScale;
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
|
|
||||||
@@ -54,17 +49,21 @@ import com.formdev.flatlaf.util.UIScale;
|
|||||||
*
|
*
|
||||||
* <!-- FlatTableHeaderUI -->
|
* <!-- FlatTableHeaderUI -->
|
||||||
*
|
*
|
||||||
* @uiDefault TableHeader.separatorColor Color
|
|
||||||
* @uiDefault TableHeader.bottomSeparatorColor Color
|
* @uiDefault TableHeader.bottomSeparatorColor Color
|
||||||
* @uiDefault TableHeader.height int
|
* @uiDefault TableHeader.height int
|
||||||
* @uiDefault TableHeader.sortIconPosition String right (default), left, top or bottom
|
* @uiDefault TableHeader.sortIconPosition String right (default), left, top or bottom
|
||||||
*
|
*
|
||||||
|
* <!-- FlatTableHeaderBorder -->
|
||||||
|
*
|
||||||
|
* @uiDefault TableHeader.cellMargins Insets
|
||||||
|
* @uiDefault TableHeader.separatorColor Color
|
||||||
|
* @uiDefault TableHeader.bottomSeparatorColor Color
|
||||||
|
*
|
||||||
* @author Karl Tauber
|
* @author Karl Tauber
|
||||||
*/
|
*/
|
||||||
public class FlatTableHeaderUI
|
public class FlatTableHeaderUI
|
||||||
extends BasicTableHeaderUI
|
extends BasicTableHeaderUI
|
||||||
{
|
{
|
||||||
protected Color separatorColor;
|
|
||||||
protected Color bottomSeparatorColor;
|
protected Color bottomSeparatorColor;
|
||||||
protected int height;
|
protected int height;
|
||||||
protected int sortIconPosition;
|
protected int sortIconPosition;
|
||||||
@@ -77,7 +76,6 @@ public class FlatTableHeaderUI
|
|||||||
protected void installDefaults() {
|
protected void installDefaults() {
|
||||||
super.installDefaults();
|
super.installDefaults();
|
||||||
|
|
||||||
separatorColor = UIManager.getColor( "TableHeader.separatorColor" );
|
|
||||||
bottomSeparatorColor = UIManager.getColor( "TableHeader.bottomSeparatorColor" );
|
bottomSeparatorColor = UIManager.getColor( "TableHeader.bottomSeparatorColor" );
|
||||||
height = UIManager.getInt( "TableHeader.height" );
|
height = UIManager.getInt( "TableHeader.height" );
|
||||||
switch( Objects.toString( UIManager.getString( "TableHeader.sortIconPosition" ), "right" ) ) {
|
switch( Objects.toString( UIManager.getString( "TableHeader.sortIconPosition" ), "right" ) ) {
|
||||||
@@ -93,27 +91,38 @@ public class FlatTableHeaderUI
|
|||||||
protected void uninstallDefaults() {
|
protected void uninstallDefaults() {
|
||||||
super.uninstallDefaults();
|
super.uninstallDefaults();
|
||||||
|
|
||||||
separatorColor = null;
|
|
||||||
bottomSeparatorColor = null;
|
bottomSeparatorColor = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paint( Graphics g, JComponent c ) {
|
public void paint( Graphics g, JComponent c ) {
|
||||||
if( header.getColumnModel().getColumnCount() <= 0 )
|
TableColumnModel columnModel = header.getColumnModel();
|
||||||
|
if( columnModel.getColumnCount() <= 0 )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// do not paint borders if JTableHeader.setDefaultRenderer() was used
|
// compute total width of all columns
|
||||||
TableCellRenderer defaultRenderer = header.getDefaultRenderer();
|
int columnCount = columnModel.getColumnCount();
|
||||||
boolean paintBorders = isSystemDefaultRenderer( defaultRenderer );
|
int totalWidth = 0;
|
||||||
if( !paintBorders ) {
|
for( int i = 0; i < columnCount; i++ )
|
||||||
// check whether the renderer delegates to the system default renderer
|
totalWidth += columnModel.getColumn( i ).getWidth();
|
||||||
Component rendererComponent = defaultRenderer.getTableCellRendererComponent(
|
|
||||||
header.getTable(), "", false, false, -1, 0 );
|
|
||||||
paintBorders = isSystemDefaultRenderer( rendererComponent );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( paintBorders )
|
if( totalWidth < header.getWidth() ) {
|
||||||
paintColumnBorders( g, c );
|
// do not paint bottom separator if JTableHeader.setDefaultRenderer() was used
|
||||||
|
TableCellRenderer defaultRenderer = header.getDefaultRenderer();
|
||||||
|
boolean paintBottomSeparator = isSystemDefaultRenderer( defaultRenderer );
|
||||||
|
if( !paintBottomSeparator && header.getTable() != null ) {
|
||||||
|
// check whether the renderer delegates to the system default renderer
|
||||||
|
Component rendererComponent = defaultRenderer.getTableCellRendererComponent(
|
||||||
|
header.getTable(), "", false, false, -1, 0 );
|
||||||
|
paintBottomSeparator = isSystemDefaultRenderer( rendererComponent );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( paintBottomSeparator ) {
|
||||||
|
int w = c.getWidth() - totalWidth;
|
||||||
|
int x = header.getComponentOrientation().isLeftToRight() ? c.getWidth() - w : 0;
|
||||||
|
paintBottomSeparator( g, c, x, w );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// temporary use own default renderer if necessary
|
// temporary use own default renderer if necessary
|
||||||
FlatTableCellHeaderRenderer sortIconRenderer = null;
|
FlatTableCellHeaderRenderer sortIconRenderer = null;
|
||||||
@@ -130,9 +139,6 @@ public class FlatTableHeaderUI
|
|||||||
sortIconRenderer.reset();
|
sortIconRenderer.reset();
|
||||||
header.setDefaultRenderer( sortIconRenderer.delegate );
|
header.setDefaultRenderer( sortIconRenderer.delegate );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( paintBorders )
|
|
||||||
paintDraggedColumnBorders( g, c );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isSystemDefaultRenderer( Object headerRenderer ) {
|
private boolean isSystemDefaultRenderer( Object headerRenderer ) {
|
||||||
@@ -141,17 +147,8 @@ public class FlatTableHeaderUI
|
|||||||
rendererClassName.equals( "sun.swing.FilePane$AlignableTableHeaderRenderer" );
|
rendererClassName.equals( "sun.swing.FilePane$AlignableTableHeaderRenderer" );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void paintColumnBorders( Graphics g, JComponent c ) {
|
protected void paintBottomSeparator( Graphics g, JComponent c, int x, int w ) {
|
||||||
int width = c.getWidth();
|
|
||||||
int height = c.getHeight();
|
|
||||||
float lineWidth = UIScale.scale( 1f );
|
float lineWidth = UIScale.scale( 1f );
|
||||||
float topLineIndent = lineWidth;
|
|
||||||
float bottomLineIndent = lineWidth * 3;
|
|
||||||
TableColumnModel columnModel = header.getColumnModel();
|
|
||||||
int columnCount = columnModel.getColumnCount();
|
|
||||||
int sepCount = columnCount;
|
|
||||||
if( hideLastVerticalLine() )
|
|
||||||
sepCount--;
|
|
||||||
|
|
||||||
Graphics2D g2 = (Graphics2D) g.create();
|
Graphics2D g2 = (Graphics2D) g.create();
|
||||||
try {
|
try {
|
||||||
@@ -159,78 +156,7 @@ public class FlatTableHeaderUI
|
|||||||
|
|
||||||
// paint bottom line
|
// paint bottom line
|
||||||
g2.setColor( bottomSeparatorColor );
|
g2.setColor( bottomSeparatorColor );
|
||||||
g2.fill( new Rectangle2D.Float( 0, height - lineWidth, width, lineWidth ) );
|
g2.fill( new Rectangle2D.Float( x, c.getHeight() - lineWidth, w, lineWidth ) );
|
||||||
|
|
||||||
// paint column separator lines
|
|
||||||
g2.setColor( separatorColor );
|
|
||||||
|
|
||||||
float y = topLineIndent;
|
|
||||||
float h = height - bottomLineIndent;
|
|
||||||
|
|
||||||
if( header.getComponentOrientation().isLeftToRight() ) {
|
|
||||||
int x = 0;
|
|
||||||
for( int i = 0; i < sepCount; i++ ) {
|
|
||||||
x += columnModel.getColumn( i ).getWidth();
|
|
||||||
g2.fill( new Rectangle2D.Float( x - lineWidth, y, lineWidth, h ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
// paint trailing separator (on right side)
|
|
||||||
if( !hideTrailingVerticalLine() )
|
|
||||||
g2.fill( new Rectangle2D.Float( header.getWidth() - lineWidth, y, lineWidth, h ) );
|
|
||||||
} else {
|
|
||||||
Rectangle cellRect = header.getHeaderRect( 0 );
|
|
||||||
int x = cellRect.x + cellRect.width;
|
|
||||||
for( int i = 0; i < sepCount; i++ ) {
|
|
||||||
x -= columnModel.getColumn( i ).getWidth();
|
|
||||||
g2.fill( new Rectangle2D.Float( x - (i < sepCount - 1 ? lineWidth : 0), y, lineWidth, h ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
// paint trailing separator (on left side)
|
|
||||||
if( !hideTrailingVerticalLine() )
|
|
||||||
g2.fill( new Rectangle2D.Float( 0, y, lineWidth, h ) );
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
g2.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void paintDraggedColumnBorders( Graphics g, JComponent c ) {
|
|
||||||
TableColumn draggedColumn = header.getDraggedColumn();
|
|
||||||
if( draggedColumn == null )
|
|
||||||
return;
|
|
||||||
|
|
||||||
// find index of dragged column
|
|
||||||
TableColumnModel columnModel = header.getColumnModel();
|
|
||||||
int columnCount = columnModel.getColumnCount();
|
|
||||||
int draggedColumnIndex = -1;
|
|
||||||
for( int i = 0; i < columnCount; i++ ) {
|
|
||||||
if( columnModel.getColumn( i ) == draggedColumn ) {
|
|
||||||
draggedColumnIndex = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( draggedColumnIndex < 0 )
|
|
||||||
return;
|
|
||||||
|
|
||||||
float lineWidth = UIScale.scale( 1f );
|
|
||||||
float topLineIndent = lineWidth;
|
|
||||||
float bottomLineIndent = lineWidth * 3;
|
|
||||||
Rectangle r = header.getHeaderRect( draggedColumnIndex );
|
|
||||||
r.x += header.getDraggedDistance();
|
|
||||||
|
|
||||||
Graphics2D g2 = (Graphics2D) g.create();
|
|
||||||
try {
|
|
||||||
FlatUIUtils.setRenderingHints( g2 );
|
|
||||||
|
|
||||||
// paint dragged bottom line
|
|
||||||
g2.setColor( bottomSeparatorColor );
|
|
||||||
g2.fill( new Rectangle2D.Float( r.x, r.y + r.height - lineWidth, r.width, lineWidth ) );
|
|
||||||
|
|
||||||
// paint dragged column separator lines
|
|
||||||
g2.setColor( separatorColor );
|
|
||||||
g2.fill( new Rectangle2D.Float( r.x, topLineIndent, lineWidth, r.height - bottomLineIndent ) );
|
|
||||||
g2.fill( new Rectangle2D.Float( r.x + r.width - lineWidth, r.y + topLineIndent, lineWidth, r.height - bottomLineIndent ) );
|
|
||||||
} finally {
|
} finally {
|
||||||
g2.dispose();
|
g2.dispose();
|
||||||
}
|
}
|
||||||
@@ -244,32 +170,6 @@ public class FlatTableHeaderUI
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean hideLastVerticalLine() {
|
|
||||||
Container viewport = header.getParent();
|
|
||||||
Container viewportParent = (viewport != null) ? viewport.getParent() : null;
|
|
||||||
if( !(viewportParent instanceof JScrollPane) )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Rectangle cellRect = header.getHeaderRect( header.getColumnModel().getColumnCount() - 1 );
|
|
||||||
|
|
||||||
// using component orientation of scroll pane here because it is also used in FlatTableUI
|
|
||||||
JScrollPane scrollPane = (JScrollPane) viewportParent;
|
|
||||||
return scrollPane.getComponentOrientation().isLeftToRight()
|
|
||||||
? cellRect.x + cellRect.width >= viewport.getWidth()
|
|
||||||
: cellRect.x <= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean hideTrailingVerticalLine() {
|
|
||||||
Container viewport = header.getParent();
|
|
||||||
Container viewportParent = (viewport != null) ? viewport.getParent() : null;
|
|
||||||
if( !(viewportParent instanceof JScrollPane) )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
JScrollPane scrollPane = (JScrollPane) viewportParent;
|
|
||||||
return viewport == scrollPane.getColumnHeader() &&
|
|
||||||
scrollPane.getCorner( ScrollPaneConstants.UPPER_TRAILING_CORNER ) == null;
|
|
||||||
}
|
|
||||||
|
|
||||||
//---- class FlatTableCellHeaderRenderer ----------------------------------
|
//---- class FlatTableCellHeaderRenderer ----------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -240,7 +240,7 @@ public class FlatTableUI
|
|||||||
if( isDragging &&
|
if( isDragging &&
|
||||||
SystemInfo.isJava_9_orLater &&
|
SystemInfo.isJava_9_orLater &&
|
||||||
((horizontalLines && y1 == y2) || (verticalLines && x1 == x2)) &&
|
((horizontalLines && y1 == y2) || (verticalLines && x1 == x2)) &&
|
||||||
wasInvokedFromPaintDraggedArea() )
|
wasInvokedFromMethod( "paintDraggedArea" ) )
|
||||||
{
|
{
|
||||||
if( y1 == y2 ) {
|
if( y1 == y2 ) {
|
||||||
// horizontal grid line
|
// horizontal grid line
|
||||||
@@ -282,22 +282,8 @@ public class FlatTableUI
|
|||||||
return wasInvokedFromMethod( "paintGrid" );
|
return wasInvokedFromMethod( "paintGrid" );
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean wasInvokedFromPaintDraggedArea() {
|
|
||||||
return wasInvokedFromMethod( "paintDraggedArea" );
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean wasInvokedFromMethod( String methodName ) {
|
private boolean wasInvokedFromMethod( String methodName ) {
|
||||||
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
|
return StackUtils.wasInvokedFrom( BasicTableUI.class.getName(), methodName, 8 );
|
||||||
for( int i = 0; i < 10 || i < stackTrace.length; i++ ) {
|
|
||||||
if( "javax.swing.plaf.basic.BasicTableUI".equals( stackTrace[i].getClassName() ) ) {
|
|
||||||
String methodName2 = stackTrace[i].getMethodName();
|
|
||||||
if( "paintCell".equals( methodName2 ) )
|
|
||||||
return false;
|
|
||||||
if( methodName.equals( methodName2 ) )
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import java.awt.Color;
|
|||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.event.FocusListener;
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JTextArea;
|
import javax.swing.JTextArea;
|
||||||
@@ -52,6 +53,7 @@ import com.formdev.flatlaf.util.HiDPIUtils;
|
|||||||
* @uiDefault Component.isIntelliJTheme boolean
|
* @uiDefault Component.isIntelliJTheme boolean
|
||||||
* @uiDefault TextArea.disabledBackground Color used if not enabled
|
* @uiDefault TextArea.disabledBackground Color used if not enabled
|
||||||
* @uiDefault TextArea.inactiveBackground Color used if not editable
|
* @uiDefault TextArea.inactiveBackground Color used if not editable
|
||||||
|
* @uiDefault TextArea.focusedBackground Color optional
|
||||||
*
|
*
|
||||||
* @author Karl Tauber
|
* @author Karl Tauber
|
||||||
*/
|
*/
|
||||||
@@ -63,6 +65,9 @@ public class FlatTextAreaUI
|
|||||||
protected Color background;
|
protected Color background;
|
||||||
protected Color disabledBackground;
|
protected Color disabledBackground;
|
||||||
protected Color inactiveBackground;
|
protected Color inactiveBackground;
|
||||||
|
protected Color focusedBackground;
|
||||||
|
|
||||||
|
private FocusListener focusListener;
|
||||||
|
|
||||||
public static ComponentUI createUI( JComponent c ) {
|
public static ComponentUI createUI( JComponent c ) {
|
||||||
return new FlatTextAreaUI();
|
return new FlatTextAreaUI();
|
||||||
@@ -84,6 +89,7 @@ public class FlatTextAreaUI
|
|||||||
background = UIManager.getColor( "TextArea.background" );
|
background = UIManager.getColor( "TextArea.background" );
|
||||||
disabledBackground = UIManager.getColor( "TextArea.disabledBackground" );
|
disabledBackground = UIManager.getColor( "TextArea.disabledBackground" );
|
||||||
inactiveBackground = UIManager.getColor( "TextArea.inactiveBackground" );
|
inactiveBackground = UIManager.getColor( "TextArea.inactiveBackground" );
|
||||||
|
focusedBackground = UIManager.getColor( "TextArea.focusedBackground" );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -93,6 +99,24 @@ public class FlatTextAreaUI
|
|||||||
background = null;
|
background = null;
|
||||||
disabledBackground = null;
|
disabledBackground = null;
|
||||||
inactiveBackground = null;
|
inactiveBackground = null;
|
||||||
|
focusedBackground = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void installListeners() {
|
||||||
|
super.installListeners();
|
||||||
|
|
||||||
|
// necessary to update focus background
|
||||||
|
focusListener = new FlatUIUtils.RepaintFocusListener( getComponent(), c -> focusedBackground != null );
|
||||||
|
getComponent().addFocusListener( focusListener );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void uninstallListeners() {
|
||||||
|
super.uninstallListeners();
|
||||||
|
|
||||||
|
getComponent().removeFocusListener( focusListener );
|
||||||
|
focusListener = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -156,14 +180,6 @@ public class FlatTextAreaUI
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void paintBackground( Graphics g ) {
|
protected void paintBackground( Graphics g ) {
|
||||||
JTextComponent c = getComponent();
|
FlatEditorPaneUI.paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground );
|
||||||
|
|
||||||
// for compatibility with IntelliJ themes
|
|
||||||
if( isIntelliJTheme && (!c.isEnabled() || !c.isEditable()) && (c.getBackground() instanceof UIResource) ) {
|
|
||||||
FlatUIUtils.paintParentBackground( g, c );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
super.paintBackground( g );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import java.awt.FontMetrics;
|
|||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.Insets;
|
import java.awt.Insets;
|
||||||
|
import java.awt.Rectangle;
|
||||||
import java.awt.event.FocusListener;
|
import java.awt.event.FocusListener;
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import javax.swing.JComboBox;
|
import javax.swing.JComboBox;
|
||||||
@@ -40,6 +41,7 @@ import javax.swing.text.JTextComponent;
|
|||||||
import com.formdev.flatlaf.FlatClientProperties;
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||||
import com.formdev.flatlaf.util.JavaCompatibility;
|
import com.formdev.flatlaf.util.JavaCompatibility;
|
||||||
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JTextField}.
|
* Provides the Flat LaF UI delegate for {@link javax.swing.JTextField}.
|
||||||
@@ -64,6 +66,7 @@ import com.formdev.flatlaf.util.JavaCompatibility;
|
|||||||
* @uiDefault Component.minimumWidth int
|
* @uiDefault Component.minimumWidth int
|
||||||
* @uiDefault Component.isIntelliJTheme boolean
|
* @uiDefault Component.isIntelliJTheme boolean
|
||||||
* @uiDefault TextField.placeholderForeground Color
|
* @uiDefault TextField.placeholderForeground Color
|
||||||
|
* @uiDefault TextField.focusedBackground Color optional
|
||||||
* @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always
|
* @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always
|
||||||
* @uiDefault TextComponent.selectAllOnMouseClick boolean
|
* @uiDefault TextComponent.selectAllOnMouseClick boolean
|
||||||
*
|
*
|
||||||
@@ -75,6 +78,7 @@ public class FlatTextFieldUI
|
|||||||
protected int minimumWidth;
|
protected int minimumWidth;
|
||||||
protected boolean isIntelliJTheme;
|
protected boolean isIntelliJTheme;
|
||||||
protected Color placeholderForeground;
|
protected Color placeholderForeground;
|
||||||
|
protected Color focusedBackground;
|
||||||
|
|
||||||
private FocusListener focusListener;
|
private FocusListener focusListener;
|
||||||
|
|
||||||
@@ -90,6 +94,7 @@ public class FlatTextFieldUI
|
|||||||
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
||||||
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
||||||
placeholderForeground = UIManager.getColor( prefix + ".placeholderForeground" );
|
placeholderForeground = UIManager.getColor( prefix + ".placeholderForeground" );
|
||||||
|
focusedBackground = UIManager.getColor( prefix + ".focusedBackground" );
|
||||||
|
|
||||||
LookAndFeel.installProperty( getComponent(), "opaque", false );
|
LookAndFeel.installProperty( getComponent(), "opaque", false );
|
||||||
|
|
||||||
@@ -101,6 +106,7 @@ public class FlatTextFieldUI
|
|||||||
super.uninstallDefaults();
|
super.uninstallDefaults();
|
||||||
|
|
||||||
placeholderForeground = null;
|
placeholderForeground = null;
|
||||||
|
focusedBackground = null;
|
||||||
|
|
||||||
MigLayoutVisualPadding.uninstall( getComponent() );
|
MigLayoutVisualPadding.uninstall( getComponent() );
|
||||||
}
|
}
|
||||||
@@ -109,7 +115,8 @@ public class FlatTextFieldUI
|
|||||||
protected void installListeners() {
|
protected void installListeners() {
|
||||||
super.installListeners();
|
super.installListeners();
|
||||||
|
|
||||||
focusListener = new FlatUIUtils.RepaintFocusListener( getComponent() );
|
// necessary to update focus border and background
|
||||||
|
focusListener = new FlatUIUtils.RepaintFocusListener( getComponent(), null );
|
||||||
getComponent().addFocusListener( focusListener );
|
getComponent().addFocusListener( focusListener );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,6 +144,7 @@ public class FlatTextFieldUI
|
|||||||
switch( e.getPropertyName() ) {
|
switch( e.getPropertyName() ) {
|
||||||
case FlatClientProperties.PLACEHOLDER_TEXT:
|
case FlatClientProperties.PLACEHOLDER_TEXT:
|
||||||
case FlatClientProperties.COMPONENT_ROUND_RECT:
|
case FlatClientProperties.COMPONENT_ROUND_RECT:
|
||||||
|
case FlatClientProperties.TEXT_FIELD_PADDING:
|
||||||
c.repaint();
|
c.repaint();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -148,8 +156,8 @@ public class FlatTextFieldUI
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void paintSafely( Graphics g ) {
|
protected void paintSafely( Graphics g ) {
|
||||||
paintBackground( g, getComponent(), isIntelliJTheme );
|
paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground );
|
||||||
paintPlaceholder( g, getComponent(), placeholderForeground );
|
paintPlaceholder( g );
|
||||||
|
|
||||||
super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) );
|
super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) );
|
||||||
}
|
}
|
||||||
@@ -159,7 +167,7 @@ public class FlatTextFieldUI
|
|||||||
// background is painted elsewhere
|
// background is painted elsewhere
|
||||||
}
|
}
|
||||||
|
|
||||||
static void paintBackground( Graphics g, JTextComponent c, boolean isIntelliJTheme ) {
|
static void paintBackground( Graphics g, JTextComponent c, boolean isIntelliJTheme, Color focusedBackground ) {
|
||||||
// do not paint background if:
|
// do not paint background if:
|
||||||
// - not opaque and
|
// - not opaque and
|
||||||
// - border is not a flat border and
|
// - border is not a flat border and
|
||||||
@@ -180,19 +188,34 @@ public class FlatTextFieldUI
|
|||||||
try {
|
try {
|
||||||
FlatUIUtils.setRenderingHints( g2 );
|
FlatUIUtils.setRenderingHints( g2 );
|
||||||
|
|
||||||
Color background = c.getBackground();
|
g2.setColor( getBackground( c, isIntelliJTheme, focusedBackground ) );
|
||||||
g2.setColor( !(background instanceof UIResource)
|
|
||||||
? background
|
|
||||||
: (isIntelliJTheme && (!c.isEnabled() || !c.isEditable())
|
|
||||||
? FlatUIUtils.getParentBackground( c )
|
|
||||||
: background) );
|
|
||||||
FlatUIUtils.paintComponentBackground( g2, 0, 0, c.getWidth(), c.getHeight(), focusWidth, arc );
|
FlatUIUtils.paintComponentBackground( g2, 0, 0, c.getWidth(), c.getHeight(), focusWidth, arc );
|
||||||
} finally {
|
} finally {
|
||||||
g2.dispose();
|
g2.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void paintPlaceholder( Graphics g, JTextComponent c, Color placeholderForeground ) {
|
static Color getBackground( JTextComponent c, boolean isIntelliJTheme, Color focusedBackground ) {
|
||||||
|
Color background = c.getBackground();
|
||||||
|
|
||||||
|
// always use explicitly set color
|
||||||
|
if( !(background instanceof UIResource) )
|
||||||
|
return background;
|
||||||
|
|
||||||
|
// focused
|
||||||
|
if( focusedBackground != null && FlatUIUtils.isPermanentFocusOwner( c ) )
|
||||||
|
return focusedBackground;
|
||||||
|
|
||||||
|
// for compatibility with IntelliJ themes
|
||||||
|
if( isIntelliJTheme && (!c.isEnabled() || !c.isEditable()) )
|
||||||
|
return FlatUIUtils.getParentBackground( c );
|
||||||
|
|
||||||
|
return background;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void paintPlaceholder( Graphics g ) {
|
||||||
|
JTextComponent c = getComponent();
|
||||||
|
|
||||||
// check whether text component is empty
|
// check whether text component is empty
|
||||||
if( c.getDocument().getLength() > 0 )
|
if( c.getDocument().getLength() > 0 )
|
||||||
return;
|
return;
|
||||||
@@ -207,16 +230,14 @@ public class FlatTextFieldUI
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// compute placeholder location
|
// compute placeholder location
|
||||||
Insets insets = c.getInsets();
|
Rectangle r = getVisibleEditorRect();
|
||||||
FontMetrics fm = c.getFontMetrics( c.getFont() );
|
FontMetrics fm = c.getFontMetrics( c.getFont() );
|
||||||
int x = insets.left;
|
int y = r.y + fm.getAscent() + ((r.height - fm.getHeight()) / 2);
|
||||||
int y = insets.top + fm.getAscent() + ((c.getHeight() - insets.top - insets.bottom - fm.getHeight()) / 2);
|
|
||||||
|
|
||||||
// paint placeholder
|
// paint placeholder
|
||||||
g.setColor( placeholderForeground );
|
g.setColor( placeholderForeground );
|
||||||
String clippedPlaceholder = JavaCompatibility.getClippedString( jc, fm,
|
String clippedPlaceholder = JavaCompatibility.getClippedString( c, fm, (String) placeholder, r.width );
|
||||||
(String) placeholder, c.getWidth() - insets.left - insets.right );
|
FlatUIUtils.drawString( c, g, clippedPlaceholder, r.x, y );
|
||||||
FlatUIUtils.drawString( c, g, clippedPlaceholder, x, y );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -246,4 +267,36 @@ public class FlatTextFieldUI
|
|||||||
size.width = Math.max( size.width, scale( minimumWidth ) + Math.round( focusWidth * 2 ) );
|
size.width = Math.max( size.width, scale( minimumWidth ) + Math.round( focusWidth * 2 ) );
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 1.4
|
||||||
|
*/
|
||||||
|
protected Insets getPadding() {
|
||||||
|
Object padding = getComponent().getClientProperty( FlatClientProperties.TEXT_FIELD_PADDING );
|
||||||
|
return (padding instanceof Insets) ? UIScale.scale( (Insets) padding ) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 1.4
|
||||||
|
*/
|
||||||
|
protected void scrollCaretToVisible() {
|
||||||
|
Caret caret = getComponent().getCaret();
|
||||||
|
if( caret instanceof FlatCaret )
|
||||||
|
((FlatCaret)caret).scrollCaretToVisible();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,17 +16,17 @@
|
|||||||
|
|
||||||
package com.formdev.flatlaf.ui;
|
package com.formdev.flatlaf.ui;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.event.FocusListener;
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JEditorPane;
|
import javax.swing.JEditorPane;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.plaf.ComponentUI;
|
import javax.swing.plaf.ComponentUI;
|
||||||
import javax.swing.plaf.UIResource;
|
|
||||||
import javax.swing.plaf.basic.BasicTextPaneUI;
|
import javax.swing.plaf.basic.BasicTextPaneUI;
|
||||||
import javax.swing.text.JTextComponent;
|
|
||||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -51,6 +51,7 @@ import com.formdev.flatlaf.util.HiDPIUtils;
|
|||||||
*
|
*
|
||||||
* @uiDefault Component.minimumWidth int
|
* @uiDefault Component.minimumWidth int
|
||||||
* @uiDefault Component.isIntelliJTheme boolean
|
* @uiDefault Component.isIntelliJTheme boolean
|
||||||
|
* @uiDefault TextPane.focusedBackground Color optional
|
||||||
*
|
*
|
||||||
* @author Karl Tauber
|
* @author Karl Tauber
|
||||||
*/
|
*/
|
||||||
@@ -59,8 +60,10 @@ public class FlatTextPaneUI
|
|||||||
{
|
{
|
||||||
protected int minimumWidth;
|
protected int minimumWidth;
|
||||||
protected boolean isIntelliJTheme;
|
protected boolean isIntelliJTheme;
|
||||||
|
protected Color focusedBackground;
|
||||||
|
|
||||||
private Object oldHonorDisplayProperties;
|
private Object oldHonorDisplayProperties;
|
||||||
|
private FocusListener focusListener;
|
||||||
|
|
||||||
public static ComponentUI createUI( JComponent c ) {
|
public static ComponentUI createUI( JComponent c ) {
|
||||||
return new FlatTextPaneUI();
|
return new FlatTextPaneUI();
|
||||||
@@ -70,8 +73,10 @@ public class FlatTextPaneUI
|
|||||||
protected void installDefaults() {
|
protected void installDefaults() {
|
||||||
super.installDefaults();
|
super.installDefaults();
|
||||||
|
|
||||||
|
String prefix = getPropertyPrefix();
|
||||||
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
||||||
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
||||||
|
focusedBackground = UIManager.getColor( prefix + ".focusedBackground" );
|
||||||
|
|
||||||
// use component font and foreground for HTML text
|
// use component font and foreground for HTML text
|
||||||
oldHonorDisplayProperties = getComponent().getClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES );
|
oldHonorDisplayProperties = getComponent().getClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES );
|
||||||
@@ -82,9 +87,28 @@ public class FlatTextPaneUI
|
|||||||
protected void uninstallDefaults() {
|
protected void uninstallDefaults() {
|
||||||
super.uninstallDefaults();
|
super.uninstallDefaults();
|
||||||
|
|
||||||
|
focusedBackground = null;
|
||||||
|
|
||||||
getComponent().putClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES, oldHonorDisplayProperties );
|
getComponent().putClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES, oldHonorDisplayProperties );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void installListeners() {
|
||||||
|
super.installListeners();
|
||||||
|
|
||||||
|
// necessary to update focus background
|
||||||
|
focusListener = new FlatUIUtils.RepaintFocusListener( getComponent(), c -> focusedBackground != null );
|
||||||
|
getComponent().addFocusListener( focusListener );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void uninstallListeners() {
|
||||||
|
super.uninstallListeners();
|
||||||
|
|
||||||
|
getComponent().removeFocusListener( focusListener );
|
||||||
|
focusListener = null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void propertyChange( PropertyChangeEvent e ) {
|
protected void propertyChange( PropertyChangeEvent e ) {
|
||||||
super.propertyChange( e );
|
super.propertyChange( e );
|
||||||
@@ -108,14 +132,6 @@ public class FlatTextPaneUI
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void paintBackground( Graphics g ) {
|
protected void paintBackground( Graphics g ) {
|
||||||
JTextComponent c = getComponent();
|
FlatEditorPaneUI.paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground );
|
||||||
|
|
||||||
// for compatibility with IntelliJ themes
|
|
||||||
if( isIntelliJTheme && (!c.isEnabled() || !c.isEditable()) && (c.getBackground() instanceof UIResource) ) {
|
|
||||||
FlatUIUtils.paintParentBackground( g, c );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
super.paintBackground( g );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -351,7 +351,7 @@ public class FlatTitlePane
|
|||||||
|
|
||||||
// set icon
|
// set icon
|
||||||
if( !images.isEmpty() )
|
if( !images.isEmpty() )
|
||||||
iconLabel.setIcon( FlatTitlePaneIcon.create( images, iconSize ) );
|
iconLabel.setIcon( new FlatTitlePaneIcon( images, iconSize ) );
|
||||||
else {
|
else {
|
||||||
// no icon set on window --> use default icon
|
// no icon set on window --> use default icon
|
||||||
Icon defaultIcon = UIManager.getIcon( "TitlePane.icon" );
|
Icon defaultIcon = UIManager.getIcon( "TitlePane.icon" );
|
||||||
@@ -521,13 +521,13 @@ public class FlatTitlePane
|
|||||||
g.drawLine( 0, debugTitleBarHeight, getWidth(), debugTitleBarHeight );
|
g.drawLine( 0, debugTitleBarHeight, getWidth(), debugTitleBarHeight );
|
||||||
}
|
}
|
||||||
if( debugHitTestSpots != null ) {
|
if( debugHitTestSpots != null ) {
|
||||||
g.setColor( Color.blue );
|
g.setColor( Color.red );
|
||||||
Point offset = SwingUtilities.convertPoint( this, 0, 0, window );
|
Point offset = SwingUtilities.convertPoint( this, 0, 0, window );
|
||||||
for( Rectangle r : debugHitTestSpots )
|
for( Rectangle r : debugHitTestSpots )
|
||||||
g.drawRect( r.x - offset.x, r.y - offset.y, r.width - 1, r.height - 1 );
|
g.drawRect( r.x - offset.x, r.y - offset.y, r.width - 1, r.height - 1 );
|
||||||
}
|
}
|
||||||
if( debugAppIconBounds != null ) {
|
if( debugAppIconBounds != null ) {
|
||||||
g.setColor( Color.red );
|
g.setColor( Color.blue);
|
||||||
Point offset = SwingUtilities.convertPoint( this, 0, 0, window );
|
Point offset = SwingUtilities.convertPoint( this, 0, 0, window );
|
||||||
Rectangle r = debugAppIconBounds;
|
Rectangle r = debugAppIconBounds;
|
||||||
g.drawRect( r.x - offset.x, r.y - offset.y, r.width - 1, r.height - 1 );
|
g.drawRect( r.x - offset.x, r.y - offset.y, r.width - 1, r.height - 1 );
|
||||||
@@ -723,14 +723,29 @@ debug*/
|
|||||||
List<Rectangle> hitTestSpots = new ArrayList<>();
|
List<Rectangle> hitTestSpots = new ArrayList<>();
|
||||||
Rectangle appIconBounds = null;
|
Rectangle appIconBounds = null;
|
||||||
if( iconLabel.isVisible() ) {
|
if( iconLabel.isVisible() ) {
|
||||||
// compute real icon size (without insets)
|
// compute real icon size (without insets; 1px wider for easier hitting)
|
||||||
Point location = SwingUtilities.convertPoint( iconLabel, 0, 0, window );
|
Point location = SwingUtilities.convertPoint( iconLabel, 0, 0, window );
|
||||||
Insets iconInsets = iconLabel.getInsets();
|
Insets iconInsets = iconLabel.getInsets();
|
||||||
Rectangle iconBounds = new Rectangle(
|
Rectangle iconBounds = new Rectangle(
|
||||||
location.x + iconInsets.left,
|
location.x + iconInsets.left - 1,
|
||||||
location.y + iconInsets.top,
|
location.y + iconInsets.top - 1,
|
||||||
iconLabel.getWidth() - iconInsets.left - iconInsets.right,
|
iconLabel.getWidth() - iconInsets.left - iconInsets.right + 2,
|
||||||
iconLabel.getHeight() - iconInsets.top - iconInsets.bottom );
|
iconLabel.getHeight() - iconInsets.top - iconInsets.bottom + 2 );
|
||||||
|
|
||||||
|
// if frame is maximized, increase icon bounds to upper-left corner
|
||||||
|
// of window to allow closing window via double-click in upper-left corner
|
||||||
|
if( window instanceof Frame &&
|
||||||
|
(((Frame)window).getExtendedState() & Frame.MAXIMIZED_BOTH) != 0 )
|
||||||
|
{
|
||||||
|
iconBounds.height += iconBounds.y;
|
||||||
|
iconBounds.y = 0;
|
||||||
|
|
||||||
|
if( window.getComponentOrientation().isLeftToRight() ) {
|
||||||
|
iconBounds.width += iconBounds.x;
|
||||||
|
iconBounds.x = 0;
|
||||||
|
} else
|
||||||
|
iconBounds.width += iconInsets.right;
|
||||||
|
}
|
||||||
|
|
||||||
if( hasJBRCustomDecoration() )
|
if( hasJBRCustomDecoration() )
|
||||||
hitTestSpots.add( iconBounds );
|
hitTestSpots.add( iconBounds );
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ import java.awt.Dimension;
|
|||||||
import java.awt.Image;
|
import java.awt.Image;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.swing.Icon;
|
|
||||||
import javax.swing.ImageIcon;
|
|
||||||
import com.formdev.flatlaf.util.MultiResolutionImageSupport;
|
import com.formdev.flatlaf.util.MultiResolutionImageSupport;
|
||||||
import com.formdev.flatlaf.util.ScaledImageIcon;
|
import com.formdev.flatlaf.util.ScaledImageIcon;
|
||||||
|
|
||||||
@@ -31,40 +29,43 @@ import com.formdev.flatlaf.util.ScaledImageIcon;
|
|||||||
public class FlatTitlePaneIcon
|
public class FlatTitlePaneIcon
|
||||||
extends ScaledImageIcon
|
extends ScaledImageIcon
|
||||||
{
|
{
|
||||||
public static Icon create( List<Image> images, Dimension size ) {
|
private final List<Image> images;
|
||||||
// collect all images including multi-resolution variants
|
|
||||||
|
/**
|
||||||
|
* @since 1.2
|
||||||
|
*/
|
||||||
|
public FlatTitlePaneIcon( List<Image> images, Dimension size ) {
|
||||||
|
super( null, size.width, size.height );
|
||||||
|
this.images = images;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Image getResolutionVariant( int destImageWidth, int destImageHeight ) {
|
||||||
|
// collect all images including multi-resolution variants for requested size
|
||||||
List<Image> allImages = new ArrayList<>();
|
List<Image> allImages = new ArrayList<>();
|
||||||
for( Image image : images ) {
|
for( Image image : images ) {
|
||||||
if( MultiResolutionImageSupport.isMultiResolutionImage( image ) )
|
if( MultiResolutionImageSupport.isMultiResolutionImage( image ) )
|
||||||
allImages.addAll( MultiResolutionImageSupport.getResolutionVariants( image ) );
|
allImages.add( MultiResolutionImageSupport.getResolutionVariant( image, destImageWidth, destImageHeight ) );
|
||||||
else
|
else
|
||||||
allImages.add( image );
|
allImages.add( image );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( allImages.size() == 1 )
|
||||||
|
return allImages.get( 0 );
|
||||||
|
|
||||||
// sort images by size
|
// sort images by size
|
||||||
allImages.sort( (image1, image2) -> {
|
allImages.sort( (image1, image2) -> {
|
||||||
return image1.getWidth( null ) - image2.getWidth( null );
|
return image1.getWidth( null ) - image2.getWidth( null );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
// create icon
|
// search for optimal image size
|
||||||
return new FlatTitlePaneIcon( allImages, size );
|
for( Image image : allImages ) {
|
||||||
}
|
|
||||||
|
|
||||||
private final List<Image> images;
|
|
||||||
|
|
||||||
private FlatTitlePaneIcon( List<Image> images, Dimension size ) {
|
|
||||||
super( new ImageIcon( images.get( 0 ) ), size.width, size.height );
|
|
||||||
this.images = images;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Image getResolutionVariant( int destImageWidth, int destImageHeight ) {
|
|
||||||
for( Image image : images ) {
|
|
||||||
if( destImageWidth <= image.getWidth( null ) &&
|
if( destImageWidth <= image.getWidth( null ) &&
|
||||||
destImageHeight <= image.getHeight( null ) )
|
destImageHeight <= image.getHeight( null ) )
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
return images.get( images.size() - 1 );
|
// use largest image
|
||||||
|
return allImages.get( allImages.size() - 1 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import java.awt.event.ContainerEvent;
|
|||||||
import java.awt.event.ContainerListener;
|
import java.awt.event.ContainerListener;
|
||||||
import javax.swing.AbstractButton;
|
import javax.swing.AbstractButton;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
|
import javax.swing.UIManager;
|
||||||
import javax.swing.border.Border;
|
import javax.swing.border.Border;
|
||||||
import javax.swing.plaf.ComponentUI;
|
import javax.swing.plaf.ComponentUI;
|
||||||
import javax.swing.plaf.basic.BasicToolBarUI;
|
import javax.swing.plaf.basic.BasicToolBarUI;
|
||||||
@@ -41,15 +42,47 @@ import javax.swing.plaf.basic.BasicToolBarUI;
|
|||||||
* @uiDefault ToolBar.floatingForeground Color
|
* @uiDefault ToolBar.floatingForeground Color
|
||||||
* @uiDefault ToolBar.isRollover boolean
|
* @uiDefault ToolBar.isRollover boolean
|
||||||
*
|
*
|
||||||
|
* <!-- FlatToolBarUI -->
|
||||||
|
*
|
||||||
|
* @uiDefault ToolBar.focusableButtons boolean
|
||||||
|
*
|
||||||
* @author Karl Tauber
|
* @author Karl Tauber
|
||||||
*/
|
*/
|
||||||
public class FlatToolBarUI
|
public class FlatToolBarUI
|
||||||
extends BasicToolBarUI
|
extends BasicToolBarUI
|
||||||
{
|
{
|
||||||
|
/** @since 1.4 */
|
||||||
|
protected boolean focusableButtons;
|
||||||
|
|
||||||
public static ComponentUI createUI( JComponent c ) {
|
public static ComponentUI createUI( JComponent c ) {
|
||||||
return new FlatToolBarUI();
|
return new FlatToolBarUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void installUI( JComponent c ) {
|
||||||
|
super.installUI( c );
|
||||||
|
|
||||||
|
// disable focusable state of buttons (when switching from another Laf)
|
||||||
|
if( !focusableButtons )
|
||||||
|
setButtonsFocusable( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void uninstallUI( JComponent c ) {
|
||||||
|
super.uninstallUI( c );
|
||||||
|
|
||||||
|
// re-enable focusable state of buttons (when switching to another Laf)
|
||||||
|
if( !focusableButtons )
|
||||||
|
setButtonsFocusable( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void installDefaults() {
|
||||||
|
super.installDefaults();
|
||||||
|
|
||||||
|
focusableButtons = UIManager.getBoolean( "ToolBar.focusableButtons" );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ContainerListener createToolBarContListener() {
|
protected ContainerListener createToolBarContListener() {
|
||||||
return new ToolBarContListener() {
|
return new ToolBarContListener() {
|
||||||
@@ -57,22 +90,36 @@ public class FlatToolBarUI
|
|||||||
public void componentAdded( ContainerEvent e ) {
|
public void componentAdded( ContainerEvent e ) {
|
||||||
super.componentAdded( e );
|
super.componentAdded( e );
|
||||||
|
|
||||||
Component c = e.getChild();
|
if( !focusableButtons ) {
|
||||||
if( c instanceof AbstractButton )
|
Component c = e.getChild();
|
||||||
c.setFocusable( false );
|
if( c instanceof AbstractButton )
|
||||||
|
c.setFocusable( false );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void componentRemoved( ContainerEvent e ) {
|
public void componentRemoved( ContainerEvent e ) {
|
||||||
super.componentRemoved( e );
|
super.componentRemoved( e );
|
||||||
|
|
||||||
Component c = e.getChild();
|
if( !focusableButtons ) {
|
||||||
if( c instanceof AbstractButton )
|
Component c = e.getChild();
|
||||||
c.setFocusable( true );
|
if( c instanceof AbstractButton )
|
||||||
|
c.setFocusable( true );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 1.4
|
||||||
|
*/
|
||||||
|
protected void setButtonsFocusable( boolean focusable ) {
|
||||||
|
for( Component c : toolBar.getComponents() ) {
|
||||||
|
if( c instanceof AbstractButton )
|
||||||
|
c.setFocusable( focusable );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// disable rollover border
|
// disable rollover border
|
||||||
@Override protected void setBorderToRollover( Component c ) {}
|
@Override protected void setBorderToRollover( Component c ) {}
|
||||||
@Override protected void setBorderToNonRollover( Component c ) {}
|
@Override protected void setBorderToNonRollover( Component c ) {}
|
||||||
|
|||||||
@@ -107,6 +107,8 @@ public class FlatTreeUI
|
|||||||
protected boolean wideSelection;
|
protected boolean wideSelection;
|
||||||
protected boolean showCellFocusIndicator;
|
protected boolean showCellFocusIndicator;
|
||||||
|
|
||||||
|
private Color defaultCellNonSelectionBackground;
|
||||||
|
|
||||||
public static ComponentUI createUI( JComponent c ) {
|
public static ComponentUI createUI( JComponent c ) {
|
||||||
return new FlatTreeUI();
|
return new FlatTreeUI();
|
||||||
}
|
}
|
||||||
@@ -125,6 +127,8 @@ public class FlatTreeUI
|
|||||||
wideSelection = UIManager.getBoolean( "Tree.wideSelection" );
|
wideSelection = UIManager.getBoolean( "Tree.wideSelection" );
|
||||||
showCellFocusIndicator = UIManager.getBoolean( "Tree.showCellFocusIndicator" );
|
showCellFocusIndicator = UIManager.getBoolean( "Tree.showCellFocusIndicator" );
|
||||||
|
|
||||||
|
defaultCellNonSelectionBackground = UIManager.getColor( "Tree.textBackground" );
|
||||||
|
|
||||||
// scale
|
// scale
|
||||||
int rowHeight = FlatUIUtils.getUIInt( "Tree.rowHeight", 16 );
|
int rowHeight = FlatUIUtils.getUIInt( "Tree.rowHeight", 16 );
|
||||||
if( rowHeight > 0 )
|
if( rowHeight > 0 )
|
||||||
@@ -144,6 +148,8 @@ public class FlatTreeUI
|
|||||||
selectionInactiveBackground = null;
|
selectionInactiveBackground = null;
|
||||||
selectionInactiveForeground = null;
|
selectionInactiveForeground = null;
|
||||||
selectionBorderColor = null;
|
selectionBorderColor = null;
|
||||||
|
|
||||||
|
defaultCellNonSelectionBackground = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -306,24 +312,24 @@ public class FlatTreeUI
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// non-wide selection
|
// non-wide selection
|
||||||
int xOffset = 0;
|
paintCellBackground( g, rendererComponent, bounds );
|
||||||
int imageOffset = 0;
|
|
||||||
|
|
||||||
if( rendererComponent instanceof JLabel ) {
|
|
||||||
JLabel label = (JLabel) rendererComponent;
|
|
||||||
Icon icon = label.getIcon();
|
|
||||||
imageOffset = (icon != null && label.getText() != null)
|
|
||||||
? icon.getIconWidth() + Math.max( label.getIconTextGap() - 1, 0 )
|
|
||||||
: 0;
|
|
||||||
xOffset = label.getComponentOrientation().isLeftToRight() ? imageOffset : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
g.fillRect( bounds.x + xOffset, bounds.y, bounds.width - imageOffset, bounds.height );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is actually not necessary because renderer should always set color
|
// this is actually not necessary because renderer should always set color
|
||||||
// before painting, but doing anyway to avoid any side effect (in bad renderers)
|
// before painting, but doing anyway to avoid any side effect (in bad renderers)
|
||||||
g.setColor( oldColor );
|
g.setColor( oldColor );
|
||||||
|
} else {
|
||||||
|
// paint cell background if DefaultTreeCellRenderer.getBackgroundNonSelectionColor() is set
|
||||||
|
if( rendererComponent instanceof DefaultTreeCellRenderer ) {
|
||||||
|
DefaultTreeCellRenderer renderer = (DefaultTreeCellRenderer) rendererComponent;
|
||||||
|
Color bg = renderer.getBackgroundNonSelectionColor();
|
||||||
|
if( bg != null && !bg.equals( defaultCellNonSelectionBackground ) ) {
|
||||||
|
Color oldColor = g.getColor();
|
||||||
|
g.setColor( bg );
|
||||||
|
paintCellBackground( g, rendererComponent, bounds );
|
||||||
|
g.setColor( oldColor );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// paint renderer
|
// paint renderer
|
||||||
@@ -337,6 +343,22 @@ public class FlatTreeUI
|
|||||||
((DefaultTreeCellRenderer)rendererComponent).setBorderSelectionColor( oldBorderSelectionColor );
|
((DefaultTreeCellRenderer)rendererComponent).setBorderSelectionColor( oldBorderSelectionColor );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void paintCellBackground( Graphics g, Component rendererComponent, Rectangle bounds ) {
|
||||||
|
int xOffset = 0;
|
||||||
|
int imageOffset = 0;
|
||||||
|
|
||||||
|
if( rendererComponent instanceof JLabel ) {
|
||||||
|
JLabel label = (JLabel) rendererComponent;
|
||||||
|
Icon icon = label.getIcon();
|
||||||
|
imageOffset = (icon != null && label.getText() != null)
|
||||||
|
? icon.getIconWidth() + Math.max( label.getIconTextGap() - 1, 0 )
|
||||||
|
: 0;
|
||||||
|
xOffset = label.getComponentOrientation().isLeftToRight() ? imageOffset : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
g.fillRect( bounds.x + xOffset, bounds.y, bounds.width - imageOffset, bounds.height );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether dropping on a row.
|
* Checks whether dropping on a row.
|
||||||
* See DefaultTreeCellRenderer.getTreeCellRendererComponent().
|
* See DefaultTreeCellRenderer.getTreeCellRendererComponent().
|
||||||
|
|||||||
@@ -94,6 +94,11 @@ public class FlatUIUtils
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Insets addInsets( Insets insets1, Insets insets2 ) {
|
public static Insets addInsets( Insets insets1, Insets insets2 ) {
|
||||||
|
if( insets1 == null )
|
||||||
|
return insets2;
|
||||||
|
if( insets2 == null )
|
||||||
|
return insets1;
|
||||||
|
|
||||||
return new Insets(
|
return new Insets(
|
||||||
insets1.top + insets2.top,
|
insets1.top + insets2.top,
|
||||||
insets1.left + insets2.left,
|
insets1.left + insets2.left,
|
||||||
@@ -660,7 +665,7 @@ public class FlatUIUtils
|
|||||||
* @since 1.1
|
* @since 1.1
|
||||||
*/
|
*/
|
||||||
public static void paintArrow( Graphics2D g, int x, int y, int width, int height,
|
public static void paintArrow( Graphics2D g, int x, int y, int width, int height,
|
||||||
int direction, boolean chevron, int arrowSize, int xOffset, int yOffset )
|
int direction, boolean chevron, int arrowSize, float xOffset, float yOffset )
|
||||||
{
|
{
|
||||||
// compute arrow width/height
|
// compute arrow width/height
|
||||||
int aw = UIScale.scale( arrowSize + (chevron ? 0 : 1) );
|
int aw = UIScale.scale( arrowSize + (chevron ? 0 : 1) );
|
||||||
@@ -679,8 +684,10 @@ public class FlatUIUtils
|
|||||||
int extra = chevron ? 1 : 0;
|
int extra = chevron ? 1 : 0;
|
||||||
|
|
||||||
// compute arrow location
|
// compute arrow location
|
||||||
int ax = x + Math.round( ((width - (aw + extra)) / 2f) + UIScale.scale( (float) xOffset ) );
|
float ox = ((width - (aw + extra)) / 2f) + UIScale.scale( xOffset );
|
||||||
int ay = y + Math.round( ((height - (ah + extra)) / 2f) + UIScale.scale( (float) yOffset ) );
|
float oy = ((height - (ah + extra)) / 2f) + UIScale.scale( yOffset );
|
||||||
|
int ax = x + ((direction == SwingConstants.WEST) ? -Math.round( -ox ) : Math.round( ox ));
|
||||||
|
int ay = y + ((direction == SwingConstants.NORTH) ? -Math.round( -oy ) : Math.round( oy ));
|
||||||
|
|
||||||
// paint arrow
|
// paint arrow
|
||||||
g.translate( ax, ay );
|
g.translate( ax, ay );
|
||||||
@@ -837,19 +844,23 @@ debug*/
|
|||||||
implements FocusListener
|
implements FocusListener
|
||||||
{
|
{
|
||||||
private final Component repaintComponent;
|
private final Component repaintComponent;
|
||||||
|
private final Predicate<Component> repaintCondition;
|
||||||
|
|
||||||
public RepaintFocusListener( Component repaintComponent ) {
|
public RepaintFocusListener( Component repaintComponent, Predicate<Component> repaintCondition ) {
|
||||||
this.repaintComponent = repaintComponent;
|
this.repaintComponent = repaintComponent;
|
||||||
|
this.repaintCondition = repaintCondition;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void focusGained( FocusEvent e ) {
|
public void focusGained( FocusEvent e ) {
|
||||||
repaintComponent.repaint();
|
if( repaintCondition == null || repaintCondition.test( repaintComponent ) )
|
||||||
|
repaintComponent.repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void focusLost( FocusEvent e ) {
|
public void focusLost( FocusEvent e ) {
|
||||||
repaintComponent.repaint();
|
if( repaintCondition == null || repaintCondition.test( repaintComponent ) )
|
||||||
|
repaintComponent.repaint();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -308,18 +308,11 @@ class FlatWindowsNativeWindowBorder
|
|||||||
this.window = window;
|
this.window = window;
|
||||||
|
|
||||||
hwnd = installImpl( window );
|
hwnd = installImpl( window );
|
||||||
|
if( hwnd == 0 )
|
||||||
|
return;
|
||||||
|
|
||||||
// remove the OS window title bar
|
// remove the OS window title bar
|
||||||
if( window instanceof JFrame && ((JFrame)window).getExtendedState() != 0 ) {
|
updateFrame( hwnd, (window instanceof JFrame) ? ((JFrame)window).getExtendedState() : 0 );
|
||||||
// In case that the frame should be maximized or minimized immediately
|
|
||||||
// when showing, then it is necessary to defer ::SetWindowPos() invocation.
|
|
||||||
// Otherwise the frame will not be maximized or minimized.
|
|
||||||
// This occurs only if frame.pack() was no invoked.
|
|
||||||
EventQueue.invokeLater( () -> {
|
|
||||||
updateFrame( hwnd );
|
|
||||||
});
|
|
||||||
} else
|
|
||||||
updateFrame( hwnd );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void uninstall() {
|
void uninstall() {
|
||||||
@@ -331,7 +324,7 @@ class FlatWindowsNativeWindowBorder
|
|||||||
|
|
||||||
private native long installImpl( Window window );
|
private native long installImpl( Window window );
|
||||||
private native void uninstallImpl( long hwnd );
|
private native void uninstallImpl( long hwnd );
|
||||||
private native void updateFrame( long hwnd );
|
private native void updateFrame( long hwnd, int state );
|
||||||
private native void showWindow( long hwnd, int cmd );
|
private native void showWindow( long hwnd, int cmd );
|
||||||
|
|
||||||
// invoked from native code
|
// invoked from native code
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* 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.util.function.BiPredicate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Karl Tauber
|
||||||
|
*/
|
||||||
|
class StackUtils
|
||||||
|
{
|
||||||
|
private static final StackUtils INSTANCE = new StackUtilsImpl();
|
||||||
|
|
||||||
|
// hide from javadoc
|
||||||
|
StackUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether current method was invoked from the given class and method.
|
||||||
|
*/
|
||||||
|
public static boolean wasInvokedFrom( String className, String methodName, int limit ) {
|
||||||
|
return wasInvokedFrom( (c,m) -> c.equals( className ) && m.equals( methodName ), limit );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether current method was invoked from a class and method using the given predicate,
|
||||||
|
* which gets the class name of the stack frame as first parameter and the method name as second parameter.
|
||||||
|
*/
|
||||||
|
public static boolean wasInvokedFrom( BiPredicate<String, String> predicate, int limit ) {
|
||||||
|
return INSTANCE.wasInvokedFromImpl( predicate, limit );
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean wasInvokedFromImpl( BiPredicate<String, String> predicate, int limit ) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* 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.util.function.BiPredicate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Karl Tauber
|
||||||
|
*/
|
||||||
|
class StackUtilsImpl
|
||||||
|
extends StackUtils
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
boolean wasInvokedFromImpl( BiPredicate<String, String> predicate, int limit ) {
|
||||||
|
int count = -2;
|
||||||
|
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
|
||||||
|
for( StackTraceElement stackTraceElement : stackTrace ) {
|
||||||
|
if( predicate.test( stackTraceElement.getClassName(), stackTraceElement.getMethodName() ) )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
count++;
|
||||||
|
if( limit > 0 && count > limit )
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -256,11 +256,6 @@ public class Graphics2DProxy
|
|||||||
delegate.dispose();
|
delegate.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void finalize() {
|
|
||||||
delegate.finalize();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return delegate.toString();
|
return delegate.toString();
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.nio.file.FileAlreadyExistsException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
@@ -144,26 +145,46 @@ public class NativeLibrary
|
|||||||
String suffix = (dot >= 0) ? name.substring( dot ) : "";
|
String suffix = (dot >= 0) ? name.substring( dot ) : "";
|
||||||
|
|
||||||
Path tempDir = getTempDir();
|
Path tempDir = getTempDir();
|
||||||
if( tempDir != null ) {
|
|
||||||
deleteTemporaryFiles( tempDir );
|
|
||||||
|
|
||||||
return Files.createTempFile( tempDir, prefix, suffix );
|
// Note:
|
||||||
} else
|
// Not using Files.createTempFile() here because it uses random number generator SecureRandom,
|
||||||
return Files.createTempFile( prefix, suffix );
|
// which may take 5-10 seconds to initialize under particular conditions.
|
||||||
|
|
||||||
|
// Use current time in nanoseconds instead of a random number.
|
||||||
|
// To avoid (theoretical) collisions, append a counter.
|
||||||
|
long nanoTime = System.nanoTime();
|
||||||
|
for( int i = 0;; i++ ) {
|
||||||
|
String s = prefix + Long.toUnsignedString( nanoTime ) + i + suffix;
|
||||||
|
try {
|
||||||
|
return Files.createFile( tempDir.resolve( s ) );
|
||||||
|
} catch( FileAlreadyExistsException ex ) {
|
||||||
|
// ignore --> increment counter and try again
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Path getTempDir() throws IOException {
|
private static Path getTempDir() throws IOException {
|
||||||
|
// get standard temporary directory
|
||||||
|
String tmpdir = System.getProperty( "java.io.tmpdir" );
|
||||||
|
|
||||||
if( SystemInfo.isWindows ) {
|
if( SystemInfo.isWindows ) {
|
||||||
// On Windows, where File.delete() and File.deleteOnExit() does not work
|
// On Windows, where File.delete() and File.deleteOnExit() does not work
|
||||||
// for loaded native libraries, they will be deleted on next application startup.
|
// for loaded native libraries, they will be deleted on next application startup.
|
||||||
// The default temporary directory may contain hundreds or thousands of files.
|
// The default temporary directory may contain hundreds or thousands of files.
|
||||||
// To make searching for "marked for deletion" files as fast as possible,
|
// To make searching for "marked for deletion" files as fast as possible,
|
||||||
// use a sub directory that contains only our temporary native libraries.
|
// use a sub directory that contains only our temporary native libraries.
|
||||||
Path tempDir = Paths.get( System.getProperty( "java.io.tmpdir" ) + "/flatlaf.temp" );
|
tmpdir += "\\flatlaf.temp";
|
||||||
Files.createDirectories( tempDir );
|
}
|
||||||
return tempDir;
|
|
||||||
} else
|
// create temporary directory
|
||||||
return null; // use standard temporary directory
|
Path tempDir = Paths.get( tmpdir );
|
||||||
|
Files.createDirectories( tempDir );
|
||||||
|
|
||||||
|
// delete no longer needed temporary files (from already exited applications)
|
||||||
|
if( SystemInfo.isWindows )
|
||||||
|
deleteTemporaryFiles( tempDir );
|
||||||
|
|
||||||
|
return tempDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void deleteTemporaryFiles( Path tempDir ) {
|
private static void deleteTemporaryFiles( Path tempDir ) {
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ debug*/
|
|||||||
double scaleFactor = systemScaleFactor * userScaleFactor;
|
double scaleFactor = systemScaleFactor * userScaleFactor;
|
||||||
|
|
||||||
// paint input image icon if not necessary to scale
|
// paint input image icon if not necessary to scale
|
||||||
if( scaleFactor == 1 && iconWidth == imageIcon.getIconWidth() && iconHeight == imageIcon.getIconHeight() ) {
|
if( scaleFactor == 1 && imageIcon != null && iconWidth == imageIcon.getIconWidth() && iconHeight == imageIcon.getIconHeight() ) {
|
||||||
imageIcon.paintIcon( c, g, x, y );
|
imageIcon.paintIcon( c, g, x, y );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ import com.formdev.flatlaf.FlatSystemProperties;
|
|||||||
* <p>
|
* <p>
|
||||||
* Two scaling modes are supported by FlatLaf for HiDPI displays:
|
* Two scaling modes are supported by FlatLaf for HiDPI displays:
|
||||||
*
|
*
|
||||||
* <h3>1) system scaling mode</h3>
|
* <h2>1) system scaling mode</h2>
|
||||||
*
|
*
|
||||||
* This mode is supported since Java 9 on all platforms and in some Java 8 VMs
|
* This mode is supported since Java 9 on all platforms and in some Java 8 VMs
|
||||||
* (e.g. Apple and JetBrains). The JRE determines the scale factor per-display and
|
* (e.g. Apple and JetBrains). The JRE determines the scale factor per-display and
|
||||||
@@ -54,7 +54,7 @@ import com.formdev.flatlaf.FlatSystemProperties;
|
|||||||
* The scale factor may be different for each connected display.
|
* The scale factor may be different for each connected display.
|
||||||
* The scale factor may change for a window when moving the window from one display to another one.
|
* The scale factor may change for a window when moving the window from one display to another one.
|
||||||
*
|
*
|
||||||
* <h3>2) user scaling mode</h3>
|
* <h2>2) user scaling mode</h2>
|
||||||
*
|
*
|
||||||
* This mode is mainly for Java 8 compatibility, but is also used on Linux
|
* This mode is mainly for Java 8 compatibility, but is also used on Linux
|
||||||
* or if the default font is changed.
|
* or if the default font is changed.
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* 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.util.function.BiPredicate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Karl Tauber
|
||||||
|
*/
|
||||||
|
class StackUtilsImpl
|
||||||
|
extends StackUtils
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
boolean wasInvokedFromImpl( BiPredicate<String, String> predicate, int limit ) {
|
||||||
|
return StackWalker.getInstance().walk( stream -> {
|
||||||
|
if( limit > 0 )
|
||||||
|
stream = stream.limit( limit + 2 );
|
||||||
|
return stream.anyMatch( f -> {
|
||||||
|
return predicate.test( f.getClassName(), f.getMethodName() );
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -166,7 +166,7 @@ Desktop.background = #3E434C
|
|||||||
|
|
||||||
#---- DesktopIcon ----
|
#---- DesktopIcon ----
|
||||||
|
|
||||||
DesktopIcon.background = lighten($Desktop.background,10%)
|
DesktopIcon.background = lighten($Desktop.background,10%,derived)
|
||||||
|
|
||||||
|
|
||||||
#---- InternalFrame ----
|
#---- InternalFrame ----
|
||||||
|
|||||||
@@ -642,7 +642,8 @@ Table.dropLineShortColor = @dropLineShortColor
|
|||||||
#---- TableHeader ----
|
#---- TableHeader ----
|
||||||
|
|
||||||
TableHeader.height = 25
|
TableHeader.height = 25
|
||||||
TableHeader.cellBorder = 2,3,2,3
|
TableHeader.cellBorder = com.formdev.flatlaf.ui.FlatTableHeaderBorder
|
||||||
|
TableHeader.cellMargins = 2,3,2,3
|
||||||
TableHeader.focusCellBackground = $TableHeader.background
|
TableHeader.focusCellBackground = $TableHeader.background
|
||||||
TableHeader.background = @textComponentBackground
|
TableHeader.background = @textComponentBackground
|
||||||
|
|
||||||
@@ -751,6 +752,7 @@ ToolBar.separatorWidth = 7
|
|||||||
ToolBar.separatorColor = $Separator.foreground
|
ToolBar.separatorColor = $Separator.foreground
|
||||||
|
|
||||||
ToolBar.spacingBorder = $Button.toolbar.spacingInsets
|
ToolBar.spacingBorder = $Button.toolbar.spacingInsets
|
||||||
|
ToolBar.focusableButtons = false
|
||||||
|
|
||||||
|
|
||||||
#---- ToolTipManager ----
|
#---- ToolTipManager ----
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ Desktop.background = #E6EBF0
|
|||||||
|
|
||||||
#---- DesktopIcon ----
|
#---- DesktopIcon ----
|
||||||
|
|
||||||
DesktopIcon.background = darken($Desktop.background,10%)
|
DesktopIcon.background = darken($Desktop.background,10%,derived)
|
||||||
|
|
||||||
|
|
||||||
#---- HelpButton ----
|
#---- HelpButton ----
|
||||||
|
|||||||
@@ -133,8 +133,8 @@ ToggleButton.endBackground = $ToggleButton.background
|
|||||||
|
|
||||||
[Dark_purple]Slider.focusedColor = fade($Component.focusColor,70%,derived)
|
[Dark_purple]Slider.focusedColor = fade($Component.focusColor,70%,derived)
|
||||||
|
|
||||||
[Dracula]ProgressBar.selectionBackground = #fff
|
[Dracula---Zihan_Ma]ProgressBar.selectionBackground = #fff
|
||||||
[Dracula]ProgressBar.selectionForeground = #fff
|
[Dracula---Zihan_Ma]ProgressBar.selectionForeground = #fff
|
||||||
|
|
||||||
[Gradianto_Dark_Fuchsia]MenuItem.checkBackground = @ijMenuCheckBackgroundL10
|
[Gradianto_Dark_Fuchsia]MenuItem.checkBackground = @ijMenuCheckBackgroundL10
|
||||||
[Gradianto_Dark_Fuchsia]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
|
[Gradianto_Dark_Fuchsia]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
|
||||||
@@ -181,7 +181,7 @@ ToggleButton.endBackground = $ToggleButton.background
|
|||||||
[One_Dark]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
|
[One_Dark]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
|
||||||
[One_Dark]Slider.focusedColor = fade(#568af2,40%)
|
[One_Dark]Slider.focusedColor = fade(#568af2,40%)
|
||||||
|
|
||||||
[Solarized_Dark]Slider.focusedColor = fade($Component.focusColor,80%,derived)
|
[Solarized_Dark---4lex4]Slider.focusedColor = fade($Component.focusColor,80%,derived)
|
||||||
|
|
||||||
[vuesion-theme]MenuItem.checkBackground = @ijMenuCheckBackgroundL10
|
[vuesion-theme]MenuItem.checkBackground = @ijMenuCheckBackgroundL10
|
||||||
[vuesion-theme]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
|
[vuesion-theme]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
|
||||||
@@ -198,6 +198,9 @@ ToggleButton.endBackground = $ToggleButton.background
|
|||||||
[dark][author-Mallowigi]MenuItem.checkBackground = @ijMenuCheckBackgroundL20
|
[dark][author-Mallowigi]MenuItem.checkBackground = @ijMenuCheckBackgroundL20
|
||||||
[dark][author-Mallowigi]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL20
|
[dark][author-Mallowigi]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL20
|
||||||
|
|
||||||
|
[Dracula---Mallowigi]ProgressBar.selectionBackground = #fff
|
||||||
|
[Dracula---Mallowigi]ProgressBar.selectionForeground = #fff
|
||||||
|
|
||||||
[Dracula_Contrast]ProgressBar.selectionBackground = #fff
|
[Dracula_Contrast]ProgressBar.selectionBackground = #fff
|
||||||
[Dracula_Contrast]ProgressBar.selectionForeground = #fff
|
[Dracula_Contrast]ProgressBar.selectionForeground = #fff
|
||||||
|
|
||||||
@@ -237,14 +240,14 @@ ToggleButton.endBackground = $ToggleButton.background
|
|||||||
[Night_Owl_Contrast]ProgressBar.selectionBackground = #ddd
|
[Night_Owl_Contrast]ProgressBar.selectionBackground = #ddd
|
||||||
[Night_Owl_Contrast]ProgressBar.selectionForeground = #ddd
|
[Night_Owl_Contrast]ProgressBar.selectionForeground = #ddd
|
||||||
|
|
||||||
[Solarized_Dark]ProgressBar.selectionBackground = #ccc
|
[Solarized_Dark---Mallowigi]ProgressBar.selectionBackground = #ccc
|
||||||
[Solarized_Dark]ProgressBar.selectionForeground = #ccc
|
[Solarized_Dark---Mallowigi]ProgressBar.selectionForeground = #ccc
|
||||||
|
|
||||||
[Material_Solarized_Dark_Contrast]ProgressBar.selectionBackground = #ccc
|
[Solarized_Dark_Contrast]ProgressBar.selectionBackground = #ccc
|
||||||
[Material_Solarized_Dark_Contrast]ProgressBar.selectionForeground = #ccc
|
[Solarized_Dark_Contrast]ProgressBar.selectionForeground = #ccc
|
||||||
|
|
||||||
[Solarized_Light]ProgressBar.selectionBackground = #222
|
[Solarized_Light---Mallowigi]ProgressBar.selectionBackground = #222
|
||||||
[Solarized_Light]ProgressBar.selectionForeground = #fff
|
[Solarized_Light---Mallowigi]ProgressBar.selectionForeground = #fff
|
||||||
|
|
||||||
[Material_Solarized_Light_Contrast]ProgressBar.selectionBackground = #222
|
[Solarized_Light_Contrast]ProgressBar.selectionBackground = #222
|
||||||
[Material_Solarized_Light_Contrast]ProgressBar.selectionForeground = #fff
|
[Solarized_Light_Contrast]ProgressBar.selectionForeground = #fff
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,203 @@
|
|||||||
|
/*
|
||||||
|
* 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.Component;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.Graphics;
|
||||||
|
import java.awt.Insets;
|
||||||
|
import javax.swing.*;
|
||||||
|
import javax.swing.border.Border;
|
||||||
|
import javax.swing.border.LineBorder;
|
||||||
|
import javax.swing.plaf.basic.BasicComboBoxEditor;
|
||||||
|
import javax.swing.plaf.basic.BasicComboBoxRenderer;
|
||||||
|
import org.junit.jupiter.api.AfterAll;
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Karl Tauber
|
||||||
|
*/
|
||||||
|
public class TestFlatComponentSizes
|
||||||
|
{
|
||||||
|
@BeforeAll
|
||||||
|
static void setup() {
|
||||||
|
TestUtils.setup( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterAll
|
||||||
|
static void cleanup() {
|
||||||
|
TestUtils.cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
static float[] factors() {
|
||||||
|
return TestUtils.FACTORS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource( "factors" )
|
||||||
|
void sizes( float factor ) {
|
||||||
|
TestUtils.scaleFont( factor );
|
||||||
|
|
||||||
|
|
||||||
|
// should have same default size (minimumWidth is 64)
|
||||||
|
JTextField textField = new JTextField();
|
||||||
|
JFormattedTextField formattedTextField = new JFormattedTextField();
|
||||||
|
JPasswordField passwordField = new JPasswordField();
|
||||||
|
JSpinner spinner = new JSpinner();
|
||||||
|
|
||||||
|
Dimension textFieldSize = textField.getPreferredSize();
|
||||||
|
assertEquals( textFieldSize, formattedTextField.getPreferredSize() );
|
||||||
|
assertEquals( textFieldSize, passwordField.getPreferredSize() );
|
||||||
|
assertEquals( textFieldSize, spinner.getPreferredSize() );
|
||||||
|
|
||||||
|
|
||||||
|
// should have same default size (minimumWidth is 72)
|
||||||
|
JButton button = new JButton( "text" );
|
||||||
|
JComboBox<String> comboBox = new JComboBox<>();
|
||||||
|
JComboBox<String> comboBoxEditable = new JComboBox<>();
|
||||||
|
comboBoxEditable.setEditable( true );
|
||||||
|
|
||||||
|
Dimension buttonSize = button.getPreferredSize();
|
||||||
|
assertEquals( buttonSize, comboBox.getPreferredSize() );
|
||||||
|
assertEquals( buttonSize, comboBoxEditable.getPreferredSize() );
|
||||||
|
|
||||||
|
|
||||||
|
// should have same height
|
||||||
|
JToggleButton toggleButton = new JToggleButton( "text" );
|
||||||
|
|
||||||
|
assertEquals( textFieldSize.height, button.getPreferredSize().height );
|
||||||
|
assertEquals( textFieldSize.height, toggleButton.getPreferredSize().height );
|
||||||
|
|
||||||
|
|
||||||
|
// should have same size
|
||||||
|
JCheckBox checkBox = new JCheckBox( "text" );
|
||||||
|
JRadioButton radioButton = new JRadioButton( "text" );
|
||||||
|
assertEquals( checkBox.getPreferredSize(), radioButton.getPreferredSize() );
|
||||||
|
|
||||||
|
|
||||||
|
// should have same size
|
||||||
|
JMenu menu = new JMenu( "text" );
|
||||||
|
JMenuItem menuItem = new JMenuItem( "text" );
|
||||||
|
JCheckBoxMenuItem checkBoxMenuItem = new JCheckBoxMenuItem( "text" );
|
||||||
|
JRadioButtonMenuItem radioButtonMenuItem = new JRadioButtonMenuItem( "text" );
|
||||||
|
|
||||||
|
Dimension menuSize = menu.getPreferredSize();
|
||||||
|
assertEquals( menuSize, menuItem.getPreferredSize() );
|
||||||
|
assertEquals( menuSize, checkBoxMenuItem.getPreferredSize() );
|
||||||
|
assertEquals( menuSize, radioButtonMenuItem.getPreferredSize() );
|
||||||
|
|
||||||
|
|
||||||
|
TestUtils.resetFont();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource( "factors" )
|
||||||
|
void comboBox( float factor ) {
|
||||||
|
TestUtils.scaleFont( factor );
|
||||||
|
|
||||||
|
String[] items = { "t" };
|
||||||
|
JComboBox<String> comboBox = new JComboBox<>( items );
|
||||||
|
JComboBox<String> comboBox2 = new JComboBox<>( items );
|
||||||
|
JComboBox<String> comboBox3 = new JComboBox<>( items );
|
||||||
|
JComboBox<String> comboBox4 = new JComboBox<>( items );
|
||||||
|
|
||||||
|
applyCustomComboBoxRendererBorder( comboBox2, new LineBorder( Color.orange, UIScale.scale( 6 ) ) );
|
||||||
|
applyCustomComboBoxRendererBorder( comboBox3, new BorderWithIcon() );
|
||||||
|
applyCustomComboBoxRendererBorder( comboBox4, null );
|
||||||
|
|
||||||
|
Dimension size = comboBox.getPreferredSize();
|
||||||
|
assertEquals( size.width, comboBox2.getPreferredSize().width );
|
||||||
|
assertEquals( size.height - (2 * UIScale.scale( 2 )) + (2 * UIScale.scale( 6 )), comboBox2.getPreferredSize().height );
|
||||||
|
assertEquals( size, comboBox3.getPreferredSize() );
|
||||||
|
assertEquals( size, comboBox4.getPreferredSize() );
|
||||||
|
|
||||||
|
TestUtils.resetFont();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings( "unchecked" )
|
||||||
|
private void applyCustomComboBoxRendererBorder( JComboBox<String> comboBox, Border border ) {
|
||||||
|
BasicComboBoxRenderer customRenderer = new BasicComboBoxRenderer();
|
||||||
|
customRenderer.setBorder( border );
|
||||||
|
comboBox.setRenderer( customRenderer );
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource( "factors" )
|
||||||
|
void comboBoxEditable( float factor ) {
|
||||||
|
TestUtils.scaleFont( factor );
|
||||||
|
|
||||||
|
String[] items = { "t" };
|
||||||
|
JComboBox<String> comboBox = new JComboBox<>( items );
|
||||||
|
JComboBox<String> comboBox2 = new JComboBox<>( items );
|
||||||
|
JComboBox<String> comboBox3 = new JComboBox<>( items );
|
||||||
|
JComboBox<String> comboBox4 = new JComboBox<>( items );
|
||||||
|
|
||||||
|
comboBox.setEditable( true );
|
||||||
|
comboBox2.setEditable( true );
|
||||||
|
comboBox3.setEditable( true );
|
||||||
|
comboBox4.setEditable( true );
|
||||||
|
|
||||||
|
applyCustomComboBoxEditorBorder( comboBox2, new LineBorder( Color.orange, UIScale.scale( 6 ) ) );
|
||||||
|
applyCustomComboBoxEditorBorder( comboBox3, new BorderWithIcon() );
|
||||||
|
applyCustomComboBoxEditorBorder( comboBox4, null );
|
||||||
|
|
||||||
|
Dimension size = comboBox.getPreferredSize();
|
||||||
|
assertEquals( size.width, comboBox2.getPreferredSize().width );
|
||||||
|
assertEquals( size.height - (2 * UIScale.scale( 2 )) + (2 * UIScale.scale( 6 )), comboBox2.getPreferredSize().height );
|
||||||
|
assertEquals( size, comboBox3.getPreferredSize() );
|
||||||
|
assertEquals( size, comboBox4.getPreferredSize() );
|
||||||
|
|
||||||
|
TestUtils.resetFont();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyCustomComboBoxEditorBorder( JComboBox<String> comboBox, Border border ) {
|
||||||
|
JTextField customTextField = new JTextField();
|
||||||
|
if( border != null )
|
||||||
|
customTextField.setBorder( border );
|
||||||
|
comboBox.setEditor( new BasicComboBoxEditor() {
|
||||||
|
@Override
|
||||||
|
protected JTextField createEditorComponent() {
|
||||||
|
return customTextField;
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
//---- class BorderWithIcon -----------------------------------------------
|
||||||
|
|
||||||
|
private static class BorderWithIcon
|
||||||
|
implements Border
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBorderOpaque() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Insets getBorderInsets( Component c ) {
|
||||||
|
return new Insets( 0, 0, 0, UIScale.scale( 16 ) + 4 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* 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 org.junit.jupiter.api.BeforeAll;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Karl Tauber
|
||||||
|
*/
|
||||||
|
public class TestFlatComponentSizesWithFocus
|
||||||
|
extends TestFlatComponentSizes
|
||||||
|
{
|
||||||
|
@BeforeAll
|
||||||
|
static void setup() {
|
||||||
|
TestUtils.setup( true );
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* 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.awt.Font;
|
||||||
|
import javax.swing.UIManager;
|
||||||
|
import com.formdev.flatlaf.FlatIntelliJLaf;
|
||||||
|
import com.formdev.flatlaf.FlatLightLaf;
|
||||||
|
import com.formdev.flatlaf.FlatSystemProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Karl Tauber
|
||||||
|
*/
|
||||||
|
public class TestUtils
|
||||||
|
{
|
||||||
|
public static final float[] FACTORS = new float[] { 1f, 1.25f, 1.5f, 1.75f, 2f, 2.25f, 2.5f, 2.75f, 3f, 3.25f, 3.5f, 3.75f, 4f, 5f, 6f };
|
||||||
|
|
||||||
|
public static void setup( boolean withFocus ) {
|
||||||
|
System.setProperty( FlatSystemProperties.UI_SCALE, "1x" );
|
||||||
|
if( withFocus )
|
||||||
|
FlatIntelliJLaf.setup();
|
||||||
|
else
|
||||||
|
FlatLightLaf.setup();
|
||||||
|
System.clearProperty( FlatSystemProperties.UI_SCALE );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void cleanup() {
|
||||||
|
UIManager.put( "defaultFont", null );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void scaleFont( float factor ) {
|
||||||
|
Font defaultFont = UIManager.getLookAndFeelDefaults().getFont( "defaultFont" );
|
||||||
|
UIManager.put( "defaultFont", defaultFont.deriveFont( (float) Math.round( defaultFont.getSize() * factor ) ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void resetFont() {
|
||||||
|
UIManager.put( "defaultFont", null );
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,18 +18,11 @@ plugins {
|
|||||||
`java-library`
|
`java-library`
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
|
||||||
maven {
|
|
||||||
// for using MigLayout snapshot
|
|
||||||
url = uri( "https://oss.sonatype.org/content/repositories/snapshots/" )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation( project( ":flatlaf-core" ) )
|
implementation( project( ":flatlaf-core" ) )
|
||||||
implementation( project( ":flatlaf-extras" ) )
|
implementation( project( ":flatlaf-extras" ) )
|
||||||
implementation( project( ":flatlaf-intellij-themes" ) )
|
implementation( project( ":flatlaf-intellij-themes" ) )
|
||||||
implementation( "com.miglayout:miglayout-swing:5.3-SNAPSHOT" )
|
implementation( "com.miglayout:miglayout-swing:5.3" )
|
||||||
implementation( "com.jgoodies:jgoodies-forms:1.9.0" )
|
implementation( "com.jgoodies:jgoodies-forms:1.9.0" )
|
||||||
// implementation( project( ":flatlaf-natives-jna" ) )
|
// implementation( project( ":flatlaf-natives-jna" ) )
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import javax.swing.plaf.metal.MetalLookAndFeel;
|
|||||||
import javax.swing.plaf.nimbus.NimbusLookAndFeel;
|
import javax.swing.plaf.nimbus.NimbusLookAndFeel;
|
||||||
import com.formdev.flatlaf.*;
|
import com.formdev.flatlaf.*;
|
||||||
import com.formdev.flatlaf.extras.FlatAnimatedLafChange;
|
import com.formdev.flatlaf.extras.FlatAnimatedLafChange;
|
||||||
|
import com.formdev.flatlaf.util.LoggingFacade;
|
||||||
import com.formdev.flatlaf.util.SystemInfo;
|
import com.formdev.flatlaf.util.SystemInfo;
|
||||||
import com.formdev.flatlaf.util.UIScale;
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
import net.miginfocom.layout.ConstraintParser;
|
import net.miginfocom.layout.ConstraintParser;
|
||||||
@@ -240,7 +241,7 @@ class ControlBar
|
|||||||
frame.setSize( Math.max( prefSize.width, width ), Math.max( prefSize.height, height ) );
|
frame.setSize( Math.max( prefSize.width, width ), Math.max( prefSize.height, height ) );
|
||||||
|
|
||||||
} catch( Exception ex ) {
|
} catch( Exception ex ) {
|
||||||
ex.printStackTrace();
|
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import com.formdev.flatlaf.FlatLightLaf;
|
|||||||
import com.formdev.flatlaf.FlatPropertiesLaf;
|
import com.formdev.flatlaf.FlatPropertiesLaf;
|
||||||
import com.formdev.flatlaf.IntelliJTheme;
|
import com.formdev.flatlaf.IntelliJTheme;
|
||||||
import com.formdev.flatlaf.demo.intellijthemes.IJThemesPanel;
|
import com.formdev.flatlaf.demo.intellijthemes.IJThemesPanel;
|
||||||
|
import com.formdev.flatlaf.util.LoggingFacade;
|
||||||
import com.formdev.flatlaf.util.StringUtils;
|
import com.formdev.flatlaf.util.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -50,7 +51,7 @@ public class DemoPrefs
|
|||||||
state = Preferences.userRoot().node( rootPath );
|
state = Preferences.userRoot().node( rootPath );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void initLaf( String[] args ) {
|
public static void setupLaf( String[] args ) {
|
||||||
// set look and feel
|
// set look and feel
|
||||||
try {
|
try {
|
||||||
if( args.length > 0 )
|
if( args.length > 0 )
|
||||||
@@ -60,11 +61,11 @@ public class DemoPrefs
|
|||||||
if( IntelliJTheme.ThemeLaf.class.getName().equals( lafClassName ) ) {
|
if( IntelliJTheme.ThemeLaf.class.getName().equals( lafClassName ) ) {
|
||||||
String theme = state.get( KEY_LAF_THEME, "" );
|
String theme = state.get( KEY_LAF_THEME, "" );
|
||||||
if( theme.startsWith( RESOURCE_PREFIX ) )
|
if( theme.startsWith( RESOURCE_PREFIX ) )
|
||||||
IntelliJTheme.install( IJThemesPanel.class.getResourceAsStream( IJThemesPanel.THEMES_PACKAGE + theme.substring( RESOURCE_PREFIX.length() ) ) );
|
IntelliJTheme.setup( IJThemesPanel.class.getResourceAsStream( IJThemesPanel.THEMES_PACKAGE + theme.substring( RESOURCE_PREFIX.length() ) ) );
|
||||||
else if( theme.startsWith( FILE_PREFIX ) )
|
else if( theme.startsWith( FILE_PREFIX ) )
|
||||||
FlatLaf.install( IntelliJTheme.createLaf( new FileInputStream( theme.substring( FILE_PREFIX.length() ) ) ) );
|
FlatLaf.setup( IntelliJTheme.createLaf( new FileInputStream( theme.substring( FILE_PREFIX.length() ) ) ) );
|
||||||
else
|
else
|
||||||
FlatLightLaf.install();
|
FlatLightLaf.setup();
|
||||||
|
|
||||||
if( !theme.isEmpty() )
|
if( !theme.isEmpty() )
|
||||||
UIManager.getLookAndFeelDefaults().put( THEME_UI_KEY, theme );
|
UIManager.getLookAndFeelDefaults().put( THEME_UI_KEY, theme );
|
||||||
@@ -73,9 +74,9 @@ public class DemoPrefs
|
|||||||
if( theme.startsWith( FILE_PREFIX ) ) {
|
if( theme.startsWith( FILE_PREFIX ) ) {
|
||||||
File themeFile = new File( theme.substring( FILE_PREFIX.length() ) );
|
File themeFile = new File( theme.substring( FILE_PREFIX.length() ) );
|
||||||
String themeName = StringUtils.removeTrailing( themeFile.getName(), ".properties" );
|
String themeName = StringUtils.removeTrailing( themeFile.getName(), ".properties" );
|
||||||
FlatLaf.install( new FlatPropertiesLaf( themeName, themeFile ) );
|
FlatLaf.setup( new FlatPropertiesLaf( themeName, themeFile ) );
|
||||||
} else
|
} else
|
||||||
FlatLightLaf.install();
|
FlatLightLaf.setup();
|
||||||
|
|
||||||
if( !theme.isEmpty() )
|
if( !theme.isEmpty() )
|
||||||
UIManager.getLookAndFeelDefaults().put( THEME_UI_KEY, theme );
|
UIManager.getLookAndFeelDefaults().put( THEME_UI_KEY, theme );
|
||||||
@@ -83,10 +84,10 @@ public class DemoPrefs
|
|||||||
UIManager.setLookAndFeel( lafClassName );
|
UIManager.setLookAndFeel( lafClassName );
|
||||||
}
|
}
|
||||||
} catch( Throwable ex ) {
|
} catch( Throwable ex ) {
|
||||||
ex.printStackTrace();
|
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||||
|
|
||||||
// fallback
|
// fallback
|
||||||
FlatLightLaf.install();
|
FlatLightLaf.setup();
|
||||||
}
|
}
|
||||||
|
|
||||||
// remember active look and feel
|
// remember active look and feel
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ public class FlatLafDemo
|
|||||||
FlatLaf.registerCustomDefaultsSource( "com.formdev.flatlaf.demo" );
|
FlatLaf.registerCustomDefaultsSource( "com.formdev.flatlaf.demo" );
|
||||||
|
|
||||||
// set look and feel
|
// set look and feel
|
||||||
DemoPrefs.initLaf( args );
|
DemoPrefs.setupLaf( args );
|
||||||
|
|
||||||
// install inspectors
|
// install inspectors
|
||||||
FlatInspector.install( "ctrl shift alt X" );
|
FlatInspector.install( "ctrl shift alt X" );
|
||||||
|
|||||||
@@ -18,8 +18,13 @@ package com.formdev.flatlaf.demo.extras;
|
|||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import com.formdev.flatlaf.extras.*;
|
import com.formdev.flatlaf.extras.*;
|
||||||
|
import com.formdev.flatlaf.extras.FlatSVGIcon.ColorFilter;
|
||||||
import com.formdev.flatlaf.extras.components.FlatTriStateCheckBox;
|
import com.formdev.flatlaf.extras.components.FlatTriStateCheckBox;
|
||||||
|
import com.formdev.flatlaf.util.HSLColor;
|
||||||
import net.miginfocom.swing.*;
|
import net.miginfocom.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.HierarchyEvent;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Karl Tauber
|
* @author Karl Tauber
|
||||||
@@ -27,6 +32,9 @@ import net.miginfocom.swing.*;
|
|||||||
public class ExtrasPanel
|
public class ExtrasPanel
|
||||||
extends JPanel
|
extends JPanel
|
||||||
{
|
{
|
||||||
|
private Timer rainbowIconTimer;
|
||||||
|
private int rainbowCounter = 0;
|
||||||
|
|
||||||
public ExtrasPanel() {
|
public ExtrasPanel() {
|
||||||
initComponents();
|
initComponents();
|
||||||
|
|
||||||
@@ -50,6 +58,34 @@ public class ExtrasPanel
|
|||||||
addSVGIcon( "errorDialog.svg" );
|
addSVGIcon( "errorDialog.svg" );
|
||||||
addSVGIcon( "informationDialog.svg" );
|
addSVGIcon( "informationDialog.svg" );
|
||||||
addSVGIcon( "warningDialog.svg" );
|
addSVGIcon( "warningDialog.svg" );
|
||||||
|
|
||||||
|
initRainbowIcon();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initRainbowIcon() {
|
||||||
|
FlatSVGIcon icon = new FlatSVGIcon( "com/formdev/flatlaf/demo/extras/svg/informationDialog.svg" );
|
||||||
|
icon.setColorFilter( new ColorFilter( color -> {
|
||||||
|
rainbowCounter += 1;
|
||||||
|
rainbowCounter %= 255;
|
||||||
|
return Color.getHSBColor( rainbowCounter / 255f, 1, 1 );
|
||||||
|
} ) );
|
||||||
|
rainbowIcon.setIcon( icon );
|
||||||
|
|
||||||
|
rainbowIconTimer = new Timer( 30, e -> {
|
||||||
|
rainbowIcon.repaint();
|
||||||
|
} );
|
||||||
|
|
||||||
|
// start rainbow timer only if panel is shown ("Extras" tab is active)
|
||||||
|
addHierarchyListener( e -> {
|
||||||
|
if( e.getID() == HierarchyEvent.HIERARCHY_CHANGED &&
|
||||||
|
(e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0 )
|
||||||
|
{
|
||||||
|
if( isShowing() )
|
||||||
|
rainbowIconTimer.start();
|
||||||
|
else
|
||||||
|
rainbowIconTimer.stop();
|
||||||
|
}
|
||||||
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addSVGIcon( String name ) {
|
private void addSVGIcon( String name ) {
|
||||||
@@ -60,6 +96,36 @@ public class ExtrasPanel
|
|||||||
triStateLabel1.setText( triStateCheckBox1.getState().toString() );
|
triStateLabel1.setText( triStateCheckBox1.getState().toString() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void redChanged() {
|
||||||
|
brighterToggleButton.setSelected( false );
|
||||||
|
|
||||||
|
Function<Color, Color> mapper = null;
|
||||||
|
if( redToggleButton.isSelected() ) {
|
||||||
|
float[] redHSL = HSLColor.fromRGB( Color.red );
|
||||||
|
mapper = color -> {
|
||||||
|
float[] hsl = HSLColor.fromRGB( color );
|
||||||
|
return HSLColor.toRGB( redHSL[0], 70, hsl[2] );
|
||||||
|
};
|
||||||
|
}
|
||||||
|
FlatSVGIcon.ColorFilter.getInstance().setMapper( mapper );
|
||||||
|
|
||||||
|
// repaint whole application window because global color filter also affects
|
||||||
|
// icons in menubar, toolbar, etc.
|
||||||
|
SwingUtilities.windowForComponent( this ).repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void brighterChanged() {
|
||||||
|
redToggleButton.setSelected( false );
|
||||||
|
|
||||||
|
FlatSVGIcon.ColorFilter.getInstance().setMapper( brighterToggleButton.isSelected()
|
||||||
|
? color -> color.brighter().brighter()
|
||||||
|
: null );
|
||||||
|
|
||||||
|
// repaint whole application window because global color filter also affects
|
||||||
|
// icons in menubar, toolbar, etc.
|
||||||
|
SwingUtilities.windowForComponent( this ).repaint();
|
||||||
|
}
|
||||||
|
|
||||||
private void initComponents() {
|
private void initComponents() {
|
||||||
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
|
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
|
||||||
label4 = new JLabel();
|
label4 = new JLabel();
|
||||||
@@ -69,6 +135,13 @@ public class ExtrasPanel
|
|||||||
label2 = new JLabel();
|
label2 = new JLabel();
|
||||||
svgIconsPanel = new JPanel();
|
svgIconsPanel = new JPanel();
|
||||||
label3 = new JLabel();
|
label3 = new JLabel();
|
||||||
|
separator1 = new JSeparator();
|
||||||
|
label5 = new JLabel();
|
||||||
|
label6 = new JLabel();
|
||||||
|
rainbowIcon = new JLabel();
|
||||||
|
label7 = new JLabel();
|
||||||
|
redToggleButton = new JToggleButton();
|
||||||
|
brighterToggleButton = new JToggleButton();
|
||||||
|
|
||||||
//======== this ========
|
//======== this ========
|
||||||
setLayout(new MigLayout(
|
setLayout(new MigLayout(
|
||||||
@@ -81,6 +154,10 @@ public class ExtrasPanel
|
|||||||
"[]para" +
|
"[]para" +
|
||||||
"[]" +
|
"[]" +
|
||||||
"[]" +
|
"[]" +
|
||||||
|
"[]" +
|
||||||
|
"[]" +
|
||||||
|
"[]" +
|
||||||
|
"[]" +
|
||||||
"[]"));
|
"[]"));
|
||||||
|
|
||||||
//---- label4 ----
|
//---- label4 ----
|
||||||
@@ -119,6 +196,30 @@ public class ExtrasPanel
|
|||||||
//---- label3 ----
|
//---- label3 ----
|
||||||
label3.setText("The icons may change colors when switching to another theme.");
|
label3.setText("The icons may change colors when switching to another theme.");
|
||||||
add(label3, "cell 1 3 2 1");
|
add(label3, "cell 1 3 2 1");
|
||||||
|
add(separator1, "cell 1 4 2 1,growx");
|
||||||
|
|
||||||
|
//---- label5 ----
|
||||||
|
label5.setText("Color filters can be also applied to icons. Globally or for each instance.");
|
||||||
|
add(label5, "cell 1 5 2 1");
|
||||||
|
|
||||||
|
//---- label6 ----
|
||||||
|
label6.setText("Rainbow color filter");
|
||||||
|
add(label6, "cell 1 6 2 1");
|
||||||
|
add(rainbowIcon, "cell 1 6 2 1");
|
||||||
|
|
||||||
|
//---- label7 ----
|
||||||
|
label7.setText("Global icon color filter");
|
||||||
|
add(label7, "cell 1 7 2 1");
|
||||||
|
|
||||||
|
//---- redToggleButton ----
|
||||||
|
redToggleButton.setText("Toggle RED");
|
||||||
|
redToggleButton.addActionListener(e -> redChanged());
|
||||||
|
add(redToggleButton, "cell 1 7 2 1");
|
||||||
|
|
||||||
|
//---- brighterToggleButton ----
|
||||||
|
brighterToggleButton.setText("Toggle brighter");
|
||||||
|
brighterToggleButton.addActionListener(e -> brighterChanged());
|
||||||
|
add(brighterToggleButton, "cell 1 7 2 1");
|
||||||
// JFormDesigner - End of component initialization //GEN-END:initComponents
|
// JFormDesigner - End of component initialization //GEN-END:initComponents
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,5 +231,12 @@ public class ExtrasPanel
|
|||||||
private JLabel label2;
|
private JLabel label2;
|
||||||
private JPanel svgIconsPanel;
|
private JPanel svgIconsPanel;
|
||||||
private JLabel label3;
|
private JLabel label3;
|
||||||
|
private JSeparator separator1;
|
||||||
|
private JLabel label5;
|
||||||
|
private JLabel label6;
|
||||||
|
private JLabel rainbowIcon;
|
||||||
|
private JLabel label7;
|
||||||
|
private JToggleButton redToggleButton;
|
||||||
|
private JToggleButton brighterToggleButton;
|
||||||
// JFormDesigner - End of variables declaration //GEN-END:variables
|
// JFormDesigner - End of variables declaration //GEN-END:variables
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
JFDML JFormDesigner: "7.0.2.0.298" Java: "14" encoding: "UTF-8"
|
JFDML JFormDesigner: "7.0.3.1.342" Java: "16" encoding: "UTF-8"
|
||||||
|
|
||||||
new FormModel {
|
new FormModel {
|
||||||
contentType: "form/swing"
|
contentType: "form/swing"
|
||||||
@@ -6,7 +6,7 @@ new FormModel {
|
|||||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||||
"$layoutConstraints": "insets dialog,hidemode 3"
|
"$layoutConstraints": "insets dialog,hidemode 3"
|
||||||
"$columnConstraints": "[][][left]"
|
"$columnConstraints": "[][][left]"
|
||||||
"$rowConstraints": "[]para[][][]"
|
"$rowConstraints": "[]para[][][][][][][]"
|
||||||
} ) {
|
} ) {
|
||||||
name: "this"
|
name: "this"
|
||||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||||
@@ -56,6 +56,48 @@ new FormModel {
|
|||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
"value": "cell 1 3 2 1"
|
"value": "cell 1 3 2 1"
|
||||||
} )
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JSeparator" ) {
|
||||||
|
name: "separator1"
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 1 4 2 1,growx"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||||
|
name: "label5"
|
||||||
|
"text": "Color filters can be also applied to icons. Globally or for each instance."
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 1 5 2 1"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||||
|
name: "label6"
|
||||||
|
"text": "Rainbow color filter"
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 1 6 2 1"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||||
|
name: "rainbowIcon"
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 1 6 2 1"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||||
|
name: "label7"
|
||||||
|
"text": "Global icon color filter"
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 1 7 2 1"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JToggleButton" ) {
|
||||||
|
name: "redToggleButton"
|
||||||
|
"text": "Toggle RED"
|
||||||
|
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "redChanged", false ) )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 1 7 2 1"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JToggleButton" ) {
|
||||||
|
name: "brighterToggleButton"
|
||||||
|
"text": "Toggle brighter"
|
||||||
|
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "brighterChanged", false ) )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 1 7 2 1"
|
||||||
|
} )
|
||||||
}, new FormLayoutConstraints( null ) {
|
}, new FormLayoutConstraints( null ) {
|
||||||
"location": new java.awt.Point( 0, 0 )
|
"location": new java.awt.Point( 0, 0 )
|
||||||
"size": new java.awt.Dimension( 500, 300 )
|
"size": new java.awt.Dimension( 500, 300 )
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import java.nio.charset.StandardCharsets;
|
|||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.StandardOpenOption;
|
import java.nio.file.StandardOpenOption;
|
||||||
|
import com.formdev.flatlaf.util.LoggingFacade;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This tool creates look and feel classes for all themes listed in themes.json.
|
* This tool creates look and feel classes for all themes listed in themes.json.
|
||||||
@@ -120,7 +121,7 @@ public class IJThemesClassGenerator
|
|||||||
Files.write( out, content.getBytes( StandardCharsets.ISO_8859_1 ),
|
Files.write( out, content.getBytes( StandardCharsets.ISO_8859_1 ),
|
||||||
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING );
|
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING );
|
||||||
} catch( IOException ex ) {
|
} catch( IOException ex ) {
|
||||||
ex.printStackTrace();
|
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,14 +161,22 @@ public class IJThemesClassGenerator
|
|||||||
"{\n" +
|
"{\n" +
|
||||||
" public static final String NAME = \"${themeName}\";\n" +
|
" public static final String NAME = \"${themeName}\";\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
" public static boolean install() {\n" +
|
" public static boolean setup() {\n" +
|
||||||
" try {\n" +
|
" try {\n" +
|
||||||
" return install( new ${themeClass}() );\n" +
|
" return setup( new ${themeClass}() );\n" +
|
||||||
" } catch( RuntimeException ex ) {\n" +
|
" } catch( RuntimeException ex ) {\n" +
|
||||||
" return false;\n" +
|
" return false;\n" +
|
||||||
" }\n" +
|
" }\n" +
|
||||||
" }\n" +
|
" }\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
|
" /**\n" +
|
||||||
|
" * @deprecated use {@link #setup()} instead; this method will be removed in a future version\n" +
|
||||||
|
" */\n" +
|
||||||
|
" @Deprecated\n" +
|
||||||
|
" public static boolean install() {\n" +
|
||||||
|
" return setup();\n" +
|
||||||
|
" }\n" +
|
||||||
|
"\n" +
|
||||||
" public static void installLafInfo() {\n" +
|
" public static void installLafInfo() {\n" +
|
||||||
" installLafInfo( NAME, ${themeClass}.class );\n" +
|
" installLafInfo( NAME, ${themeClass}.class );\n" +
|
||||||
" }\n" +
|
" }\n" +
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* 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.demo.intellijthemes;
|
||||||
|
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import com.formdev.flatlaf.json.Json;
|
||||||
|
import com.formdev.flatlaf.json.ParseException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tool checks whether there are duplicate name fields in all theme .json files.
|
||||||
|
*
|
||||||
|
* This is important for following file, where the name is used for theme specific UI defaults:
|
||||||
|
* flatlaf-core/src/main/resources/com/formdev/flatlaf/IntelliJTheme$ThemeLaf.properties
|
||||||
|
*
|
||||||
|
* @author Karl Tauber
|
||||||
|
*/
|
||||||
|
public class IJThemesDuplicateNameChecker
|
||||||
|
{
|
||||||
|
public static void main( String[] args ) {
|
||||||
|
IJThemesManager themesManager = new IJThemesManager();
|
||||||
|
themesManager.loadBundledThemes();
|
||||||
|
|
||||||
|
HashSet<String> names = new HashSet<>();
|
||||||
|
for( IJThemeInfo ti : themesManager.bundledThemes ) {
|
||||||
|
if( ti.sourceCodeUrl == null || ti.sourceCodePath == null )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
String jsonPath = "../flatlaf-intellij-themes/src/main/resources" + IJThemesPanel.THEMES_PACKAGE + ti.resourceName;
|
||||||
|
String name;
|
||||||
|
try {
|
||||||
|
name = readNameFromJson( jsonPath );
|
||||||
|
} catch( IOException ex ) {
|
||||||
|
System.err.println( "Failed to read '" + jsonPath + "'" );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( names.contains( name ) )
|
||||||
|
System.out.println( "Duplicate name '" + name + "'" );
|
||||||
|
names.add( name );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String readNameFromJson( String jsonPath ) throws IOException {
|
||||||
|
try( Reader reader = new InputStreamReader( new FileInputStream( jsonPath ), StandardCharsets.UTF_8 ) ) {
|
||||||
|
@SuppressWarnings( "unchecked" )
|
||||||
|
Map<String, Object> json = (Map<String, Object>) Json.parse( reader );
|
||||||
|
return (String) json.get( "name" );
|
||||||
|
} catch( ParseException ex ) {
|
||||||
|
throw new IOException( ex.getMessage(), ex );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,6 +26,7 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import com.formdev.flatlaf.json.Json;
|
import com.formdev.flatlaf.json.Json;
|
||||||
|
import com.formdev.flatlaf.util.LoggingFacade;
|
||||||
import com.formdev.flatlaf.util.StringUtils;
|
import com.formdev.flatlaf.util.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -46,7 +47,7 @@ class IJThemesManager
|
|||||||
try( Reader reader = new InputStreamReader( getClass().getResourceAsStream( "themes.json" ), StandardCharsets.UTF_8 ) ) {
|
try( Reader reader = new InputStreamReader( getClass().getResourceAsStream( "themes.json" ), StandardCharsets.UTF_8 ) ) {
|
||||||
json = (Map<String, Object>) Json.parse( reader );
|
json = (Map<String, Object>) Json.parse( reader );
|
||||||
} catch( IOException ex ) {
|
} catch( IOException ex ) {
|
||||||
ex.printStackTrace();
|
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ import com.formdev.flatlaf.IntelliJTheme;
|
|||||||
import com.formdev.flatlaf.demo.DemoPrefs;
|
import com.formdev.flatlaf.demo.DemoPrefs;
|
||||||
import com.formdev.flatlaf.extras.FlatAnimatedLafChange;
|
import com.formdev.flatlaf.extras.FlatAnimatedLafChange;
|
||||||
import com.formdev.flatlaf.extras.FlatSVGIcon;
|
import com.formdev.flatlaf.extras.FlatSVGIcon;
|
||||||
|
import com.formdev.flatlaf.util.LoggingFacade;
|
||||||
import com.formdev.flatlaf.util.StringUtils;
|
import com.formdev.flatlaf.util.StringUtils;
|
||||||
import net.miginfocom.swing.*;
|
import net.miginfocom.swing.*;
|
||||||
|
|
||||||
@@ -259,7 +260,7 @@ public class IJThemesPanel
|
|||||||
try {
|
try {
|
||||||
UIManager.setLookAndFeel( themeInfo.lafClassName );
|
UIManager.setLookAndFeel( themeInfo.lafClassName );
|
||||||
} catch( Exception ex ) {
|
} catch( Exception ex ) {
|
||||||
ex.printStackTrace();
|
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||||
showInformationDialog( "Failed to create '" + themeInfo.lafClassName + "'.", ex );
|
showInformationDialog( "Failed to create '" + themeInfo.lafClassName + "'.", ex );
|
||||||
}
|
}
|
||||||
} else if( themeInfo.themeFile != null ) {
|
} else if( themeInfo.themeFile != null ) {
|
||||||
@@ -267,19 +268,19 @@ public class IJThemesPanel
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if( themeInfo.themeFile.getName().endsWith( ".properties" ) ) {
|
if( themeInfo.themeFile.getName().endsWith( ".properties" ) ) {
|
||||||
FlatLaf.install( new FlatPropertiesLaf( themeInfo.name, themeInfo.themeFile ) );
|
FlatLaf.setup( new FlatPropertiesLaf( themeInfo.name, themeInfo.themeFile ) );
|
||||||
} else
|
} else
|
||||||
FlatLaf.install( IntelliJTheme.createLaf( new FileInputStream( themeInfo.themeFile ) ) );
|
FlatLaf.setup( IntelliJTheme.createLaf( new FileInputStream( themeInfo.themeFile ) ) );
|
||||||
|
|
||||||
DemoPrefs.getState().put( DemoPrefs.KEY_LAF_THEME, DemoPrefs.FILE_PREFIX + themeInfo.themeFile );
|
DemoPrefs.getState().put( DemoPrefs.KEY_LAF_THEME, DemoPrefs.FILE_PREFIX + themeInfo.themeFile );
|
||||||
} catch( Exception ex ) {
|
} catch( Exception ex ) {
|
||||||
ex.printStackTrace();
|
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||||
showInformationDialog( "Failed to load '" + themeInfo.themeFile + "'.", ex );
|
showInformationDialog( "Failed to load '" + themeInfo.themeFile + "'.", ex );
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
FlatAnimatedLafChange.showSnapshot();
|
FlatAnimatedLafChange.showSnapshot();
|
||||||
|
|
||||||
IntelliJTheme.install( getClass().getResourceAsStream( THEMES_PACKAGE + themeInfo.resourceName ) );
|
IntelliJTheme.setup( getClass().getResourceAsStream( THEMES_PACKAGE + themeInfo.resourceName ) );
|
||||||
DemoPrefs.getState().put( DemoPrefs.KEY_LAF_THEME, DemoPrefs.RESOURCE_PREFIX + themeInfo.resourceName );
|
DemoPrefs.getState().put( DemoPrefs.KEY_LAF_THEME, DemoPrefs.RESOURCE_PREFIX + themeInfo.resourceName );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import java.net.URLConnection;
|
|||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.StandardCopyOption;
|
import java.nio.file.StandardCopyOption;
|
||||||
|
import com.formdev.flatlaf.util.LoggingFacade;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This tool updates all IntelliJ themes listed in themes.json by downloading
|
* This tool updates all IntelliJ themes listed in themes.json by downloading
|
||||||
@@ -61,7 +62,7 @@ public class IJThemesUpdater
|
|||||||
URLConnection con = url.openConnection();
|
URLConnection con = url.openConnection();
|
||||||
Files.copy( con.getInputStream(), out, StandardCopyOption.REPLACE_EXISTING );
|
Files.copy( con.getInputStream(), out, StandardCopyOption.REPLACE_EXISTING );
|
||||||
} catch( IOException ex ) {
|
} catch( IOException ex ) {
|
||||||
ex.printStackTrace();
|
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -302,6 +302,22 @@
|
|||||||
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
|
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
|
||||||
"sourceCodePath": "blob/master/src/main/resources/themes/GitHub Contrast.theme.json"
|
"sourceCodePath": "blob/master/src/main/resources/themes/GitHub Contrast.theme.json"
|
||||||
},
|
},
|
||||||
|
"material-theme-ui-lite/GitHub Dark.theme.json": {
|
||||||
|
"name": "Material Theme UI Lite / GitHub Dark",
|
||||||
|
"dark": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
|
||||||
|
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
|
||||||
|
"sourceCodePath": "blob/master/src/main/resources/themes/GitHub Dark.theme.json"
|
||||||
|
},
|
||||||
|
"material-theme-ui-lite/GitHub Dark Contrast.theme.json": {
|
||||||
|
"name": "Material Theme UI Lite / GitHub Dark Contrast",
|
||||||
|
"dark": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
|
||||||
|
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
|
||||||
|
"sourceCodePath": "blob/master/src/main/resources/themes/GitHub Dark Contrast.theme.json"
|
||||||
|
},
|
||||||
"material-theme-ui-lite/Light Owl.theme.json": {
|
"material-theme-ui-lite/Light Owl.theme.json": {
|
||||||
"name": "Material Theme UI Lite / Light Owl",
|
"name": "Material Theme UI Lite / Light Owl",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|||||||
@@ -34,18 +34,6 @@ java {
|
|||||||
withJavadocJar()
|
withJavadocJar()
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks {
|
|
||||||
javadoc {
|
|
||||||
options {
|
|
||||||
this as StandardJavadocDocletOptions
|
|
||||||
use( true )
|
|
||||||
tags = listOf( "uiDefault", "clientProperty" )
|
|
||||||
addStringOption( "Xdoclint:all,-missing", "-Xdoclint:all,-missing" )
|
|
||||||
}
|
|
||||||
isFailOnError = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
flatlafPublish {
|
flatlafPublish {
|
||||||
artifactId = "flatlaf-extras"
|
artifactId = "flatlaf-extras"
|
||||||
name = "FlatLaf Extras"
|
name = "FlatLaf Extras"
|
||||||
|
|||||||
@@ -44,8 +44,10 @@ import java.awt.event.WindowListener;
|
|||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.beans.PropertyChangeSupport;
|
import java.beans.PropertyChangeSupport;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import javax.swing.AbstractButton;
|
import javax.swing.AbstractButton;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
|
import javax.swing.JLayeredPane;
|
||||||
import javax.swing.JMenuBar;
|
import javax.swing.JMenuBar;
|
||||||
import javax.swing.JRootPane;
|
import javax.swing.JRootPane;
|
||||||
import javax.swing.JToolBar;
|
import javax.swing.JToolBar;
|
||||||
@@ -55,6 +57,7 @@ import javax.swing.Popup;
|
|||||||
import javax.swing.PopupFactory;
|
import javax.swing.PopupFactory;
|
||||||
import javax.swing.RootPaneContainer;
|
import javax.swing.RootPaneContainer;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
|
import javax.swing.UIManager;
|
||||||
import javax.swing.border.Border;
|
import javax.swing.border.Border;
|
||||||
import javax.swing.border.EmptyBorder;
|
import javax.swing.border.EmptyBorder;
|
||||||
import javax.swing.border.LineBorder;
|
import javax.swing.border.LineBorder;
|
||||||
@@ -62,6 +65,7 @@ import javax.swing.plaf.UIResource;
|
|||||||
import javax.swing.text.JTextComponent;
|
import javax.swing.text.JTextComponent;
|
||||||
import com.formdev.flatlaf.FlatClientProperties;
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||||
|
import com.formdev.flatlaf.util.SystemInfo;
|
||||||
import com.formdev.flatlaf.util.UIScale;
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -87,9 +91,13 @@ import com.formdev.flatlaf.util.UIScale;
|
|||||||
*/
|
*/
|
||||||
public class FlatInspector
|
public class FlatInspector
|
||||||
{
|
{
|
||||||
private static final Integer HIGHLIGHT_LAYER = 401;
|
private static final Integer HIGHLIGHT_LAYER = JLayeredPane.POPUP_LAYER - 1;
|
||||||
|
|
||||||
private static final int KEY_MODIFIERS_MASK = InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK | InputEvent.ALT_DOWN_MASK | InputEvent.META_DOWN_MASK;
|
private static final int KEY_MODIFIERS_MASK =
|
||||||
|
InputEvent.CTRL_DOWN_MASK |
|
||||||
|
InputEvent.SHIFT_DOWN_MASK |
|
||||||
|
InputEvent.ALT_DOWN_MASK |
|
||||||
|
InputEvent.META_DOWN_MASK;
|
||||||
|
|
||||||
private final JRootPane rootPane;
|
private final JRootPane rootPane;
|
||||||
private final MouseMotionListener mouseMotionListener;
|
private final MouseMotionListener mouseMotionListener;
|
||||||
@@ -103,7 +111,8 @@ public class FlatInspector
|
|||||||
private int lastX;
|
private int lastX;
|
||||||
private int lastY;
|
private int lastY;
|
||||||
private int inspectParentLevel;
|
private int inspectParentLevel;
|
||||||
private boolean wasCtrlOrShiftKeyPressed;
|
private boolean wasModifierKeyPressed;
|
||||||
|
private boolean showClassHierarchy;
|
||||||
|
|
||||||
private JComponent highlightFigure;
|
private JComponent highlightFigure;
|
||||||
private Popup popup;
|
private Popup popup;
|
||||||
@@ -160,9 +169,9 @@ public class FlatInspector
|
|||||||
if( id == KeyEvent.KEY_PRESSED ) {
|
if( id == KeyEvent.KEY_PRESSED ) {
|
||||||
// this avoids that the inspection level is changed when UI inspector
|
// this avoids that the inspection level is changed when UI inspector
|
||||||
// is enabled with keyboard shortcut (e.g. Ctrl+Shift+Alt+X)
|
// is enabled with keyboard shortcut (e.g. Ctrl+Shift+Alt+X)
|
||||||
if( keyCode == KeyEvent.VK_CONTROL || keyCode == KeyEvent.VK_SHIFT )
|
if( keyCode == KeyEvent.VK_CONTROL || keyCode == KeyEvent.VK_SHIFT || keyCode == KeyEvent.VK_ALT )
|
||||||
wasCtrlOrShiftKeyPressed = true;
|
wasModifierKeyPressed = true;
|
||||||
} else if( id == KeyEvent.KEY_RELEASED && wasCtrlOrShiftKeyPressed ) {
|
} else if( id == KeyEvent.KEY_RELEASED && wasModifierKeyPressed ) {
|
||||||
if( keyCode == KeyEvent.VK_CONTROL ) {
|
if( keyCode == KeyEvent.VK_CONTROL ) {
|
||||||
inspectParentLevel++;
|
inspectParentLevel++;
|
||||||
int parentLevel = inspect( lastX, lastY );
|
int parentLevel = inspect( lastX, lastY );
|
||||||
@@ -179,6 +188,9 @@ public class FlatInspector
|
|||||||
inspectParentLevel = Math.max( parentLevel - 1, 0 );
|
inspectParentLevel = Math.max( parentLevel - 1, 0 );
|
||||||
inspect( lastX, lastY );
|
inspect( lastX, lastY );
|
||||||
}
|
}
|
||||||
|
} else if( keyCode == KeyEvent.VK_ALT && lastComponent != null) {
|
||||||
|
showClassHierarchy = !showClassHierarchy;
|
||||||
|
showToolTip( lastComponent, lastX, lastY, inspectParentLevel );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -401,7 +413,7 @@ public class FlatInspector
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
JToolTip tip = new JToolTip();
|
JToolTip tip = new JToolTip();
|
||||||
tip.setTipText( buildToolTipText( c, parentLevel ) );
|
tip.setTipText( buildToolTipText( c, parentLevel, showClassHierarchy ) );
|
||||||
tip.putClientProperty( FlatClientProperties.POPUP_FORCE_HEAVY_WEIGHT, true );
|
tip.putClientProperty( FlatClientProperties.POPUP_FORCE_HEAVY_WEIGHT, true );
|
||||||
|
|
||||||
Point pt = new Point( x, y );
|
Point pt = new Point( x, y );
|
||||||
@@ -427,16 +439,13 @@ public class FlatInspector
|
|||||||
popup.show();
|
popup.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String buildToolTipText( Component c, int parentLevel ) {
|
private static String buildToolTipText( Component c, int parentLevel, boolean classHierarchy ) {
|
||||||
StringBuilder buf = new StringBuilder( 1500 );
|
StringBuilder buf = new StringBuilder( 1500 );
|
||||||
buf.append( "<html><style>" );
|
buf.append( "<html><style>" );
|
||||||
buf.append( "td { padding: 0 10 0 0; }" );
|
buf.append( "td { padding: 0 10 0 0; }" );
|
||||||
buf.append( "</style><table>" );
|
buf.append( "</style><table>" );
|
||||||
|
|
||||||
String name = c.getClass().getName();
|
appendRow( buf, "Class", toString( c.getClass(), classHierarchy ) );
|
||||||
name = name.substring( name.lastIndexOf( '.' ) + 1 );
|
|
||||||
Package pkg = c.getClass().getPackage();
|
|
||||||
appendRow( buf, "Class", name + " (" + (pkg != null ? pkg.getName() : "-") + ")" );
|
|
||||||
appendRow( buf, "Size", c.getWidth() + ", " + c.getHeight() + " @ " + c.getX() + ", " + c.getY() );
|
appendRow( buf, "Size", c.getWidth() + ", " + c.getHeight() + " @ " + c.getX() + ", " + c.getY() );
|
||||||
|
|
||||||
if( c instanceof Container )
|
if( c instanceof Container )
|
||||||
@@ -463,7 +472,7 @@ public class FlatInspector
|
|||||||
appendRow( buf, "Max size", maxSize.width + ", " + maxSize.height );
|
appendRow( buf, "Max size", maxSize.width + ", " + maxSize.height );
|
||||||
|
|
||||||
if( c instanceof JComponent )
|
if( c instanceof JComponent )
|
||||||
appendRow( buf, "Border", toString( ((JComponent)c).getBorder() ) );
|
appendRow( buf, "Border", toString( ((JComponent)c).getBorder(), classHierarchy ) );
|
||||||
|
|
||||||
appendRow( buf, "Background", toString( c.getBackground() ) );
|
appendRow( buf, "Background", toString( c.getBackground() ) );
|
||||||
appendRow( buf, "Foreground", toString( c.getForeground() ) );
|
appendRow( buf, "Foreground", toString( c.getForeground() ) );
|
||||||
@@ -471,10 +480,18 @@ public class FlatInspector
|
|||||||
|
|
||||||
if( c instanceof JComponent ) {
|
if( c instanceof JComponent ) {
|
||||||
try {
|
try {
|
||||||
Field f = JComponent.class.getDeclaredField( "ui" );
|
Object ui;
|
||||||
f.setAccessible( true );
|
if( SystemInfo.isJava_9_orLater ) {
|
||||||
Object ui = f.get( c );
|
// Java 9+: use public method JComponent.getUI()
|
||||||
appendRow( buf, "UI", (ui != null ? ui.getClass().getName() : "null") );
|
Method m = JComponent.class.getMethod( "getUI" );
|
||||||
|
ui = m.invoke( c );
|
||||||
|
} else {
|
||||||
|
// Java 8: read protected field 'ui'
|
||||||
|
Field f = JComponent.class.getDeclaredField( "ui" );
|
||||||
|
f.setAccessible( true );
|
||||||
|
ui = f.get( c );
|
||||||
|
}
|
||||||
|
appendRow( buf, "UI", (ui != null ? toString( ui.getClass(), classHierarchy ) : "null") );
|
||||||
} catch( Exception ex ) {
|
} catch( Exception ex ) {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
@@ -483,7 +500,7 @@ public class FlatInspector
|
|||||||
if( c instanceof Container ) {
|
if( c instanceof Container ) {
|
||||||
LayoutManager layout = ((Container)c).getLayout();
|
LayoutManager layout = ((Container)c).getLayout();
|
||||||
if( layout != null )
|
if( layout != null )
|
||||||
appendRow( buf, "Layout", layout.getClass().getName() );
|
appendRow( buf, "Layout", toString( layout.getClass(), classHierarchy ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
appendRow( buf, "Enabled", String.valueOf( c.isEnabled() ) );
|
appendRow( buf, "Enabled", String.valueOf( c.isEnabled() ) );
|
||||||
@@ -493,16 +510,23 @@ public class FlatInspector
|
|||||||
appendRow( buf, "ContentAreaFilled", String.valueOf( ((AbstractButton)c).isContentAreaFilled() ) );
|
appendRow( buf, "ContentAreaFilled", String.valueOf( ((AbstractButton)c).isContentAreaFilled() ) );
|
||||||
appendRow( buf, "Focusable", String.valueOf( c.isFocusable() ) );
|
appendRow( buf, "Focusable", String.valueOf( c.isFocusable() ) );
|
||||||
appendRow( buf, "Left-to-right", String.valueOf( c.getComponentOrientation().isLeftToRight() ) );
|
appendRow( buf, "Left-to-right", String.valueOf( c.getComponentOrientation().isLeftToRight() ) );
|
||||||
appendRow( buf, "Parent", (c.getParent() != null ? c.getParent().getClass().getName() : "null") );
|
appendRow( buf, "Parent", (c.getParent() != null ? toString( c.getParent().getClass(), classHierarchy ) : "null") );
|
||||||
|
|
||||||
|
// append parent level
|
||||||
buf.append( "<tr><td colspan=\"2\">" );
|
buf.append( "<tr><td colspan=\"2\">" );
|
||||||
if( parentLevel > 0 )
|
if( parentLevel > 0 )
|
||||||
buf.append( "<br>Parent level: " + parentLevel );
|
buf.append( "<br>Parent level: " + parentLevel );
|
||||||
|
|
||||||
if( parentLevel > 0 )
|
// append modifier keys hint
|
||||||
buf.append( "<br>(press Ctrl/Shift to increase/decrease level)" );
|
buf.append( "<br>(" )
|
||||||
else
|
.append( (parentLevel > 0)
|
||||||
buf.append( "<br>(press Ctrl key to inspect parent)" );
|
? "press <b>Ctrl/Shift</b> to increase/decrease level"
|
||||||
|
: "press <b>Ctrl</b> key to inspect parent" )
|
||||||
|
.append( "; " )
|
||||||
|
.append( classHierarchy
|
||||||
|
? "press <b>Alt</b> key to hide class hierarchy"
|
||||||
|
: "press <b>Alt</b> key to show class hierarchy" )
|
||||||
|
.append( ')' );
|
||||||
|
|
||||||
buf.append( "</td></tr>" );
|
buf.append( "</td></tr>" );
|
||||||
buf.append( "</table></html>" );
|
buf.append( "</table></html>" );
|
||||||
@@ -511,13 +535,46 @@ public class FlatInspector
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void appendRow( StringBuilder buf, String key, String value ) {
|
private static void appendRow( StringBuilder buf, String key, String value ) {
|
||||||
buf.append( "<tr><td>" )
|
buf.append( "<tr><td valign=\"top\">" )
|
||||||
.append( key )
|
.append( key )
|
||||||
.append( ":</td><td>" )
|
.append( ":</td><td>" )
|
||||||
.append( value )
|
.append( value )
|
||||||
.append( "</td></tr>" );
|
.append( "</td></tr>" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String toString( Class<?> cls, boolean classHierarchy ) {
|
||||||
|
StringBuilder buf = new StringBuilder( 100 );
|
||||||
|
int level = 0;
|
||||||
|
|
||||||
|
while( cls != null ) {
|
||||||
|
if( level > 0 ) {
|
||||||
|
if( cls == Object.class )
|
||||||
|
break;
|
||||||
|
buf.append( "<br> " );
|
||||||
|
for( int i = 1; i < level; i++ )
|
||||||
|
buf.append( " " );
|
||||||
|
buf.append( "\u2570 " );
|
||||||
|
}
|
||||||
|
level++;
|
||||||
|
|
||||||
|
String name = cls.getName();
|
||||||
|
int dot = name.lastIndexOf( '.' );
|
||||||
|
String pkg = (dot >= 0) ? name.substring( 0, dot ) : "-";
|
||||||
|
String simpleName = (dot >= 0) ? name.substring( dot + 1 ) : name;
|
||||||
|
buf.append( simpleName ).append( ' ' ).append( toDimmedText( "(" + pkg + ")" ) );
|
||||||
|
|
||||||
|
if( UIResource.class.isAssignableFrom( cls ) )
|
||||||
|
buf.append( " UI" );
|
||||||
|
|
||||||
|
if( !classHierarchy )
|
||||||
|
break;
|
||||||
|
|
||||||
|
cls = cls.getSuperclass();
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
private static String toString( Insets insets ) {
|
private static String toString( Insets insets ) {
|
||||||
if( insets == null )
|
if( insets == null )
|
||||||
return "null";
|
return "null";
|
||||||
@@ -563,18 +620,31 @@ public class FlatInspector
|
|||||||
+ (f instanceof UIResource ? " UI" : "");
|
+ (f instanceof UIResource ? " UI" : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String toString( Border b ) {
|
private static String toString( Border b, boolean classHierarchy ) {
|
||||||
if( b == null )
|
if( b == null )
|
||||||
return "null";
|
return "null";
|
||||||
|
|
||||||
String s = b.getClass().getName();
|
String s = toString( b.getClass(), classHierarchy );
|
||||||
|
|
||||||
if( b instanceof EmptyBorder )
|
if( b instanceof EmptyBorder ) {
|
||||||
s += '(' + toString( ((EmptyBorder)b).getBorderInsets() ) + ')';
|
String borderInsets = " (" + toString( ((EmptyBorder)b).getBorderInsets() ) + ')';
|
||||||
|
int brIndex = s.indexOf( "<br>" );
|
||||||
if( b instanceof UIResource )
|
if( brIndex >= 0 )
|
||||||
s += " UI";
|
s = s.substring( 0, brIndex ) + borderInsets + s.substring( brIndex );
|
||||||
|
else
|
||||||
|
s += borderInsets;
|
||||||
|
}
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String toDimmedText( String text ) {
|
||||||
|
Color color = UIManager.getColor( "Label.disabledForeground" );
|
||||||
|
if( color == null )
|
||||||
|
color = UIManager.getColor( "Label.disabledText" );
|
||||||
|
if( color == null )
|
||||||
|
color = Color.GRAY;
|
||||||
|
return String.format( "<span color=\"#%06x\">%s</span>",
|
||||||
|
color.getRGB() & 0xffffff, text );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import java.awt.image.BufferedImage;
|
|||||||
import java.awt.image.RGBImageFilter;
|
import java.awt.image.RGBImageFilter;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
@@ -41,6 +42,7 @@ import com.formdev.flatlaf.FlatLaf.DisabledIconProvider;
|
|||||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||||
import com.formdev.flatlaf.util.Graphics2DProxy;
|
import com.formdev.flatlaf.util.Graphics2DProxy;
|
||||||
import com.formdev.flatlaf.util.GrayFilter;
|
import com.formdev.flatlaf.util.GrayFilter;
|
||||||
|
import com.formdev.flatlaf.util.LoggingFacade;
|
||||||
import com.formdev.flatlaf.util.MultiResolutionImageSupport;
|
import com.formdev.flatlaf.util.MultiResolutionImageSupport;
|
||||||
import com.formdev.flatlaf.util.UIScale;
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
import com.kitfox.svg.SVGDiagram;
|
import com.kitfox.svg.SVGDiagram;
|
||||||
@@ -66,6 +68,8 @@ public class FlatSVGIcon
|
|||||||
private final boolean disabled;
|
private final boolean disabled;
|
||||||
private final ClassLoader classLoader;
|
private final ClassLoader classLoader;
|
||||||
|
|
||||||
|
private ColorFilter colorFilter;
|
||||||
|
|
||||||
private SVGDiagram diagram;
|
private SVGDiagram diagram;
|
||||||
private boolean dark;
|
private boolean dark;
|
||||||
|
|
||||||
@@ -159,17 +163,82 @@ public class FlatSVGIcon
|
|||||||
this( name, -1, -1, scale, false, classLoader );
|
this( name, -1, -1, scale, false, classLoader );
|
||||||
}
|
}
|
||||||
|
|
||||||
private FlatSVGIcon( String name, int width, int height, float scale, boolean disabled, ClassLoader classLoader ) {
|
protected FlatSVGIcon( String name, int width, int height, float scale, boolean disabled, ClassLoader classLoader ) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.classLoader = classLoader;
|
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
this.scale = scale;
|
this.scale = scale;
|
||||||
this.disabled = disabled;
|
this.disabled = disabled;
|
||||||
|
this.classLoader = classLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the SVG resource (a '/'-separated path).
|
||||||
|
*
|
||||||
|
* @since 1.2
|
||||||
|
*/
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the custom icon width specified in {@link #FlatSVGIcon(String, int, int)},
|
||||||
|
* {@link #FlatSVGIcon(String, int, int, ClassLoader)} or {@link #derive(int, int)}.
|
||||||
|
* Otherwise {@code -1} is returned.
|
||||||
|
* <p>
|
||||||
|
* To get the painted icon width, use {@link #getIconWidth()}.
|
||||||
|
*
|
||||||
|
* @since 1.2
|
||||||
|
*/
|
||||||
|
public int getWidth() {
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the custom icon height specified in {@link #FlatSVGIcon(String, int, int)},
|
||||||
|
* {@link #FlatSVGIcon(String, int, int, ClassLoader)} or {@link #derive(int, int)}.
|
||||||
|
* Otherwise {@code -1} is returned.
|
||||||
|
* <p>
|
||||||
|
* To get the painted icon height, use {@link #getIconHeight()}.
|
||||||
|
*
|
||||||
|
* @since 1.2
|
||||||
|
*/
|
||||||
|
public int getHeight() {
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the amount by which the icon size is scaled. Usually {@code 1}.
|
||||||
|
*
|
||||||
|
* @since 1.2
|
||||||
|
*/
|
||||||
|
public float getScale() {
|
||||||
|
return scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the icon is pained in "disabled" state.
|
||||||
|
*
|
||||||
|
* @see #getDisabledIcon()
|
||||||
|
* @since 1.2
|
||||||
|
*/
|
||||||
|
public boolean isDisabled() {
|
||||||
|
return disabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the class loader used to load the SVG resource.
|
||||||
|
*
|
||||||
|
* @since 1.2
|
||||||
|
*/
|
||||||
|
public ClassLoader getClassLoader() {
|
||||||
|
return classLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new icon with given width and height, which is derived from this icon.
|
* Creates a new icon with given width and height, which is derived from this icon.
|
||||||
|
* <p>
|
||||||
|
* If the icon has a color filter, then it is shared with the new icon.
|
||||||
*
|
*
|
||||||
* @param width the width of the new icon
|
* @param width the width of the new icon
|
||||||
* @param height the height of the new icon
|
* @param height the height of the new icon
|
||||||
@@ -179,7 +248,8 @@ public class FlatSVGIcon
|
|||||||
if( width == this.width && height == this.height )
|
if( width == this.width && height == this.height )
|
||||||
return this;
|
return this;
|
||||||
|
|
||||||
FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, false, classLoader );
|
FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, disabled, classLoader );
|
||||||
|
icon.colorFilter = colorFilter;
|
||||||
icon.diagram = diagram;
|
icon.diagram = diagram;
|
||||||
icon.dark = dark;
|
icon.dark = dark;
|
||||||
return icon;
|
return icon;
|
||||||
@@ -187,6 +257,8 @@ public class FlatSVGIcon
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new icon with given scaling, which is derived from this icon.
|
* Creates a new icon with given scaling, which is derived from this icon.
|
||||||
|
* <p>
|
||||||
|
* If the icon has a color filter, then it is shared with the new icon.
|
||||||
*
|
*
|
||||||
* @param scale the amount by which the icon size is scaled
|
* @param scale the amount by which the icon size is scaled
|
||||||
* @return a new icon
|
* @return a new icon
|
||||||
@@ -195,7 +267,8 @@ public class FlatSVGIcon
|
|||||||
if( scale == this.scale )
|
if( scale == this.scale )
|
||||||
return this;
|
return this;
|
||||||
|
|
||||||
FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, false, classLoader );
|
FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, disabled, classLoader );
|
||||||
|
icon.colorFilter = colorFilter;
|
||||||
icon.diagram = diagram;
|
icon.diagram = diagram;
|
||||||
icon.dark = dark;
|
icon.dark = dark;
|
||||||
return icon;
|
return icon;
|
||||||
@@ -203,6 +276,8 @@ public class FlatSVGIcon
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new icon with disabled appearance, which is derived from this icon.
|
* Creates a new icon with disabled appearance, which is derived from this icon.
|
||||||
|
* <p>
|
||||||
|
* If the icon has a color filter, then it is shared with the new icon.
|
||||||
*
|
*
|
||||||
* @return a new icon
|
* @return a new icon
|
||||||
*/
|
*/
|
||||||
@@ -212,11 +287,42 @@ public class FlatSVGIcon
|
|||||||
return this;
|
return this;
|
||||||
|
|
||||||
FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, true, classLoader );
|
FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, true, classLoader );
|
||||||
|
icon.colorFilter = colorFilter;
|
||||||
icon.diagram = diagram;
|
icon.diagram = diagram;
|
||||||
icon.dark = dark;
|
icon.dark = dark;
|
||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the currently active color filter or {@code null}.
|
||||||
|
*
|
||||||
|
* @since 1.2
|
||||||
|
*/
|
||||||
|
public ColorFilter getColorFilter() {
|
||||||
|
return colorFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a color filter that can freely modify colors of this icon during painting.
|
||||||
|
* <p>
|
||||||
|
* This method accepts a {@link ColorFilter}. Usually you would want to use a ColorFilter created using the
|
||||||
|
* {@link ColorFilter#ColorFilter(Function)} constructor.
|
||||||
|
* <p>
|
||||||
|
* This can be used to brighten colors of the icon:
|
||||||
|
* <pre>icon.setColorFilter( new FlatSVGIcon.ColorFilter( color -> color.brighter() ) );</pre>
|
||||||
|
* <p>
|
||||||
|
* Using a filter, icons can also be turned monochrome (painted with a single color):
|
||||||
|
* <pre>icon.setColorFilter( new FlatSVGIcon.ColorFilter( color -> Color.RED ) );</pre>
|
||||||
|
* <p>
|
||||||
|
* Note: If a filter is already set, it will be replaced.
|
||||||
|
*
|
||||||
|
* @param colorFilter The color filter
|
||||||
|
* @since 1.2
|
||||||
|
*/
|
||||||
|
public void setColorFilter( ColorFilter colorFilter ) {
|
||||||
|
this.colorFilter = colorFilter;
|
||||||
|
}
|
||||||
|
|
||||||
private void update() {
|
private void update() {
|
||||||
if( dark == isDarkLaf() && diagram != null )
|
if( dark == isDarkLaf() && diagram != null )
|
||||||
return;
|
return;
|
||||||
@@ -230,7 +336,7 @@ public class FlatSVGIcon
|
|||||||
try {
|
try {
|
||||||
diagram = svgUniverse.getDiagram( url.toURI() );
|
diagram = svgUniverse.getDiagram( url.toURI() );
|
||||||
} catch( URISyntaxException ex ) {
|
} catch( URISyntaxException ex ) {
|
||||||
ex.printStackTrace();
|
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to load SVG icon '" + url + "'.", ex );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -303,7 +409,7 @@ public class FlatSVGIcon
|
|||||||
: GrayFilter.createDisabledIconFilter( dark );
|
: GrayFilter.createDisabledIconFilter( dark );
|
||||||
}
|
}
|
||||||
|
|
||||||
Graphics2D g2 = new GraphicsFilter( (Graphics2D) g.create(), ColorFilter.getInstance(), grayFilter );
|
Graphics2D g2 = new GraphicsFilter( (Graphics2D) g.create(), colorFilter, ColorFilter.getInstance(), grayFilter );
|
||||||
|
|
||||||
try {
|
try {
|
||||||
FlatUIUtils.setRenderingHints( g2 );
|
FlatUIUtils.setRenderingHints( g2 );
|
||||||
@@ -383,7 +489,14 @@ public class FlatSVGIcon
|
|||||||
|
|
||||||
private static Boolean darkLaf;
|
private static Boolean darkLaf;
|
||||||
|
|
||||||
private static boolean isDarkLaf() {
|
/**
|
||||||
|
* Checks whether the current look and feel is dark.
|
||||||
|
* <p>
|
||||||
|
* Uses {@link FlatLaf#isLafDark()} and caches the result.
|
||||||
|
*
|
||||||
|
* @since 1.2
|
||||||
|
*/
|
||||||
|
public static boolean isDarkLaf() {
|
||||||
if( darkLaf == null ) {
|
if( darkLaf == null ) {
|
||||||
lafChanged();
|
lafChanged();
|
||||||
|
|
||||||
@@ -401,53 +514,253 @@ public class FlatSVGIcon
|
|||||||
|
|
||||||
//---- class ColorFilter --------------------------------------------------
|
//---- class ColorFilter --------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A color filter that can modify colors of a painted {@link FlatSVGIcon}.
|
||||||
|
* <p>
|
||||||
|
* The ColorFilter modifies color in two ways.
|
||||||
|
* Either using a color map, where specific colors are mapped to different ones.
|
||||||
|
* And/or by modifying the colors in a mapper function.
|
||||||
|
* <p>
|
||||||
|
* When filtering a color, mappings are applied first, then the mapper function is applied.
|
||||||
|
* <p>
|
||||||
|
* Global {@link FlatSVGIcon} ColorFilter can be retrieved using the {@link ColorFilter#getInstance()} method.
|
||||||
|
*/
|
||||||
public static class ColorFilter
|
public static class ColorFilter
|
||||||
{
|
{
|
||||||
private static ColorFilter instance;
|
private static ColorFilter instance;
|
||||||
|
|
||||||
private final Map<Integer, String> rgb2keyMap = new HashMap<>();
|
private Map<Integer, String> rgb2keyMap;
|
||||||
private final Map<Color, Color> color2colorMap = new HashMap<>();
|
private Map<Color, Color> colorMap;
|
||||||
|
private Map<Color, Color> darkColorMap;
|
||||||
|
private Function<Color, Color> mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the global ColorFilter that is applied to all icons.
|
||||||
|
*/
|
||||||
public static ColorFilter getInstance() {
|
public static ColorFilter getInstance() {
|
||||||
if( instance == null )
|
if( instance == null ) {
|
||||||
instance = new ColorFilter();
|
instance = new ColorFilter();
|
||||||
|
|
||||||
|
// add default color palette
|
||||||
|
instance.rgb2keyMap = new HashMap<>();
|
||||||
|
for( FlatIconColors c : FlatIconColors.values() )
|
||||||
|
instance.rgb2keyMap.put( c.rgb, c.key );
|
||||||
|
}
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an empty color filter.
|
||||||
|
*/
|
||||||
public ColorFilter() {
|
public ColorFilter() {
|
||||||
for( FlatIconColors c : FlatIconColors.values() )
|
|
||||||
rgb2keyMap.put( c.rgb, c.key );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addAll( Map<Color, Color> from2toMap ) {
|
/**
|
||||||
color2colorMap.putAll( from2toMap );
|
* Creates a color filter with a color modifying function that changes painted colors.
|
||||||
|
* The {@link Function} gets passed the original color and returns a modified one.
|
||||||
|
* <p>
|
||||||
|
* Examples:
|
||||||
|
* A ColorFilter can be used to brighten colors of the icon:
|
||||||
|
* <pre>new ColorFilter( color -> color.brighter() );</pre>
|
||||||
|
* <p>
|
||||||
|
* Using a ColorFilter, icons can also be turned monochrome (painted with a single color):
|
||||||
|
* <pre>new ColorFilter( color -> Color.RED );</pre>
|
||||||
|
*
|
||||||
|
* @param mapper The color mapper function
|
||||||
|
* @since 1.2
|
||||||
|
*/
|
||||||
|
public ColorFilter( Function<Color, Color> mapper ) {
|
||||||
|
setMapper( mapper );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add( Color from, Color to ) {
|
/**
|
||||||
color2colorMap.put( from, to );
|
* Returns a color modifying function or {@code null}
|
||||||
|
*
|
||||||
|
* @since 1.2
|
||||||
|
*/
|
||||||
|
public Function<Color, Color> getMapper() {
|
||||||
|
return mapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void remove( Color from ) {
|
/**
|
||||||
color2colorMap.remove( from );
|
* Sets a color modifying function that changes painted colors.
|
||||||
|
* The {@link Function} gets passed the original color and returns a modified one.
|
||||||
|
* <p>
|
||||||
|
* Examples:
|
||||||
|
* A ColorFilter can be used to brighten colors of the icon:
|
||||||
|
* <pre>filter.setMapper( color -> color.brighter() );</pre>
|
||||||
|
* <p>
|
||||||
|
* Using a ColorFilter, icons can also be turned monochrome (painted with a single color):
|
||||||
|
* <pre>filter.setMapper( color -> Color.RED );</pre>
|
||||||
|
*
|
||||||
|
* @param mapper The color mapper function
|
||||||
|
* @since 1.2
|
||||||
|
*/
|
||||||
|
public void setMapper( Function<Color, Color> mapper ) {
|
||||||
|
this.mapper = mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the color mappings used for light themes.
|
||||||
|
*
|
||||||
|
* @since 1.2
|
||||||
|
*/
|
||||||
|
public Map<Color, Color> getLightColorMap() {
|
||||||
|
return (colorMap != null)
|
||||||
|
? Collections.unmodifiableMap( colorMap )
|
||||||
|
: Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the color mappings used for dark themes.
|
||||||
|
*
|
||||||
|
* @since 1.2
|
||||||
|
*/
|
||||||
|
public Map<Color, Color> getDarkColorMap() {
|
||||||
|
return (darkColorMap != null)
|
||||||
|
? Collections.unmodifiableMap( darkColorMap )
|
||||||
|
: getLightColorMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds color mappings. Used for light and dark themes.
|
||||||
|
*/
|
||||||
|
public ColorFilter addAll( Map<Color, Color> from2toMap ) {
|
||||||
|
ensureColorMap();
|
||||||
|
|
||||||
|
colorMap.putAll( from2toMap );
|
||||||
|
if( darkColorMap != null )
|
||||||
|
darkColorMap.putAll( from2toMap );
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a color mappings, which has different colors for light and dark themes.
|
||||||
|
*
|
||||||
|
* @since 1.2
|
||||||
|
*/
|
||||||
|
public ColorFilter addAll( Map<Color, Color> from2toLightMap, Map<Color, Color> from2toDarkMap ) {
|
||||||
|
ensureColorMap();
|
||||||
|
ensureDarkColorMap();
|
||||||
|
|
||||||
|
colorMap.putAll( from2toLightMap );
|
||||||
|
darkColorMap.putAll( from2toDarkMap );
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a color mapping. Used for light and dark themes.
|
||||||
|
*/
|
||||||
|
public ColorFilter add( Color from, Color to ) {
|
||||||
|
ensureColorMap();
|
||||||
|
|
||||||
|
colorMap.put( from, to );
|
||||||
|
if( darkColorMap != null )
|
||||||
|
darkColorMap.put( from, to );
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a color mapping, which has different colors for light and dark themes.
|
||||||
|
*
|
||||||
|
* @since 1.2
|
||||||
|
*/
|
||||||
|
public ColorFilter add( Color from, Color toLight, Color toDark ) {
|
||||||
|
ensureColorMap();
|
||||||
|
ensureDarkColorMap();
|
||||||
|
|
||||||
|
if( toLight != null )
|
||||||
|
colorMap.put( from, toLight );
|
||||||
|
if( toDark != null )
|
||||||
|
darkColorMap.put( from, toDark );
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a specific color mapping.
|
||||||
|
*/
|
||||||
|
public ColorFilter remove( Color from ) {
|
||||||
|
if( colorMap != null )
|
||||||
|
colorMap.remove( from );
|
||||||
|
if( darkColorMap != null )
|
||||||
|
darkColorMap.remove( from );
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all color mappings.
|
||||||
|
*
|
||||||
|
* @since 1.2
|
||||||
|
*/
|
||||||
|
public ColorFilter removeAll() {
|
||||||
|
colorMap = null;
|
||||||
|
darkColorMap = null;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureColorMap() {
|
||||||
|
if( colorMap == null )
|
||||||
|
colorMap = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureDarkColorMap() {
|
||||||
|
if( darkColorMap == null )
|
||||||
|
darkColorMap = new HashMap<>( colorMap );
|
||||||
}
|
}
|
||||||
|
|
||||||
public Color filter( Color color ) {
|
public Color filter( Color color ) {
|
||||||
Color newColor = color2colorMap.get( color );
|
// apply mappings
|
||||||
if( newColor != null )
|
color = applyMappings( color );
|
||||||
return newColor;
|
|
||||||
|
|
||||||
String colorKey = rgb2keyMap.get( color.getRGB() & 0xffffff );
|
// apply mapper function
|
||||||
if( colorKey == null )
|
if( mapper != null )
|
||||||
return color;
|
color = mapper.apply( color );
|
||||||
|
|
||||||
newColor = UIManager.getColor( colorKey );
|
return color;
|
||||||
if( newColor == null )
|
|
||||||
return color;
|
|
||||||
|
|
||||||
return (newColor.getAlpha() != color.getAlpha())
|
|
||||||
? new Color( (newColor.getRGB() & 0x00ffffff) | (color.getRGB() & 0xff000000) )
|
|
||||||
: newColor;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private Color applyMappings( Color color ) {
|
||||||
|
if( colorMap != null ) {
|
||||||
|
Map<Color, Color> map = (darkColorMap != null && isDarkLaf()) ? darkColorMap : colorMap;
|
||||||
|
Color newColor = map.get( color );
|
||||||
|
if( newColor != null )
|
||||||
|
return newColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( rgb2keyMap != null ) {
|
||||||
|
// RGB is mapped to a key in UI defaults, which contains the real color.
|
||||||
|
// IntelliJ themes define such theme specific icon colors in .theme.json files.
|
||||||
|
String colorKey = rgb2keyMap.get( color.getRGB() & 0xffffff );
|
||||||
|
if( colorKey == null )
|
||||||
|
return color;
|
||||||
|
|
||||||
|
Color newColor = UIManager.getColor( colorKey );
|
||||||
|
if( newColor == null )
|
||||||
|
return color;
|
||||||
|
|
||||||
|
// preserve alpha of original color
|
||||||
|
return (newColor.getAlpha() != color.getAlpha())
|
||||||
|
? new Color( (newColor.getRGB() & 0x00ffffff) | (color.getRGB() & 0xff000000) )
|
||||||
|
: newColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a color modifying function that uses {@link RGBImageFilter#filterRGB(int, int, int)}.
|
||||||
|
* Can be set to a {@link ColorFilter} using {@link ColorFilter#setMapper(Function)}.
|
||||||
|
*
|
||||||
|
* @see GrayFilter
|
||||||
|
* @since 1.2
|
||||||
|
*/
|
||||||
|
public static Function<Color, Color> createRGBImageFilterFunction( RGBImageFilter rgbImageFilter ) {
|
||||||
|
return color -> {
|
||||||
|
int oldRGB = color.getRGB();
|
||||||
|
int newRGB = rgbImageFilter.filterRGB( 0, 0, oldRGB );
|
||||||
|
return (newRGB != oldRGB) ? new Color( newRGB, true ) : color;
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//---- class GraphicsFilter -----------------------------------------------
|
//---- class GraphicsFilter -----------------------------------------------
|
||||||
@@ -456,11 +769,15 @@ public class FlatSVGIcon
|
|||||||
extends Graphics2DProxy
|
extends Graphics2DProxy
|
||||||
{
|
{
|
||||||
private final ColorFilter colorFilter;
|
private final ColorFilter colorFilter;
|
||||||
|
private final ColorFilter globalColorFilter;
|
||||||
private final RGBImageFilter grayFilter;
|
private final RGBImageFilter grayFilter;
|
||||||
|
|
||||||
public GraphicsFilter( Graphics2D delegate, ColorFilter colorFilter, RGBImageFilter grayFilter ) {
|
GraphicsFilter( Graphics2D delegate, ColorFilter colorFilter,
|
||||||
|
ColorFilter globalColorFilter, RGBImageFilter grayFilter )
|
||||||
|
{
|
||||||
super( delegate );
|
super( delegate );
|
||||||
this.colorFilter = colorFilter;
|
this.colorFilter = colorFilter;
|
||||||
|
this.globalColorFilter = globalColorFilter;
|
||||||
this.grayFilter = grayFilter;
|
this.grayFilter = grayFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -477,8 +794,14 @@ public class FlatSVGIcon
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Color filterColor( Color color ) {
|
private Color filterColor( Color color ) {
|
||||||
if( colorFilter != null )
|
if( colorFilter != null ) {
|
||||||
color = colorFilter.filter( color );
|
Color newColor = colorFilter.filter( color );
|
||||||
|
color = (newColor != color)
|
||||||
|
? newColor
|
||||||
|
: globalColorFilter.filter( color );
|
||||||
|
} else
|
||||||
|
color = globalColorFilter.filter( color );
|
||||||
|
|
||||||
if( grayFilter != null ) {
|
if( grayFilter != null ) {
|
||||||
int oldRGB = color.getRGB();
|
int oldRGB = color.getRGB();
|
||||||
int newRGB = grayFilter.filterRGB( 0, 0, oldRGB );
|
int newRGB = grayFilter.filterRGB( 0, 0, oldRGB );
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.formdev.flatlaf.extras;
|
package com.formdev.flatlaf.extras;
|
||||||
|
|
||||||
|
import java.awt.Dimension;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.Image;
|
import java.awt.Image;
|
||||||
import java.awt.RenderingHints;
|
import java.awt.RenderingHints;
|
||||||
@@ -23,8 +24,11 @@ import java.awt.image.BufferedImage;
|
|||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.swing.JWindow;
|
import javax.swing.JWindow;
|
||||||
|
import com.formdev.flatlaf.util.MultiResolutionImageSupport;
|
||||||
|
import com.formdev.flatlaf.util.SystemInfo;
|
||||||
import com.kitfox.svg.SVGCache;
|
import com.kitfox.svg.SVGCache;
|
||||||
import com.kitfox.svg.SVGDiagram;
|
import com.kitfox.svg.SVGDiagram;
|
||||||
import com.kitfox.svg.SVGException;
|
import com.kitfox.svg.SVGException;
|
||||||
@@ -40,22 +44,51 @@ public class FlatSVGUtils
|
|||||||
* Creates from the given SVG a list of icon images with different sizes that
|
* Creates from the given SVG a list of icon images with different sizes that
|
||||||
* can be used for windows headers. The SVG should have a size of 16x16,
|
* can be used for windows headers. The SVG should have a size of 16x16,
|
||||||
* otherwise it is scaled.
|
* otherwise it is scaled.
|
||||||
|
* <p>
|
||||||
|
* If running on Windows in Java 9 or later and multi-resolution image support is available,
|
||||||
|
* then a single multi-resolution image is returned that creates images on demand
|
||||||
|
* for requested sizes from SVG.
|
||||||
|
* This has the advantage that only images for used sizes are created.
|
||||||
|
* Also if unusual sizes are requested (e.g. 18x18), then they are created from SVG.
|
||||||
*
|
*
|
||||||
* @param svgName the name of the SVG resource (a '/'-separated path)
|
* @param svgName the name of the SVG resource (a '/'-separated path)
|
||||||
* @return list of icon images with different sizes (16x16, 24x24, 32x32, 48x48 and 64x64)
|
* @return list of icon images with different sizes (16x16, 20x20, 24x24, 28x28, 32x32, 48x48 and 64x64)
|
||||||
* @throws RuntimeException if failed to load or render SVG file
|
* @throws RuntimeException if failed to load or render SVG file
|
||||||
* @see JWindow#setIconImages(List)
|
* @see JWindow#setIconImages(List)
|
||||||
*/
|
*/
|
||||||
public static List<Image> createWindowIconImages( String svgName ) {
|
public static List<Image> createWindowIconImages( String svgName ) {
|
||||||
SVGDiagram diagram = loadSVG( svgName );
|
SVGDiagram diagram = loadSVG( svgName );
|
||||||
|
|
||||||
return Arrays.asList(
|
if( SystemInfo.isWindows && MultiResolutionImageSupport.isAvailable() ) {
|
||||||
svg2image( diagram, 16, 16 ),
|
// use a multi-resolution image that creates images on demand for requested sizes
|
||||||
svg2image( diagram, 24, 24 ),
|
return Collections.singletonList( MultiResolutionImageSupport.create( 0,
|
||||||
svg2image( diagram, 32, 32 ),
|
new Dimension[] {
|
||||||
svg2image( diagram, 48, 48 ),
|
// Listing all these sizes here is actually not necessary because
|
||||||
svg2image( diagram, 64, 64 )
|
// any size is created on demand when
|
||||||
);
|
// MultiResolutionImage.getResolutionVariant(double destImageWidth, double destImageHeight)
|
||||||
|
// is invoked.
|
||||||
|
// This sizes are only used by MultiResolutionImage.getResolutionVariants().
|
||||||
|
new Dimension( 16, 16 ), // 100%
|
||||||
|
new Dimension( 20, 20 ), // 125%
|
||||||
|
new Dimension( 24, 24 ), // 150%
|
||||||
|
new Dimension( 28, 28 ), // 175%
|
||||||
|
new Dimension( 32, 32 ), // 200%
|
||||||
|
new Dimension( 48, 48 ), // 300%
|
||||||
|
new Dimension( 64, 64 ), // 400%
|
||||||
|
}, dim -> {
|
||||||
|
return svg2image( diagram, dim.width, dim.height );
|
||||||
|
} ) );
|
||||||
|
} else {
|
||||||
|
return Arrays.asList(
|
||||||
|
svg2image( diagram, 16, 16 ), // 100%
|
||||||
|
svg2image( diagram, 20, 20 ), // 125%
|
||||||
|
svg2image( diagram, 24, 24 ), // 150%
|
||||||
|
svg2image( diagram, 28, 28 ), // 175%
|
||||||
|
svg2image( diagram, 32, 32 ), // 200%
|
||||||
|
svg2image( diagram, 48, 48 ), // 300%
|
||||||
|
svg2image( diagram, 64, 64 ) // 400%
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
|||||||
import com.formdev.flatlaf.util.DerivedColor;
|
import com.formdev.flatlaf.util.DerivedColor;
|
||||||
import com.formdev.flatlaf.util.GrayFilter;
|
import com.formdev.flatlaf.util.GrayFilter;
|
||||||
import com.formdev.flatlaf.util.HSLColor;
|
import com.formdev.flatlaf.util.HSLColor;
|
||||||
|
import com.formdev.flatlaf.util.LoggingFacade;
|
||||||
import com.formdev.flatlaf.util.ScaledEmptyBorder;
|
import com.formdev.flatlaf.util.ScaledEmptyBorder;
|
||||||
import com.formdev.flatlaf.util.UIScale;
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
|
|
||||||
@@ -377,11 +378,12 @@ public class FlatUIDefaultsInspector
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Properties loadDerivedColorKeys() {
|
private Properties loadDerivedColorKeys() {
|
||||||
|
String name = "/com/formdev/flatlaf/extras/resources/DerivedColorKeys.properties";
|
||||||
Properties properties = new Properties();
|
Properties properties = new Properties();
|
||||||
try( InputStream in = getClass().getResourceAsStream( "/com/formdev/flatlaf/extras/resources/DerivedColorKeys.properties" ) ) {
|
try( InputStream in = getClass().getResourceAsStream( name ) ) {
|
||||||
properties.load( in );
|
properties.load( in );
|
||||||
} catch( IOException ex ) {
|
} catch( IOException ex ) {
|
||||||
ex.printStackTrace();
|
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to load '" + name + "'.", ex );
|
||||||
}
|
}
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ public class FlatButton
|
|||||||
implements FlatComponentExtension
|
implements FlatComponentExtension
|
||||||
{
|
{
|
||||||
// NOTE: enum names must be equal to allowed strings
|
// NOTE: enum names must be equal to allowed strings
|
||||||
public enum ButtonType { none, square, roundRect, tab, help, toolBarButton };
|
public enum ButtonType { none, square, roundRect, tab, help, toolBarButton, borderless }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns type of a button.
|
* Returns type of a button.
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import java.awt.Color;
|
|||||||
import java.awt.Insets;
|
import java.awt.Insets;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
|
import com.formdev.flatlaf.util.LoggingFacade;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base interface for all FlatLaf component extensions.
|
* Base interface for all FlatLaf component extensions.
|
||||||
@@ -87,7 +88,7 @@ public interface FlatComponentExtension
|
|||||||
try {
|
try {
|
||||||
return Enum.valueOf( enumType, (String) value );
|
return Enum.valueOf( enumType, (String) value );
|
||||||
} catch( IllegalArgumentException ex ) {
|
} catch( IllegalArgumentException ex ) {
|
||||||
ex.printStackTrace();
|
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Unknown enum value '" + value + "' in enum '" + enumType.getName() + "'.", ex );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package com.formdev.flatlaf.extras.components;
|
|||||||
|
|
||||||
import static com.formdev.flatlaf.FlatClientProperties.*;
|
import static com.formdev.flatlaf.FlatClientProperties.*;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
import java.awt.Insets;
|
||||||
import javax.swing.JFormattedTextField;
|
import javax.swing.JFormattedTextField;
|
||||||
import com.formdev.flatlaf.extras.components.FlatTextField.SelectAllOnFocusPolicy;
|
import com.formdev.flatlaf.extras.components.FlatTextField.SelectAllOnFocusPolicy;
|
||||||
|
|
||||||
@@ -61,6 +62,27 @@ public class FlatFormattedTextField
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the padding of the text.
|
||||||
|
*
|
||||||
|
* @since 1.4
|
||||||
|
*/
|
||||||
|
public Insets getPadding() {
|
||||||
|
return (Insets) getClientProperty( TEXT_FIELD_PADDING );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the padding of the text.
|
||||||
|
* This changes the location and size of the text view within the component bounds,
|
||||||
|
* but does not affect the size of the component.
|
||||||
|
*
|
||||||
|
* @since 1.4
|
||||||
|
*/
|
||||||
|
public void setPadding( Insets padding ) {
|
||||||
|
putClientProperty( TEXT_FIELD_PADDING, padding );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns minimum width of a component.
|
* Returns minimum width of a component.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package com.formdev.flatlaf.extras.components;
|
|||||||
|
|
||||||
import static com.formdev.flatlaf.FlatClientProperties.*;
|
import static com.formdev.flatlaf.FlatClientProperties.*;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
import java.awt.Insets;
|
||||||
import javax.swing.JPasswordField;
|
import javax.swing.JPasswordField;
|
||||||
import com.formdev.flatlaf.extras.components.FlatTextField.SelectAllOnFocusPolicy;
|
import com.formdev.flatlaf.extras.components.FlatTextField.SelectAllOnFocusPolicy;
|
||||||
|
|
||||||
@@ -61,6 +62,27 @@ public class FlatPasswordField
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the padding of the text.
|
||||||
|
*
|
||||||
|
* @since 1.4
|
||||||
|
*/
|
||||||
|
public Insets getPadding() {
|
||||||
|
return (Insets) getClientProperty( TEXT_FIELD_PADDING );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the padding of the text.
|
||||||
|
* This changes the location and size of the text view within the component bounds,
|
||||||
|
* but does not affect the size of the component.
|
||||||
|
*
|
||||||
|
* @since 1.4
|
||||||
|
*/
|
||||||
|
public void setPadding( Insets padding ) {
|
||||||
|
putClientProperty( TEXT_FIELD_PADDING, padding );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns minimum width of a component.
|
* Returns minimum width of a component.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package com.formdev.flatlaf.extras.components;
|
|||||||
|
|
||||||
import static com.formdev.flatlaf.FlatClientProperties.*;
|
import static com.formdev.flatlaf.FlatClientProperties.*;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
import java.awt.Insets;
|
||||||
import javax.swing.JTextField;
|
import javax.swing.JTextField;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -63,6 +64,27 @@ public class FlatTextField
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the padding of the text.
|
||||||
|
*
|
||||||
|
* @since 1.4
|
||||||
|
*/
|
||||||
|
public Insets getPadding() {
|
||||||
|
return (Insets) getClientProperty( TEXT_FIELD_PADDING );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the padding of the text.
|
||||||
|
* This changes the location and size of the text view within the component bounds,
|
||||||
|
* but does not affect the size of the component.
|
||||||
|
*
|
||||||
|
* @since 1.4
|
||||||
|
*/
|
||||||
|
public void setPadding( Insets padding ) {
|
||||||
|
putClientProperty( TEXT_FIELD_PADDING, padding );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns minimum width of a component.
|
* Returns minimum width of a component.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -88,6 +88,11 @@ ComboBox.buttonPressedArrowColor = ComboBox.buttonArrowColor
|
|||||||
Component.custom.borderColor = null
|
Component.custom.borderColor = null
|
||||||
|
|
||||||
|
|
||||||
|
#---- HelpButton ----
|
||||||
|
|
||||||
|
DesktopIcon.background = Desktop.background
|
||||||
|
|
||||||
|
|
||||||
#---- HelpButton ----
|
#---- HelpButton ----
|
||||||
|
|
||||||
HelpButton.disabledBackground = HelpButton.background
|
HelpButton.disabledBackground = HelpButton.background
|
||||||
|
|||||||
@@ -86,6 +86,8 @@ Name | Class
|
|||||||
[Dracula Contrast (Material)](https://github.com/mallowigi/material-theme-ui-lite) | `com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatDraculaContrastIJTheme`
|
[Dracula Contrast (Material)](https://github.com/mallowigi/material-theme-ui-lite) | `com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatDraculaContrastIJTheme`
|
||||||
[GitHub (Material)](https://github.com/mallowigi/material-theme-ui-lite) | `com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatGitHubIJTheme`
|
[GitHub (Material)](https://github.com/mallowigi/material-theme-ui-lite) | `com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatGitHubIJTheme`
|
||||||
[GitHub Contrast (Material)](https://github.com/mallowigi/material-theme-ui-lite) | `com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatGitHubContrastIJTheme`
|
[GitHub Contrast (Material)](https://github.com/mallowigi/material-theme-ui-lite) | `com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatGitHubContrastIJTheme`
|
||||||
|
[GitHub Dark (Material)](https://github.com/mallowigi/material-theme-ui-lite) | `com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatGitHubDarkIJTheme`
|
||||||
|
[GitHub Dark Contrast (Material)](https://github.com/mallowigi/material-theme-ui-lite) | `com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatGitHubDarkContrastIJTheme`
|
||||||
[Light Owl (Material)](https://github.com/mallowigi/material-theme-ui-lite) | `com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatLightOwlIJTheme`
|
[Light Owl (Material)](https://github.com/mallowigi/material-theme-ui-lite) | `com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatLightOwlIJTheme`
|
||||||
[Light Owl Contrast (Material)](https://github.com/mallowigi/material-theme-ui-lite) | `com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatLightOwlContrastIJTheme`
|
[Light Owl Contrast (Material)](https://github.com/mallowigi/material-theme-ui-lite) | `com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatLightOwlContrastIJTheme`
|
||||||
[Material Darker (Material)](https://github.com/mallowigi/material-theme-ui-lite) | `com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatMaterialDarkerIJTheme`
|
[Material Darker (Material)](https://github.com/mallowigi/material-theme-ui-lite) | `com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatMaterialDarkerIJTheme`
|
||||||
|
|||||||
@@ -33,17 +33,6 @@ java {
|
|||||||
withJavadocJar()
|
withJavadocJar()
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks {
|
|
||||||
javadoc {
|
|
||||||
options {
|
|
||||||
this as StandardJavadocDocletOptions
|
|
||||||
use( true )
|
|
||||||
tags = listOf( "uiDefault", "clientProperty" )
|
|
||||||
}
|
|
||||||
isFailOnError = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
flatlafPublish {
|
flatlafPublish {
|
||||||
artifactId = "flatlaf-intellij-themes"
|
artifactId = "flatlaf-intellij-themes"
|
||||||
name = "FlatLaf IntelliJ Themes Pack"
|
name = "FlatLaf IntelliJ Themes Pack"
|
||||||
|
|||||||
@@ -68,6 +68,8 @@ public class FlatAllIJThemes
|
|||||||
new FlatIJLookAndFeelInfo( "Dracula Contrast (Material)", "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatDraculaContrastIJTheme", true ),
|
new FlatIJLookAndFeelInfo( "Dracula Contrast (Material)", "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatDraculaContrastIJTheme", true ),
|
||||||
new FlatIJLookAndFeelInfo( "GitHub (Material)", "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatGitHubIJTheme", false ),
|
new FlatIJLookAndFeelInfo( "GitHub (Material)", "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatGitHubIJTheme", false ),
|
||||||
new FlatIJLookAndFeelInfo( "GitHub Contrast (Material)", "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatGitHubContrastIJTheme", false ),
|
new FlatIJLookAndFeelInfo( "GitHub Contrast (Material)", "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatGitHubContrastIJTheme", false ),
|
||||||
|
new FlatIJLookAndFeelInfo( "GitHub Dark (Material)", "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatGitHubDarkIJTheme", true ),
|
||||||
|
new FlatIJLookAndFeelInfo( "GitHub Dark Contrast (Material)", "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatGitHubDarkContrastIJTheme", true ),
|
||||||
new FlatIJLookAndFeelInfo( "Light Owl (Material)", "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatLightOwlIJTheme", false ),
|
new FlatIJLookAndFeelInfo( "Light Owl (Material)", "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatLightOwlIJTheme", false ),
|
||||||
new FlatIJLookAndFeelInfo( "Light Owl Contrast (Material)", "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatLightOwlContrastIJTheme", false ),
|
new FlatIJLookAndFeelInfo( "Light Owl Contrast (Material)", "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatLightOwlContrastIJTheme", false ),
|
||||||
new FlatIJLookAndFeelInfo( "Material Darker (Material)", "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatMaterialDarkerIJTheme", true ),
|
new FlatIJLookAndFeelInfo( "Material Darker (Material)", "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatMaterialDarkerIJTheme", true ),
|
||||||
|
|||||||
@@ -31,14 +31,22 @@ public class FlatArcDarkIJTheme
|
|||||||
{
|
{
|
||||||
public static final String NAME = "Arc Dark";
|
public static final String NAME = "Arc Dark";
|
||||||
|
|
||||||
public static boolean install() {
|
public static boolean setup() {
|
||||||
try {
|
try {
|
||||||
return install( new FlatArcDarkIJTheme() );
|
return setup( new FlatArcDarkIJTheme() );
|
||||||
} catch( RuntimeException ex ) {
|
} catch( RuntimeException ex ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public static boolean install() {
|
||||||
|
return setup();
|
||||||
|
}
|
||||||
|
|
||||||
public static void installLafInfo() {
|
public static void installLafInfo() {
|
||||||
installLafInfo( NAME, FlatArcDarkIJTheme.class );
|
installLafInfo( NAME, FlatArcDarkIJTheme.class );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,14 +31,22 @@ public class FlatArcDarkOrangeIJTheme
|
|||||||
{
|
{
|
||||||
public static final String NAME = "Arc Dark - Orange";
|
public static final String NAME = "Arc Dark - Orange";
|
||||||
|
|
||||||
public static boolean install() {
|
public static boolean setup() {
|
||||||
try {
|
try {
|
||||||
return install( new FlatArcDarkOrangeIJTheme() );
|
return setup( new FlatArcDarkOrangeIJTheme() );
|
||||||
} catch( RuntimeException ex ) {
|
} catch( RuntimeException ex ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public static boolean install() {
|
||||||
|
return setup();
|
||||||
|
}
|
||||||
|
|
||||||
public static void installLafInfo() {
|
public static void installLafInfo() {
|
||||||
installLafInfo( NAME, FlatArcDarkOrangeIJTheme.class );
|
installLafInfo( NAME, FlatArcDarkOrangeIJTheme.class );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,14 +31,22 @@ public class FlatArcIJTheme
|
|||||||
{
|
{
|
||||||
public static final String NAME = "Arc";
|
public static final String NAME = "Arc";
|
||||||
|
|
||||||
public static boolean install() {
|
public static boolean setup() {
|
||||||
try {
|
try {
|
||||||
return install( new FlatArcIJTheme() );
|
return setup( new FlatArcIJTheme() );
|
||||||
} catch( RuntimeException ex ) {
|
} catch( RuntimeException ex ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public static boolean install() {
|
||||||
|
return setup();
|
||||||
|
}
|
||||||
|
|
||||||
public static void installLafInfo() {
|
public static void installLafInfo() {
|
||||||
installLafInfo( NAME, FlatArcIJTheme.class );
|
installLafInfo( NAME, FlatArcIJTheme.class );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,14 +31,22 @@ public class FlatArcOrangeIJTheme
|
|||||||
{
|
{
|
||||||
public static final String NAME = "Arc - Orange";
|
public static final String NAME = "Arc - Orange";
|
||||||
|
|
||||||
public static boolean install() {
|
public static boolean setup() {
|
||||||
try {
|
try {
|
||||||
return install( new FlatArcOrangeIJTheme() );
|
return setup( new FlatArcOrangeIJTheme() );
|
||||||
} catch( RuntimeException ex ) {
|
} catch( RuntimeException ex ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public static boolean install() {
|
||||||
|
return setup();
|
||||||
|
}
|
||||||
|
|
||||||
public static void installLafInfo() {
|
public static void installLafInfo() {
|
||||||
installLafInfo( NAME, FlatArcOrangeIJTheme.class );
|
installLafInfo( NAME, FlatArcOrangeIJTheme.class );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,14 +31,22 @@ public class FlatCarbonIJTheme
|
|||||||
{
|
{
|
||||||
public static final String NAME = "Carbon";
|
public static final String NAME = "Carbon";
|
||||||
|
|
||||||
public static boolean install() {
|
public static boolean setup() {
|
||||||
try {
|
try {
|
||||||
return install( new FlatCarbonIJTheme() );
|
return setup( new FlatCarbonIJTheme() );
|
||||||
} catch( RuntimeException ex ) {
|
} catch( RuntimeException ex ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public static boolean install() {
|
||||||
|
return setup();
|
||||||
|
}
|
||||||
|
|
||||||
public static void installLafInfo() {
|
public static void installLafInfo() {
|
||||||
installLafInfo( NAME, FlatCarbonIJTheme.class );
|
installLafInfo( NAME, FlatCarbonIJTheme.class );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,14 +31,22 @@ public class FlatCobalt2IJTheme
|
|||||||
{
|
{
|
||||||
public static final String NAME = "Cobalt 2";
|
public static final String NAME = "Cobalt 2";
|
||||||
|
|
||||||
public static boolean install() {
|
public static boolean setup() {
|
||||||
try {
|
try {
|
||||||
return install( new FlatCobalt2IJTheme() );
|
return setup( new FlatCobalt2IJTheme() );
|
||||||
} catch( RuntimeException ex ) {
|
} catch( RuntimeException ex ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public static boolean install() {
|
||||||
|
return setup();
|
||||||
|
}
|
||||||
|
|
||||||
public static void installLafInfo() {
|
public static void installLafInfo() {
|
||||||
installLafInfo( NAME, FlatCobalt2IJTheme.class );
|
installLafInfo( NAME, FlatCobalt2IJTheme.class );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,14 +31,22 @@ public class FlatCyanLightIJTheme
|
|||||||
{
|
{
|
||||||
public static final String NAME = "Cyan light";
|
public static final String NAME = "Cyan light";
|
||||||
|
|
||||||
public static boolean install() {
|
public static boolean setup() {
|
||||||
try {
|
try {
|
||||||
return install( new FlatCyanLightIJTheme() );
|
return setup( new FlatCyanLightIJTheme() );
|
||||||
} catch( RuntimeException ex ) {
|
} catch( RuntimeException ex ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public static boolean install() {
|
||||||
|
return setup();
|
||||||
|
}
|
||||||
|
|
||||||
public static void installLafInfo() {
|
public static void installLafInfo() {
|
||||||
installLafInfo( NAME, FlatCyanLightIJTheme.class );
|
installLafInfo( NAME, FlatCyanLightIJTheme.class );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,14 +31,22 @@ public class FlatDarkFlatIJTheme
|
|||||||
{
|
{
|
||||||
public static final String NAME = "Dark Flat";
|
public static final String NAME = "Dark Flat";
|
||||||
|
|
||||||
public static boolean install() {
|
public static boolean setup() {
|
||||||
try {
|
try {
|
||||||
return install( new FlatDarkFlatIJTheme() );
|
return setup( new FlatDarkFlatIJTheme() );
|
||||||
} catch( RuntimeException ex ) {
|
} catch( RuntimeException ex ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public static boolean install() {
|
||||||
|
return setup();
|
||||||
|
}
|
||||||
|
|
||||||
public static void installLafInfo() {
|
public static void installLafInfo() {
|
||||||
installLafInfo( NAME, FlatDarkFlatIJTheme.class );
|
installLafInfo( NAME, FlatDarkFlatIJTheme.class );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,14 +31,22 @@ public class FlatDarkPurpleIJTheme
|
|||||||
{
|
{
|
||||||
public static final String NAME = "Dark purple";
|
public static final String NAME = "Dark purple";
|
||||||
|
|
||||||
public static boolean install() {
|
public static boolean setup() {
|
||||||
try {
|
try {
|
||||||
return install( new FlatDarkPurpleIJTheme() );
|
return setup( new FlatDarkPurpleIJTheme() );
|
||||||
} catch( RuntimeException ex ) {
|
} catch( RuntimeException ex ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public static boolean install() {
|
||||||
|
return setup();
|
||||||
|
}
|
||||||
|
|
||||||
public static void installLafInfo() {
|
public static void installLafInfo() {
|
||||||
installLafInfo( NAME, FlatDarkPurpleIJTheme.class );
|
installLafInfo( NAME, FlatDarkPurpleIJTheme.class );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,14 +31,22 @@ public class FlatDraculaIJTheme
|
|||||||
{
|
{
|
||||||
public static final String NAME = "Dracula";
|
public static final String NAME = "Dracula";
|
||||||
|
|
||||||
public static boolean install() {
|
public static boolean setup() {
|
||||||
try {
|
try {
|
||||||
return install( new FlatDraculaIJTheme() );
|
return setup( new FlatDraculaIJTheme() );
|
||||||
} catch( RuntimeException ex ) {
|
} catch( RuntimeException ex ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public static boolean install() {
|
||||||
|
return setup();
|
||||||
|
}
|
||||||
|
|
||||||
public static void installLafInfo() {
|
public static void installLafInfo() {
|
||||||
installLafInfo( NAME, FlatDraculaIJTheme.class );
|
installLafInfo( NAME, FlatDraculaIJTheme.class );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,14 +31,22 @@ public class FlatGradiantoDarkFuchsiaIJTheme
|
|||||||
{
|
{
|
||||||
public static final String NAME = "Gradianto Dark Fuchsia";
|
public static final String NAME = "Gradianto Dark Fuchsia";
|
||||||
|
|
||||||
public static boolean install() {
|
public static boolean setup() {
|
||||||
try {
|
try {
|
||||||
return install( new FlatGradiantoDarkFuchsiaIJTheme() );
|
return setup( new FlatGradiantoDarkFuchsiaIJTheme() );
|
||||||
} catch( RuntimeException ex ) {
|
} catch( RuntimeException ex ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public static boolean install() {
|
||||||
|
return setup();
|
||||||
|
}
|
||||||
|
|
||||||
public static void installLafInfo() {
|
public static void installLafInfo() {
|
||||||
installLafInfo( NAME, FlatGradiantoDarkFuchsiaIJTheme.class );
|
installLafInfo( NAME, FlatGradiantoDarkFuchsiaIJTheme.class );
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user