mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2026-02-11 06:27:13 -06:00
Compare commits
113 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f842530537 | ||
|
|
63077bbb19 | ||
|
|
4dad337377 | ||
|
|
10a965d765 | ||
|
|
3e9c9c9066 | ||
|
|
8b5a738e65 | ||
|
|
2c041dce3a | ||
|
|
ef151c68f4 | ||
|
|
52feaac92a | ||
|
|
cddbb3d7d4 | ||
|
|
42764550e6 | ||
|
|
6ee737b314 | ||
|
|
f460ef7685 | ||
|
|
9977bcb468 | ||
|
|
7437d984c7 | ||
|
|
5cd0b2403c | ||
|
|
a372da22f3 | ||
|
|
8b10d3ba5a | ||
|
|
a8b15c6a12 | ||
|
|
23bac7e5fd | ||
|
|
b82ee2ef61 | ||
|
|
b7761f4b71 | ||
|
|
f9a4f9771c | ||
|
|
d2acb2c98a | ||
|
|
d60bd5df14 | ||
|
|
73b6ca3762 | ||
|
|
6c18431a30 | ||
|
|
a49d20249f | ||
|
|
ad384acd57 | ||
|
|
69851b7f3a | ||
|
|
92b53bf0df | ||
|
|
93e0496fd2 | ||
|
|
5151951f46 | ||
|
|
58dbccec2d | ||
|
|
90de14d013 | ||
|
|
5f961618bf | ||
|
|
37c375e2fa | ||
|
|
1758c175ed | ||
|
|
96f2a02cfa | ||
|
|
96d4bda6c8 | ||
|
|
02cf6050a1 | ||
|
|
38cf32a2e9 | ||
|
|
2ae7589d14 | ||
|
|
bcb2e1f0a1 | ||
|
|
14932d3f07 | ||
|
|
c3b9dc397d | ||
|
|
58b653f55d | ||
|
|
1dcdc42dde | ||
|
|
58a0a16985 | ||
|
|
a117243f14 | ||
|
|
22411060be | ||
|
|
045263ae58 | ||
|
|
024b6daaf6 | ||
|
|
bd5512c121 | ||
|
|
9afce83a02 | ||
|
|
07a8bd9486 | ||
|
|
bcdc0a8fce | ||
|
|
b295809432 | ||
|
|
52763ab932 | ||
|
|
99666265c9 | ||
|
|
af3e280d74 | ||
|
|
b57e4c0565 | ||
|
|
aca9931560 | ||
|
|
d09e166e4a | ||
|
|
68a7a60ff2 | ||
|
|
f21261914b | ||
|
|
7b11339fdc | ||
|
|
081fd43d98 | ||
|
|
ef2eedfc7c | ||
|
|
0dba9265be | ||
|
|
301aae9b8e | ||
|
|
c63f4e9662 | ||
|
|
47508dc6ac | ||
|
|
3a8879608a | ||
|
|
b221889549 | ||
|
|
c00d99b85f | ||
|
|
0bf87b753d | ||
|
|
53f2730064 | ||
|
|
d487c3b005 | ||
|
|
fef6ae7ff7 | ||
|
|
f6b42754de | ||
|
|
2ae9bb381d | ||
|
|
53bde84710 | ||
|
|
d006ac27ff | ||
|
|
c478d28b71 | ||
|
|
99f7b9ad84 | ||
|
|
ab58101ce3 | ||
|
|
d8f3682dc0 | ||
|
|
1fec7ba553 | ||
|
|
418f55f34e | ||
|
|
05d795b2ae | ||
|
|
a365b750d9 | ||
|
|
0aecfb565f | ||
|
|
0cf4edd9e5 | ||
|
|
dd7b7c6aef | ||
|
|
0bd677c46b | ||
|
|
1a131d5206 | ||
|
|
016e515ae2 | ||
|
|
456ceb3c58 | ||
|
|
2169be1b45 | ||
|
|
49eb0b0201 | ||
|
|
2e222bcdea | ||
|
|
c7fa475128 | ||
|
|
4174b065f3 | ||
|
|
df6256d989 | ||
|
|
c27db56321 | ||
|
|
97bed8554a | ||
|
|
751c0e16e9 | ||
|
|
936de60700 | ||
|
|
f6b64d48ec | ||
|
|
b043da7d4c | ||
|
|
7e47cc2443 | ||
|
|
b8b45f9442 |
14
.github/workflows/ci.yml
vendored
14
.github/workflows/ci.yml
vendored
@@ -28,13 +28,13 @@ jobs:
|
||||
- 17 # LTS
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: gradle/wrapper-validation-action@v1
|
||||
if: matrix.java == '8'
|
||||
|
||||
- name: Setup Java ${{ matrix.java }}
|
||||
uses: actions/setup-java@v2
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: ${{ matrix.java }}
|
||||
distribution: adopt # Java 8 and 11 are pre-installed on ubuntu-latest
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
run: ./gradlew build
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
if: matrix.java == '11'
|
||||
with:
|
||||
name: FlatLaf-build-artifacts
|
||||
@@ -63,10 +63,10 @@ jobs:
|
||||
github.repository == 'JFormDesigner/FlatLaf'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Java 11
|
||||
uses: actions/setup-java@v2
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: 11
|
||||
distribution: adopt # pre-installed on ubuntu-latest
|
||||
@@ -99,10 +99,10 @@ jobs:
|
||||
github.repository == 'JFormDesigner/FlatLaf'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Java 11
|
||||
uses: actions/setup-java@v2
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: 11
|
||||
distribution: adopt # pre-installed on ubuntu-latest
|
||||
|
||||
9
.github/workflows/natives.yml
vendored
9
.github/workflows/natives.yml
vendored
@@ -25,12 +25,12 @@ jobs:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: gradle/wrapper-validation-action@v1
|
||||
|
||||
- name: Setup Java 11
|
||||
uses: actions/setup-java@v2
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: 11
|
||||
distribution: adopt
|
||||
@@ -39,11 +39,12 @@ jobs:
|
||||
- name: Build with Gradle
|
||||
# --no-daemon is necessary on Windows otherwise caching Gradle would fail with:
|
||||
# tar.exe: Couldn't open ~/.gradle/caches/modules-2/modules-2.lock: Permission denied
|
||||
run: ./gradlew :flatlaf-natives-windows:build --no-daemon
|
||||
run: ./gradlew :flatlaf-natives-windows:build-natives --no-daemon
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: FlatLaf-natives-windows-build-artifacts
|
||||
path: |
|
||||
flatlaf-core/src/main/resources/com/formdev/flatlaf/natives
|
||||
flatlaf-natives/flatlaf-natives-windows/build
|
||||
|
||||
151
CHANGELOG.md
151
CHANGELOG.md
@@ -1,6 +1,155 @@
|
||||
FlatLaf Change Log
|
||||
==================
|
||||
|
||||
## 2.4
|
||||
|
||||
#### New features and improvements
|
||||
|
||||
- Native window decorations (Windows 10/11 only):
|
||||
- There is now a small area at top of the embedded menu bar to resize the
|
||||
window.
|
||||
- Improved window title bar layout for small window widths:
|
||||
- Width of iconify/maximize/close buttons is reduced (if necessary) to give
|
||||
more space to embedded menu bar and title.
|
||||
- Window title now has a minimum width to always allow moving window
|
||||
(click-and-drag on window title). Instead, embedded menu bar is made
|
||||
smaller.
|
||||
- Option to show window icon beside window title, if menu bar is embedded or
|
||||
title is centered. Set UI value `TitlePane.showIconBesideTitle` to `true`.
|
||||
- No longer reduce height of window title bar if it has an embedded menu bar
|
||||
and is maximized.
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- ComboBox: Fixed vertical alignment of text in popup list with text in combo
|
||||
box in IntelliJ/Darcula themes.
|
||||
- Menus: Fixed application freeze under very special conditions (invoking
|
||||
`FlatLaf.initialize()` twice in NetBeans GUI builder) and using menu that has
|
||||
submenus. See
|
||||
[NetBeans issue #4231](https://github.com/apache/netbeans/issues/4231#issuecomment-1179611682)
|
||||
for details.
|
||||
- MenuItem: Fixed sometimes wrapped HTML text on HiDPI screens on Windows.
|
||||
- TableHeader: Fixed exception when changing table structure (e.g. removing
|
||||
column) from a table header popup menu action. (issue #532)
|
||||
- `HiDPIUtils.paintAtScale1x()` now supports rotated graphics. (issue #557)
|
||||
- Typography: No longer use `Consolas` or `Courier New` as monospaced font on
|
||||
Windows because they have bad vertically placement.
|
||||
- Native window decorations (Windows 10/11 only):
|
||||
- Do not center window title if embedded menu bar is empty or has no menus at
|
||||
left side, but some components at right side. (issue #558)
|
||||
- Do not use window decorations if system property `sun.java2d.opengl` is
|
||||
`true` on Windows 10. (issue #540)
|
||||
- Fixed missing top window border in dark themes if window drop shadows are
|
||||
disabled in system settings. (issue #554; Windows 10 only)
|
||||
- Right-to-left component orientation of title bar was lost when switching
|
||||
theme.
|
||||
|
||||
|
||||
## 2.3
|
||||
|
||||
#### New features and improvements
|
||||
|
||||
- FileChooser: Added (optional) shortcuts panel. On Windows it contains "Recent
|
||||
Items", "Desktop", "Documents", "This PC" and "Network". On macOS and Linux it
|
||||
is empty/hidden. (issue #100)
|
||||
- Button and ToggleButton: Added missing foreground colors for hover, pressed,
|
||||
focused and selected states. (issue #535)
|
||||
- Table: Optionally paint alternating rows below table if table is smaller than
|
||||
scroll pane. Set UI value `Table.paintOutsideAlternateRows` to `true`.
|
||||
Requires that `Table.alternateRowColor` is set to a color. (issue #504)
|
||||
- ToggleButton: Made the underline placement of tab-style toggle buttons
|
||||
configurable. (PR #530; issue #529)
|
||||
- Added spanish translation. (PR #525)
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- IntelliJ Themes: Fixed `TitledBorder` text color in "Monokai Pro" theme.
|
||||
(issue #524)
|
||||
|
||||
|
||||
## 2.2
|
||||
|
||||
#### New features and improvements
|
||||
|
||||
- SplitPane: Allow limiting one-touch expanding to a single side (set client
|
||||
property `JSplitPane.expandableSide` to `"left"` or `"right"`). (issue #355)
|
||||
- TabbedPane: Selected tab underline color now changes depending on whether the
|
||||
focus is within the tab content. (issue #398)
|
||||
- IntelliJ Themes:
|
||||
- Added "Monokai Pro" and "Xcode-Dark" themes.
|
||||
- TabbedPane now use different background color for selected tabs in all "Arc"
|
||||
themes, in "Hiberbee Dark" and in all "Material UI Lite" themes.
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- Native window decorations (Windows 10/11 only): Fixed wrong window title
|
||||
character encoding used in Windows taskbar. (issue #502)
|
||||
- Button: Fixed icon layout and preferred width of default buttons that use bold
|
||||
font. (issue #506)
|
||||
- FileChooser: Enabled full row selection for details view to fix alternate row
|
||||
coloring. (issue #512)
|
||||
- SplitPane: Fixed `StackOverflowError` caused by layout loop that may occur
|
||||
under special circumstances. (issue #513)
|
||||
- Table: Slightly changed grid colors to make grid better recognizable. (issue
|
||||
#514)
|
||||
- ToolBar: Fixed endless loop in focus navigation that may occur under special
|
||||
circumstances. (issue #505)
|
||||
- IntelliJ Themes: `Component.accentColor` UI property now has useful theme
|
||||
specific values. (issue #507)
|
||||
|
||||
|
||||
## 2.1
|
||||
|
||||
#### New features and improvements
|
||||
|
||||
- Menus: Improved usability of submenus. (PR #490; issue #247)
|
||||
- Menus: Scroll large menus using mouse wheel or up/down arrows. (issue #225)
|
||||
- Linux: Support using custom window decorations. Enable with
|
||||
`JFrame.setDefaultLookAndFeelDecorated(true)` and
|
||||
`JDialog.setDefaultLookAndFeelDecorated(true)` before creating a window.
|
||||
(issue #482)
|
||||
- ScrollBar: Added UI value `ScrollBar.minimumButtonSize` to specify minimum
|
||||
scroll arrow button size (if shown). (issue #493)
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- PasswordField: Fixed reveal button appearance in IntelliJ themes. (issue #494)
|
||||
- ScrollBar: Center and scale arrows in scroll up/down buttons (if shown).
|
||||
(issue #493)
|
||||
- TextArea, TextPane and EditorPane: No longer select all text when component is
|
||||
focused for the first time. (issue #498; regression in FlatLaf 2.0)
|
||||
- TabbedPane: Disable all items in "Show Hidden Tabs" popup menu if tabbed pane
|
||||
is disabled.
|
||||
|
||||
#### Incompatibilities
|
||||
|
||||
- Method `FlatUIUtils.paintArrow()` (and class `FlatArrowButton`) now paints
|
||||
arrows one pixel smaller than before. To fix this, increase parameter
|
||||
`arrowSize` by one.
|
||||
|
||||
|
||||
## 2.0.2
|
||||
|
||||
- Native window decorations (Windows 10/11 only): Fixed rendering artifacts on
|
||||
HiDPI screens when dragging window partly offscreen and back into screen
|
||||
bounds. (issue #477)
|
||||
- Repaint component when setting client property `JComponent.outline` (issue
|
||||
#480).
|
||||
- macOS: Fixed NPE when using some icons in main menu items. (issue #483)
|
||||
|
||||
|
||||
## 2.0.1
|
||||
|
||||
- Fixed memory leak in Panel, Separator and ToolBarSeparator. (issue #471;
|
||||
regression in FlatLaf 2.0)
|
||||
- ToolTip: Fixed wrong tooltip location if component overrides
|
||||
`JComponent.getToolTipLocation()` and wants place tooltip under mouse
|
||||
location. (issue #468)
|
||||
- Extras: Added copy constructor to `FlatSVGIcon`. (issue #465)
|
||||
- Moved `module-info.class` from `META-INF\versions\9\` to root folder of JARs.
|
||||
(issue #466)
|
||||
|
||||
|
||||
## 2.0
|
||||
|
||||
- Added system property `flatlaf.nativeLibraryPath` to load native libraries
|
||||
@@ -58,7 +207,7 @@ FlatLaf Change Log
|
||||
- Possibility to hide window title bar icon (for single window set client
|
||||
property `JRootPane.titleBarShowIcon` to `false`; for all windows set UI
|
||||
value `TitlePane.showIcon` to `false`).
|
||||
- OptionPane: Hide window title bar icon by default. Can be be made visibly by
|
||||
- OptionPane: Hide window title bar icon by default. Can be made visibly by
|
||||
setting UI default `OptionPane.showIcon` to `true`. (issue #416)
|
||||
- No longer show the Java "duke/cup" icon if no window icon image is set.
|
||||
(issue #416)
|
||||
|
||||
23
README.md
23
README.md
@@ -11,9 +11,9 @@ scales on **HiDPI** displays and runs on Java 8 or newer.
|
||||
The look is heavily inspired by **Darcula** and **IntelliJ** themes from
|
||||
IntelliJ IDEA 2019.2+ and uses almost the same colors and icons.
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
IntelliJ Platform Themes
|
||||
@@ -105,6 +105,16 @@ For more information and documentation visit
|
||||
- [System Properties](https://www.formdev.com/flatlaf/system-properties/)
|
||||
|
||||
|
||||
Theme Editor
|
||||
------------
|
||||
|
||||
The Theme Editor that supports editing FlatLaf theme properties files. See
|
||||
[Theme Editor documentation](https://www.formdev.com/flatlaf/theme-editor/) for
|
||||
details and downloads.
|
||||
|
||||

|
||||
|
||||
|
||||
Buzz
|
||||
----
|
||||
|
||||
@@ -116,6 +126,8 @@ Buzz
|
||||
Applications using FlatLaf
|
||||
--------------------------
|
||||
|
||||
-  [Ultorg](https://www.ultorg.com/) (**commercial**) - a
|
||||
visual query system for relational databases
|
||||
-  [MooInfo](https://github.com/rememberber/MooInfo) -
|
||||
visual implementation of OSHI, to view information about the system and
|
||||
hardware
|
||||
@@ -154,9 +166,10 @@ Applications using FlatLaf
|
||||
- [Total Validator](https://www.totalvalidator.com/) 15 (**commercial**) -
|
||||
checks your website
|
||||
- [j-lawyer](https://github.com/jlawyerorg/j-lawyer-org) - Kanzleisoftware
|
||||
- [MegaMek](https://github.com/MegaMek/megamek) v0.47.4 and
|
||||
[MekHQ](https://github.com/MegaMek/mekhq) v0.47.5 - a turn-based sci-fi board
|
||||
game
|
||||
- [MegaMek](https://github.com/MegaMek/megamek),
|
||||
[MegaMekLab](https://github.com/MegaMek/megameklab) and
|
||||
[MekHQ](https://github.com/MegaMek/mekhq) v0.47.5+ - a sci-fi tabletop
|
||||
BattleTech simulator suite handling battles, unit building, and campaigns
|
||||
- [GUIslice Builder](https://github.com/ImpulseAdventure/GUIslice-Builder)
|
||||
0.13.b024 - GUI builder for
|
||||
[GUIslice](https://github.com/ImpulseAdventure/GUIslice), a lightweight GUI
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
val releaseVersion = "2.0"
|
||||
val developmentVersion = "2.1-SNAPSHOT"
|
||||
val releaseVersion = "2.4"
|
||||
val developmentVersion = "2.5-SNAPSHOT"
|
||||
|
||||
version = if( java.lang.Boolean.getBoolean( "release" ) ) releaseVersion else developmentVersion
|
||||
|
||||
|
||||
@@ -61,12 +61,8 @@ if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) {
|
||||
}
|
||||
|
||||
jar {
|
||||
manifest.attributes( "Multi-Release" to "true" )
|
||||
|
||||
into( "META-INF/versions/9" ) {
|
||||
from( sourceSets["module-info"].output ) {
|
||||
include( "module-info.class" )
|
||||
}
|
||||
from( sourceSets["module-info"].output ) {
|
||||
include( "module-info.class" )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,11 +43,6 @@ tasks {
|
||||
options.headerOutputDirectory.set( buildDir.resolve( "generated/jni-headers" ) )
|
||||
}
|
||||
|
||||
processResources {
|
||||
// build native libraries
|
||||
dependsOn( ":flatlaf-natives-windows:assemble" )
|
||||
}
|
||||
|
||||
jar {
|
||||
archiveBaseName.set( "flatlaf" )
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#Signature file v4.1
|
||||
#Version 1.6
|
||||
#Version 2.3
|
||||
|
||||
CLSS public abstract interface com.formdev.flatlaf.FlatClientProperties
|
||||
fld public final static java.lang.String BUTTON_TYPE = "JButton.buttonType"
|
||||
@@ -30,7 +30,12 @@ fld public final static java.lang.String SELECT_ALL_ON_FOCUS_POLICY = "JTextFiel
|
||||
fld public final static java.lang.String SELECT_ALL_ON_FOCUS_POLICY_ALWAYS = "always"
|
||||
fld public final static java.lang.String SELECT_ALL_ON_FOCUS_POLICY_NEVER = "never"
|
||||
fld public final static java.lang.String SELECT_ALL_ON_FOCUS_POLICY_ONCE = "once"
|
||||
fld public final static java.lang.String SPLIT_PANE_EXPANDABLE_SIDE = "JSplitPane.expandableSide"
|
||||
fld public final static java.lang.String SPLIT_PANE_EXPANDABLE_SIDE_LEFT = "left"
|
||||
fld public final static java.lang.String SPLIT_PANE_EXPANDABLE_SIDE_RIGHT = "right"
|
||||
fld public final static java.lang.String SQUARE_SIZE = "JButton.squareSize"
|
||||
fld public final static java.lang.String STYLE = "FlatLaf.style"
|
||||
fld public final static java.lang.String STYLE_CLASS = "FlatLaf.styleClass"
|
||||
fld public final static java.lang.String TABBED_PANE_ALIGN_CENTER = "center"
|
||||
fld public final static java.lang.String TABBED_PANE_ALIGN_FILL = "fill"
|
||||
fld public final static java.lang.String TABBED_PANE_ALIGN_LEADING = "leading"
|
||||
@@ -59,6 +64,9 @@ fld public final static java.lang.String TABBED_PANE_TAB_CLOSE_TOOLTIPTEXT = "JT
|
||||
fld public final static java.lang.String TABBED_PANE_TAB_HEIGHT = "JTabbedPane.tabHeight"
|
||||
fld public final static java.lang.String TABBED_PANE_TAB_ICON_PLACEMENT = "JTabbedPane.tabIconPlacement"
|
||||
fld public final static java.lang.String TABBED_PANE_TAB_INSETS = "JTabbedPane.tabInsets"
|
||||
fld public final static java.lang.String TABBED_PANE_TAB_TYPE = "JTabbedPane.tabType"
|
||||
fld public final static java.lang.String TABBED_PANE_TAB_TYPE_CARD = "card"
|
||||
fld public final static java.lang.String TABBED_PANE_TAB_TYPE_UNDERLINED = "underlined"
|
||||
fld public final static java.lang.String TABBED_PANE_TAB_WIDTH_MODE = "JTabbedPane.tabWidthMode"
|
||||
fld public final static java.lang.String TABBED_PANE_TAB_WIDTH_MODE_COMPACT = "compact"
|
||||
fld public final static java.lang.String TABBED_PANE_TAB_WIDTH_MODE_EQUAL = "equal"
|
||||
@@ -67,12 +75,21 @@ fld public final static java.lang.String TABBED_PANE_TRAILING_COMPONENT = "JTabb
|
||||
fld public final static java.lang.String TAB_BUTTON_SELECTED_BACKGROUND = "JToggleButton.tab.selectedBackground"
|
||||
fld public final static java.lang.String TAB_BUTTON_UNDERLINE_COLOR = "JToggleButton.tab.underlineColor"
|
||||
fld public final static java.lang.String TAB_BUTTON_UNDERLINE_HEIGHT = "JToggleButton.tab.underlineHeight"
|
||||
fld public final static java.lang.String TAB_BUTTON_UNDERLINE_PLACEMENT = "JToggleButton.tab.underlinePlacement"
|
||||
fld public final static java.lang.String TEXT_FIELD_CLEAR_CALLBACK = "JTextField.clearCallback"
|
||||
fld public final static java.lang.String TEXT_FIELD_LEADING_COMPONENT = "JTextField.leadingComponent"
|
||||
fld public final static java.lang.String TEXT_FIELD_LEADING_ICON = "JTextField.leadingIcon"
|
||||
fld public final static java.lang.String TEXT_FIELD_PADDING = "JTextField.padding"
|
||||
fld public final static java.lang.String TEXT_FIELD_SHOW_CLEAR_BUTTON = "JTextField.showClearButton"
|
||||
fld public final static java.lang.String TEXT_FIELD_TRAILING_COMPONENT = "JTextField.trailingComponent"
|
||||
fld public final static java.lang.String TEXT_FIELD_TRAILING_ICON = "JTextField.trailingIcon"
|
||||
fld public final static java.lang.String TITLE_BAR_BACKGROUND = "JRootPane.titleBarBackground"
|
||||
fld public final static java.lang.String TITLE_BAR_FOREGROUND = "JRootPane.titleBarForeground"
|
||||
fld public final static java.lang.String TITLE_BAR_SHOW_ICON = "JRootPane.titleBarShowIcon"
|
||||
fld public final static java.lang.String TREE_PAINT_SELECTION = "JTree.paintSelection"
|
||||
fld public final static java.lang.String TREE_WIDE_SELECTION = "JTree.wideSelection"
|
||||
fld public final static java.lang.String USE_WINDOW_DECORATIONS = "JRootPane.useWindowDecorations"
|
||||
meth public static <%0 extends java.lang.Object> {%%0} clientProperty(javax.swing.JComponent,java.lang.String,{%%0},java.lang.Class<{%%0}>)
|
||||
meth public static boolean clientPropertyBoolean(javax.swing.JComponent,java.lang.String,boolean)
|
||||
meth public static boolean clientPropertyEquals(javax.swing.JComponent,java.lang.String,java.lang.Object)
|
||||
meth public static int clientPropertyInt(javax.swing.JComponent,java.lang.String,int)
|
||||
@@ -165,6 +182,7 @@ meth public boolean isSupportedLookAndFeel()
|
||||
meth public final boolean equals(java.lang.Object)
|
||||
meth public final int hashCode()
|
||||
meth public java.lang.String getID()
|
||||
meth public java.util.Map<java.lang.String,java.lang.String> getExtraDefaults()
|
||||
meth public javax.swing.Icon getDisabledIcon(javax.swing.JComponent,javax.swing.Icon)
|
||||
meth public javax.swing.UIDefaults getDefaults()
|
||||
meth public static boolean install(javax.swing.LookAndFeel)
|
||||
@@ -174,6 +192,8 @@ meth public static boolean isShowMnemonics()
|
||||
meth public static boolean isUseNativeWindowDecorations()
|
||||
meth public static boolean setup(javax.swing.LookAndFeel)
|
||||
meth public static boolean supportsNativeWindowDecorations()
|
||||
meth public static java.lang.Object parseDefaultsValue(java.lang.String,java.lang.String,java.lang.Class<?>)
|
||||
meth public static java.util.Map<java.lang.String,java.lang.String> getGlobalExtraDefaults()
|
||||
meth public static javax.swing.UIDefaults$ActiveValue createActiveFontValue(float)
|
||||
meth public static void hideMnemonics()
|
||||
meth public static void initIconColors(javax.swing.UIDefaults,boolean)
|
||||
@@ -181,22 +201,26 @@ meth public static void installLafInfo(java.lang.String,java.lang.Class<? extend
|
||||
meth public static void registerCustomDefaultsSource(java.io.File)
|
||||
meth public static void registerCustomDefaultsSource(java.lang.String)
|
||||
meth public static void registerCustomDefaultsSource(java.lang.String,java.lang.ClassLoader)
|
||||
meth public static void registerCustomDefaultsSource(java.net.URL)
|
||||
meth public static void repaintAllFramesAndDialogs()
|
||||
meth public static void revalidateAndRepaintAllFramesAndDialogs()
|
||||
meth public static void runWithUIDefaultsGetter(java.util.function.Function<java.lang.Object,java.lang.Object>,java.lang.Runnable)
|
||||
meth public static void setGlobalExtraDefaults(java.util.Map<java.lang.String,java.lang.String>)
|
||||
meth public static void setUseNativeWindowDecorations(boolean)
|
||||
meth public static void showMnemonics(java.awt.Component)
|
||||
meth public static void unregisterCustomDefaultsSource(java.io.File)
|
||||
meth public static void unregisterCustomDefaultsSource(java.lang.String)
|
||||
meth public static void unregisterCustomDefaultsSource(java.lang.String,java.lang.ClassLoader)
|
||||
meth public static void unregisterCustomDefaultsSource(java.net.URL)
|
||||
meth public static void updateUI()
|
||||
meth public static void updateUILater()
|
||||
meth public void initialize()
|
||||
meth public void registerUIDefaultsGetter(java.util.function.Function<java.lang.Object,java.lang.Object>)
|
||||
meth public void setExtraDefaults(java.util.Map<java.lang.String,java.lang.String>)
|
||||
meth public void uninitialize()
|
||||
meth public void unregisterUIDefaultsGetter(java.util.function.Function<java.lang.Object,java.lang.Object>)
|
||||
supr javax.swing.plaf.basic.BasicLookAndFeel
|
||||
hfds DESKTOPFONTHINTS,aquaLoaded,customDefaultsSources,desktopPropertyListener,desktopPropertyName,desktopPropertyName2,mnemonicHandler,oldPopupFactory,postInitialization,uiDefaultsGetters,updateUIPending
|
||||
hfds DESKTOPFONTHINTS,aquaLoaded,customDefaultsSources,desktopPropertyListener,desktopPropertyName,desktopPropertyName2,extraDefaults,globalExtraDefaults,mnemonicHandler,oldPopupFactory,postInitialization,subMenuUsabilityHelper,uiDefaultsGetters,updateUIPending
|
||||
hcls ActiveFont,FlatUIDefaults,ImageIconUIResource
|
||||
|
||||
CLSS public abstract interface static com.formdev.flatlaf.FlatLaf$DisabledIconProvider
|
||||
@@ -231,6 +255,7 @@ hfds baseTheme,dark,name,properties
|
||||
CLSS public abstract interface com.formdev.flatlaf.FlatSystemProperties
|
||||
fld public final static java.lang.String ANIMATION = "flatlaf.animation"
|
||||
fld public final static java.lang.String MENUBAR_EMBEDDED = "flatlaf.menuBarEmbedded"
|
||||
fld public final static java.lang.String NATIVE_LIBRARY_PATH = "flatlaf.nativeLibraryPath"
|
||||
fld public final static java.lang.String UI_SCALE = "flatlaf.uiScale"
|
||||
fld public final static java.lang.String UI_SCALE_ALLOW_SCALE_DOWN = "flatlaf.uiScale.allowScaleDown"
|
||||
fld public final static java.lang.String UI_SCALE_ENABLED = "flatlaf.uiScale.enabled"
|
||||
@@ -330,7 +355,15 @@ innr public static HSLIncreaseDecrease
|
||||
innr public static Mix
|
||||
meth public !varargs static java.awt.Color applyFunctions(java.awt.Color,com.formdev.flatlaf.util.ColorFunctions$ColorFunction[])
|
||||
meth public static float clamp(float)
|
||||
meth public static float luma(java.awt.Color)
|
||||
meth public static java.awt.Color darken(java.awt.Color,float)
|
||||
meth public static java.awt.Color desaturate(java.awt.Color,float)
|
||||
meth public static java.awt.Color lighten(java.awt.Color,float)
|
||||
meth public static java.awt.Color mix(java.awt.Color,java.awt.Color,float)
|
||||
meth public static java.awt.Color saturate(java.awt.Color,float)
|
||||
meth public static java.awt.Color shade(java.awt.Color,float)
|
||||
meth public static java.awt.Color spin(java.awt.Color,float)
|
||||
meth public static java.awt.Color tint(java.awt.Color,float)
|
||||
supr java.lang.Object
|
||||
|
||||
CLSS public abstract interface static com.formdev.flatlaf.util.ColorFunctions$ColorFunction
|
||||
@@ -566,6 +599,7 @@ meth public static java.util.List<java.awt.Image> getResolutionVariants(java.awt
|
||||
supr java.lang.Object
|
||||
|
||||
CLSS public com.formdev.flatlaf.util.NativeLibrary
|
||||
cons public init(java.io.File,boolean)
|
||||
cons public init(java.lang.String,java.lang.ClassLoader,boolean)
|
||||
meth public boolean isLoaded()
|
||||
supr java.lang.Object
|
||||
@@ -589,23 +623,59 @@ meth public void paintIcon(java.awt.Component,java.awt.Graphics,int,int)
|
||||
supr java.lang.Object
|
||||
hfds iconHeight,iconWidth,imageIcon,lastImage,lastSystemScaleFactor,lastUserScaleFactor
|
||||
|
||||
CLSS public com.formdev.flatlaf.util.SoftCache<%0 extends java.lang.Object, %1 extends java.lang.Object>
|
||||
cons public init()
|
||||
cons public init(int)
|
||||
intf java.util.Map<{com.formdev.flatlaf.util.SoftCache%0},{com.formdev.flatlaf.util.SoftCache%1}>
|
||||
meth public boolean containsKey(java.lang.Object)
|
||||
meth public boolean containsValue(java.lang.Object)
|
||||
meth public boolean isEmpty()
|
||||
meth public int size()
|
||||
meth public java.util.Collection<{com.formdev.flatlaf.util.SoftCache%1}> values()
|
||||
meth public java.util.Set<java.util.Map$Entry<{com.formdev.flatlaf.util.SoftCache%0},{com.formdev.flatlaf.util.SoftCache%1}>> entrySet()
|
||||
meth public java.util.Set<{com.formdev.flatlaf.util.SoftCache%0}> keySet()
|
||||
meth public void clear()
|
||||
meth public void forEach(java.util.function.BiConsumer<? super {com.formdev.flatlaf.util.SoftCache%0},? super {com.formdev.flatlaf.util.SoftCache%1}>)
|
||||
meth public void putAll(java.util.Map<? extends {com.formdev.flatlaf.util.SoftCache%0},? extends {com.formdev.flatlaf.util.SoftCache%1}>)
|
||||
meth public void replaceAll(java.util.function.BiFunction<? super {com.formdev.flatlaf.util.SoftCache%0},? super {com.formdev.flatlaf.util.SoftCache%1},? extends {com.formdev.flatlaf.util.SoftCache%1}>)
|
||||
meth public {com.formdev.flatlaf.util.SoftCache%1} get(java.lang.Object)
|
||||
meth public {com.formdev.flatlaf.util.SoftCache%1} put({com.formdev.flatlaf.util.SoftCache%0},{com.formdev.flatlaf.util.SoftCache%1})
|
||||
meth public {com.formdev.flatlaf.util.SoftCache%1} remove(java.lang.Object)
|
||||
supr java.lang.Object
|
||||
hfds map,queue
|
||||
hcls CacheReference
|
||||
|
||||
CLSS public com.formdev.flatlaf.util.StringUtils
|
||||
cons public init()
|
||||
meth public static boolean isEmpty(java.lang.String)
|
||||
meth public static boolean isTrimmedEmpty(java.lang.String)
|
||||
meth public static java.lang.String removeLeading(java.lang.String,java.lang.String)
|
||||
meth public static java.lang.String removeTrailing(java.lang.String,java.lang.String)
|
||||
meth public static java.lang.String substringTrimmed(java.lang.String,int)
|
||||
meth public static java.lang.String substringTrimmed(java.lang.String,int,int)
|
||||
meth public static java.util.List<java.lang.String> split(java.lang.String,char)
|
||||
meth public static java.util.List<java.lang.String> split(java.lang.String,char,boolean,boolean)
|
||||
supr java.lang.Object
|
||||
|
||||
CLSS public com.formdev.flatlaf.util.SwingUtils
|
||||
cons public init()
|
||||
meth public static <%0 extends java.awt.Component> {%%0} getComponentByName(java.awt.Container,java.lang.String)
|
||||
supr java.lang.Object
|
||||
|
||||
CLSS public com.formdev.flatlaf.util.SystemInfo
|
||||
cons public init()
|
||||
fld public final static boolean isAARCH64
|
||||
fld public final static boolean isJava_11_orLater
|
||||
fld public final static boolean isJava_12_orLater
|
||||
fld public final static boolean isJava_15_orLater
|
||||
fld public final static boolean isJava_17_orLater
|
||||
fld public final static boolean isJava_18_orLater
|
||||
fld public final static boolean isJava_9_orLater
|
||||
fld public final static boolean isJetBrainsJVM
|
||||
fld public final static boolean isJetBrainsJVM_11_orLater
|
||||
fld public final static boolean isKDE
|
||||
fld public final static boolean isLinux
|
||||
fld public final static boolean isMacFullWindowContentSupported
|
||||
fld public final static boolean isMacOS
|
||||
fld public final static boolean isMacOS_10_11_ElCapitan_orLater
|
||||
fld public final static boolean isMacOS_10_14_Mojave_orLater
|
||||
@@ -615,6 +685,8 @@ fld public final static boolean isWebswing
|
||||
fld public final static boolean isWinPE
|
||||
fld public final static boolean isWindows
|
||||
fld public final static boolean isWindows_10_orLater
|
||||
fld public final static boolean isWindows_11_orLater
|
||||
fld public final static boolean isX86
|
||||
fld public final static boolean isX86_64
|
||||
fld public final static long javaVersion
|
||||
fld public final static long osVersion
|
||||
@@ -627,6 +699,7 @@ cons public init()
|
||||
meth public static boolean isSystemScalingEnabled()
|
||||
meth public static double getSystemScaleFactor(java.awt.Graphics2D)
|
||||
meth public static double getSystemScaleFactor(java.awt.GraphicsConfiguration)
|
||||
meth public static float computeFontScaleFactor(java.awt.Font)
|
||||
meth public static float getUserScaleFactor()
|
||||
meth public static float scale(float)
|
||||
meth public static float unscale(float)
|
||||
@@ -933,6 +1006,34 @@ CLSS public abstract interface !annotation java.lang.annotation.Target
|
||||
intf java.lang.annotation.Annotation
|
||||
meth public abstract java.lang.annotation.ElementType[] value()
|
||||
|
||||
CLSS public abstract interface java.util.Map<%0 extends java.lang.Object, %1 extends java.lang.Object>
|
||||
innr public abstract interface static Entry
|
||||
meth public abstract boolean containsKey(java.lang.Object)
|
||||
meth public abstract boolean containsValue(java.lang.Object)
|
||||
meth public abstract boolean equals(java.lang.Object)
|
||||
meth public abstract boolean isEmpty()
|
||||
meth public abstract int hashCode()
|
||||
meth public abstract int size()
|
||||
meth public abstract java.util.Collection<{java.util.Map%1}> values()
|
||||
meth public abstract java.util.Set<java.util.Map$Entry<{java.util.Map%0},{java.util.Map%1}>> entrySet()
|
||||
meth public abstract java.util.Set<{java.util.Map%0}> keySet()
|
||||
meth public abstract void clear()
|
||||
meth public abstract void putAll(java.util.Map<? extends {java.util.Map%0},? extends {java.util.Map%1}>)
|
||||
meth public abstract {java.util.Map%1} get(java.lang.Object)
|
||||
meth public abstract {java.util.Map%1} put({java.util.Map%0},{java.util.Map%1})
|
||||
meth public abstract {java.util.Map%1} remove(java.lang.Object)
|
||||
meth public boolean remove(java.lang.Object,java.lang.Object)
|
||||
meth public boolean replace({java.util.Map%0},{java.util.Map%1},{java.util.Map%1})
|
||||
meth public void forEach(java.util.function.BiConsumer<? super {java.util.Map%0},? super {java.util.Map%1}>)
|
||||
meth public void replaceAll(java.util.function.BiFunction<? super {java.util.Map%0},? super {java.util.Map%1},? extends {java.util.Map%1}>)
|
||||
meth public {java.util.Map%1} compute({java.util.Map%0},java.util.function.BiFunction<? super {java.util.Map%0},? super {java.util.Map%1},? extends {java.util.Map%1}>)
|
||||
meth public {java.util.Map%1} computeIfAbsent({java.util.Map%0},java.util.function.Function<? super {java.util.Map%0},? extends {java.util.Map%1}>)
|
||||
meth public {java.util.Map%1} computeIfPresent({java.util.Map%0},java.util.function.BiFunction<? super {java.util.Map%0},? super {java.util.Map%1},? extends {java.util.Map%1}>)
|
||||
meth public {java.util.Map%1} getOrDefault(java.lang.Object,{java.util.Map%1})
|
||||
meth public {java.util.Map%1} merge({java.util.Map%0},{java.util.Map%1},java.util.function.BiFunction<? super {java.util.Map%1},? super {java.util.Map%1},? extends {java.util.Map%1}>)
|
||||
meth public {java.util.Map%1} putIfAbsent({java.util.Map%0},{java.util.Map%1})
|
||||
meth public {java.util.Map%1} replace({java.util.Map%0},{java.util.Map%1})
|
||||
|
||||
CLSS public abstract interface javax.swing.Icon
|
||||
meth public abstract int getIconHeight()
|
||||
meth public abstract int getIconWidth()
|
||||
|
||||
@@ -391,6 +391,40 @@ public interface FlatClientProperties
|
||||
*/
|
||||
String SCROLL_PANE_SMOOTH_SCROLLING = "JScrollPane.smoothScrolling";
|
||||
|
||||
//---- JSplitPane ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Specifies what side of the spilt pane is allowed to expand
|
||||
* via one-touch expanding arrow buttons.
|
||||
* Requires that one-touch expanding is enabled with
|
||||
* {@link javax.swing.JSplitPane#setOneTouchExpandable(boolean)}.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JSplitPane}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.String}<br>
|
||||
* <strong>Allowed Values</strong>
|
||||
* {@link #SPLIT_PANE_EXPANDABLE_SIDE_LEFT} or
|
||||
* {@link #SPLIT_PANE_EXPANDABLE_SIDE_RIGHT}
|
||||
*
|
||||
* @since 2.2
|
||||
*/
|
||||
String SPLIT_PANE_EXPANDABLE_SIDE = "JSplitPane.expandableSide";
|
||||
|
||||
/**
|
||||
* Allow expanding only left/top side of the split pane.
|
||||
*
|
||||
* @see #SPLIT_PANE_EXPANDABLE_SIDE
|
||||
* @since 2.2
|
||||
*/
|
||||
String SPLIT_PANE_EXPANDABLE_SIDE_LEFT = "left";
|
||||
|
||||
/**
|
||||
* Allow expanding only right/bottom side of the split pane.
|
||||
*
|
||||
* @see #SPLIT_PANE_EXPANDABLE_SIDE
|
||||
* @since 2.2
|
||||
*/
|
||||
String SPLIT_PANE_EXPANDABLE_SIDE_RIGHT = "right";
|
||||
|
||||
//---- JTabbedPane --------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -958,7 +992,22 @@ public interface FlatClientProperties
|
||||
//---- JToggleButton ------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Height of underline if toggle button type is {@link #BUTTON_TYPE_TAB}.
|
||||
* Placement of underline if toggle button type is {@link #BUTTON_TYPE_TAB}
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JToggleButton}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Integer}<br>
|
||||
* <strong>SupportedValues:</strong>
|
||||
* {@link SwingConstants#BOTTOM} (default)
|
||||
* {@link SwingConstants#TOP},
|
||||
* {@link SwingConstants#LEFT} or
|
||||
* {@link SwingConstants#RIGHT}
|
||||
*
|
||||
* @since 2.3
|
||||
*/
|
||||
String TAB_BUTTON_UNDERLINE_PLACEMENT = "JToggleButton.tab.underlinePlacement";
|
||||
|
||||
/**
|
||||
* Thickness of underline if toggle button type is {@link #BUTTON_TYPE_TAB}.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JToggleButton}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Integer}
|
||||
|
||||
@@ -26,7 +26,7 @@ import javax.swing.UIDefaults;
|
||||
* Allows loading of additional .properties files from addon JARs.
|
||||
* {@link java.util.ServiceLoader} is used to load extensions of this class from addon JARs.
|
||||
* <p>
|
||||
* If you extend this class in a addon JAR, you also have to add a text file named
|
||||
* If you extend this class in an addon JAR, you also have to add a text file named
|
||||
* {@code META-INF/services/com.formdev.flatlaf.FlatDefaultsAddon}
|
||||
* to the addon JAR. The file must contain a single line with the class name.
|
||||
* <p>
|
||||
@@ -61,7 +61,7 @@ public abstract class FlatDefaultsAddon
|
||||
|
||||
/**
|
||||
* Returns the priority used to sort addon loading.
|
||||
* The order is only important if you want overwrite UI defaults of other addons.
|
||||
* The order is only important if you want to overwrite UI defaults of other addons.
|
||||
* Lower numbers mean higher priority.
|
||||
* Returns 10000 by default.
|
||||
*/
|
||||
|
||||
@@ -19,7 +19,7 @@ package com.formdev.flatlaf;
|
||||
/**
|
||||
* Default color palette for action icons and object icons.
|
||||
* <p>
|
||||
* The idea is to use only this well defined set of colors in SVG icons and
|
||||
* The idea is to use only this well-defined set of colors in SVG icons, and
|
||||
* then they are replaced at runtime to dark variants or to other theme colors.
|
||||
* Then a single SVG icon (light variant) can be used for dark themes too.
|
||||
* IntelliJ Platform uses this mechanism to allow themes to change IntelliJ Platform icons.
|
||||
@@ -35,7 +35,7 @@ package com.formdev.flatlaf;
|
||||
* <p>
|
||||
* You may use these colors also in your application (outside of SVG icons), but do
|
||||
* not use the RGB values defined in this enum.<br>
|
||||
* Instead use {@code UIManager.getColor( FlatIconColors.ACTIONS_GREY.key )}.
|
||||
* Instead, use {@code UIManager.getColor( FlatIconColors.ACTIONS_GREY.key )}.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
|
||||
@@ -596,7 +596,7 @@ class FlatInputMaps
|
||||
//---- class LazyInputMapEx -----------------------------------------------
|
||||
|
||||
/**
|
||||
* Lazily creates a input map.
|
||||
* Lazily creates an input map.
|
||||
* Similar to {@link UIDefaults.LazyInputMap}, but can use multiple bindings arrays.
|
||||
*/
|
||||
private static class LazyInputMapEx
|
||||
|
||||
@@ -103,6 +103,7 @@ public abstract class FlatLaf
|
||||
|
||||
private PopupFactory oldPopupFactory;
|
||||
private MnemonicHandler mnemonicHandler;
|
||||
private boolean subMenuUsabilityHelperInstalled;
|
||||
|
||||
private Consumer<UIDefaults> postInitialization;
|
||||
private List<Function<Object, Object>> uiDefaultsGetters;
|
||||
@@ -166,18 +167,19 @@ public abstract class FlatLaf
|
||||
* Returns whether FlatLaf supports custom window decorations.
|
||||
* This depends on the operating system and on the used Java runtime.
|
||||
* <p>
|
||||
* This method returns {@code true} on Windows 10 (see exception below), {@code false} otherwise.
|
||||
* This method returns {@code true} on Windows 10/11 (see exception below)
|
||||
* and on Linux, {@code false} otherwise.
|
||||
* <p>
|
||||
* Returns also {@code false} on Windows 10 if:
|
||||
* Returns also {@code false} on Windows 10/11 if:
|
||||
* <ul>
|
||||
* <li>FlatLaf native window border support is available (requires Windows 10)</li>
|
||||
* <li>FlatLaf native window border support is available (requires Windows 10/11)</li>
|
||||
* <li>running in
|
||||
* <a href="https://confluence.jetbrains.com/display/JBR/JetBrains+Runtime">JetBrains Runtime 11 (or later)</a>
|
||||
* (<a href="https://github.com/JetBrains/JetBrainsRuntime">source code on github</a>)
|
||||
* and JBR supports custom window decorations
|
||||
* </li>
|
||||
* </ul>
|
||||
* In this cases, custom decorations are enabled by the root pane.
|
||||
* In these cases, custom decorations are enabled by the root pane.
|
||||
* Usage of {@link JFrame#setDefaultLookAndFeelDecorated(boolean)} or
|
||||
* {@link JDialog#setDefaultLookAndFeelDecorated(boolean)} is not necessary.
|
||||
*/
|
||||
@@ -190,7 +192,7 @@ public abstract class FlatLaf
|
||||
FlatNativeWindowBorder.isSupported() )
|
||||
return false;
|
||||
|
||||
return SystemInfo.isWindows_10_orLater;
|
||||
return SystemInfo.isWindows_10_orLater || SystemInfo.isLinux;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -230,6 +232,15 @@ public abstract class FlatLaf
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
// do not initialize if this is not the current look and feel
|
||||
// This is only necessary for special Laf usage. E.g. in GUI builders,
|
||||
// which may use multiple Lafs and may invoke this method directly.
|
||||
// This avoids that listeners and factories are installed multiple times.
|
||||
// In case of the NetBeans GUI builder, which does not invoke uninitialize(),
|
||||
// this also avoids that listeners stay registered in the system.
|
||||
if( UIManager.getLookAndFeel() != this )
|
||||
return;
|
||||
|
||||
if( SystemInfo.isMacOS )
|
||||
initializeAqua();
|
||||
|
||||
@@ -243,6 +254,9 @@ public abstract class FlatLaf
|
||||
mnemonicHandler = new MnemonicHandler();
|
||||
mnemonicHandler.install();
|
||||
|
||||
// install submenu usability helper
|
||||
subMenuUsabilityHelperInstalled = SubMenuUsabilityHelper.install();
|
||||
|
||||
// listen to desktop property changes to update UI if system font or scaling changes
|
||||
if( SystemInfo.isWindows ) {
|
||||
// Windows 10 allows increasing font size independent of scaling:
|
||||
@@ -298,6 +312,10 @@ public abstract class FlatLaf
|
||||
|
||||
@Override
|
||||
public void uninitialize() {
|
||||
// do not uninitialize if this is not the current look and feel
|
||||
if( UIManager.getLookAndFeel() != this )
|
||||
return;
|
||||
|
||||
// remove desktop property listener
|
||||
if( desktopPropertyListener != null ) {
|
||||
Toolkit toolkit = Toolkit.getDefaultToolkit();
|
||||
@@ -322,6 +340,12 @@ public abstract class FlatLaf
|
||||
mnemonicHandler = null;
|
||||
}
|
||||
|
||||
// uninstall submenu usability helper
|
||||
if( subMenuUsabilityHelperInstalled ) {
|
||||
SubMenuUsabilityHelper.uninstall();
|
||||
subMenuUsabilityHelperInstalled = false;
|
||||
}
|
||||
|
||||
// restore default link color
|
||||
new HTMLEditorKit().getStyleSheet().addRule( "a, address { color: blue; }" );
|
||||
postInitialization = null;
|
||||
@@ -605,7 +629,7 @@ public abstract class FlatLaf
|
||||
uiFont = ((ActiveFont)defaultFont).derive( baseFont, fontSize -> {
|
||||
return Math.round( fontSize * UIScale.computeFontScaleFactor( baseFont ) );
|
||||
} );
|
||||
};
|
||||
}
|
||||
|
||||
// increase font size if system property "flatlaf.uiScale" is set
|
||||
uiFont = UIScale.applyCustomScaleFactor( uiFont );
|
||||
@@ -760,7 +784,7 @@ public abstract class FlatLaf
|
||||
* Invoke this method before setting the look and feel.
|
||||
* <p>
|
||||
* If using Java modules, the package must be opened in {@code module-info.java}.
|
||||
* Otherwise use {@link #registerCustomDefaultsSource(URL)}.
|
||||
* Otherwise, use {@link #registerCustomDefaultsSource(URL)}.
|
||||
*
|
||||
* @param packageName a package name (e.g. "com.myapp.resources")
|
||||
*/
|
||||
@@ -862,7 +886,7 @@ public abstract class FlatLaf
|
||||
* E.g. using {@link UIManager#setLookAndFeel(LookAndFeel)} or {@link #setup(LookAndFeel)}.
|
||||
* <p>
|
||||
* The global extra defaults are useful for smaller additional defaults that may change.
|
||||
* E.g. accent color. Otherwise FlatLaf properties files should be used.
|
||||
* E.g. accent color. Otherwise, FlatLaf properties files should be used.
|
||||
* See {@link #registerCustomDefaultsSource(String)}.
|
||||
* <p>
|
||||
* The keys and values are strings in same format as in FlatLaf properties files.
|
||||
@@ -894,7 +918,7 @@ public abstract class FlatLaf
|
||||
* E.g. using {@link UIManager#setLookAndFeel(LookAndFeel)} or {@link #setup(LookAndFeel)}.
|
||||
* <p>
|
||||
* The extra defaults are useful for smaller additional defaults that may change.
|
||||
* E.g. accent color. Otherwise FlatLaf properties files should be used.
|
||||
* E.g. accent color. Otherwise, FlatLaf properties files should be used.
|
||||
* See {@link #registerCustomDefaultsSource(String)}.
|
||||
* <p>
|
||||
* The keys and values are strings in same format as in FlatLaf properties files.
|
||||
@@ -951,7 +975,7 @@ public abstract class FlatLaf
|
||||
// re-set current LaF
|
||||
UIManager.setLookAndFeel( lookAndFeel );
|
||||
|
||||
// must fire property change events ourself because old and new LaF are the same
|
||||
// must fire property change events ourselves because old and new LaF are the same
|
||||
PropertyChangeEvent e = new PropertyChangeEvent( UIManager.class, "lookAndFeel", lookAndFeel, lookAndFeel );
|
||||
for( PropertyChangeListener l : UIManager.getPropertyChangeListeners() )
|
||||
l.propertyChange( e );
|
||||
@@ -995,7 +1019,7 @@ public abstract class FlatLaf
|
||||
/**
|
||||
* Returns whether native window decorations are supported on current platform.
|
||||
* <p>
|
||||
* This requires Windows 10, but may be disabled if running in special environments
|
||||
* This requires Windows 10/11, but may be disabled if running in special environments
|
||||
* (JetBrains Projector, Webswing or WinPE) or if loading native library fails.
|
||||
* If system property {@link FlatSystemProperties#USE_WINDOW_DECORATIONS} is set to
|
||||
* {@code false}, then this method also returns {@code false}.
|
||||
|
||||
@@ -34,7 +34,7 @@ public interface FlatSystemProperties
|
||||
* To replace the Java 9+ system scale factor, use system property "sun.java2d.uiScale",
|
||||
* which has the same syntax as this one.
|
||||
* <p>
|
||||
* Since FlatLaf 1.1.2: Scale factors less then 100% are allowed.
|
||||
* Since FlatLaf 1.1.2: Scale factors less than 100% are allowed.
|
||||
* <p>
|
||||
* <strong>Allowed Values</strong> e.g. {@code 1.5}, {@code 1.5x}, {@code 150%} or {@code 144dpi} (96dpi is 100%)<br>
|
||||
*/
|
||||
|
||||
@@ -37,6 +37,7 @@ import com.formdev.flatlaf.json.ParseException;
|
||||
import com.formdev.flatlaf.util.ColorFunctions;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.StringUtils;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
|
||||
/**
|
||||
* This class supports loading IntelliJ .theme.json files and using them as a Laf.
|
||||
@@ -162,8 +163,11 @@ public class IntelliJTheme
|
||||
applyCheckBoxColors( defaults );
|
||||
|
||||
// copy values
|
||||
for( Map.Entry<String, String> e : uiKeyCopying.entrySet() )
|
||||
defaults.put( e.getKey(), defaults.get( e.getValue() ) );
|
||||
for( Map.Entry<String, String> e : uiKeyCopying.entrySet() ) {
|
||||
Object value = defaults.get( e.getValue() );
|
||||
if( value != null )
|
||||
defaults.put( e.getKey(), value );
|
||||
}
|
||||
|
||||
// IDEA does not paint button background if disabled, but FlatLaf does
|
||||
Object panelBackground = defaults.get( "Panel.background" );
|
||||
@@ -175,7 +179,7 @@ public class IntelliJTheme
|
||||
defaults.put( "Button.hoverBorderColor", defaults.get( "Button.focusedBorderColor" ) );
|
||||
defaults.put( "HelpButton.hoverBorderColor", defaults.get( "Button.focusedBorderColor" ) );
|
||||
|
||||
// IDEA uses a SVG icon for the help button, but paints the background with Button.startBackground and Button.endBackground
|
||||
// IDEA uses an SVG icon for the help button, but paints the background with Button.startBackground and Button.endBackground
|
||||
Object helpButtonBackground = defaults.get( "Button.startBackground" );
|
||||
Object helpButtonBorderColor = defaults.get( "Button.startBorderColor" );
|
||||
if( helpButtonBackground == null )
|
||||
@@ -242,7 +246,19 @@ public class IntelliJTheme
|
||||
defaults.put( "Tree.rowHeight", 22 );
|
||||
|
||||
// apply theme specific UI defaults at the end to allow overwriting
|
||||
defaults.putAll( themeSpecificDefaults );
|
||||
for( Map.Entry<Object, Object> e : themeSpecificDefaults.entrySet() ) {
|
||||
Object key = e.getKey();
|
||||
Object value = e.getValue();
|
||||
|
||||
// append styles to existing styles
|
||||
if( key instanceof String && ((String)key).startsWith( "[style]" ) ) {
|
||||
Object oldValue = defaults.get( key );
|
||||
if( oldValue != null )
|
||||
value = oldValue + "; " + value;
|
||||
}
|
||||
|
||||
defaults.put( key, value );
|
||||
}
|
||||
}
|
||||
|
||||
private Map<Object, Object> removeThemeSpecificDefaults( UIDefaults defaults ) {
|
||||
@@ -299,8 +315,19 @@ public class IntelliJTheme
|
||||
@SuppressWarnings( "unchecked" )
|
||||
private void apply( String key, Object value, UIDefaults defaults, ArrayList<Object> defaultsKeysCache, Set<String> uiKeys ) {
|
||||
if( value instanceof Map ) {
|
||||
for( Map.Entry<String, Object> e : ((Map<String, Object>)value).entrySet() )
|
||||
apply( key + '.' + e.getKey(), e.getValue(), defaults, defaultsKeysCache, uiKeys );
|
||||
Map<String, Object> map = (Map<String, Object>)value;
|
||||
if( map.containsKey( "os.default" ) || map.containsKey( "os.windows" ) || map.containsKey( "os.mac" ) || map.containsKey( "os.linux" ) ) {
|
||||
String osKey = SystemInfo.isWindows ? "os.windows"
|
||||
: SystemInfo.isMacOS ? "os.mac"
|
||||
: SystemInfo.isLinux ? "os.linux" : null;
|
||||
if( osKey != null && map.containsKey( osKey ) )
|
||||
apply( key, map.get( osKey ), defaults, defaultsKeysCache, uiKeys );
|
||||
else if( map.containsKey( "os.default" ) )
|
||||
apply( key, map.get( "os.default" ), defaults, defaultsKeysCache, uiKeys );
|
||||
} else {
|
||||
for( Map.Entry<String, Object> e : map.entrySet() )
|
||||
apply( key + '.' + e.getKey(), e.getValue(), defaults, defaultsKeysCache, uiKeys );
|
||||
}
|
||||
} else {
|
||||
if( "".equals( value ) )
|
||||
return; // ignore empty value
|
||||
@@ -534,12 +561,12 @@ public class IntelliJTheme
|
||||
}
|
||||
|
||||
/** Rename UI default keys (key --> value). */
|
||||
private static Map<String, String> uiKeyMapping = new HashMap<>();
|
||||
private static final Map<String, String> uiKeyMapping = new HashMap<>();
|
||||
/** Copy UI default keys (value --> key). */
|
||||
private static Map<String, String> uiKeyCopying = new HashMap<>();
|
||||
private static Map<String, String> uiKeyInverseMapping = new HashMap<>();
|
||||
private static Map<String, String> checkboxKeyMapping = new HashMap<>();
|
||||
private static Map<String, String> checkboxDuplicateColors = new HashMap<>();
|
||||
private static final Map<String, String> uiKeyCopying = new HashMap<>();
|
||||
private static final Map<String, String> uiKeyInverseMapping = new HashMap<>();
|
||||
private static final Map<String, String> checkboxKeyMapping = new HashMap<>();
|
||||
private static final Map<String, String> checkboxDuplicateColors = new HashMap<>();
|
||||
|
||||
static {
|
||||
// ComboBox
|
||||
@@ -600,6 +627,11 @@ public class IntelliJTheme
|
||||
uiKeyCopying.put( "Spinner.buttonSeparatorColor", "Component.borderColor" );
|
||||
uiKeyCopying.put( "Spinner.buttonDisabledSeparatorColor", "Component.disabledBorderColor" );
|
||||
|
||||
// TabbedPane
|
||||
uiKeyCopying.put( "TabbedPane.selectedBackground", "DefaultTabs.underlinedTabBackground" );
|
||||
uiKeyCopying.put( "TabbedPane.selectedForeground", "DefaultTabs.underlinedTabForeground" );
|
||||
uiKeyCopying.put( "TabbedPane.inactiveUnderlineColor", "DefaultTabs.inactiveUnderlineColor" );
|
||||
|
||||
// TitlePane
|
||||
uiKeyCopying.put( "TitlePane.inactiveBackground", "TitlePane.background" );
|
||||
uiKeyMapping.put( "TitlePane.infoForeground", "TitlePane.foreground" );
|
||||
|
||||
@@ -170,7 +170,7 @@ class LinuxFontPolicy
|
||||
|
||||
Object value = Toolkit.getDefaultToolkit().getDesktopProperty( "gnome.Xft/DPI" );
|
||||
if( value instanceof Integer ) {
|
||||
int dpi = ((Integer)value).intValue() / 1024;
|
||||
int dpi = (Integer) value / 1024;
|
||||
if( dpi == -1 )
|
||||
dpi = 96;
|
||||
if( dpi < 50 )
|
||||
@@ -197,7 +197,7 @@ class LinuxFontPolicy
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default font for KDE for KDE configuration files.
|
||||
* Gets the default font for KDE from KDE configuration files.
|
||||
*
|
||||
* The Swing fonts are not updated when the user changes system font size
|
||||
* (System Settings > Fonts > Force Font DPI). A application restart is necessary.
|
||||
@@ -278,7 +278,7 @@ class LinuxFontPolicy
|
||||
// read config file
|
||||
ArrayList<String> lines = new ArrayList<>( 200 );
|
||||
try( BufferedReader reader = new BufferedReader( new FileReader( file ) ) ) {
|
||||
String line = null;
|
||||
String line;
|
||||
while( (line = reader.readLine()) != null )
|
||||
lines.add( line );
|
||||
} catch( IOException ex ) {
|
||||
|
||||
@@ -0,0 +1,336 @@
|
||||
/*
|
||||
* Copyright 2022 FormDev Software GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf;
|
||||
|
||||
import java.awt.AWTEvent;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.MouseInfo;
|
||||
import java.awt.Point;
|
||||
import java.awt.PointerInfo;
|
||||
import java.awt.Polygon;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.MouseEvent;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLayeredPane;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.MenuElement;
|
||||
import javax.swing.MenuSelectionManager;
|
||||
import javax.swing.RootPaneContainer;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.Timer;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
|
||||
/**
|
||||
* Improves usability of submenus by using a
|
||||
* <a href="https://height.app/blog/guide-to-build-context-menus#safe-triangle">safe triangle</a>
|
||||
* to avoid that the submenu closes while the user moves the mouse to it.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
class SubMenuUsabilityHelper
|
||||
implements ChangeListener
|
||||
{
|
||||
private static final String KEY_USE_SAFE_TRIANGLE = "Menu.useSafeTriangle";
|
||||
private static final String KEY_SHOW_SAFE_TRIANGLE = "FlatLaf.debug.menu.showSafeTriangle";
|
||||
|
||||
// Using a static field to ensure that there is only one instance in the system.
|
||||
// Multiple instances would freeze the application.
|
||||
// https://github.com/apache/netbeans/issues/4231#issuecomment-1179616607
|
||||
private static SubMenuUsabilityHelper instance;
|
||||
|
||||
private SubMenuEventQueue subMenuEventQueue;
|
||||
private SafeTrianglePainter safeTrianglePainter;
|
||||
private boolean changePending;
|
||||
|
||||
// mouse location in screen coordinates
|
||||
private int mouseX;
|
||||
private int mouseY;
|
||||
|
||||
// target popup bounds in screen coordinates
|
||||
private int targetX;
|
||||
private int targetTopY;
|
||||
private int targetBottomY;
|
||||
|
||||
private Rectangle invokerBounds;
|
||||
|
||||
static synchronized boolean install() {
|
||||
if( instance != null )
|
||||
return false;
|
||||
|
||||
instance = new SubMenuUsabilityHelper();
|
||||
MenuSelectionManager.defaultManager().addChangeListener( instance );
|
||||
return true;
|
||||
}
|
||||
|
||||
static synchronized void uninstall() {
|
||||
if( instance == null )
|
||||
return;
|
||||
|
||||
MenuSelectionManager.defaultManager().removeChangeListener( instance );
|
||||
instance.uninstallEventQueue();
|
||||
instance = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stateChanged( ChangeEvent e ) {
|
||||
if( !FlatUIUtils.getUIBoolean( KEY_USE_SAFE_TRIANGLE, true ))
|
||||
return;
|
||||
|
||||
// handle menu selection change later, but only once in case of temporary changes
|
||||
// e.g. moving mouse from one menu item to another one, fires two events:
|
||||
// 1. old menu item is removed from menu selection
|
||||
// 2. new menu item is added to menu selection
|
||||
synchronized( this ) {
|
||||
if( changePending )
|
||||
return;
|
||||
changePending = true;
|
||||
}
|
||||
|
||||
EventQueue.invokeLater( () -> {
|
||||
synchronized( this ) {
|
||||
changePending = false;
|
||||
}
|
||||
menuSelectionChanged();
|
||||
} );
|
||||
}
|
||||
|
||||
private void menuSelectionChanged() {
|
||||
MenuElement[] path = MenuSelectionManager.defaultManager().getSelectedPath();
|
||||
|
||||
/*debug
|
||||
System.out.println( "--- " + path.length );
|
||||
for( int i = 0; i < path.length; i++ )
|
||||
System.out.println( " " + i + ": " + path[i].getClass().getName() );
|
||||
debug*/
|
||||
|
||||
// find submenu in menu selection
|
||||
int subMenuIndex = findSubMenu( path );
|
||||
|
||||
// uninstall if there is no submenu in selection
|
||||
if( subMenuIndex < 0 || subMenuIndex != path.length - 1 ) {
|
||||
uninstallEventQueue();
|
||||
return;
|
||||
}
|
||||
|
||||
// get current mouse location
|
||||
PointerInfo pointerInfo = MouseInfo.getPointerInfo();
|
||||
Point mouseLocation = (pointerInfo != null) ? pointerInfo.getLocation() : new Point();
|
||||
mouseX = mouseLocation.x;
|
||||
mouseY = mouseLocation.y;
|
||||
|
||||
// check whether popup is showing, which is e.g. not the case if it is empty
|
||||
JPopupMenu popup = (JPopupMenu) path[subMenuIndex];
|
||||
if( !popup.isShowing() ) {
|
||||
uninstallEventQueue();
|
||||
return;
|
||||
}
|
||||
|
||||
// get invoker screen bounds
|
||||
Component invoker = popup.getInvoker();
|
||||
invokerBounds = (invoker != null)
|
||||
? new Rectangle( invoker.getLocationOnScreen(), invoker.getSize() )
|
||||
: null;
|
||||
|
||||
// check whether mouse location is within invoker
|
||||
if( invokerBounds != null && !invokerBounds.contains( mouseX, mouseY ) ) {
|
||||
uninstallEventQueue();
|
||||
return;
|
||||
}
|
||||
|
||||
// compute top/bottom target locations
|
||||
Point popupLocation = popup.getLocationOnScreen();
|
||||
Dimension popupSize = popup.getSize();
|
||||
targetX = (mouseX < popupLocation.x + (popupSize.width / 2))
|
||||
? popupLocation.x
|
||||
: popupLocation.x + popupSize.width;
|
||||
targetTopY = popupLocation.y;
|
||||
targetBottomY = popupLocation.y + popupSize.height;
|
||||
|
||||
// install own event queue to supress mouse events when mouse is moved within safe triangle
|
||||
if( subMenuEventQueue == null )
|
||||
subMenuEventQueue = new SubMenuEventQueue();
|
||||
|
||||
// create safe triangle painter
|
||||
if( safeTrianglePainter == null && UIManager.getBoolean( KEY_SHOW_SAFE_TRIANGLE ) )
|
||||
safeTrianglePainter = new SafeTrianglePainter( popup );
|
||||
}
|
||||
|
||||
private void uninstallEventQueue() {
|
||||
if( subMenuEventQueue != null ) {
|
||||
subMenuEventQueue.uninstall();
|
||||
subMenuEventQueue = null;
|
||||
}
|
||||
|
||||
if( safeTrianglePainter != null ) {
|
||||
safeTrianglePainter.uninstall();
|
||||
safeTrianglePainter = null;
|
||||
}
|
||||
}
|
||||
|
||||
private int findSubMenu( MenuElement[] path ) {
|
||||
for( int i = path.length - 1; i >= 1; i-- ) {
|
||||
if( path[i] instanceof JPopupMenu &&
|
||||
path[i - 1] instanceof JMenu &&
|
||||
!((JMenu)path[i - 1]).isTopLevelMenu() )
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private Polygon createSafeTriangle() {
|
||||
return new Polygon(
|
||||
new int[] { mouseX, targetX, targetX },
|
||||
new int[] { mouseY, targetTopY, targetBottomY },
|
||||
3 );
|
||||
}
|
||||
|
||||
//---- class SubMenuEventQueue --------------------------------------------
|
||||
|
||||
private class SubMenuEventQueue
|
||||
extends EventQueue
|
||||
{
|
||||
private Timer mouseUpdateTimer;
|
||||
private Timer timeoutTimer;
|
||||
|
||||
private int newMouseX;
|
||||
private int newMouseY;
|
||||
private AWTEvent lastMouseEvent;
|
||||
|
||||
SubMenuEventQueue() {
|
||||
// timer used to slightly delay update of mouse location used for safe triangle
|
||||
mouseUpdateTimer = new Timer( 50, e -> {
|
||||
mouseX = newMouseX;
|
||||
mouseY = newMouseY;
|
||||
|
||||
if( safeTrianglePainter != null )
|
||||
safeTrianglePainter.repaint();
|
||||
} );
|
||||
mouseUpdateTimer.setRepeats( false );
|
||||
|
||||
// timer used to timeout safe triangle when mouse stops moving
|
||||
timeoutTimer = new Timer( 200, e -> {
|
||||
if( invokerBounds != null && !invokerBounds.contains( newMouseX, newMouseY ) ) {
|
||||
// post last mouse event, which selects menu item at mouse location
|
||||
if( lastMouseEvent != null ) {
|
||||
postEvent( lastMouseEvent );
|
||||
lastMouseEvent = null;
|
||||
}
|
||||
|
||||
uninstallEventQueue();
|
||||
return;
|
||||
}
|
||||
} );
|
||||
timeoutTimer.setRepeats( false );
|
||||
|
||||
Toolkit.getDefaultToolkit().getSystemEventQueue().push( this );
|
||||
}
|
||||
|
||||
void uninstall() {
|
||||
mouseUpdateTimer.stop();
|
||||
mouseUpdateTimer = null;
|
||||
|
||||
timeoutTimer.stop();
|
||||
timeoutTimer = null;
|
||||
|
||||
lastMouseEvent = null;
|
||||
|
||||
super.pop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dispatchEvent( AWTEvent e ) {
|
||||
int id = e.getID();
|
||||
|
||||
if( e instanceof MouseEvent &&
|
||||
(id == MouseEvent.MOUSE_MOVED || id == MouseEvent.MOUSE_DRAGGED) )
|
||||
{
|
||||
newMouseX = ((MouseEvent)e).getXOnScreen();
|
||||
newMouseY = ((MouseEvent)e).getYOnScreen();
|
||||
|
||||
if( safeTrianglePainter != null )
|
||||
safeTrianglePainter.repaint();
|
||||
|
||||
mouseUpdateTimer.stop();
|
||||
timeoutTimer.stop();
|
||||
|
||||
// check whether mouse moved within safe triangle
|
||||
if( createSafeTriangle().contains( newMouseX, newMouseY ) ) {
|
||||
// update mouse location delayed (this changes the safe triangle)
|
||||
mouseUpdateTimer.start();
|
||||
|
||||
timeoutTimer.start();
|
||||
|
||||
// remember last mouse event, which will be posted if the mouse stops moving
|
||||
lastMouseEvent = e;
|
||||
|
||||
// ignore mouse event
|
||||
return;
|
||||
}
|
||||
|
||||
// update mouse location immediately (this changes the safe triangle)
|
||||
mouseX = newMouseX;
|
||||
mouseY = newMouseY;
|
||||
}
|
||||
|
||||
super.dispatchEvent( e );
|
||||
}
|
||||
}
|
||||
|
||||
//---- class SafeTrianglePainter ------------------------------------------
|
||||
|
||||
private class SafeTrianglePainter
|
||||
extends JComponent
|
||||
{
|
||||
SafeTrianglePainter( JPopupMenu popup ) {
|
||||
Window window = SwingUtilities.windowForComponent( popup.getInvoker() );
|
||||
if( window instanceof RootPaneContainer ) {
|
||||
JLayeredPane layeredPane = ((RootPaneContainer)window).getLayeredPane();
|
||||
setSize( layeredPane.getSize() );
|
||||
layeredPane.add( this, new Integer( JLayeredPane.POPUP_LAYER + 1 ) );
|
||||
}
|
||||
}
|
||||
|
||||
void uninstall() {
|
||||
Container parent = getParent();
|
||||
if( parent != null ) {
|
||||
parent.remove( this );
|
||||
parent.repaint();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintComponent( Graphics g ) {
|
||||
Point locationOnScreen = getLocationOnScreen();
|
||||
g.translate( -locationOnScreen.x, -locationOnScreen.y );
|
||||
|
||||
g.setColor( Color.red );
|
||||
((Graphics2D)g).draw( createSafeTriangle() );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -350,7 +350,7 @@ class UIDefaultsLoader
|
||||
enum ValueType { UNKNOWN, STRING, BOOLEAN, CHARACTER, INTEGER, INTEGERORFLOAT, FLOAT, BORDER, ICON, INSETS, DIMENSION, COLOR, FONT,
|
||||
SCALEDINTEGER, SCALEDFLOAT, SCALEDINSETS, SCALEDDIMENSION, INSTANCE, CLASS, GRAYFILTER, NULL, LAZY }
|
||||
|
||||
private static ValueType[] tempResultValueType = new ValueType[1];
|
||||
private static final ValueType[] tempResultValueType = new ValueType[1];
|
||||
private static Map<Class<?>, ValueType> javaValueTypes;
|
||||
private static Map<String, ValueType> knownValueTypes;
|
||||
|
||||
@@ -466,6 +466,10 @@ class UIDefaultsLoader
|
||||
if( knownValueTypes == null ) {
|
||||
// create lazy
|
||||
knownValueTypes = new HashMap<>();
|
||||
// system colors
|
||||
knownValueTypes.put( "activeCaptionBorder", ValueType.COLOR );
|
||||
knownValueTypes.put( "inactiveCaptionBorder", ValueType.COLOR );
|
||||
knownValueTypes.put( "windowBorder", ValueType.COLOR );
|
||||
// SplitPane
|
||||
knownValueTypes.put( "SplitPane.dividerSize", ValueType.INTEGER );
|
||||
knownValueTypes.put( "SplitPaneDivider.gripDotSize", ValueType.INTEGER );
|
||||
@@ -780,6 +784,7 @@ class UIDefaultsLoader
|
||||
case "tint": return parseColorMix( "#fff", params, resolver, reportError );
|
||||
case "shade": return parseColorMix( "#000", params, resolver, reportError );
|
||||
case "contrast": return parseColorContrast( params, resolver, reportError );
|
||||
case "over": return parseColorOver( params, resolver, reportError );
|
||||
}
|
||||
} finally {
|
||||
parseColorDepth--;
|
||||
@@ -792,7 +797,7 @@ class UIDefaultsLoader
|
||||
* Syntax: if(condition,trueValue,falseValue)
|
||||
* <p>
|
||||
* This "if" function is only used if the "if" is passed as parameter to another
|
||||
* color function. Otherwise the general "if" function is used.
|
||||
* color function. Otherwise, the general "if" function is used.
|
||||
*/
|
||||
private static Object parseColorIf( String value, List<String> params, Function<String, String> resolver, boolean reportError ) {
|
||||
if( params.size() != 3 )
|
||||
@@ -847,7 +852,7 @@ class UIDefaultsLoader
|
||||
int lightness = parsePercentage( params.get( 2 ) );
|
||||
int alpha = hasAlpha ? parsePercentage( params.get( 3 ) ) : 100;
|
||||
|
||||
float[] hsl = new float[] { hue, saturation, lightness };
|
||||
float[] hsl = { hue, saturation, lightness };
|
||||
return new ColorUIResource( HSLColor.toRGB( hsl, alpha / 100f ) );
|
||||
}
|
||||
|
||||
@@ -1041,6 +1046,33 @@ class UIDefaultsLoader
|
||||
return parseColorOrFunction( resolver.apply( darkOrLightColor ), resolver, reportError );
|
||||
}
|
||||
|
||||
/**
|
||||
* Syntax: over(foreground,background)
|
||||
* - foreground: a foreground color (e.g. #f00) or a color function;
|
||||
* the alpha of this color is used as weight to mix the two colors
|
||||
* - background: a background color (e.g. #f00) or a color function
|
||||
*/
|
||||
private static Object parseColorOver( List<String> params, Function<String, String> resolver, boolean reportError ) {
|
||||
String foregroundStr = params.get( 0 );
|
||||
String backgroundStr = params.get( 1 );
|
||||
|
||||
// parse foreground color
|
||||
ColorUIResource foreground = (ColorUIResource) parseColorOrFunction( resolver.apply( foregroundStr ), resolver, reportError );
|
||||
if( foreground == null || foreground.getAlpha() == 255 )
|
||||
return foreground;
|
||||
|
||||
Color foreground2 = new Color( foreground.getRGB() );
|
||||
|
||||
// parse background color
|
||||
ColorUIResource background = (ColorUIResource) parseColorOrFunction( resolver.apply( backgroundStr ), resolver, reportError );
|
||||
if( background == null )
|
||||
return foreground2;
|
||||
|
||||
// create new color
|
||||
float weight = foreground.getAlpha() / 255f;
|
||||
return new ColorUIResource( ColorFunctions.mix( foreground2, background, weight ) );
|
||||
}
|
||||
|
||||
private static Object parseFunctionBaseColor( String colorStr, ColorFunction function,
|
||||
boolean derived, Function<String, String> resolver, boolean reportError )
|
||||
{
|
||||
@@ -1209,7 +1241,7 @@ class UIDefaultsLoader
|
||||
}
|
||||
|
||||
Integer integer = parseInteger( value, true );
|
||||
if( integer.intValue() < min || integer.intValue() > max )
|
||||
if( integer < min || integer > max )
|
||||
throw new NumberFormatException( "integer '" + value + "' out of range (" + min + '-' + max + ')' );
|
||||
return integer;
|
||||
}
|
||||
@@ -1250,28 +1282,28 @@ class UIDefaultsLoader
|
||||
|
||||
private static ActiveValue parseScaledInteger( String value ) {
|
||||
int val = parseInteger( value, true );
|
||||
return (ActiveValue) t -> {
|
||||
return t -> {
|
||||
return UIScale.scale( val );
|
||||
};
|
||||
}
|
||||
|
||||
private static ActiveValue parseScaledFloat( String value ) {
|
||||
float val = parseFloat( value, true );
|
||||
return (ActiveValue) t -> {
|
||||
return t -> {
|
||||
return UIScale.scale( val );
|
||||
};
|
||||
}
|
||||
|
||||
private static ActiveValue parseScaledInsets( String value ) {
|
||||
Insets insets = parseInsets( value );
|
||||
return (ActiveValue) t -> {
|
||||
return t -> {
|
||||
return UIScale.scale( insets );
|
||||
};
|
||||
}
|
||||
|
||||
private static ActiveValue parseScaledDimension( String value ) {
|
||||
Dimension dimension = parseDimension( value );
|
||||
return (ActiveValue) t -> {
|
||||
return t -> {
|
||||
return UIScale.scale( dimension );
|
||||
};
|
||||
}
|
||||
|
||||
@@ -23,13 +23,13 @@ import java.awt.Graphics2D;
|
||||
import com.formdev.flatlaf.util.AnimatedIcon;
|
||||
|
||||
/**
|
||||
* Base class for animated icons that scales width and height, creates and initializes
|
||||
* Base class for animated icons that scale width and height, creates and initializes
|
||||
* a scaled graphics context for icon painting.
|
||||
* <p>
|
||||
* Subclasses do not need to scale icon painting.
|
||||
* <p>
|
||||
* This class does not store any state information (needed for animation) in its instance.
|
||||
* Instead a client property is set on the painted component.
|
||||
* Instead, a client property is set on the painted component.
|
||||
* This makes it possible to use a share icon instance for multiple components.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
|
||||
@@ -51,7 +51,7 @@ public class FlatAscendingSortIcon
|
||||
boolean chevron = this.chevron;
|
||||
Color sortIconColor = this.sortIconColor;
|
||||
|
||||
// Because this icons are always shared for all table headers,
|
||||
// Because this icon is always shared for all table headers,
|
||||
// get icon specific style from FlatTableHeaderUI.
|
||||
JTableHeader tableHeader = (JTableHeader) SwingUtilities.getAncestorOfClass( JTableHeader.class, c );
|
||||
if( tableHeader != null ) {
|
||||
|
||||
@@ -96,8 +96,8 @@ public class FlatHelpButtonIcon
|
||||
</svg>
|
||||
*/
|
||||
|
||||
boolean enabled = c.isEnabled();
|
||||
boolean focused = FlatUIUtils.isPermanentFocusOwner( c );
|
||||
boolean enabled = c == null || c.isEnabled();
|
||||
boolean focused = c != null && FlatUIUtils.isPermanentFocusOwner( c );
|
||||
|
||||
float xy = 0.5f;
|
||||
float wh = iconSize() - 1;
|
||||
|
||||
@@ -63,7 +63,7 @@ public class FlatMenuArrowIcon
|
||||
|
||||
@Override
|
||||
protected void paintIcon( Component c, Graphics2D g ) {
|
||||
if( !c.getComponentOrientation().isLeftToRight() )
|
||||
if( c != null && !c.getComponentOrientation().isLeftToRight() )
|
||||
g.rotate( Math.toRadians( 180 ), width / 2., height / 2. );
|
||||
|
||||
g.setColor( getArrowColor( c ) );
|
||||
@@ -82,7 +82,7 @@ public class FlatMenuArrowIcon
|
||||
if( c instanceof JMenu && ((JMenu)c).isSelected() && !isUnderlineSelection() )
|
||||
return selectionForeground;
|
||||
|
||||
return c.isEnabled() ? arrowColor : disabledArrowColor;
|
||||
return c == null || c.isEnabled() ? arrowColor : disabledArrowColor;
|
||||
}
|
||||
|
||||
protected boolean isUnderlineSelection() {
|
||||
|
||||
@@ -76,7 +76,7 @@ public class FlatTreeCollapsedIcon
|
||||
}
|
||||
|
||||
/**
|
||||
* Because this icons are always shared for all trees,
|
||||
* Because this icon is always shared for all trees,
|
||||
* get icon specific style from FlatTreeUI.
|
||||
*/
|
||||
static <T> T getStyleFromTreeUI( Component c, Function<FlatTreeUI, T> f ) {
|
||||
|
||||
@@ -18,8 +18,8 @@ package com.formdev.flatlaf.resources;
|
||||
|
||||
/**
|
||||
* The only purpose of this file is to add a .class file to this package to make it non-empty.
|
||||
* Otherwise the compiler outputs a warning because this package is opend in module-info.java.
|
||||
* Also when using --patch-module (e.g. from an IDE), an error would occur for empty packages.
|
||||
* Otherwise, the compiler outputs a warning because this package is opened in module-info.java.
|
||||
* Also, when using --patch-module (e.g. from an IDE), an error would occur for empty packages.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
|
||||
@@ -37,7 +37,7 @@ public class FlatArrowButton
|
||||
extends BasicArrowButton
|
||||
implements UIResource
|
||||
{
|
||||
public static final int DEFAULT_ARROW_WIDTH = 8;
|
||||
public static final int DEFAULT_ARROW_WIDTH = 9;
|
||||
|
||||
protected boolean chevron;
|
||||
protected Color foreground;
|
||||
@@ -211,6 +211,6 @@ public class FlatArrowButton
|
||||
if( vert && parent instanceof JComponent && FlatUIUtils.hasRoundBorder( (JComponent) parent ) )
|
||||
x -= scale( parent.getComponentOrientation().isLeftToRight() ? 1 : -1 );
|
||||
|
||||
FlatUIUtils.paintArrow( g, x, 0, getWidth(), getHeight(), getDirection(), chevron, arrowWidth, xOffset, yOffset );
|
||||
FlatUIUtils.paintArrow( g, x, 0, getWidth(), getHeight(), getDirection(), chevron, getArrowWidth(), getXOffset(), getYOffset() );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,7 +159,7 @@ public class FlatButtonBorder
|
||||
public Insets getBorderInsets( Component c, Insets insets ) {
|
||||
if( FlatButtonUI.isToolBarButton( c ) ) {
|
||||
// In toolbars, use button margin only if explicitly set.
|
||||
// Otherwise use toolbar margin specified in UI defaults.
|
||||
// Otherwise, use toolbar margin specified in UI defaults.
|
||||
Insets margin = (c instanceof AbstractButton)
|
||||
? ((AbstractButton)c).getMargin()
|
||||
: null;
|
||||
|
||||
@@ -42,6 +42,7 @@ import javax.swing.JTextField;
|
||||
import javax.swing.JToggleButton;
|
||||
import javax.swing.JToolBar;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ButtonUI;
|
||||
@@ -77,20 +78,27 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault Button.startBackground Color optional; if set, a gradient paint is used and Button.background is ignored
|
||||
* @uiDefault Button.endBackground Color optional; if set, a gradient paint is used
|
||||
* @uiDefault Button.focusedBackground Color optional
|
||||
* @uiDefault Button.focusedForeground Color optional
|
||||
* @uiDefault Button.hoverBackground Color optional
|
||||
* @uiDefault Button.hoverForeground Color optional
|
||||
* @uiDefault Button.pressedBackground Color optional
|
||||
* @uiDefault Button.pressedForeground Color optional
|
||||
* @uiDefault Button.selectedBackground Color
|
||||
* @uiDefault Button.selectedForeground Color
|
||||
* @uiDefault Button.disabledBackground Color optional
|
||||
* @uiDefault Button.disabledText Color
|
||||
* @uiDefault Button.disabledSelectedBackground Color
|
||||
* @uiDefault Button.disabledSelectedForeground Color optional
|
||||
* @uiDefault Button.default.background Color
|
||||
* @uiDefault Button.default.startBackground Color optional; if set, a gradient paint is used and Button.default.background is ignored
|
||||
* @uiDefault Button.default.endBackground Color optional; if set, a gradient paint is used
|
||||
* @uiDefault Button.default.foreground Color
|
||||
* @uiDefault Button.default.focusedBackground Color optional
|
||||
* @uiDefault Button.default.focusedForeground Color optional
|
||||
* @uiDefault Button.default.hoverBackground Color optional
|
||||
* @uiDefault Button.default.hoverForeground Color optional
|
||||
* @uiDefault Button.default.pressedBackground Color optional
|
||||
* @uiDefault Button.default.pressedForeground Color optional
|
||||
* @uiDefault Button.default.boldText boolean
|
||||
* @uiDefault Button.paintShadow boolean default is false
|
||||
* @uiDefault Button.shadowWidth int default is 2
|
||||
@@ -98,8 +106,13 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault Button.default.shadowColor Color optional
|
||||
* @uiDefault Button.toolbar.spacingInsets Insets
|
||||
* @uiDefault Button.toolbar.hoverBackground Color
|
||||
* @uiDefault Button.toolbar.hoverForeground Color optional
|
||||
* @uiDefault Button.toolbar.pressedBackground Color
|
||||
* @uiDefault Button.toolbar.pressedForeground Color optional
|
||||
* @uiDefault Button.toolbar.selectedBackground Color
|
||||
* @uiDefault Button.toolbar.selectedForeground Color optional
|
||||
* @uiDefault Button.toolbar.disabledSelectedBackground Color optional
|
||||
* @uiDefault Button.toolbar.disabledSelectedForeground Color optional
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
@@ -116,20 +129,27 @@ public class FlatButtonUI
|
||||
protected Color startBackground;
|
||||
protected Color endBackground;
|
||||
@Styleable protected Color focusedBackground;
|
||||
/** @since 2.3 */ @Styleable protected Color focusedForeground;
|
||||
@Styleable protected Color hoverBackground;
|
||||
/** @since 2.3 */ @Styleable protected Color hoverForeground;
|
||||
@Styleable protected Color pressedBackground;
|
||||
/** @since 2.3 */ @Styleable protected Color pressedForeground;
|
||||
@Styleable protected Color selectedBackground;
|
||||
@Styleable protected Color selectedForeground;
|
||||
@Styleable protected Color disabledBackground;
|
||||
@Styleable protected Color disabledText;
|
||||
@Styleable protected Color disabledSelectedBackground;
|
||||
/** @since 2.3 */ @Styleable protected Color disabledSelectedForeground;
|
||||
|
||||
@Styleable(dot=true) protected Color defaultBackground;
|
||||
protected Color defaultEndBackground;
|
||||
@Styleable(dot=true) protected Color defaultForeground;
|
||||
@Styleable(dot=true) protected Color defaultFocusedBackground;
|
||||
/** @since 2.3 */ @Styleable(dot=true) protected Color defaultFocusedForeground;
|
||||
@Styleable(dot=true) protected Color defaultHoverBackground;
|
||||
/** @since 2.3 */ @Styleable(dot=true) protected Color defaultHoverForeground;
|
||||
@Styleable(dot=true) protected Color defaultPressedBackground;
|
||||
/** @since 2.3 */ @Styleable(dot=true) protected Color defaultPressedForeground;
|
||||
@Styleable(dot=true) protected boolean defaultBoldText;
|
||||
|
||||
@Styleable protected boolean paintShadow;
|
||||
@@ -138,8 +158,13 @@ public class FlatButtonUI
|
||||
@Styleable(dot=true) protected Color defaultShadowColor;
|
||||
|
||||
@Styleable(dot=true) protected Color toolbarHoverBackground;
|
||||
/** @since 2.3 */ @Styleable(dot=true) protected Color toolbarHoverForeground;
|
||||
@Styleable(dot=true) protected Color toolbarPressedBackground;
|
||||
/** @since 2.3 */ @Styleable(dot=true) protected Color toolbarPressedForeground;
|
||||
@Styleable(dot=true) protected Color toolbarSelectedBackground;
|
||||
/** @since 2.3 */ @Styleable(dot=true) protected Color toolbarSelectedForeground;
|
||||
/** @since 2.3 */ @Styleable(dot=true) protected Color toolbarDisabledSelectedBackground;
|
||||
/** @since 2.3 */ @Styleable(dot=true) protected Color toolbarDisabledSelectedForeground;
|
||||
|
||||
// only used via styling (not in UI defaults, but has likewise client properties)
|
||||
/** @since 2 */ @Styleable protected String buttonType;
|
||||
@@ -189,20 +214,27 @@ public class FlatButtonUI
|
||||
startBackground = UIManager.getColor( prefix + "startBackground" );
|
||||
endBackground = UIManager.getColor( prefix + "endBackground" );
|
||||
focusedBackground = UIManager.getColor( prefix + "focusedBackground" );
|
||||
focusedForeground = UIManager.getColor( prefix + "focusedForeground" );
|
||||
hoverBackground = UIManager.getColor( prefix + "hoverBackground" );
|
||||
hoverForeground = UIManager.getColor( prefix + "hoverForeground" );
|
||||
pressedBackground = UIManager.getColor( prefix + "pressedBackground" );
|
||||
pressedForeground = UIManager.getColor( prefix + "pressedForeground" );
|
||||
selectedBackground = UIManager.getColor( prefix + "selectedBackground" );
|
||||
selectedForeground = UIManager.getColor( prefix + "selectedForeground" );
|
||||
disabledBackground = UIManager.getColor( prefix + "disabledBackground" );
|
||||
disabledText = UIManager.getColor( prefix + "disabledText" );
|
||||
disabledSelectedBackground = UIManager.getColor( prefix + "disabledSelectedBackground" );
|
||||
disabledSelectedForeground = UIManager.getColor( prefix + "disabledSelectedForeground" );
|
||||
|
||||
defaultBackground = FlatUIUtils.getUIColor( "Button.default.startBackground", "Button.default.background" );
|
||||
defaultEndBackground = UIManager.getColor( "Button.default.endBackground" );
|
||||
defaultForeground = UIManager.getColor( "Button.default.foreground" );
|
||||
defaultFocusedBackground = UIManager.getColor( "Button.default.focusedBackground" );
|
||||
defaultFocusedForeground = UIManager.getColor( "Button.default.focusedForeground" );
|
||||
defaultHoverBackground = UIManager.getColor( "Button.default.hoverBackground" );
|
||||
defaultHoverForeground = UIManager.getColor( "Button.default.hoverForeground" );
|
||||
defaultPressedBackground = UIManager.getColor( "Button.default.pressedBackground" );
|
||||
defaultPressedForeground = UIManager.getColor( "Button.default.pressedForeground" );
|
||||
defaultBoldText = UIManager.getBoolean( "Button.default.boldText" );
|
||||
|
||||
paintShadow = UIManager.getBoolean( "Button.paintShadow" );
|
||||
@@ -211,8 +243,13 @@ public class FlatButtonUI
|
||||
defaultShadowColor = UIManager.getColor( "Button.default.shadowColor" );
|
||||
|
||||
toolbarHoverBackground = UIManager.getColor( prefix + "toolbar.hoverBackground" );
|
||||
toolbarHoverForeground = UIManager.getColor( prefix + "toolbar.hoverForeground" );
|
||||
toolbarPressedBackground = UIManager.getColor( prefix + "toolbar.pressedBackground" );
|
||||
toolbarPressedForeground = UIManager.getColor( prefix + "toolbar.pressedForeground" );
|
||||
toolbarSelectedBackground = UIManager.getColor( prefix + "toolbar.selectedBackground" );
|
||||
toolbarSelectedForeground = UIManager.getColor( prefix + "toolbar.selectedForeground" );
|
||||
toolbarDisabledSelectedBackground = UIManager.getColor( prefix + "toolbar.disabledSelectedBackground" );
|
||||
toolbarDisabledSelectedForeground = UIManager.getColor( prefix + "toolbar.disabledSelectedForeground" );
|
||||
|
||||
helpButtonIcon = UIManager.getIcon( "HelpButton.icon" );
|
||||
defaultMargin = UIManager.getInsets( prefix + "margin" );
|
||||
@@ -262,6 +299,10 @@ public class FlatButtonUI
|
||||
b.repaint();
|
||||
break;
|
||||
|
||||
case OUTLINE:
|
||||
b.repaint();
|
||||
break;
|
||||
|
||||
case STYLE:
|
||||
case STYLE_CLASS:
|
||||
if( shared && FlatStylingSupport.hasStyleProperty( b ) ) {
|
||||
@@ -339,7 +380,7 @@ public class FlatButtonUI
|
||||
|
||||
/**
|
||||
* Returns true if the button has an icon but no text,
|
||||
* or it it does not have an icon and the text is either "..." or one character.
|
||||
* or it does not have an icon and the text is either "..." or one character.
|
||||
*/
|
||||
static boolean isIconOnlyOrSingleCharacterButton( Component c ) {
|
||||
if( !(c instanceof JButton) && !(c instanceof JToggleButton) )
|
||||
@@ -490,6 +531,23 @@ public class FlatButtonUI
|
||||
super.paint( FlatLabelUI.createGraphicsHTMLTextYCorrection( g, c ), c );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintIcon( Graphics g, JComponent c, Rectangle iconRect ) {
|
||||
// correct icon location when using bold font for default button
|
||||
int xOffset = defaultBoldPlainWidthDiff( c ) / 2;
|
||||
if( xOffset > 0 ) {
|
||||
boolean ltr = c.getComponentOrientation().isLeftToRight();
|
||||
switch( ((AbstractButton)c).getHorizontalTextPosition() ) {
|
||||
case SwingConstants.RIGHT: iconRect.x -= xOffset; break;
|
||||
case SwingConstants.LEFT: iconRect.x += xOffset; break;
|
||||
case SwingConstants.TRAILING: iconRect.x -= ltr ? xOffset : -xOffset; break;
|
||||
case SwingConstants.LEADING: iconRect.x += ltr ? xOffset : -xOffset; break;
|
||||
}
|
||||
}
|
||||
|
||||
super.paintIcon( g, c, iconRect );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintText( Graphics g, AbstractButton b, Rectangle textRect, String text ) {
|
||||
if( isHelpButton( b ) )
|
||||
@@ -510,6 +568,8 @@ public class FlatButtonUI
|
||||
}
|
||||
|
||||
public static void paintText( Graphics g, AbstractButton b, Rectangle textRect, String text, Color foreground ) {
|
||||
if(foreground == null)
|
||||
foreground=Color.red;
|
||||
FontMetrics fm = b.getFontMetrics( b.getFont() );
|
||||
int mnemonicIndex = FlatLaf.isShowMnemonics() ? b.getDisplayedMnemonicIndex() : -1;
|
||||
|
||||
@@ -523,11 +583,14 @@ public class FlatButtonUI
|
||||
|
||||
// selected state
|
||||
if( ((AbstractButton)c).isSelected() ) {
|
||||
// in toolbar use same background colors for disabled and enabled because
|
||||
// in toolbar, if toolbarDisabledSelectedBackground is null,
|
||||
// use same background colors for disabled and enabled because
|
||||
// we assume that toolbar icon is shown disabled
|
||||
return buttonStateColor( c,
|
||||
toolBarButton ? toolbarSelectedBackground : selectedBackground,
|
||||
toolBarButton ? toolbarSelectedBackground : disabledSelectedBackground,
|
||||
toolBarButton
|
||||
? (toolbarDisabledSelectedBackground != null ? toolbarDisabledSelectedBackground : toolbarSelectedBackground)
|
||||
: disabledSelectedBackground,
|
||||
null,
|
||||
null,
|
||||
toolBarButton ? toolbarPressedBackground : pressedBackground );
|
||||
@@ -569,6 +632,9 @@ public class FlatButtonUI
|
||||
public static Color buttonStateColor( Component c, Color enabledColor, Color disabledColor,
|
||||
Color focusedColor, Color hoverColor, Color pressedColor )
|
||||
{
|
||||
if( c == null )
|
||||
return enabledColor;
|
||||
|
||||
if( !c.isEnabled() )
|
||||
return disabledColor;
|
||||
|
||||
@@ -589,18 +655,48 @@ public class FlatButtonUI
|
||||
}
|
||||
|
||||
protected Color getForeground( JComponent c ) {
|
||||
if( !c.isEnabled() )
|
||||
return disabledText;
|
||||
boolean toolBarButton = isToolBarButton( c ) || isBorderlessButton( c );
|
||||
|
||||
if( ((AbstractButton)c).isSelected() && !(isToolBarButton( c ) || isBorderlessButton( c )) )
|
||||
return selectedForeground;
|
||||
// selected state
|
||||
if( ((AbstractButton)c).isSelected() ) {
|
||||
return buttonStateColor( c,
|
||||
toolBarButton
|
||||
? (toolbarSelectedForeground != null ? toolbarSelectedForeground : c.getForeground())
|
||||
: selectedForeground,
|
||||
toolBarButton
|
||||
? (toolbarDisabledSelectedForeground != null ? toolbarDisabledSelectedForeground : disabledText)
|
||||
: (disabledSelectedForeground != null ? disabledSelectedForeground : disabledText),
|
||||
null,
|
||||
null,
|
||||
toolBarButton ? toolbarPressedForeground : pressedForeground );
|
||||
}
|
||||
|
||||
// toolbar button
|
||||
if( toolBarButton ) {
|
||||
return buttonStateColor( c,
|
||||
c.getForeground(),
|
||||
disabledText,
|
||||
null,
|
||||
toolbarHoverForeground,
|
||||
toolbarPressedForeground );
|
||||
}
|
||||
|
||||
boolean def = isDefaultButton( c );
|
||||
return buttonStateColor( c,
|
||||
getForegroundBase( c, def ),
|
||||
disabledText,
|
||||
isCustomForeground( c.getForeground() ) ? null : (def ? defaultFocusedForeground : focusedForeground),
|
||||
def ? defaultHoverForeground : hoverForeground,
|
||||
def ? defaultPressedForeground : pressedForeground );
|
||||
}
|
||||
|
||||
/** @since 2.3 */
|
||||
protected Color getForegroundBase( JComponent c, boolean def ) {
|
||||
// use component foreground if explicitly set
|
||||
Color fg = c.getForeground();
|
||||
if( isCustomForeground( fg ) )
|
||||
return fg;
|
||||
|
||||
boolean def = isDefaultButton( c );
|
||||
return def ? defaultForeground : fg;
|
||||
}
|
||||
|
||||
@@ -617,6 +713,9 @@ public class FlatButtonUI
|
||||
if( prefSize == null )
|
||||
return null;
|
||||
|
||||
// increase width when using bold font for default button
|
||||
prefSize.width += defaultBoldPlainWidthDiff( c );
|
||||
|
||||
// make square or apply minimum width/height
|
||||
boolean isIconOnlyOrSingleCharacter = isIconOnlyOrSingleCharacterButton( c );
|
||||
if( clientPropertyBoolean( c, SQUARE_SIZE, squareSize ) ) {
|
||||
@@ -637,6 +736,23 @@ public class FlatButtonUI
|
||||
return prefSize;
|
||||
}
|
||||
|
||||
private int defaultBoldPlainWidthDiff( JComponent c ) {
|
||||
if( defaultBoldText && isDefaultButton( c ) && c.getFont() instanceof UIResource ) {
|
||||
String text = ((AbstractButton)c).getText();
|
||||
if( text == null || text.isEmpty() )
|
||||
return 0;
|
||||
|
||||
Font font = c.getFont();
|
||||
Font boldFont = font.deriveFont( Font.BOLD );
|
||||
int boldWidth = c.getFontMetrics( boldFont ).stringWidth( text );
|
||||
int plainWidth = c.getFontMetrics( font ).stringWidth( text );
|
||||
if( boldWidth > plainWidth )
|
||||
return boldWidth - plainWidth;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private boolean hasDefaultMargins( JComponent c ) {
|
||||
Insets margin = ((AbstractButton)c).getMargin();
|
||||
return margin instanceof UIResource && Objects.equals( margin, defaultMargin );
|
||||
|
||||
@@ -96,7 +96,7 @@ public class FlatCaret
|
||||
|
||||
// if text component is focused, then caret and selection are visible,
|
||||
// but when switching theme, the component does not yet have
|
||||
// an highlighter and the selection is not painted
|
||||
// a highlighter and the selection is not painted
|
||||
// --> make selection temporary invisible later, then the caret
|
||||
// adds selection highlights to the text component highlighter
|
||||
if( isSelectionVisible() ) {
|
||||
@@ -236,7 +236,7 @@ public class FlatCaret
|
||||
if( selectAllOnFocusPolicy == null )
|
||||
selectAllOnFocusPolicy = this.selectAllOnFocusPolicy;
|
||||
|
||||
if( SELECT_ALL_ON_FOCUS_POLICY_NEVER.equals( selectAllOnFocusPolicy ) )
|
||||
if( selectAllOnFocusPolicy == null || SELECT_ALL_ON_FOCUS_POLICY_NEVER.equals( selectAllOnFocusPolicy ) )
|
||||
return;
|
||||
|
||||
if( !SELECT_ALL_ON_FOCUS_POLICY_ALWAYS.equals( selectAllOnFocusPolicy ) ) {
|
||||
|
||||
@@ -86,6 +86,11 @@ import com.formdev.flatlaf.util.SystemInfo;
|
||||
* @uiDefault ComboBox.padding Insets
|
||||
* @uiDefault ComboBox.squareButton boolean default is true
|
||||
*
|
||||
* <!-- BasicComboPopup -->
|
||||
*
|
||||
* @uiDefault ComboBox.selectionBackground Color
|
||||
* @uiDefault ComboBox.selectionForeground Color
|
||||
*
|
||||
* <!-- FlatComboBoxUI -->
|
||||
*
|
||||
* @uiDefault ComboBox.minimumWidth int
|
||||
@@ -354,6 +359,7 @@ public class FlatComboBoxUI
|
||||
break;
|
||||
|
||||
case COMPONENT_ROUND_RECT:
|
||||
case OUTLINE:
|
||||
comboBox.repaint();
|
||||
break;
|
||||
|
||||
@@ -602,7 +608,7 @@ public class FlatComboBoxUI
|
||||
|
||||
boolean shouldValidate = (c instanceof JPanel);
|
||||
|
||||
paddingBorder.install( c );
|
||||
paddingBorder.install( c, 0 );
|
||||
currentValuePane.paintComponent( g, c, comboBox, bounds.x, bounds.y, bounds.width, bounds.height, shouldValidate );
|
||||
paddingBorder.uninstall();
|
||||
|
||||
@@ -676,7 +682,7 @@ public class FlatComboBoxUI
|
||||
|
||||
@Override
|
||||
protected Dimension getSizeForComponent( Component comp ) {
|
||||
paddingBorder.install( comp );
|
||||
paddingBorder.install( comp, 0 );
|
||||
Dimension size = super.getSizeForComponent( comp );
|
||||
paddingBorder.uninstall();
|
||||
return size;
|
||||
@@ -699,7 +705,7 @@ public class FlatComboBoxUI
|
||||
return true;
|
||||
|
||||
Component editorComponent = comboBox.getEditor().getEditorComponent();
|
||||
return (editorComponent != null) ? FlatUIUtils.isPermanentFocusOwner( editorComponent ) : false;
|
||||
return editorComponent != null && FlatUIUtils.isPermanentFocusOwner( editorComponent );
|
||||
} else
|
||||
return FlatUIUtils.isPermanentFocusOwner( comboBox );
|
||||
}
|
||||
@@ -894,7 +900,7 @@ public class FlatComboBoxUI
|
||||
Component c = renderer.getListCellRendererComponent( list, value, index, isSelected, cellHasFocus );
|
||||
c.applyComponentOrientation( comboBox.getComponentOrientation() );
|
||||
|
||||
paddingBorder.install( c );
|
||||
paddingBorder.install( c, Math.round( FlatUIUtils.getBorderFocusWidth( comboBox ) ) );
|
||||
|
||||
return c;
|
||||
}
|
||||
@@ -917,6 +923,7 @@ public class FlatComboBoxUI
|
||||
private Insets padding;
|
||||
private JComponent rendererComponent;
|
||||
private Border rendererBorder;
|
||||
private int focusWidth;
|
||||
|
||||
CellPaddingBorder( Insets padding ) {
|
||||
this.padding = padding;
|
||||
@@ -924,10 +931,12 @@ public class FlatComboBoxUI
|
||||
|
||||
// using synchronized to avoid problems with code that modifies combo box
|
||||
// (model, selection, etc) not on AWT thread (which should be not done)
|
||||
synchronized void install( Component c ) {
|
||||
synchronized void install( Component c, int focusWidth ) {
|
||||
if( !(c instanceof JComponent) )
|
||||
return;
|
||||
|
||||
this.focusWidth = focusWidth;
|
||||
|
||||
JComponent jc = (JComponent) c;
|
||||
Border oldBorder = jc.getBorder();
|
||||
if( oldBorder == this )
|
||||
@@ -981,6 +990,12 @@ public class FlatComboBoxUI
|
||||
insets.bottom = padding.bottom;
|
||||
insets.right = padding.right;
|
||||
}
|
||||
|
||||
// if used in popup list, add focus width for exact vertical alignment
|
||||
// of text in popup list with text in combobox
|
||||
insets.left += focusWidth;
|
||||
insets.right += focusWidth;
|
||||
|
||||
return insets;
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ public class FlatEmptyBorder
|
||||
protected static Insets scaleInsets( Component c, Insets insets,
|
||||
int top, int left, int bottom, int right )
|
||||
{
|
||||
boolean leftToRight = left == right || c.getComponentOrientation().isLeftToRight();
|
||||
boolean leftToRight = left == right || c == null || c.getComponentOrientation().isLeftToRight();
|
||||
insets.left = scale( leftToRight ? left : right );
|
||||
insets.top = scale( top );
|
||||
insets.right = scale( leftToRight ? right : left );
|
||||
|
||||
@@ -19,11 +19,21 @@ package com.formdev.flatlaf.ui;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Image;
|
||||
import java.awt.Insets;
|
||||
import java.awt.LayoutManager;
|
||||
import java.awt.RenderingHints;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.function.Function;
|
||||
import javax.swing.AbstractButton;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.ButtonGroup;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
@@ -34,12 +44,16 @@ import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.JToggleButton;
|
||||
import javax.swing.JToolBar;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.filechooser.FileSystemView;
|
||||
import javax.swing.filechooser.FileView;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.metal.MetalFileChooserUI;
|
||||
import javax.swing.table.TableCellRenderer;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.ScaledImageIcon;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
@@ -133,12 +147,21 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault FileChooser.listViewActionLabelText String
|
||||
* @uiDefault FileChooser.detailsViewActionLabelText String
|
||||
*
|
||||
* <!-- FlatFileChooserUI -->
|
||||
*
|
||||
* @uiDefault FileChooser.shortcuts.buttonSize Dimension optional; default is 84,64
|
||||
* @uiDefault FileChooser.shortcuts.iconSize Dimension optional; default is 32,32
|
||||
* @uiDefault FileChooser.shortcuts.filesFunction Function<File[], File[]>
|
||||
* @uiDefault FileChooser.shortcuts.displayNameFunction Function<File, String>
|
||||
* @uiDefault FileChooser.shortcuts.iconFunction Function<File, Icon>
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatFileChooserUI
|
||||
extends MetalFileChooserUI
|
||||
{
|
||||
private final FlatFileView fileView = new FlatFileView();
|
||||
private FlatShortcutsPanel shortcutsPanel;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatFileChooserUI( (JFileChooser) c );
|
||||
@@ -153,6 +176,25 @@ public class FlatFileChooserUI
|
||||
super.installComponents( fc );
|
||||
|
||||
patchUI( fc );
|
||||
|
||||
if( !UIManager.getBoolean( "FileChooser.noPlacesBar" ) ) { // same as in Windows L&F
|
||||
FlatShortcutsPanel panel = createShortcutsPanel( fc );
|
||||
if( panel.getComponentCount() > 0 ) {
|
||||
shortcutsPanel = panel;
|
||||
fc.add( shortcutsPanel, BorderLayout.LINE_START );
|
||||
fc.addPropertyChangeListener( shortcutsPanel );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uninstallComponents( JFileChooser fc ) {
|
||||
super.uninstallComponents( fc );
|
||||
|
||||
if( shortcutsPanel != null ) {
|
||||
fc.removePropertyChangeListener( shortcutsPanel );
|
||||
shortcutsPanel = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void patchUI( JFileChooser fc ) {
|
||||
@@ -192,6 +234,25 @@ public class FlatFileChooserUI
|
||||
} catch( ArrayIndexOutOfBoundsException ex ) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
// put north, center and south components into a new panel so that
|
||||
// the shortcuts panel (at west) gets full height
|
||||
LayoutManager layout = fc.getLayout();
|
||||
if( layout instanceof BorderLayout ) {
|
||||
BorderLayout borderLayout = (BorderLayout) layout;
|
||||
borderLayout.setHgap( 8 );
|
||||
|
||||
Component north = borderLayout.getLayoutComponent( BorderLayout.NORTH );
|
||||
Component center = borderLayout.getLayoutComponent( BorderLayout.CENTER );
|
||||
Component south = borderLayout.getLayoutComponent( BorderLayout.SOUTH );
|
||||
if( north != null && center != null && south != null ) {
|
||||
JPanel p = new JPanel( new BorderLayout( 0, 11 ) );
|
||||
p.add( north, BorderLayout.NORTH );
|
||||
p.add( center, BorderLayout.CENTER );
|
||||
p.add( south, BorderLayout.SOUTH );
|
||||
fc.add( p, BorderLayout.CENTER );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -250,9 +311,19 @@ public class FlatFileChooserUI
|
||||
return p;
|
||||
}
|
||||
|
||||
/** @since 2.3 */
|
||||
protected FlatShortcutsPanel createShortcutsPanel( JFileChooser fc ) {
|
||||
return new FlatShortcutsPanel( fc );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize( JComponent c ) {
|
||||
return UIScale.scale( super.getPreferredSize( c ) );
|
||||
Dimension prefSize = super.getPreferredSize( c );
|
||||
Dimension minSize = getMinimumSize( c );
|
||||
int shortcutsPanelWidth = (shortcutsPanel != null) ? shortcutsPanel.getPreferredSize().width : 0;
|
||||
return new Dimension(
|
||||
Math.max( prefSize.width, minSize.width + shortcutsPanelWidth ),
|
||||
Math.max( prefSize.height, minSize.height ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -316,4 +387,234 @@ public class FlatFileChooserUI
|
||||
return icon;
|
||||
}
|
||||
}
|
||||
|
||||
//---- class FlatShortcutsPanel -------------------------------------------
|
||||
|
||||
/** @since 2.3 */
|
||||
public static class FlatShortcutsPanel
|
||||
extends JToolBar
|
||||
implements PropertyChangeListener
|
||||
{
|
||||
private final JFileChooser fc;
|
||||
|
||||
private final Dimension buttonSize;
|
||||
private final Dimension iconSize;
|
||||
private final Function<File[], File[]> filesFunction;
|
||||
private final Function<File, String> displayNameFunction;
|
||||
private final Function<File, Icon> iconFunction;
|
||||
|
||||
protected final File[] files;
|
||||
protected final JToggleButton[] buttons;
|
||||
protected final ButtonGroup buttonGroup;
|
||||
|
||||
@SuppressWarnings( "unchecked" )
|
||||
public FlatShortcutsPanel( JFileChooser fc ) {
|
||||
super( JToolBar.VERTICAL );
|
||||
this.fc = fc;
|
||||
setFloatable( false );
|
||||
|
||||
buttonSize = UIScale.scale( getUIDimension( "FileChooser.shortcuts.buttonSize", 84, 64 ) );
|
||||
iconSize = getUIDimension( "FileChooser.shortcuts.iconSize", 32, 32 );
|
||||
|
||||
filesFunction = (Function<File[], File[]>) UIManager.get( "FileChooser.shortcuts.filesFunction" );
|
||||
displayNameFunction = (Function<File, String>) UIManager.get( "FileChooser.shortcuts.displayNameFunction" );
|
||||
iconFunction = (Function<File, Icon>) UIManager.get( "FileChooser.shortcuts.iconFunction" );
|
||||
|
||||
FileSystemView fsv = fc.getFileSystemView();
|
||||
File[] files = getChooserShortcutPanelFiles( fsv );
|
||||
if( filesFunction != null )
|
||||
files = filesFunction.apply( files );
|
||||
this.files = files;
|
||||
|
||||
// create toolbar buttons
|
||||
buttons = new JToggleButton[files.length];
|
||||
buttonGroup = new ButtonGroup();
|
||||
for( int i = 0; i < files.length; i++ ) {
|
||||
// wrap drive path
|
||||
if( fsv.isFileSystemRoot( files[i] ) )
|
||||
files[i] = fsv.createFileObject( files[i].getAbsolutePath() );
|
||||
|
||||
File file = files[i];
|
||||
String name = getDisplayName( fsv, file );
|
||||
Icon icon = getIcon( fsv, file );
|
||||
|
||||
// remove path from name
|
||||
int lastSepIndex = name.lastIndexOf( File.separatorChar );
|
||||
if( lastSepIndex >= 0 && lastSepIndex < name.length() - 1 )
|
||||
name = name.substring( lastSepIndex + 1 );
|
||||
|
||||
// scale icon (if necessary)
|
||||
if( icon instanceof ImageIcon )
|
||||
icon = new ScaledImageIcon( (ImageIcon) icon, iconSize.width, iconSize.height );
|
||||
else if( icon != null )
|
||||
icon = new ShortcutIcon( icon, iconSize.width, iconSize.height );
|
||||
|
||||
// create button
|
||||
JToggleButton button = createButton( name, icon );
|
||||
button.addActionListener( e -> {
|
||||
fc.setCurrentDirectory( file );
|
||||
} );
|
||||
|
||||
add( button );
|
||||
buttonGroup.add( button );
|
||||
buttons[i] = button;
|
||||
}
|
||||
|
||||
directoryChanged( fc.getCurrentDirectory() );
|
||||
}
|
||||
|
||||
private Dimension getUIDimension( String key, int defaultWidth, int defaultHeight ) {
|
||||
Dimension size = UIManager.getDimension( key );
|
||||
if( size == null )
|
||||
size = new Dimension( defaultWidth, defaultHeight );
|
||||
return size;
|
||||
}
|
||||
|
||||
protected JToggleButton createButton( String name, Icon icon ) {
|
||||
JToggleButton button = new JToggleButton( name, icon );
|
||||
button.setVerticalTextPosition( SwingConstants.BOTTOM );
|
||||
button.setHorizontalTextPosition( SwingConstants.CENTER );
|
||||
button.setAlignmentX( Component.CENTER_ALIGNMENT );
|
||||
button.setIconTextGap( 0 );
|
||||
button.setPreferredSize( buttonSize );
|
||||
button.setMaximumSize( buttonSize );
|
||||
return button;
|
||||
}
|
||||
|
||||
protected File[] getChooserShortcutPanelFiles( FileSystemView fsv ) {
|
||||
try {
|
||||
if( SystemInfo.isJava_12_orLater ) {
|
||||
Method m = fsv.getClass().getMethod( "getChooserShortcutPanelFiles" );
|
||||
File[] files = (File[]) m.invoke( fsv );
|
||||
|
||||
// on macOS and Linux, files consists only of the user home directory
|
||||
if( files.length == 1 && files[0].equals( new File( System.getProperty( "user.home" ) ) ) )
|
||||
files = new File[0];
|
||||
|
||||
return files;
|
||||
} else if( SystemInfo.isWindows ) {
|
||||
Class<?> cls = Class.forName( "sun.awt.shell.ShellFolder" );
|
||||
Method m = cls.getMethod( "get", String.class );
|
||||
return (File[]) m.invoke( null, "fileChooserShortcutPanelFolders" );
|
||||
}
|
||||
} catch( IllegalAccessException ex ) {
|
||||
// do not log because access may be denied via VM option '--illegal-access=deny'
|
||||
} catch( Exception ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
|
||||
// fallback
|
||||
return new File[0];
|
||||
}
|
||||
|
||||
protected String getDisplayName( FileSystemView fsv, File file ) {
|
||||
if( displayNameFunction != null ) {
|
||||
String name = displayNameFunction.apply( file );
|
||||
if( name != null )
|
||||
return name;
|
||||
}
|
||||
|
||||
return fsv.getSystemDisplayName( file );
|
||||
}
|
||||
|
||||
protected Icon getIcon( FileSystemView fsv, File file ) {
|
||||
if( iconFunction != null ) {
|
||||
Icon icon = iconFunction.apply( file );
|
||||
if( icon != null )
|
||||
return icon;
|
||||
}
|
||||
|
||||
// Java 17+ supports getting larger system icons
|
||||
try {
|
||||
if( SystemInfo.isJava_17_orLater ) {
|
||||
Method m = fsv.getClass().getMethod( "getSystemIcon", File.class, int.class, int.class );
|
||||
return (Icon) m.invoke( fsv, file, iconSize.width, iconSize.height );
|
||||
} else if( iconSize.width > 16 || iconSize.height > 16 ) {
|
||||
Class<?> cls = Class.forName( "sun.awt.shell.ShellFolder" );
|
||||
if( cls.isInstance( file ) ) {
|
||||
Method m = file.getClass().getMethod( "getIcon", boolean.class );
|
||||
m.setAccessible( true );
|
||||
Image image = (Image) m.invoke( file, true );
|
||||
if( image != null )
|
||||
return new ImageIcon( image );
|
||||
}
|
||||
}
|
||||
} catch( IllegalAccessException ex ) {
|
||||
// do not log because access may be denied via VM option '--illegal-access=deny'
|
||||
} catch( Exception ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
|
||||
// get system icon in default size 16x16
|
||||
return fsv.getSystemIcon( file );
|
||||
}
|
||||
|
||||
protected void directoryChanged( File file ) {
|
||||
if( file != null ) {
|
||||
String absolutePath = file.getAbsolutePath();
|
||||
for( int i = 0; i < files.length; i++ ) {
|
||||
// also compare path because otherwise selecting "Documents"
|
||||
// in "Look in" combobox would not select "Documents" shortcut item
|
||||
if( files[i].equals( file ) || files[i].getAbsolutePath().equals( absolutePath ) ) {
|
||||
buttons[i].setSelected( true );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buttonGroup.clearSelection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void propertyChange( PropertyChangeEvent e ) {
|
||||
switch( e.getPropertyName() ) {
|
||||
case JFileChooser.DIRECTORY_CHANGED_PROPERTY:
|
||||
directoryChanged( fc.getCurrentDirectory() );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---- class ShortcutIcon -------------------------------------------------
|
||||
|
||||
private static class ShortcutIcon
|
||||
implements Icon
|
||||
{
|
||||
private final Icon icon;
|
||||
private final int iconWidth;
|
||||
private final int iconHeight;
|
||||
|
||||
ShortcutIcon( Icon icon, int iconWidth, int iconHeight ) {
|
||||
this.icon = icon;
|
||||
this.iconWidth = iconWidth;
|
||||
this.iconHeight = iconHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintIcon( Component c, Graphics g, int x, int y ) {
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
try {
|
||||
// set rendering hint for the case that the icon is a bitmap (not used for vector icons)
|
||||
g2.setRenderingHint( RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC );
|
||||
|
||||
double scale = (double) getIconWidth() / (double) icon.getIconWidth();
|
||||
g2.translate( x, y );
|
||||
g2.scale( scale, scale );
|
||||
|
||||
icon.paintIcon( c, g2, 0, 0 );
|
||||
} finally {
|
||||
g2.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconWidth() {
|
||||
return UIScale.scale( iconWidth );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconHeight() {
|
||||
return UIScale.scale( iconHeight );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ public class FlatListCellBorder
|
||||
}
|
||||
|
||||
/**
|
||||
* Because this borders are always shared for all lists,
|
||||
* Because this border is always shared for all lists,
|
||||
* get border specific style from FlatListUI.
|
||||
*/
|
||||
static <T> T getStyleFromListUI( Component c, Function<FlatListUI, T> f ) {
|
||||
|
||||
@@ -212,7 +212,7 @@ public class FlatListUI
|
||||
/**
|
||||
* Toggle selection colors from focused to inactive and vice versa.
|
||||
*
|
||||
* This is not a optimal solution but much easier than rewriting the whole paint methods.
|
||||
* This is not an optimal solution but much easier than rewriting the whole paint methods.
|
||||
*
|
||||
* Using a LaF specific renderer was avoided because often a custom renderer is
|
||||
* already used in applications. Then either the inactive colors are not used,
|
||||
|
||||
@@ -18,8 +18,10 @@ package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Insets;
|
||||
import java.awt.LayoutManager;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
@@ -27,6 +29,7 @@ import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.ActionMap;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuBar;
|
||||
@@ -40,11 +43,13 @@ import javax.swing.plaf.ActionMapUIResource;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicMenuBarUI;
|
||||
import javax.swing.plaf.basic.DefaultMenuLayout;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JMenuBar}.
|
||||
@@ -100,6 +105,10 @@ public class FlatMenuBarUI
|
||||
super.installDefaults();
|
||||
|
||||
LookAndFeel.installProperty( menuBar, "opaque", false );
|
||||
|
||||
LayoutManager layout = menuBar.getLayout();
|
||||
if( layout == null || layout instanceof UIResource )
|
||||
menuBar.setLayout( new FlatMenuBarLayout( menuBar ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -210,7 +219,7 @@ public class FlatMenuBarUI
|
||||
// check whether:
|
||||
// - TitlePane.unifiedBackground is true and
|
||||
// - menu bar is the "main" menu bar and
|
||||
// - window has custom decorations enabled
|
||||
// - window root pane has custom decoration style
|
||||
|
||||
JRootPane rootPane;
|
||||
// (not storing value of "TitlePane.unifiedBackground" in class to allow changing at runtime)
|
||||
@@ -218,7 +227,131 @@ public class FlatMenuBarUI
|
||||
(rootPane = SwingUtilities.getRootPane( c )) != null &&
|
||||
rootPane.getParent() instanceof Window &&
|
||||
rootPane.getJMenuBar() == c &&
|
||||
FlatNativeWindowBorder.hasCustomDecoration( (Window) rootPane.getParent() );
|
||||
rootPane.getWindowDecorationStyle() != JRootPane.NONE;
|
||||
}
|
||||
|
||||
//---- class FlatMenuBarLayout --------------------------------------------
|
||||
|
||||
/**
|
||||
* @since 2.4
|
||||
*/
|
||||
protected static class FlatMenuBarLayout
|
||||
extends DefaultMenuLayout
|
||||
{
|
||||
public FlatMenuBarLayout( Container target ) {
|
||||
super( target, BoxLayout.LINE_AXIS );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void layoutContainer( Container target ) {
|
||||
super.layoutContainer( target );
|
||||
|
||||
|
||||
// The only purpose of the code below is to make sure that a horizontal glue,
|
||||
// which can be used to move window and displays the window title in embedded menu bar,
|
||||
// is always visible within the menu bar bounds and has a minimum width.
|
||||
// If this is not the case, the horizontal glue is made larger and
|
||||
// components that are on the left side of the glue are made smaller.
|
||||
|
||||
|
||||
// get root pane and check whether this menu bar is the root pane menu bar
|
||||
JRootPane rootPane = SwingUtilities.getRootPane( target );
|
||||
if( rootPane == null || rootPane.getJMenuBar() != target )
|
||||
return;
|
||||
|
||||
// get title pane and check whether menu bar is embedded
|
||||
FlatTitlePane titlePane = FlatRootPaneUI.getTitlePane( rootPane );
|
||||
if( titlePane == null || !titlePane.isMenuBarEmbedded() )
|
||||
return;
|
||||
|
||||
// check whether there is a horizontal glue (used for window title in embedded menu bar)
|
||||
// and check minimum width of horizontal glue
|
||||
Component horizontalGlue = titlePane.findHorizontalGlue( (JMenuBar) target );
|
||||
int minTitleWidth = UIScale.scale( titlePane.titleMinimumWidth );
|
||||
if( horizontalGlue != null && horizontalGlue.getWidth() < minTitleWidth ) {
|
||||
// get index of glue component
|
||||
int glueIndex = -1;
|
||||
Component[] components = target.getComponents();
|
||||
for( int i = components.length - 1; i >= 0; i-- ) {
|
||||
if( components[i] == horizontalGlue ) {
|
||||
glueIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( glueIndex < 0 )
|
||||
return; // should never happen
|
||||
|
||||
if( target.getComponentOrientation().isLeftToRight() ) {
|
||||
// left-to-right
|
||||
|
||||
// make horizontal glue wider (minimum title width)
|
||||
int offset = minTitleWidth - horizontalGlue.getWidth();
|
||||
horizontalGlue.setSize( minTitleWidth, horizontalGlue.getHeight() );
|
||||
|
||||
// check whether glue is fully visible
|
||||
int minGlueX = target.getWidth() - target.getInsets().right - minTitleWidth;
|
||||
if( minGlueX < horizontalGlue.getX() ) {
|
||||
// move glue to the left to make it fully visible
|
||||
offset -= (horizontalGlue.getX() - minGlueX);
|
||||
horizontalGlue.setLocation( minGlueX, horizontalGlue.getY() );
|
||||
|
||||
// shrink and move components that are on the left side of the glue
|
||||
for( int i = glueIndex - 1; i >= 0; i-- ) {
|
||||
Component c = components[i];
|
||||
if( c.getX() > minGlueX ) {
|
||||
// move component and set width to zero
|
||||
c.setBounds( minGlueX, c.getY(), 0, c.getHeight() );
|
||||
} else {
|
||||
// reduce size of component
|
||||
c.setSize( minGlueX - c.getX(), c.getHeight() );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// move components that are on the right side of the glue
|
||||
for( int i = glueIndex + 1; i < components.length; i++ ) {
|
||||
Component c = components[i];
|
||||
c.setLocation( c.getX() + offset, c.getY() );
|
||||
}
|
||||
} else {
|
||||
// right-to-left
|
||||
|
||||
// make horizontal glue wider (minimum title width)
|
||||
int offset = minTitleWidth - horizontalGlue.getWidth();
|
||||
horizontalGlue.setBounds( horizontalGlue.getX() - offset, horizontalGlue.getY(),
|
||||
minTitleWidth, horizontalGlue.getHeight() );
|
||||
|
||||
// check whether glue is fully visible
|
||||
int minGlueX = target.getInsets().left;
|
||||
if( minGlueX > horizontalGlue.getX() ) {
|
||||
// move glue to the right to make it fully visible
|
||||
offset -= (horizontalGlue.getX() - minGlueX);
|
||||
horizontalGlue.setLocation( minGlueX, horizontalGlue.getY() );
|
||||
|
||||
// shrink and move components that are on the right side of the glue
|
||||
int x = horizontalGlue.getX() + horizontalGlue.getWidth();
|
||||
for( int i = glueIndex - 1; i >= 0; i-- ) {
|
||||
Component c = components[i];
|
||||
if( c.getX() + c.getWidth() < x ) {
|
||||
// move component and set width to zero
|
||||
c.setBounds( x, c.getY(), 0, c.getHeight() );
|
||||
} else {
|
||||
// move component and reduce size
|
||||
c.setBounds( x, c.getY(), c.getWidth() - (x - c.getX()), c.getHeight() );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// move components that are on the left side of the glue
|
||||
for( int i = glueIndex + 1; i < components.length; i++ ) {
|
||||
Component c = components[i];
|
||||
c.setLocation( c.getX() - offset, c.getY() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---- class TakeFocus ----------------------------------------------------
|
||||
|
||||
@@ -35,7 +35,7 @@ import javax.swing.plaf.MenuBarUI;
|
||||
public class FlatMenuItemBorder
|
||||
extends FlatMarginBorder
|
||||
{
|
||||
// only used if parent menubar is not a instance of FlatMenuBarUI
|
||||
// only used if parent menubar is not an instance of FlatMenuBarUI
|
||||
private final Insets menuBarItemMargins = UIManager.getInsets( "MenuBar.itemMargins" );
|
||||
|
||||
@Override
|
||||
|
||||
@@ -446,6 +446,19 @@ debug*/
|
||||
protected static void paintHTMLText( Graphics g, JMenuItem menuItem,
|
||||
Rectangle textRect, View htmlView, Color selectionForeground )
|
||||
{
|
||||
// On Windows, using Segoe UI font, Java 15 or older and scaling greater than 1,
|
||||
// the width of the HTML view may be initially too small (because component
|
||||
// is not connected to a GraphicsConfiguration when getPreferredSize() is invoked).
|
||||
// Since Java 16, this seems to be fixed somehow by doing popup menu layout twice.
|
||||
//
|
||||
// If using a too small width for htmlView.paint(), the view would rearrange
|
||||
// its children and wrap them to two lines. To avoid this, use view preferred X span
|
||||
// for painting. Core Lafs actually do the same in class MenuItemLayoutHelper.
|
||||
//
|
||||
// Example HTML text that causes the problem: "<html>some <b>HTML</b> <i>text</i></html>"
|
||||
textRect = new Rectangle( textRect );
|
||||
textRect.width = (int) htmlView.getPreferredSpan( View.X_AXIS );
|
||||
|
||||
if( isArmedOrSelected( menuItem ) && selectionForeground != null )
|
||||
g = new GraphicsProxyWithTextColor( (Graphics2D) g, selectionForeground );
|
||||
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2022 FormDev Software GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.io.File;
|
||||
import com.formdev.flatlaf.FlatSystemProperties;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.NativeLibrary;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
|
||||
/**
|
||||
* Helper class to load FlatLaf native library (.dll, .so or .dylib),
|
||||
* if available for current operating system and CPU architecture.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
* @since 2.3
|
||||
*/
|
||||
class FlatNativeLibrary
|
||||
{
|
||||
private static NativeLibrary nativeLibrary;
|
||||
|
||||
/**
|
||||
* Loads native library (if available) and returns whether loaded successfully.
|
||||
* Returns {@code false} if no native library is available.
|
||||
*/
|
||||
static synchronized boolean isLoaded() {
|
||||
initialize();
|
||||
return (nativeLibrary != null) ? nativeLibrary.isLoaded() : false;
|
||||
}
|
||||
|
||||
private static void initialize() {
|
||||
if( nativeLibrary != null )
|
||||
return;
|
||||
|
||||
String libraryName;
|
||||
if( SystemInfo.isWindows_10_orLater && (SystemInfo.isX86 || SystemInfo.isX86_64) ) {
|
||||
// Windows: requires Windows 10 (x86 or x86_64)
|
||||
|
||||
libraryName = "flatlaf-windows-x86";
|
||||
if( SystemInfo.isX86_64 )
|
||||
libraryName += "_64";
|
||||
|
||||
// load jawt native library
|
||||
loadJAWT();
|
||||
} else
|
||||
return; // no native library available for current OS or CPU architecture
|
||||
|
||||
// load native library
|
||||
nativeLibrary = createNativeLibrary( libraryName );
|
||||
}
|
||||
|
||||
private static NativeLibrary createNativeLibrary( String libraryName ) {
|
||||
String libraryPath = System.getProperty( FlatSystemProperties.NATIVE_LIBRARY_PATH );
|
||||
if( libraryPath != null ) {
|
||||
File libraryFile = new File( libraryPath, System.mapLibraryName( libraryName ) );
|
||||
if( libraryFile.exists() )
|
||||
return new NativeLibrary( libraryFile, true );
|
||||
else
|
||||
LoggingFacade.INSTANCE.logSevere( "Did not find external library " + libraryFile + ", using extracted library instead", null );
|
||||
}
|
||||
|
||||
return new NativeLibrary( "com/formdev/flatlaf/natives/" + libraryName, null, true );
|
||||
}
|
||||
|
||||
private static void loadJAWT() {
|
||||
if( SystemInfo.isJava_9_orLater )
|
||||
return;
|
||||
|
||||
// In Java 8, load jawt.dll (part of JRE) explicitly because it
|
||||
// is not found when running application with <jdk>/bin/java.exe.
|
||||
// When using <jdk>/jre/bin/java.exe, it is found.
|
||||
// jawt.dll is located in <jdk>/jre/bin/.
|
||||
// Java 9 and later do not have this problem.
|
||||
try {
|
||||
System.loadLibrary( "jawt" );
|
||||
} catch( UnsatisfiedLinkError ex ) {
|
||||
// log error only if native library jawt.dll not already loaded
|
||||
String message = ex.getMessage();
|
||||
if( message == null || !message.contains( "already loaded in another classloader" ) )
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
} catch( Exception ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,11 +42,13 @@ import com.formdev.flatlaf.util.SystemInfo;
|
||||
public class FlatNativeWindowBorder
|
||||
{
|
||||
// can use window decorations if:
|
||||
// - on Windows 10
|
||||
// - on Windows 10 or later
|
||||
// - not if system property "sun.java2d.opengl" is true on Windows 10
|
||||
// - not when running in JetBrains Projector, Webswing or WinPE
|
||||
// - not disabled via system property
|
||||
private static final boolean canUseWindowDecorations =
|
||||
SystemInfo.isWindows_10_orLater &&
|
||||
(SystemInfo.isWindows_11_orLater || !FlatSystemProperties.getBoolean( "sun.java2d.opengl", false )) &&
|
||||
!SystemInfo.isProjector &&
|
||||
!SystemInfo.isWebswing &&
|
||||
!SystemInfo.isWinPE &&
|
||||
|
||||
@@ -18,12 +18,14 @@ package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Map;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicPanelUI;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
@@ -43,13 +45,12 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
*/
|
||||
public class FlatPanelUI
|
||||
extends BasicPanelUI
|
||||
implements StyleableUI
|
||||
implements StyleableUI, PropertyChangeListener
|
||||
{
|
||||
// only used via styling (not in UI defaults)
|
||||
/** @since 2 */ @Styleable protected int arc = -1;
|
||||
|
||||
private final boolean shared;
|
||||
private PropertyChangeListener propertyChangeListener;
|
||||
private Map<String, Object> oldStyleValues;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
@@ -67,9 +68,7 @@ public class FlatPanelUI
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
propertyChangeListener = FlatStylingSupport.createPropertyChangeListener(
|
||||
c, () -> stylePropertyChange( (JPanel) c ), null );
|
||||
c.addPropertyChangeListener( propertyChangeListener );
|
||||
c.addPropertyChangeListener( this );
|
||||
|
||||
installStyle( (JPanel) c );
|
||||
}
|
||||
@@ -78,21 +77,28 @@ public class FlatPanelUI
|
||||
public void uninstallUI( JComponent c ) {
|
||||
super.uninstallUI( c );
|
||||
|
||||
c.removePropertyChangeListener( propertyChangeListener );
|
||||
propertyChangeListener = null;
|
||||
c.removePropertyChangeListener( this );
|
||||
|
||||
oldStyleValues = null;
|
||||
}
|
||||
|
||||
private void stylePropertyChange( JPanel c ) {
|
||||
if( shared && FlatStylingSupport.hasStyleProperty( c ) ) {
|
||||
// unshare component UI if necessary
|
||||
// updateUI() invokes installStyle() from installUI()
|
||||
c.updateUI();
|
||||
} else
|
||||
installStyle( c );
|
||||
c.revalidate();
|
||||
c.repaint();
|
||||
/** @since 2.0.1 */
|
||||
@Override
|
||||
public void propertyChange( PropertyChangeEvent e ) {
|
||||
switch( e.getPropertyName() ) {
|
||||
case FlatClientProperties.STYLE:
|
||||
case FlatClientProperties.STYLE_CLASS:
|
||||
JPanel c = (JPanel) e.getSource();
|
||||
if( shared && FlatStylingSupport.hasStyleProperty( c ) ) {
|
||||
// unshare component UI if necessary
|
||||
// updateUI() invokes installStyle() from installUI()
|
||||
c.updateUI();
|
||||
} else
|
||||
installStyle( c );
|
||||
c.revalidate();
|
||||
c.repaint();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
|
||||
@@ -16,10 +16,12 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.AWTEvent;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.GraphicsDevice;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
@@ -33,6 +35,7 @@ import java.awt.Toolkit;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.event.ComponentListener;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import javax.swing.JComponent;
|
||||
@@ -140,7 +143,7 @@ public class FlatPopupFactory
|
||||
* <p>
|
||||
* On a dual screen setup, where screens use different scale factors, it may happen
|
||||
* that the window location changes when showing a heavy weight popup window.
|
||||
* E.g. when opening an dialog on the secondary screen and making combobox popup visible.
|
||||
* E.g. when opening a dialog on the secondary screen and making combobox popup visible.
|
||||
* <p>
|
||||
* This is a workaround for https://bugs.openjdk.java.net/browse/JDK-8224608
|
||||
*/
|
||||
@@ -219,7 +222,7 @@ public class FlatPopupFactory
|
||||
* and corrects the y-location so that the tooltip is placed above the mouse location.
|
||||
*/
|
||||
private Point fixToolTipLocation( Component owner, Component contents, int x, int y ) {
|
||||
if( !(contents instanceof JToolTip) || !wasInvokedFromToolTipManager() )
|
||||
if( !(contents instanceof JToolTip) || !wasInvokedFromToolTipManager() || hasTipLocation( owner ) )
|
||||
return null;
|
||||
|
||||
PointerInfo pointerInfo = MouseInfo.getPointerInfo();
|
||||
@@ -264,6 +267,35 @@ public class FlatPopupFactory
|
||||
return StackUtils.wasInvokedFrom( ToolTipManager.class.getName(), "showTipWindow", 8 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the owner component returns a tooltip location in
|
||||
* JComponent.getToolTipLocation(MouseEvent).
|
||||
*/
|
||||
private boolean hasTipLocation( Component owner ) {
|
||||
if( !(owner instanceof JComponent) )
|
||||
return false;
|
||||
|
||||
AWTEvent e = EventQueue.getCurrentEvent();
|
||||
MouseEvent me;
|
||||
if( e instanceof MouseEvent )
|
||||
me = (MouseEvent) e;
|
||||
else {
|
||||
// no mouse event available because a timer is used to show the tooltip
|
||||
// --> create mouse event from current mouse location
|
||||
PointerInfo pointerInfo = MouseInfo.getPointerInfo();
|
||||
if( pointerInfo == null )
|
||||
return false;
|
||||
|
||||
Point location = new Point( pointerInfo.getLocation());
|
||||
SwingUtilities.convertPointFromScreen( location, owner );
|
||||
me = new MouseEvent( owner, MouseEvent.MOUSE_MOVED, System.currentTimeMillis(),
|
||||
0, location.x, location.y, 0, false );
|
||||
}
|
||||
|
||||
return me.getSource() == owner &&
|
||||
((JComponent)owner).getToolTipLocation( me ) != null;
|
||||
}
|
||||
|
||||
//---- class NonFlashingPopup ---------------------------------------------
|
||||
|
||||
private class NonFlashingPopup
|
||||
|
||||
@@ -16,18 +16,58 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.GraphicsDevice;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Insets;
|
||||
import java.awt.LayoutManager;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.awt.event.MouseWheelEvent;
|
||||
import java.awt.event.MouseWheelListener;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JViewport;
|
||||
import javax.swing.MenuElement;
|
||||
import javax.swing.MenuSelectionManager;
|
||||
import javax.swing.Popup;
|
||||
import javax.swing.PopupFactory;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.Timer;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.event.MenuKeyEvent;
|
||||
import javax.swing.event.MenuKeyListener;
|
||||
import javax.swing.event.PopupMenuEvent;
|
||||
import javax.swing.event.PopupMenuListener;
|
||||
import javax.swing.plaf.ButtonUI;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicComboPopup;
|
||||
import javax.swing.plaf.basic.BasicMenuItemUI;
|
||||
import javax.swing.plaf.basic.BasicPopupMenuUI;
|
||||
import javax.swing.plaf.basic.DefaultMenuLayout;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
|
||||
@@ -41,12 +81,22 @@ import com.formdev.flatlaf.util.LoggingFacade;
|
||||
* @uiDefault PopupMenu.foreground Color
|
||||
* @uiDefault PopupMenu.border Border
|
||||
*
|
||||
* <!-- FlatPopupMenuUI -->
|
||||
*
|
||||
* @uiDefault Component.arrowType String chevron (default) or triangle
|
||||
* @uiDefault PopupMenu.scrollArrowColor Color
|
||||
* @uiDefault PopupMenu.hoverScrollArrowBackground Color optional
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatPopupMenuUI
|
||||
extends BasicPopupMenuUI
|
||||
implements StyleableUI
|
||||
{
|
||||
/** @since 2.1 */ @Styleable protected String arrowType;
|
||||
/** @since 2.1 */ @Styleable protected Color scrollArrowColor;
|
||||
/** @since 2.1 */ @Styleable protected Color hoverScrollArrowBackground;
|
||||
|
||||
private PropertyChangeListener propertyChangeListener;
|
||||
private Map<String, Object> oldStyleValues;
|
||||
private AtomicBoolean borderShared;
|
||||
@@ -74,9 +124,21 @@ public class FlatPopupMenuUI
|
||||
public void installDefaults() {
|
||||
super.installDefaults();
|
||||
|
||||
arrowType = UIManager.getString( "Component.arrowType" );
|
||||
scrollArrowColor = UIManager.getColor( "PopupMenu.scrollArrowColor" );
|
||||
hoverScrollArrowBackground = UIManager.getColor( "PopupMenu.hoverScrollArrowBackground" );
|
||||
|
||||
LayoutManager layout = popupMenu.getLayout();
|
||||
if( layout == null || layout instanceof UIResource )
|
||||
popupMenu.setLayout( new FlatMenuLayout( popupMenu, BoxLayout.Y_AXIS ) );
|
||||
popupMenu.setLayout( new FlatPopupMenuLayout( popupMenu, BoxLayout.Y_AXIS ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void uninstallDefaults() {
|
||||
super.uninstallDefaults();
|
||||
|
||||
scrollArrowColor = null;
|
||||
hoverScrollArrowBackground = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -122,12 +184,61 @@ public class FlatPopupMenuUI
|
||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this, popupMenu.getBorder() );
|
||||
}
|
||||
|
||||
//---- class FlatMenuLayout -----------------------------------------------
|
||||
@Override
|
||||
public Popup getPopup( JPopupMenu popup, int x, int y ) {
|
||||
// do not add scroller to combobox popups or to popups that already have a scroll pane
|
||||
if( popup instanceof BasicComboPopup ||
|
||||
(popup.getComponentCount() > 0 && popup.getComponent( 0 ) instanceof JScrollPane) )
|
||||
return super.getPopup( popup, x, y );
|
||||
|
||||
protected static class FlatMenuLayout
|
||||
// do not add scroller if popup fits into screen
|
||||
Dimension prefSize = popup.getPreferredSize();
|
||||
int screenHeight = getScreenHeightAt( x, y );
|
||||
if( prefSize.height <= screenHeight )
|
||||
return super.getPopup( popup, x, y );
|
||||
|
||||
// create scroller
|
||||
FlatPopupScroller scroller = new FlatPopupScroller( popup );
|
||||
scroller.setPreferredSize( new Dimension( prefSize.width, screenHeight ) );
|
||||
|
||||
// create popup
|
||||
PopupFactory popupFactory = PopupFactory.getSharedInstance();
|
||||
return popupFactory.getPopup( popup.getInvoker(), scroller, x, y );
|
||||
}
|
||||
|
||||
private int getScreenHeightAt( int x, int y ) {
|
||||
// find GraphicsConfiguration at popup location (similar to JPopupMenu.getCurrentGraphicsConfiguration())
|
||||
GraphicsConfiguration gc = null;
|
||||
for( GraphicsDevice device : GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices() ) {
|
||||
if( device.getType() == GraphicsDevice.TYPE_RASTER_SCREEN ) {
|
||||
GraphicsConfiguration dgc = device.getDefaultConfiguration();
|
||||
if( dgc.getBounds().contains( x, y ) ) {
|
||||
gc = dgc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( gc == null && popupMenu.getInvoker() != null )
|
||||
gc = popupMenu.getInvoker().getGraphicsConfiguration();
|
||||
|
||||
// compute screen height
|
||||
// (always subtract screen insets because there is no API to detect whether
|
||||
// the popup can overlap the taskbar; see JPopupMenu.canPopupOverlapTaskBar())
|
||||
Toolkit toolkit = Toolkit.getDefaultToolkit();
|
||||
Rectangle screenBounds = (gc != null) ? gc.getBounds() : new Rectangle( toolkit.getScreenSize() );
|
||||
Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets( gc );
|
||||
return screenBounds.height - screenInsets.top - screenInsets.bottom;
|
||||
}
|
||||
|
||||
//---- class FlatPopupMenuLayout ------------------------------------------
|
||||
|
||||
/**
|
||||
* @since 2.4
|
||||
*/
|
||||
protected static class FlatPopupMenuLayout
|
||||
extends DefaultMenuLayout
|
||||
{
|
||||
public FlatMenuLayout( Container target, int axis ) {
|
||||
public FlatPopupMenuLayout( Container target, int axis ) {
|
||||
super( target, axis );
|
||||
}
|
||||
|
||||
@@ -138,4 +249,206 @@ public class FlatPopupMenuUI
|
||||
return super.preferredLayoutSize( target );
|
||||
}
|
||||
}
|
||||
|
||||
//---- class FlatPopupScroller --------------------------------------------
|
||||
|
||||
private class FlatPopupScroller
|
||||
extends JPanel
|
||||
implements MouseWheelListener, PopupMenuListener, MenuKeyListener
|
||||
{
|
||||
private final JPopupMenu popup;
|
||||
|
||||
private final JScrollPane scrollPane;
|
||||
private final JButton scrollUpButton;
|
||||
private final JButton scrollDownButton;
|
||||
private int unitIncrement;
|
||||
|
||||
FlatPopupScroller( JPopupMenu popup ) {
|
||||
super( new BorderLayout() );
|
||||
this.popup = popup;
|
||||
|
||||
// this panel is required to avoid that JPopupMenu.setLocation() will be invoked
|
||||
// while scrolling, because this would call JPopupMenu.showPopup()
|
||||
JPanel view = new JPanel( new BorderLayout() );
|
||||
view.add( popup, BorderLayout.CENTER );
|
||||
|
||||
scrollPane = new JScrollPane( view, JScrollPane.VERTICAL_SCROLLBAR_NEVER, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER );
|
||||
scrollPane.setBorder( null );
|
||||
|
||||
scrollUpButton = new ArrowButton( SwingConstants.NORTH );
|
||||
scrollDownButton = new ArrowButton( SwingConstants.SOUTH );
|
||||
|
||||
add( scrollPane, BorderLayout.CENTER );
|
||||
add( scrollUpButton, BorderLayout.NORTH );
|
||||
add( scrollDownButton, BorderLayout.SOUTH );
|
||||
|
||||
setBackground( popup.getBackground() );
|
||||
setBorder( popup.getBorder() );
|
||||
popup.setBorder( null );
|
||||
|
||||
popup.addPopupMenuListener( this );
|
||||
popup.addMouseWheelListener( this );
|
||||
popup.addMenuKeyListener( this );
|
||||
|
||||
updateArrowButtons();
|
||||
}
|
||||
|
||||
void scroll( int unitsToScroll ) {
|
||||
if( unitIncrement == 0 )
|
||||
unitIncrement = new JMenuItem( "X" ).getPreferredSize().height;
|
||||
|
||||
JViewport viewport = scrollPane.getViewport();
|
||||
Point viewPosition = viewport.getViewPosition();
|
||||
int newY = viewPosition.y + (unitIncrement * unitsToScroll);
|
||||
if( newY < 0 )
|
||||
newY = 0;
|
||||
else
|
||||
newY = Math.min( newY, viewport.getViewSize().height - viewport.getExtentSize().height );
|
||||
viewport.setViewPosition( new Point( viewPosition.x, newY ) );
|
||||
|
||||
updateArrowButtons();
|
||||
}
|
||||
|
||||
void updateArrowButtons() {
|
||||
JViewport viewport = scrollPane.getViewport();
|
||||
Point viewPosition = viewport.getViewPosition();
|
||||
|
||||
scrollUpButton.setVisible( viewPosition.y > 0 );
|
||||
scrollDownButton.setVisible( viewPosition.y < viewport.getViewSize().height - viewport.getExtentSize().height );
|
||||
}
|
||||
|
||||
//---- interface PopupMenuListener ----
|
||||
|
||||
@Override
|
||||
public void popupMenuWillBecomeInvisible( PopupMenuEvent e ) {
|
||||
// restore popup border
|
||||
popup.setBorder( getBorder() );
|
||||
|
||||
popup.removePopupMenuListener( this );
|
||||
popup.removeMouseWheelListener( this );
|
||||
popup.removeMenuKeyListener( this );
|
||||
}
|
||||
|
||||
@Override public void popupMenuWillBecomeVisible( PopupMenuEvent e ) {}
|
||||
@Override public void popupMenuCanceled( PopupMenuEvent e ) {}
|
||||
|
||||
//---- interface MouseWheelListener ----
|
||||
|
||||
/**
|
||||
* Scroll when user rotates mouse wheel.
|
||||
*/
|
||||
@Override
|
||||
public void mouseWheelMoved( MouseWheelEvent e ) {
|
||||
// convert mouse location before scrolling
|
||||
Point mouseLocation = SwingUtilities.convertPoint( (Component) e.getSource(), e.getPoint(), this );
|
||||
|
||||
// scroll
|
||||
scroll( e.getUnitsToScroll() );
|
||||
|
||||
// select menu item at mouse location
|
||||
Component c = SwingUtilities.getDeepestComponentAt( this, mouseLocation.x, mouseLocation.y );
|
||||
if( c instanceof JMenuItem ) {
|
||||
ButtonUI ui = ((JMenuItem)c).getUI();
|
||||
if( ui instanceof BasicMenuItemUI )
|
||||
MenuSelectionManager.defaultManager().setSelectedPath( ((BasicMenuItemUI)ui).getPath() );
|
||||
}
|
||||
|
||||
// this avoids that the popup is closed when running on Java 8
|
||||
// https://bugs.openjdk.java.net/browse/JDK-8075063
|
||||
e.consume();
|
||||
}
|
||||
|
||||
//---- interface MenuKeyListener ----
|
||||
|
||||
/**
|
||||
* Scroll when user presses Up or Down keys.
|
||||
*/
|
||||
@Override
|
||||
public void menuKeyPressed( MenuKeyEvent e ) {
|
||||
// use invokeLater() because menu selection is not yet updated because
|
||||
// this listener is invoked before another listener that updates the menu selection
|
||||
EventQueue.invokeLater( () -> {
|
||||
if( !isDisplayable() )
|
||||
return;
|
||||
|
||||
MenuElement[] path = MenuSelectionManager.defaultManager().getSelectedPath();
|
||||
if( path.length == 0 )
|
||||
return;
|
||||
|
||||
// scroll selected menu item to visible area
|
||||
Component c = path[path.length - 1].getComponent();
|
||||
JViewport viewport = scrollPane.getViewport();
|
||||
Point pt = SwingUtilities.convertPoint( c, 0, 0, viewport );
|
||||
viewport.scrollRectToVisible( new Rectangle( pt, c.getSize() ) );
|
||||
|
||||
// update arrow buttons
|
||||
boolean upVisible = scrollUpButton.isVisible();
|
||||
updateArrowButtons();
|
||||
if( !upVisible && scrollUpButton.isVisible() ) {
|
||||
// if "up" button becomes visible, make sure that bottom menu item stays visible
|
||||
Point viewPosition = viewport.getViewPosition();
|
||||
int newY = viewPosition.y + scrollUpButton.getPreferredSize().height;
|
||||
viewport.setViewPosition( new Point( viewPosition.x, newY ) );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
@Override public void menuKeyTyped( MenuKeyEvent e ) {}
|
||||
@Override public void menuKeyReleased( MenuKeyEvent e ) {}
|
||||
|
||||
//---- class ArrowButton ----------------------------------------------
|
||||
|
||||
private class ArrowButton
|
||||
extends FlatArrowButton
|
||||
implements MouseListener, ActionListener
|
||||
{
|
||||
private Timer timer;
|
||||
|
||||
ArrowButton( int direction ) {
|
||||
super( direction, arrowType, scrollArrowColor, null, null, hoverScrollArrowBackground, null, null );
|
||||
|
||||
addMouseListener( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint( Graphics g ) {
|
||||
// always fill background to paint over border on HiDPI screens
|
||||
g.setColor( popup.getBackground() );
|
||||
g.fillRect( 0, 0, getWidth(), getHeight() );
|
||||
|
||||
super.paint( g );
|
||||
}
|
||||
|
||||
//---- interface MouseListener ----
|
||||
|
||||
@Override public void mouseClicked( MouseEvent e ) {}
|
||||
@Override public void mousePressed( MouseEvent e ) {}
|
||||
@Override public void mouseReleased( MouseEvent e ) {}
|
||||
|
||||
@Override
|
||||
public void mouseEntered( MouseEvent e ) {
|
||||
if( timer == null )
|
||||
timer = new Timer( 50, this );
|
||||
timer.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited( MouseEvent e ) {
|
||||
if( timer != null )
|
||||
timer.stop();
|
||||
}
|
||||
|
||||
//---- interface ActionListener ----
|
||||
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e ) {
|
||||
if( timer != null && !isDisplayable() ) {
|
||||
timer.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
scroll( direction == SwingConstants.NORTH ? -1 : 1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,7 +199,7 @@ public class FlatRadioButtonUI
|
||||
return infos;
|
||||
}
|
||||
|
||||
private static Insets tempInsets = new Insets( 0, 0, 0, 0 );
|
||||
private static final Insets tempInsets = new Insets( 0, 0, 0, 0 );
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize( JComponent c ) {
|
||||
@@ -212,7 +212,7 @@ public class FlatRadioButtonUI
|
||||
if( focusWidth > 0 ) {
|
||||
// Increase preferred width and height if insets were explicitly reduced (e.g. with
|
||||
// an EmptyBorder) and icon has a focus width, which is not included in icon size.
|
||||
// Otherwise the component may be too small and outer focus border may be cut off.
|
||||
// Otherwise, the component may be too small and outer focus border may be cut off.
|
||||
Insets insets = c.getInsets( tempInsets );
|
||||
size.width += Math.max( focusWidth - insets.left, 0 ) + Math.max( focusWidth - insets.right, 0 );
|
||||
size.height += Math.max( focusWidth - insets.top, 0 ) + Math.max( focusWidth - insets.bottom, 0 );
|
||||
|
||||
@@ -179,8 +179,8 @@ public class FlatRootPaneUI
|
||||
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.
|
||||
// On HiDPI screens, where scaling is used, there may be white lines on the
|
||||
// bottom and on 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().
|
||||
@@ -364,6 +364,12 @@ public class FlatRootPaneUI
|
||||
((FlatRootPaneUI)ui).titlePane.isMenuBarEmbedded();
|
||||
}
|
||||
|
||||
/** @since 2.4 */
|
||||
protected static FlatTitlePane getTitlePane( JRootPane rootPane ) {
|
||||
RootPaneUI ui = rootPane.getUI();
|
||||
return ui instanceof FlatRootPaneUI ? ((FlatRootPaneUI)ui).titlePane : null;
|
||||
}
|
||||
|
||||
//---- class FlatRootLayout -----------------------------------------------
|
||||
|
||||
protected class FlatRootLayout
|
||||
@@ -510,7 +516,7 @@ public class FlatRootPaneUI
|
||||
return;
|
||||
|
||||
Container parent = c.getParent();
|
||||
boolean active = parent instanceof Window ? ((Window)parent).isActive() : false;
|
||||
boolean active = parent instanceof Window && ((Window)parent).isActive();
|
||||
|
||||
g.setColor( FlatUIUtils.deriveColor( active ? activeBorderColor : inactiveBorderColor, baseBorderColor ) );
|
||||
HiDPIUtils.paintAtScale1x( (Graphics2D) g, x, y, width, height, this::paintImpl );
|
||||
@@ -522,9 +528,7 @@ public class FlatRootPaneUI
|
||||
|
||||
protected boolean isWindowMaximized( Component c ) {
|
||||
Container parent = c.getParent();
|
||||
return parent instanceof Frame
|
||||
? (((Frame)parent).getExtendedState() & Frame.MAXIMIZED_BOTH) != 0
|
||||
: false;
|
||||
return parent instanceof Frame && (((Frame)parent).getExtendedState() & Frame.MAXIMIZED_BOTH) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
*
|
||||
* <!-- FlatScrollBarUI -->
|
||||
*
|
||||
* @uiDefault ScrollBar.minimumButtonSize Dimension
|
||||
* @uiDefault ScrollBar.trackInsets Insets
|
||||
* @uiDefault ScrollBar.thumbInsets Insets
|
||||
* @uiDefault ScrollBar.trackArc int
|
||||
@@ -83,6 +84,7 @@ public class FlatScrollBarUI
|
||||
// overrides BasicScrollBarUI.supportsAbsolutePositioning (which is private)
|
||||
@Styleable protected boolean allowsAbsolutePositioning;
|
||||
|
||||
/** @since 2.1 */ @Styleable protected Dimension minimumButtonSize;
|
||||
@Styleable protected Insets trackInsets;
|
||||
@Styleable protected Insets thumbInsets;
|
||||
@Styleable protected int trackArc;
|
||||
@@ -142,6 +144,7 @@ public class FlatScrollBarUI
|
||||
|
||||
allowsAbsolutePositioning = super.getSupportsAbsolutePositioning();
|
||||
|
||||
minimumButtonSize = UIManager.getDimension( "ScrollBar.minimumButtonSize" );
|
||||
trackInsets = UIManager.getInsets( "ScrollBar.trackInsets" );
|
||||
thumbInsets = UIManager.getInsets( "ScrollBar.thumbInsets" );
|
||||
trackArc = UIManager.getInt( "ScrollBar.trackArc" );
|
||||
@@ -171,6 +174,7 @@ public class FlatScrollBarUI
|
||||
protected void uninstallDefaults() {
|
||||
super.uninstallDefaults();
|
||||
|
||||
minimumButtonSize = null;
|
||||
trackInsets = null;
|
||||
thumbInsets = null;
|
||||
hoverTrackColor = null;
|
||||
@@ -451,7 +455,6 @@ public class FlatScrollBarUI
|
||||
super( direction, type, foreground, disabledForeground,
|
||||
hoverForeground, hoverBackground, pressedForeground, pressedBackground );
|
||||
|
||||
setArrowWidth( FlatArrowButton.DEFAULT_ARROW_WIDTH - 2 );
|
||||
setFocusable( false );
|
||||
setRequestFocusEnabled( false );
|
||||
}
|
||||
@@ -461,6 +464,18 @@ public class FlatScrollBarUI
|
||||
null, hoverButtonBackground, null, pressedButtonBackground );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getArrowWidth() {
|
||||
// scale arrow size depending on scroll bar width
|
||||
// (6 is default arrow width; 10 is base scroll bar width)
|
||||
int arrowWidth = Math.round( 6 * (scrollBarWidth / 10f) );
|
||||
|
||||
// compute arrow size that leaves equal space on both sides (arrow is centered)
|
||||
arrowWidth = scrollBarWidth - (((scrollBarWidth - arrowWidth) / 2) * 2);
|
||||
|
||||
return arrowWidth;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Color deriveBackground( Color background ) {
|
||||
return FlatUIUtils.deriveColor( background, scrollbar.getBackground() );
|
||||
@@ -469,8 +484,9 @@ public class FlatScrollBarUI
|
||||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
if( isShowButtons() ) {
|
||||
int w = UIScale.scale( scrollBarWidth );
|
||||
return new Dimension( w, w );
|
||||
int w = UIScale.scale( Math.max( scrollBarWidth, (minimumButtonSize != null) ? minimumButtonSize.width : 0 ) );
|
||||
int h = UIScale.scale( Math.max( scrollBarWidth, (minimumButtonSize != null) ? minimumButtonSize.height : 0 ) );
|
||||
return new Dimension( w, h );
|
||||
} else
|
||||
return new Dimension();
|
||||
}
|
||||
|
||||
@@ -291,6 +291,10 @@ public class FlatScrollPaneUI
|
||||
}
|
||||
break;
|
||||
|
||||
case FlatClientProperties.OUTLINE:
|
||||
scrollpane.repaint();
|
||||
break;
|
||||
|
||||
case FlatClientProperties.STYLE:
|
||||
case FlatClientProperties.STYLE_CLASS:
|
||||
installStyle();
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Map;
|
||||
import javax.swing.JComponent;
|
||||
@@ -28,6 +29,7 @@ import javax.swing.JSeparator;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicSeparatorUI;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
@@ -50,7 +52,7 @@ import com.formdev.flatlaf.util.LoggingFacade;
|
||||
*/
|
||||
public class FlatSeparatorUI
|
||||
extends BasicSeparatorUI
|
||||
implements StyleableUI
|
||||
implements StyleableUI, PropertyChangeListener
|
||||
{
|
||||
@Styleable protected int height;
|
||||
@Styleable protected int stripeWidth;
|
||||
@@ -58,7 +60,6 @@ public class FlatSeparatorUI
|
||||
|
||||
private final boolean shared;
|
||||
private boolean defaults_initialized = false;
|
||||
private PropertyChangeListener propertyChangeListener;
|
||||
private Map<String, Object> oldStyleValues;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
@@ -109,28 +110,33 @@ public class FlatSeparatorUI
|
||||
protected void installListeners( JSeparator s ) {
|
||||
super.installListeners( s );
|
||||
|
||||
propertyChangeListener = FlatStylingSupport.createPropertyChangeListener(
|
||||
s, () -> stylePropertyChange( s ), null );
|
||||
s.addPropertyChangeListener( propertyChangeListener );
|
||||
s.addPropertyChangeListener( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void uninstallListeners( JSeparator s ) {
|
||||
super.uninstallListeners( s );
|
||||
|
||||
s.removePropertyChangeListener( propertyChangeListener );
|
||||
propertyChangeListener = null;
|
||||
s.removePropertyChangeListener( this );
|
||||
}
|
||||
|
||||
private void stylePropertyChange( JSeparator s ) {
|
||||
if( shared && FlatStylingSupport.hasStyleProperty( s ) ) {
|
||||
// unshare component UI if necessary
|
||||
// updateUI() invokes installStyle() from installUI()
|
||||
s.updateUI();
|
||||
} else
|
||||
installStyle( s );
|
||||
s.revalidate();
|
||||
s.repaint();
|
||||
/** @since 2.0.1 */
|
||||
@Override
|
||||
public void propertyChange( PropertyChangeEvent e ) {
|
||||
switch( e.getPropertyName() ) {
|
||||
case FlatClientProperties.STYLE:
|
||||
case FlatClientProperties.STYLE_CLASS:
|
||||
JSeparator s = (JSeparator) e.getSource();
|
||||
if( shared && FlatStylingSupport.hasStyleProperty( s ) ) {
|
||||
// unshare component UI if necessary
|
||||
// updateUI() invokes installStyle() from installUI()
|
||||
s.updateUI();
|
||||
} else
|
||||
installStyle( s );
|
||||
s.revalidate();
|
||||
s.repaint();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
|
||||
@@ -234,7 +234,7 @@ public class FlatSliderUI
|
||||
return -1;
|
||||
|
||||
// use default font (instead of slider font) because the slider font size
|
||||
// may be different to label font size, but we want align the track/thumb with labels
|
||||
// may be different to label font size, but we want to align the track/thumb with labels
|
||||
Font font = UIManager.getFont( "defaultFont" );
|
||||
if( font == null )
|
||||
font = slider.getFont();
|
||||
|
||||
@@ -293,9 +293,7 @@ public class FlatSpinnerUI
|
||||
return true;
|
||||
|
||||
JTextField textField = getEditorTextField( spinner.getEditor() );
|
||||
return (textField != null)
|
||||
? FlatUIUtils.isPermanentFocusOwner( textField )
|
||||
: false;
|
||||
return textField != null && FlatUIUtils.isPermanentFocusOwner( textField );
|
||||
}
|
||||
|
||||
protected Color getBackground( boolean enabled ) {
|
||||
@@ -447,7 +445,7 @@ public class FlatSpinnerUI
|
||||
Insets padding = scale( FlatSpinnerUI.this.padding );
|
||||
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 arrow buttons width is the same as the inner height so that the arrow buttons area is square
|
||||
int minimumWidth = FlatUIUtils.minimumWidth( spinner, FlatSpinnerUI.this.minimumWidth );
|
||||
int innerHeight = editorSize.height + padding.top + padding.bottom;
|
||||
float focusWidth = FlatUIUtils.getBorderFocusWidth( spinner );
|
||||
@@ -538,6 +536,7 @@ public class FlatSpinnerUI
|
||||
break;
|
||||
|
||||
case FlatClientProperties.COMPONENT_ROUND_RECT:
|
||||
case FlatClientProperties.OUTLINE:
|
||||
spinner.repaint();
|
||||
break;
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicSplitPaneDivider;
|
||||
import javax.swing.plaf.basic.BasicSplitPaneUI;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
|
||||
@@ -52,6 +53,13 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault SplitPaneDivider.border Border
|
||||
* @uiDefault SplitPaneDivider.draggingColor Color only used if continuousLayout is false
|
||||
*
|
||||
* <!-- BasicSplitPaneDivider -->
|
||||
*
|
||||
* @uiDefault SplitPane.oneTouchButtonSize int
|
||||
* @uiDefault SplitPane.oneTouchButtonOffset int
|
||||
* @uiDefault SplitPane.centerOneTouchButtons boolean
|
||||
* @uiDefault SplitPane.supportsOneTouchButtons boolean optional; default is true
|
||||
*
|
||||
* <!-- JSplitPane -->
|
||||
*
|
||||
* @uiDefault SplitPane.continuousLayout boolean
|
||||
@@ -235,7 +243,7 @@ public class FlatSplitPaneUI
|
||||
switch( e.getPropertyName() ) {
|
||||
case JSplitPane.DIVIDER_LOCATION_PROPERTY:
|
||||
// necessary to show/hide one-touch buttons on expand/collapse
|
||||
revalidate();
|
||||
doLayout();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -345,7 +353,7 @@ public class FlatSplitPaneUI
|
||||
if( leftButton == null || rightButton == null || !splitPane.isOneTouchExpandable() )
|
||||
return;
|
||||
|
||||
// increase side of buttons, which makes them easier to hit by the user
|
||||
// increase size of buttons, which makes them easier to hit by the user
|
||||
// and avoids cut arrows at small divider sizes
|
||||
int extraSize = UIScale.scale( 4 );
|
||||
if( orientation == JSplitPane.VERTICAL_SPLIT ) {
|
||||
@@ -360,10 +368,19 @@ public class FlatSplitPaneUI
|
||||
|
||||
// hide buttons if not applicable
|
||||
boolean leftCollapsed = isLeftCollapsed();
|
||||
if( leftCollapsed )
|
||||
boolean rightCollapsed = isRightCollapsed();
|
||||
if( leftCollapsed || rightCollapsed ) {
|
||||
leftButton.setVisible( !leftCollapsed );
|
||||
rightButton.setVisible( !rightCollapsed );
|
||||
} else {
|
||||
Object expandableSide = splitPane.getClientProperty( FlatClientProperties.SPLIT_PANE_EXPANDABLE_SIDE );
|
||||
leftButton.setVisible( expandableSide == null || !FlatClientProperties.SPLIT_PANE_EXPANDABLE_SIDE_LEFT.equals( expandableSide ) );
|
||||
rightButton.setVisible( expandableSide == null || !FlatClientProperties.SPLIT_PANE_EXPANDABLE_SIDE_RIGHT.equals( expandableSide ) );
|
||||
}
|
||||
|
||||
// move right button if left button is hidden
|
||||
if( !leftButton.isVisible() )
|
||||
rightButton.setLocation( leftButton.getLocation() );
|
||||
leftButton.setVisible( !leftCollapsed );
|
||||
rightButton.setVisible( !isRightCollapsed() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -359,7 +359,7 @@ public class FlatStylingSupport
|
||||
* @param key the name of the field
|
||||
* @param value the new value
|
||||
* @return the old value of the field
|
||||
* @throws UnknownStyleException if object does not have a annotated field with given name
|
||||
* @throws UnknownStyleException if object does not have an annotated field with given name
|
||||
* @throws IllegalArgumentException if value type does not fit to expected type
|
||||
*/
|
||||
public static Object applyToAnnotatedObject( Object obj, String key, Object value )
|
||||
@@ -517,7 +517,7 @@ public class FlatStylingSupport
|
||||
* @param key the name of the field
|
||||
* @param value the new value
|
||||
* @return the old value of the field
|
||||
* @throws UnknownStyleException if object does not have a annotated field with given name
|
||||
* @throws UnknownStyleException if object does not have an annotated field with given name
|
||||
* @throws IllegalArgumentException if value type does not fit to expected type
|
||||
*/
|
||||
public static Object applyToAnnotatedObjectOrComponent( Object obj, Object comp, String key, Object value )
|
||||
|
||||
@@ -59,6 +59,7 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.IntConsumer;
|
||||
import java.util.function.Predicate;
|
||||
import javax.accessibility.Accessible;
|
||||
import javax.accessibility.AccessibleContext;
|
||||
import javax.swing.Action;
|
||||
@@ -82,10 +83,12 @@ import javax.swing.event.ChangeListener;
|
||||
import javax.swing.event.PopupMenuEvent;
|
||||
import javax.swing.event.PopupMenuListener;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.TabbedPaneUI;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicTabbedPaneUI;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import javax.swing.text.View;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.icons.FlatTabbedPaneCloseIcon;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
@@ -127,6 +130,7 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault TabbedPane.selectedBackground Color optional
|
||||
* @uiDefault TabbedPane.selectedForeground Color
|
||||
* @uiDefault TabbedPane.underlineColor Color
|
||||
* @uiDefault TabbedPane.inactiveUnderlineColor Color
|
||||
* @uiDefault TabbedPane.disabledUnderlineColor Color
|
||||
* @uiDefault TabbedPane.hoverColor Color
|
||||
* @uiDefault TabbedPane.focusColor Color
|
||||
@@ -198,6 +202,7 @@ public class FlatTabbedPaneUI
|
||||
@Styleable protected Color selectedBackground;
|
||||
@Styleable protected Color selectedForeground;
|
||||
@Styleable protected Color underlineColor;
|
||||
/** @since 2.2 */ @Styleable protected Color inactiveUnderlineColor;
|
||||
@Styleable protected Color disabledUnderlineColor;
|
||||
@Styleable protected Color hoverColor;
|
||||
@Styleable protected Color focusColor;
|
||||
@@ -288,6 +293,7 @@ public class FlatTabbedPaneUI
|
||||
|
||||
super.installUI( c );
|
||||
|
||||
FlatSelectedTabRepainter.install();
|
||||
installStyle();
|
||||
}
|
||||
|
||||
@@ -318,6 +324,7 @@ public class FlatTabbedPaneUI
|
||||
selectedBackground = UIManager.getColor( "TabbedPane.selectedBackground" );
|
||||
selectedForeground = UIManager.getColor( "TabbedPane.selectedForeground" );
|
||||
underlineColor = UIManager.getColor( "TabbedPane.underlineColor" );
|
||||
inactiveUnderlineColor = FlatUIUtils.getUIColor( "TabbedPane.inactiveUnderlineColor", underlineColor );
|
||||
disabledUnderlineColor = UIManager.getColor( "TabbedPane.disabledUnderlineColor" );
|
||||
hoverColor = UIManager.getColor( "TabbedPane.hoverColor" );
|
||||
focusColor = UIManager.getColor( "TabbedPane.focusColor" );
|
||||
@@ -385,6 +392,7 @@ public class FlatTabbedPaneUI
|
||||
selectedBackground = null;
|
||||
selectedForeground = null;
|
||||
underlineColor = null;
|
||||
inactiveUnderlineColor = null;
|
||||
disabledUnderlineColor = null;
|
||||
hoverColor = null;
|
||||
focusColor = null;
|
||||
@@ -650,7 +658,7 @@ public class FlatTabbedPaneUI
|
||||
case "tabIconPlacement": value = parseTabIconPlacement( (String) value ); break;
|
||||
}
|
||||
} else {
|
||||
Object oldValue = null;
|
||||
Object oldValue;
|
||||
switch( key ) {
|
||||
// BasicTabbedPaneUI
|
||||
case "tabInsets": oldValue = tabInsets; tabInsets = (Insets) value; return oldValue;
|
||||
@@ -733,7 +741,6 @@ public class FlatTabbedPaneUI
|
||||
|
||||
// increase size of repaint region to include part of content border
|
||||
if( contentSeparatorHeight > 0 &&
|
||||
getTabType() == TAB_TYPE_CARD &&
|
||||
clientPropertyBoolean( tabPane, TABBED_PANE_SHOW_CONTENT_SEPARATOR, true ) )
|
||||
{
|
||||
int sh = scale( contentSeparatorHeight );
|
||||
@@ -1205,7 +1212,9 @@ public class FlatTabbedPaneUI
|
||||
}
|
||||
|
||||
protected void paintTabSelection( Graphics g, int tabPlacement, int x, int y, int w, int h ) {
|
||||
g.setColor( tabPane.isEnabled() ? underlineColor : disabledUnderlineColor );
|
||||
g.setColor( tabPane.isEnabled()
|
||||
? (isTabbedPaneOrChildFocused() ? underlineColor : inactiveUnderlineColor)
|
||||
: disabledUnderlineColor );
|
||||
|
||||
// paint underline selection
|
||||
boolean atBottom = (getTabType() != TAB_TYPE_CARD);
|
||||
@@ -1236,6 +1245,23 @@ public class FlatTabbedPaneUI
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2.2 */
|
||||
@SuppressWarnings( "unchecked" )
|
||||
protected boolean isTabbedPaneOrChildFocused() {
|
||||
KeyboardFocusManager keyboardFocusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
|
||||
|
||||
Object value = tabPane.getClientProperty( FlatClientProperties.COMPONENT_FOCUS_OWNER );
|
||||
if( value instanceof Predicate ) {
|
||||
return ((Predicate<JComponent>)value).test( tabPane ) &&
|
||||
FlatUIUtils.isInActiveWindow( tabPane, keyboardFocusManager.getActiveWindow() );
|
||||
}
|
||||
|
||||
Component focusOwner = keyboardFocusManager.getPermanentFocusOwner();
|
||||
return focusOwner != null &&
|
||||
SwingUtilities.isDescendingFrom( focusOwner, tabPane ) &&
|
||||
FlatUIUtils.isInActiveWindow( focusOwner, keyboardFocusManager.getActiveWindow() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Actually does nearly the same as super.paintContentBorder() but
|
||||
* - not using UIManager.getColor("TabbedPane.contentAreaColor") to be GUI builder friendly
|
||||
@@ -1841,7 +1867,7 @@ public class FlatTabbedPaneUI
|
||||
super( direction, arrowType,
|
||||
FlatTabbedPaneUI.this.foreground, FlatTabbedPaneUI.this.disabledForeground,
|
||||
null, buttonHoverBackground, null, buttonPressedBackground );
|
||||
setArrowWidth( 10 );
|
||||
setArrowWidth( 11 );
|
||||
}
|
||||
|
||||
protected void updateStyle() {
|
||||
@@ -1983,7 +2009,7 @@ public class FlatTabbedPaneUI
|
||||
}
|
||||
|
||||
protected JMenuItem createTabMenuItem( int tabIndex ) {
|
||||
// search for tab name in this places
|
||||
// search for tab name in these places
|
||||
// 1. tab title
|
||||
// 2. text of label or text component in custom tab component (including children)
|
||||
// 3. accessible name of tab
|
||||
@@ -2016,7 +2042,7 @@ public class FlatTabbedPaneUI
|
||||
menuItem.setOpaque( true );
|
||||
}
|
||||
|
||||
if( !tabPane.isEnabledAt( tabIndex ) )
|
||||
if( !tabPane.isEnabled() || !tabPane.isEnabledAt( tabIndex ) )
|
||||
menuItem.setEnabled( false );
|
||||
|
||||
menuItem.addActionListener( e -> selectTab( tabIndex ) );
|
||||
@@ -2412,7 +2438,7 @@ public class FlatTabbedPaneUI
|
||||
if( tabPane == null || tabViewport == null )
|
||||
return;
|
||||
|
||||
if( !scrolled || tabViewport == null )
|
||||
if( !scrolled )
|
||||
return;
|
||||
scrolled = false;
|
||||
|
||||
@@ -2525,9 +2551,7 @@ public class FlatTabbedPaneUI
|
||||
setRolloverTab( tabIndex );
|
||||
|
||||
// check whether mouse hit tab close area
|
||||
boolean hitClose = isTabClosable( tabIndex )
|
||||
? getTabCloseHitArea( tabIndex ).contains( x, y )
|
||||
: false;
|
||||
boolean hitClose = isTabClosable( tabIndex ) && getTabCloseHitArea( tabIndex ).contains( x, y );
|
||||
if( e.getID() == MouseEvent.MOUSE_PRESSED )
|
||||
pressedTabIndex = hitClose ? tabIndex : -1;
|
||||
setRolloverTabClose( hitClose );
|
||||
@@ -2550,8 +2574,7 @@ public class FlatTabbedPaneUI
|
||||
if( tabIndex == lastTipTabIndex )
|
||||
return; // closeTip already set
|
||||
|
||||
if( tabIndex != lastTipTabIndex )
|
||||
restoreTabToolTip();
|
||||
restoreTabToolTip();
|
||||
|
||||
lastTipTabIndex = tabIndex;
|
||||
lastTip = tabPane.getToolTipTextAt( lastTipTabIndex );
|
||||
@@ -3344,4 +3367,77 @@ public class FlatTabbedPaneUI
|
||||
delegate.actionPerformed( e );
|
||||
}
|
||||
}
|
||||
|
||||
//---- class FlatSelectedTabRepainter -------------------------------------
|
||||
|
||||
private static class FlatSelectedTabRepainter
|
||||
implements PropertyChangeListener//, Runnable
|
||||
{
|
||||
private static FlatSelectedTabRepainter instance;
|
||||
|
||||
private KeyboardFocusManager keyboardFocusManager;
|
||||
|
||||
static void install() {
|
||||
synchronized( FlatSelectedTabRepainter.class ) {
|
||||
if( instance != null )
|
||||
return;
|
||||
|
||||
instance = new FlatSelectedTabRepainter();
|
||||
}
|
||||
}
|
||||
|
||||
FlatSelectedTabRepainter() {
|
||||
keyboardFocusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
|
||||
keyboardFocusManager.addPropertyChangeListener( this );
|
||||
}
|
||||
|
||||
private void uninstall() {
|
||||
synchronized( FlatSelectedTabRepainter.class ) {
|
||||
if( instance == null )
|
||||
return;
|
||||
|
||||
keyboardFocusManager.removePropertyChangeListener( this );
|
||||
keyboardFocusManager = null;
|
||||
instance = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void propertyChange( PropertyChangeEvent e ) {
|
||||
// uninstall if no longer using FlatLaf
|
||||
if( !(UIManager.getLookAndFeel() instanceof FlatLaf) ) {
|
||||
uninstall();
|
||||
return;
|
||||
}
|
||||
|
||||
switch( e.getPropertyName() ) {
|
||||
case "permanentFocusOwner":
|
||||
Object oldValue = e.getOldValue();
|
||||
Object newValue = e.getNewValue();
|
||||
if( oldValue instanceof Component )
|
||||
repaintSelectedTabs( (Component) oldValue );
|
||||
if( newValue instanceof Component )
|
||||
repaintSelectedTabs( (Component) newValue );
|
||||
break;
|
||||
|
||||
case "activeWindow":
|
||||
repaintSelectedTabs( keyboardFocusManager.getPermanentFocusOwner() );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void repaintSelectedTabs( Component c ) {
|
||||
if( c instanceof JTabbedPane )
|
||||
repaintSelectedTab( (JTabbedPane) c );
|
||||
|
||||
while( (c = SwingUtilities.getAncestorOfClass( JTabbedPane.class, c )) != null )
|
||||
repaintSelectedTab( (JTabbedPane) c );
|
||||
}
|
||||
|
||||
private void repaintSelectedTab( JTabbedPane tabbedPane ) {
|
||||
TabbedPaneUI ui = tabbedPane.getUI();
|
||||
if( ui instanceof FlatTabbedPaneUI )
|
||||
((FlatTabbedPaneUI) ui).repaintTab( tabbedPane.getSelectedIndex() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ public class FlatTableCellBorder
|
||||
}
|
||||
|
||||
/**
|
||||
* Because this borders are always shared for all tables,
|
||||
* Because this border is always shared for all tables,
|
||||
* get border specific style from FlatTableUI.
|
||||
*/
|
||||
static <T> T getStyleFromTableUI( Component c, Function<FlatTableUI, T> f ) {
|
||||
|
||||
@@ -39,7 +39,9 @@ import javax.swing.event.MouseInputListener;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicTableHeaderUI;
|
||||
import javax.swing.table.JTableHeader;
|
||||
import javax.swing.table.TableCellRenderer;
|
||||
import javax.swing.table.TableColumn;
|
||||
import javax.swing.table.TableColumnModel;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
@@ -195,6 +197,8 @@ public class FlatTableHeaderUI
|
||||
|
||||
@Override
|
||||
public void paint( Graphics g, JComponent c ) {
|
||||
fixDraggedAndResizingColumns( header );
|
||||
|
||||
TableColumnModel columnModel = header.getColumnModel();
|
||||
if( columnModel.getColumnCount() <= 0 )
|
||||
return;
|
||||
@@ -269,6 +273,32 @@ public class FlatTableHeaderUI
|
||||
return size;
|
||||
}
|
||||
|
||||
static void fixDraggedAndResizingColumns( JTableHeader header ) {
|
||||
if( header == null )
|
||||
return;
|
||||
|
||||
// Dragged column may be outdated in the case that the table structure
|
||||
// was changed from a table header popup menu action. In this case
|
||||
// the paint methods in BasicTableHeaderUI and BasicTableUI would throw exceptions.
|
||||
TableColumn draggedColumn = header.getDraggedColumn();
|
||||
if( draggedColumn != null && !isValidColumn( header.getColumnModel(), draggedColumn ) )
|
||||
header.setDraggedColumn( null );
|
||||
|
||||
// also clear outdated resizing column (although this seems not cause exceptions)
|
||||
TableColumn resizingColumn = header.getResizingColumn();
|
||||
if( resizingColumn != null && !isValidColumn( header.getColumnModel(), resizingColumn ) )
|
||||
header.setResizingColumn( null );
|
||||
}
|
||||
|
||||
private static boolean isValidColumn( TableColumnModel cm, TableColumn column ) {
|
||||
int count = cm.getColumnCount();
|
||||
for( int i = 0; i < count; i++ ) {
|
||||
if( cm.getColumn( i ) == column )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//---- class FlatTableCellHeaderRenderer ----------------------------------
|
||||
|
||||
/**
|
||||
|
||||
@@ -80,6 +80,7 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault Table.intercellSpacing Dimension
|
||||
* @uiDefault Table.selectionInactiveBackground Color
|
||||
* @uiDefault Table.selectionInactiveForeground Color
|
||||
* @uiDefault Table.paintOutsideAlternateRows boolean
|
||||
*
|
||||
* <!-- FlatTableCellBorder -->
|
||||
*
|
||||
@@ -95,7 +96,7 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
*/
|
||||
public class FlatTableUI
|
||||
extends BasicTableUI
|
||||
implements StyleableUI
|
||||
implements StyleableUI, FlatViewportUI.ViewportPainter
|
||||
{
|
||||
protected boolean showHorizontalLines;
|
||||
protected boolean showVerticalLines;
|
||||
@@ -288,7 +289,7 @@ public class FlatTableUI
|
||||
/**
|
||||
* Toggle selection colors from focused to inactive and vice versa.
|
||||
*
|
||||
* This is not a optimal solution but much easier than rewriting the whole paint methods.
|
||||
* This is not an optimal solution but much easier than rewriting the whole paint methods.
|
||||
*
|
||||
* Using a LaF specific renderer was avoided because often a custom renderer is
|
||||
* already used in applications. Then either the inactive colors are not used,
|
||||
@@ -313,6 +314,8 @@ public class FlatTableUI
|
||||
|
||||
@Override
|
||||
public void paint( Graphics g, JComponent c ) {
|
||||
FlatTableHeaderUI.fixDraggedAndResizingColumns( table.getTableHeader() );
|
||||
|
||||
boolean horizontalLines = table.getShowHorizontalLines();
|
||||
boolean verticalLines = table.getShowVerticalLines();
|
||||
if( horizontalLines || verticalLines ) {
|
||||
@@ -421,4 +424,38 @@ public class FlatTableUI
|
||||
? (viewport != rowHeader)
|
||||
: (viewport == rowHeader || rowHeader == null);
|
||||
}
|
||||
|
||||
/** @since 2.3 */
|
||||
@Override
|
||||
public void paintViewport( Graphics g, JComponent c, JViewport viewport ) {
|
||||
int viewportWidth = viewport.getWidth();
|
||||
int viewportHeight = viewport.getHeight();
|
||||
|
||||
// fill viewport background in same color as table background
|
||||
if( viewport.isOpaque() ) {
|
||||
g.setColor( table.getBackground() );
|
||||
g.fillRect( 0, 0, viewportWidth, viewportHeight );
|
||||
}
|
||||
|
||||
// paint alternating empty rows
|
||||
boolean paintOutside = UIManager.getBoolean( "Table.paintOutsideAlternateRows" );
|
||||
Color alternateColor;
|
||||
if( paintOutside && (alternateColor = UIManager.getColor( "Table.alternateRowColor" )) != null ) {
|
||||
g.setColor( alternateColor );
|
||||
|
||||
int rowCount = table.getRowCount();
|
||||
|
||||
// paint alternating empty rows below the table
|
||||
int tableHeight = table.getHeight();
|
||||
if( tableHeight < viewportHeight ) {
|
||||
int tableWidth = table.getWidth();
|
||||
int rowHeight = table.getRowHeight();
|
||||
|
||||
for( int y = tableHeight, row = rowCount; y < viewportHeight; y += rowHeight, row++ ) {
|
||||
if( row % 2 != 0 )
|
||||
g.fillRect( 0, y, tableWidth, rowHeight );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,6 +232,7 @@ public class FlatTextFieldUI
|
||||
switch( e.getPropertyName() ) {
|
||||
case PLACEHOLDER_TEXT:
|
||||
case COMPONENT_ROUND_RECT:
|
||||
case OUTLINE:
|
||||
case TEXT_FIELD_PADDING:
|
||||
c.repaint();
|
||||
break;
|
||||
@@ -368,7 +369,7 @@ public class FlatTextFieldUI
|
||||
if( !(oldBackground instanceof UIResource) )
|
||||
return;
|
||||
|
||||
// do not update background if it currently has a unknown color (assigned from outside)
|
||||
// do not update background if it currently has an unknown color (assigned from outside)
|
||||
if( oldBackground != background &&
|
||||
oldBackground != disabledBackground &&
|
||||
oldBackground != inactiveBackground &&
|
||||
@@ -609,7 +610,7 @@ debug*/
|
||||
* Returns the rectangle used to paint leading and trailing icons.
|
||||
* It invokes {@code super.getVisibleEditorRect()} and reduces left and/or
|
||||
* right margin if the text field has leading or trailing icons or components.
|
||||
* Also the preferred widths of leading and trailing components are removed.
|
||||
* Also, the preferred widths of leading and trailing components are removed.
|
||||
*
|
||||
* @since 2
|
||||
*/
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.awt.Container;
|
||||
import java.awt.Dialog;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Frame;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
@@ -50,13 +51,13 @@ import javax.accessibility.AccessibleContext;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JRootPane;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.AbstractBorder;
|
||||
@@ -83,10 +84,14 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault TitlePane.iconMargins Insets
|
||||
* @uiDefault TitlePane.titleMargins Insets
|
||||
* @uiDefault TitlePane.menuBarEmbedded boolean
|
||||
* @uiDefault TitlePane.titleMinimumWidth int
|
||||
* @uiDefault TitlePane.buttonMinimumWidth int
|
||||
* @uiDefault TitlePane.buttonMaximizedHeight int
|
||||
* @uiDefault TitlePane.centerTitle boolean
|
||||
* @uiDefault TitlePane.centerTitleIfMenuBarEmbedded boolean
|
||||
* @uiDefault TitlePane.showIconBesideTitle boolean
|
||||
* @uiDefault TitlePane.menuBarTitleGap int
|
||||
* @uiDefault TitlePane.menuBarResizeHeight int
|
||||
* @uiDefault TitlePane.closeIcon Icon
|
||||
* @uiDefault TitlePane.iconifyIcon Icon
|
||||
* @uiDefault TitlePane.maximizeIcon Icon
|
||||
@@ -107,10 +112,15 @@ public class FlatTitlePane
|
||||
/** @since 2 */ protected final boolean showIcon = FlatUIUtils.getUIBoolean( "TitlePane.showIcon", true );
|
||||
/** @since 2 */ protected final int noIconLeftGap = FlatUIUtils.getUIInt( "TitlePane.noIconLeftGap", 8 );
|
||||
protected final Dimension iconSize = UIManager.getDimension( "TitlePane.iconSize" );
|
||||
/** @since 2.4 */ protected final int titleMinimumWidth = FlatUIUtils.getUIInt( "TitlePane.titleMinimumWidth", 60 );
|
||||
/** @since 2.4 */ protected final int buttonMinimumWidth = FlatUIUtils.getUIInt( "TitlePane.buttonMinimumWidth", 30 );
|
||||
protected final int buttonMaximizedHeight = UIManager.getInt( "TitlePane.buttonMaximizedHeight" );
|
||||
protected final boolean centerTitle = UIManager.getBoolean( "TitlePane.centerTitle" );
|
||||
protected final boolean centerTitleIfMenuBarEmbedded = FlatUIUtils.getUIBoolean( "TitlePane.centerTitleIfMenuBarEmbedded", true );
|
||||
protected final int menuBarTitleGap = FlatUIUtils.getUIInt( "TitlePane.menuBarTitleGap", 20 );
|
||||
/** @since 2.4 */ protected final boolean showIconBesideTitle = UIManager.getBoolean( "TitlePane.showIconBesideTitle" );
|
||||
protected final int menuBarTitleGap = FlatUIUtils.getUIInt( "TitlePane.menuBarTitleGap", 40 );
|
||||
/** @since 2.4 */ protected final int menuBarTitleMinimumGap = FlatUIUtils.getUIInt( "TitlePane.menuBarTitleMinimumGap", 12 );
|
||||
/** @since 2.4 */ protected final int menuBarResizeHeight = FlatUIUtils.getUIInt( "TitlePane.menuBarResizeHeight", 4 );
|
||||
|
||||
protected final JRootPane rootPane;
|
||||
|
||||
@@ -142,6 +152,8 @@ public class FlatTitlePane
|
||||
|
||||
// necessary for closing window with double-click on icon
|
||||
iconLabel.addMouseListener( handler );
|
||||
|
||||
applyComponentOrientation( rootPane.getComponentOrientation() );
|
||||
}
|
||||
|
||||
protected FlatTitlePaneBorder createTitlePaneBorder() {
|
||||
@@ -163,7 +175,6 @@ public class FlatTitlePane
|
||||
};
|
||||
iconLabel.setBorder( new FlatEmptyBorder( UIManager.getInsets( "TitlePane.iconMargins" ) ) );
|
||||
titleLabel.setBorder( new FlatEmptyBorder( UIManager.getInsets( "TitlePane.titleMargins" ) ) );
|
||||
titleLabel.setHorizontalAlignment( SwingConstants.CENTER );
|
||||
|
||||
leftPanel.setLayout( new BoxLayout( leftPanel, BoxLayout.LINE_AXIS ) );
|
||||
leftPanel.setOpaque( false );
|
||||
@@ -183,18 +194,52 @@ public class FlatTitlePane
|
||||
setLayout( new BorderLayout() {
|
||||
@Override
|
||||
public void layoutContainer( Container target ) {
|
||||
super.layoutContainer( target );
|
||||
|
||||
// make left panel (with embedded menu bar) smaller if horizontal space is rare
|
||||
// to avoid that embedded menu bar overlaps button bar
|
||||
// compute available bounds
|
||||
Insets insets = target.getInsets();
|
||||
int width = target.getWidth() - insets.left - insets.right;
|
||||
if( leftPanel.getWidth() + buttonPanel.getWidth() > width ) {
|
||||
int oldWidth = leftPanel.getWidth();
|
||||
int newWidth = Math.max( width - buttonPanel.getWidth(), 0 );
|
||||
leftPanel.setSize( newWidth, leftPanel.getHeight() );
|
||||
if( !getComponentOrientation().isLeftToRight() )
|
||||
leftPanel.setLocation( leftPanel.getX() + (oldWidth - newWidth), leftPanel.getY() );
|
||||
int x = insets.left;
|
||||
int y = insets.top;
|
||||
int w = target.getWidth() - insets.left - insets.right;
|
||||
int h = target.getHeight() - insets.top - insets.bottom;
|
||||
|
||||
// compute widths
|
||||
int leftWidth = leftPanel.getPreferredSize().width;
|
||||
int buttonsWidth = buttonPanel.getPreferredSize().width;
|
||||
int titleWidth = w - leftWidth - buttonsWidth;
|
||||
int minTitleWidth = UIScale.scale( titleMinimumWidth );
|
||||
|
||||
// increase minimum width if icon is show besides the title
|
||||
Icon icon = titleLabel.getIcon();
|
||||
if( icon != null ) {
|
||||
Insets iconInsets = iconLabel.getInsets();
|
||||
int iconTextGap = titleLabel.getComponentOrientation().isLeftToRight() ? iconInsets.right : iconInsets.left;
|
||||
minTitleWidth += icon.getIconWidth() + iconTextGap;
|
||||
}
|
||||
|
||||
// if title is too small, reduce width of buttons
|
||||
if( titleWidth < minTitleWidth ) {
|
||||
buttonsWidth = Math.max( buttonsWidth - (minTitleWidth - titleWidth), buttonPanel.getMinimumSize().width );
|
||||
titleWidth = w - leftWidth - buttonsWidth;
|
||||
}
|
||||
|
||||
// if title is still too small, reduce width of left panel (icon and embedded menu bar)
|
||||
if( titleWidth < minTitleWidth ) {
|
||||
int minLeftWidth = iconLabel.isVisible()
|
||||
? iconLabel.getWidth() - iconLabel.getInsets().right
|
||||
: UIScale.scale( noIconLeftGap );
|
||||
leftWidth = Math.max( leftWidth - (minTitleWidth - titleWidth), minLeftWidth );
|
||||
titleWidth = w - leftWidth - buttonsWidth;
|
||||
}
|
||||
|
||||
if( target.getComponentOrientation().isLeftToRight() ) {
|
||||
// left-to-right
|
||||
leftPanel.setBounds( x, y, leftWidth, h );
|
||||
titleLabel.setBounds( x + leftWidth, y, titleWidth, h );
|
||||
buttonPanel.setBounds( x + leftWidth + titleWidth, y, buttonsWidth, h );
|
||||
} else {
|
||||
// right-to-left
|
||||
buttonPanel.setBounds( x, y, buttonsWidth, h );
|
||||
titleLabel.setBounds( x + buttonsWidth, y, titleWidth, h );
|
||||
leftPanel.setBounds( x + buttonsWidth + titleWidth, y, leftWidth, h );
|
||||
}
|
||||
|
||||
// If menu bar is embedded and contains a horizontal glue component,
|
||||
@@ -233,10 +278,7 @@ public class FlatTitlePane
|
||||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
Dimension size = super.getPreferredSize();
|
||||
if( buttonMaximizedHeight > 0 &&
|
||||
window instanceof Frame &&
|
||||
(((Frame)window).getExtendedState() & Frame.MAXIMIZED_BOTH) != 0 )
|
||||
{
|
||||
if( buttonMaximizedHeight > 0 && isWindowMaximized() && !hasVisibleEmbeddedMenuBar( rootPane.getJMenuBar() ) ) {
|
||||
// make title pane height smaller when frame is maximized
|
||||
size = new Dimension( size.width, Math.min( size.height, UIScale.scale( buttonMaximizedHeight ) ) );
|
||||
}
|
||||
@@ -248,7 +290,7 @@ public class FlatTitlePane
|
||||
if( rootPane.getWindowDecorationStyle() == JRootPane.FRAME ) {
|
||||
// JRootPane.FRAME works only for frames (and not for dialogs)
|
||||
// but at this time the owner window type is unknown (not yet added)
|
||||
// so we add the iconify/maximize/restore buttons and they are shown
|
||||
// so we add the iconify/maximize/restore buttons, and they are shown
|
||||
// later in frameStateChanged(), which is invoked from addNotify()
|
||||
|
||||
buttonPanel.add( iconifyButton );
|
||||
@@ -259,7 +301,13 @@ public class FlatTitlePane
|
||||
}
|
||||
|
||||
protected JButton createButton( String iconKey, String accessibleName, ActionListener action ) {
|
||||
JButton button = new JButton( UIManager.getIcon( iconKey ) );
|
||||
JButton button = new JButton( UIManager.getIcon( iconKey ) ) {
|
||||
@Override
|
||||
public Dimension getMinimumSize() {
|
||||
// allow the button to shrink if space is rare
|
||||
return new Dimension( UIScale.scale( buttonMinimumWidth ), super.getMinimumSize().height );
|
||||
}
|
||||
};
|
||||
button.setFocusable( false );
|
||||
button.setContentAreaFilled( false );
|
||||
button.setBorder( BorderFactory.createEmptyBorder() );
|
||||
@@ -356,11 +404,12 @@ public class FlatTitlePane
|
||||
boolean hasIcon = (images != null && !images.isEmpty());
|
||||
|
||||
// set icon
|
||||
iconLabel.setIcon( hasIcon ? new FlatTitlePaneIcon( images, iconSize ) : null );
|
||||
iconLabel.setIcon( hasIcon && !showIconBesideTitle ? new FlatTitlePaneIcon( images, iconSize ) : null );
|
||||
titleLabel.setIcon( hasIcon && showIconBesideTitle ? new FlatTitlePaneIcon( images, iconSize ) : null );
|
||||
|
||||
// show/hide icon
|
||||
iconLabel.setVisible( hasIcon );
|
||||
leftPanel.setBorder( hasIcon ? null : FlatUIUtils.nonUIResource( new FlatEmptyBorder( 0, noIconLeftGap, 0, 0 ) ) );
|
||||
iconLabel.setVisible( hasIcon && !showIconBesideTitle );
|
||||
leftPanel.setBorder( hasIcon && !showIconBesideTitle ? null : FlatUIUtils.nonUIResource( new FlatEmptyBorder( 0, noIconLeftGap, 0, 0 ) ) );
|
||||
|
||||
updateNativeTitleBarHeightAndHitTestSpotsLater();
|
||||
}
|
||||
@@ -420,7 +469,7 @@ public class FlatTitlePane
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this title pane currently has an visible and embedded menubar.
|
||||
* Returns whether this title pane currently has a visible and embedded menubar.
|
||||
*/
|
||||
protected boolean hasVisibleEmbeddedMenuBar( JMenuBar menuBar ) {
|
||||
return menuBar != null && menuBar.isVisible() && isMenuBarEmbedded();
|
||||
@@ -567,6 +616,11 @@ debug*/
|
||||
frame.setExtendedState( frame.getExtendedState() | Frame.ICONIFIED );
|
||||
}
|
||||
|
||||
/** @since 2.4 */
|
||||
protected boolean isWindowMaximized() {
|
||||
return window instanceof Frame && (((Frame)window).getExtendedState() & Frame.MAXIMIZED_BOTH) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maximizes the window.
|
||||
*/
|
||||
@@ -615,7 +669,7 @@ debug*/
|
||||
int maximizedWidth = screenBounds.width;
|
||||
int maximizedHeight = screenBounds.height;
|
||||
|
||||
if( !isMaximizedBoundsFixed() ) {
|
||||
if( SystemInfo.isWindows && !isMaximizedBoundsFixed() ) {
|
||||
// on Java 8 to 14, maximized x,y are 0,0 based on all screens in a multi-screen environment
|
||||
maximizedX = 0;
|
||||
maximizedY = 0;
|
||||
@@ -729,7 +783,7 @@ debug*/
|
||||
List<Rectangle> hitTestSpots = new ArrayList<>();
|
||||
Rectangle appIconBounds = null;
|
||||
|
||||
if( iconLabel.isVisible() ) {
|
||||
if( !showIconBesideTitle && iconLabel.isVisible() ) {
|
||||
// compute real icon size (without insets; 1px larger for easier hitting)
|
||||
Point location = SwingUtilities.convertPoint( iconLabel, 0, 0, window );
|
||||
Insets iconInsets = iconLabel.getInsets();
|
||||
@@ -741,9 +795,7 @@ debug*/
|
||||
|
||||
// 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 )
|
||||
{
|
||||
if( isWindowMaximized() ) {
|
||||
iconBounds.height += iconBounds.y;
|
||||
iconBounds.y = 0;
|
||||
|
||||
@@ -758,6 +810,38 @@ debug*/
|
||||
hitTestSpots.add( iconBounds );
|
||||
else
|
||||
appIconBounds = iconBounds;
|
||||
} else if( showIconBesideTitle && titleLabel.getIcon() != null && titleLabel.getUI() instanceof FlatTitleLabelUI ) {
|
||||
FlatTitleLabelUI ui = (FlatTitleLabelUI) titleLabel.getUI();
|
||||
|
||||
// compute real icon bounds
|
||||
Insets insets = titleLabel.getInsets();
|
||||
Rectangle viewR = new Rectangle( insets.left, insets.top,
|
||||
titleLabel.getWidth() - insets.left - insets.right,
|
||||
titleLabel.getHeight() - insets.top - insets.bottom );
|
||||
Rectangle iconR = new Rectangle();
|
||||
Rectangle textR = new Rectangle();
|
||||
ui.layoutCL( titleLabel, titleLabel.getFontMetrics( titleLabel.getFont() ),
|
||||
titleLabel.getText(), titleLabel.getIcon(),
|
||||
viewR, iconR, textR );
|
||||
|
||||
// Windows shows the window system menu only in the upper-left corner
|
||||
if( iconR.x == 0 ) {
|
||||
// convert icon location to window coordinates
|
||||
Point location = SwingUtilities.convertPoint( titleLabel, 0, 0, window );
|
||||
iconR.x += location.x;
|
||||
iconR.y += location.y;
|
||||
|
||||
// make icon bounds 1px larger for easier hitting
|
||||
iconR.x -= 1;
|
||||
iconR.y -= 1;
|
||||
iconR.width += 2;
|
||||
iconR.height += 2;
|
||||
|
||||
if( hasJBRCustomDecoration() )
|
||||
hitTestSpots.add( iconR );
|
||||
else
|
||||
appIconBounds = iconR;
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle r = getNativeHitTestSpot( buttonPanel );
|
||||
@@ -768,11 +852,20 @@ debug*/
|
||||
if( hasVisibleEmbeddedMenuBar( menuBar ) ) {
|
||||
r = getNativeHitTestSpot( menuBar );
|
||||
if( r != null ) {
|
||||
// if frame is resizable and not maximized, make menu bar hit test spot smaller at top
|
||||
// to have a small area above the menu bar to resize the window
|
||||
if( window instanceof Frame && ((Frame)window).isResizable() && !isWindowMaximized() ) {
|
||||
// limit to 8, because Windows does not use a larger height
|
||||
int resizeHeight = UIScale.scale( Math.min( menuBarResizeHeight, 8 ) );
|
||||
r.y += resizeHeight;
|
||||
r.height -= resizeHeight;
|
||||
}
|
||||
|
||||
Component horizontalGlue = findHorizontalGlue( menuBar );
|
||||
if( horizontalGlue != null ) {
|
||||
// If menu bar is embedded and contains a horizontal glue component,
|
||||
// then split the hit test spot into two spots so that
|
||||
// the glue component area can used to move the window.
|
||||
// the glue component area can be used to move the window.
|
||||
|
||||
Point glueLocation = SwingUtilities.convertPoint( horizontalGlue, 0, 0, window );
|
||||
int x2 = glueLocation.x + horizontalGlue.getWidth();
|
||||
@@ -854,7 +947,7 @@ debug*/
|
||||
} else if( borderColor != null && (rootPane.getJMenuBar() == null || !rootPane.getJMenuBar().isVisible()) )
|
||||
insets.bottom += UIScale.scale( 1 );
|
||||
|
||||
if( !SystemInfo.isWindows_11_orLater && hasNativeCustomDecoration() && !isWindowMaximized( c ) )
|
||||
if( !SystemInfo.isWindows_11_orLater && hasNativeCustomDecoration() && !isWindowMaximized() )
|
||||
insets = FlatUIUtils.addInsets( insets, WindowTopBorder.getInstance().getBorderInsets() );
|
||||
|
||||
return insets;
|
||||
@@ -873,7 +966,7 @@ debug*/
|
||||
FlatUIUtils.paintFilledRectangle( g, borderColor, x, y + height - lineHeight, width, lineHeight );
|
||||
}
|
||||
|
||||
if( !SystemInfo.isWindows_11_orLater && hasNativeCustomDecoration() && !isWindowMaximized( c ) )
|
||||
if( !SystemInfo.isWindows_11_orLater && hasNativeCustomDecoration() && !isWindowMaximized() )
|
||||
WindowTopBorder.getInstance().paintBorder( c, g, x, y, width, height );
|
||||
}
|
||||
|
||||
@@ -881,12 +974,6 @@ debug*/
|
||||
JMenuBar menuBar = rootPane.getJMenuBar();
|
||||
return hasVisibleEmbeddedMenuBar( menuBar ) ? menuBar.getBorder() : null;
|
||||
}
|
||||
|
||||
protected boolean isWindowMaximized( Component c ) {
|
||||
return window instanceof Frame
|
||||
? (((Frame)window).getExtendedState() & Frame.MAXIMIZED_BOTH) != 0
|
||||
: false;
|
||||
}
|
||||
}
|
||||
|
||||
//---- class FlatTitleLabelUI ---------------------------------------------
|
||||
@@ -900,32 +987,101 @@ debug*/
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintEnabledText( JLabel l, Graphics g, String s, int textX, int textY ) {
|
||||
boolean hasEmbeddedMenuBar = hasVisibleEmbeddedMenuBar( rootPane.getJMenuBar() );
|
||||
int labelWidth = l.getWidth();
|
||||
int textWidth = labelWidth - (textX * 2);
|
||||
int gap = UIScale.scale( menuBarTitleGap );
|
||||
protected String layoutCL( JLabel label, FontMetrics fontMetrics, String text, Icon icon,
|
||||
Rectangle viewR, Rectangle iconR, Rectangle textR )
|
||||
{
|
||||
JMenuBar menuBar = rootPane.getJMenuBar();
|
||||
boolean hasEmbeddedMenuBar = hasVisibleEmbeddedMenuBar( menuBar );
|
||||
boolean hasEmbeddedLeadingMenus = hasEmbeddedMenuBar && hasLeadingMenus( menuBar );
|
||||
boolean leftToRight = getComponentOrientation().isLeftToRight();
|
||||
|
||||
// The passed in textX coordinate is always to horizontally center the text within the label bounds.
|
||||
// Modify textX so that the text is painted either centered within the window bounds or leading aligned.
|
||||
boolean center = hasEmbeddedMenuBar ? centerTitleIfMenuBarEmbedded : centerTitle;
|
||||
if( center ) {
|
||||
// If window is wide enough, center title within window bounds.
|
||||
// Otherwise leave it centered within free space (label bounds).
|
||||
int centeredTextX = ((l.getParent().getWidth() - textWidth) / 2) - l.getX();
|
||||
if( centeredTextX >= gap && centeredTextX + textWidth <= labelWidth - gap )
|
||||
textX = centeredTextX;
|
||||
} else {
|
||||
// leading aligned
|
||||
boolean leftToRight = getComponentOrientation().isLeftToRight();
|
||||
Insets insets = l.getInsets();
|
||||
int leadingInset = hasEmbeddedMenuBar ? gap : (leftToRight ? insets.left : insets.right);
|
||||
int leadingTextX = leftToRight ? leadingInset : labelWidth - leadingInset - textWidth;
|
||||
if( leftToRight ? leadingTextX < textX : leadingTextX > textX )
|
||||
textX = leadingTextX;
|
||||
if( hasEmbeddedMenuBar ) {
|
||||
int minGap = UIScale.scale( menuBarTitleMinimumGap );
|
||||
|
||||
// apply minimum leading gap (between embedded menu bar and title)
|
||||
if( hasEmbeddedLeadingMenus ) {
|
||||
if( leftToRight )
|
||||
viewR.x += minGap;
|
||||
viewR.width -= minGap;
|
||||
}
|
||||
|
||||
// apply minimum trailing gap (between title and right aligned components of embedded menu bar)
|
||||
Component horizontalGlue = findHorizontalGlue( menuBar );
|
||||
if( horizontalGlue != null && menuBar.getComponent( menuBar.getComponentCount() - 1 ) != horizontalGlue ) {
|
||||
if( !leftToRight )
|
||||
viewR.x += minGap;
|
||||
viewR.width -= minGap;
|
||||
}
|
||||
}
|
||||
|
||||
super.paintEnabledText( l, g, s, textX, textY );
|
||||
// compute icon width and gap (if icon is show besides the title)
|
||||
int iconTextGap = 0;
|
||||
int iconWidthAndGap = 0;
|
||||
if( icon != null ) {
|
||||
Insets iconInsets = iconLabel.getInsets();
|
||||
iconTextGap = leftToRight ? iconInsets.right : iconInsets.left;
|
||||
iconWidthAndGap = icon.getIconWidth() + iconTextGap;
|
||||
}
|
||||
|
||||
// layout title and icon (if show besides the title)
|
||||
String clippedText = SwingUtilities.layoutCompoundLabel( label, fontMetrics, text, icon,
|
||||
label.getVerticalAlignment(), label.getHorizontalAlignment(),
|
||||
label.getVerticalTextPosition(), label.getHorizontalTextPosition(),
|
||||
viewR, iconR, textR,
|
||||
iconTextGap );
|
||||
|
||||
// compute text X location
|
||||
if( !clippedText.equals( text ) ) {
|
||||
// if text is clipped, align to left (or right)
|
||||
textR.x = leftToRight
|
||||
? viewR.x + iconWidthAndGap
|
||||
: viewR.x + viewR.width - iconWidthAndGap - textR.width;
|
||||
} else {
|
||||
int leadingGap = hasEmbeddedLeadingMenus ? UIScale.scale( menuBarTitleGap - menuBarTitleMinimumGap ) : 0;
|
||||
|
||||
boolean center = hasEmbeddedLeadingMenus ? centerTitleIfMenuBarEmbedded : centerTitle;
|
||||
if( center ) {
|
||||
// If window is wide enough, center title within window bounds.
|
||||
// Otherwise, center within free space (label bounds).
|
||||
Container parent = label.getParent();
|
||||
int centeredTextX = (parent != null) ? ((parent.getWidth() - textR.width - iconWidthAndGap) / 2) + iconWidthAndGap - label.getX() : -1;
|
||||
textR.x = (centeredTextX >= viewR.x + leadingGap && centeredTextX + textR.width <= viewR.x + viewR.width - leadingGap)
|
||||
? centeredTextX
|
||||
: viewR.x + ((viewR.width - textR.width - iconWidthAndGap) / 2) + iconWidthAndGap;
|
||||
} else {
|
||||
// leading aligned with leading gap, which is reduced if space is rare
|
||||
textR.x = leftToRight
|
||||
? Math.min( viewR.x + leadingGap + iconWidthAndGap, viewR.x + viewR.width - textR.width )
|
||||
: Math.max( viewR.x + viewR.width - leadingGap - iconWidthAndGap - textR.width, viewR.x );
|
||||
}
|
||||
}
|
||||
|
||||
// compute icon X location (relative to text X location)
|
||||
if( icon != null ) {
|
||||
iconR.x = leftToRight
|
||||
? textR.x - iconWidthAndGap
|
||||
: textR.x + textR.width + iconTextGap;
|
||||
}
|
||||
|
||||
return clippedText;
|
||||
}
|
||||
|
||||
private boolean hasLeadingMenus( JMenuBar menuBar ) {
|
||||
// check whether menu bar is empty
|
||||
if( menuBar.getComponentCount() == 0 || menuBar.getWidth() == 0 )
|
||||
return false;
|
||||
|
||||
// check whether menu bar has a leading glue component
|
||||
// (no menus/components at left side)
|
||||
Component horizontalGlue = findHorizontalGlue( menuBar );
|
||||
if( horizontalGlue != null ) {
|
||||
boolean leftToRight = getComponentOrientation().isLeftToRight();
|
||||
if( (leftToRight && horizontalGlue.getX() == 0) ||
|
||||
(!leftToRight && horizontalGlue.getX() + horizontalGlue.getWidth() == menuBar.getWidth()) )
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1018,6 +1174,9 @@ debug*/
|
||||
if( window == null )
|
||||
return; // should newer occur
|
||||
|
||||
if( !SwingUtilities.isLeftMouseButton( e ) )
|
||||
return;
|
||||
|
||||
dragOffset = SwingUtilities.convertPoint( FlatTitlePane.this, e.getPoint(), window );
|
||||
}
|
||||
|
||||
@@ -1032,6 +1191,9 @@ debug*/
|
||||
if( window == null )
|
||||
return; // should newer occur
|
||||
|
||||
if( !SwingUtilities.isLeftMouseButton( e ) )
|
||||
return;
|
||||
|
||||
if( hasNativeCustomDecoration() )
|
||||
return; // do nothing if having native window border
|
||||
|
||||
|
||||
@@ -21,12 +21,8 @@ import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import javax.swing.AbstractButton;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JToggleButton;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.*;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
|
||||
@@ -52,15 +48,29 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault ToggleButton.iconTextGap int
|
||||
* @uiDefault ToggleButton.startBackground Color optional; if set, a gradient paint is used and ToggleButton.background is ignored
|
||||
* @uiDefault ToggleButton.endBackground Color optional; if set, a gradient paint is used
|
||||
* @uiDefault ToggleButton.pressedBackground Color
|
||||
* @uiDefault ToggleButton.focusedBackground Color optional
|
||||
* @uiDefault ToggleButton.focusedForeground Color optional
|
||||
* @uiDefault ToggleButton.hoverBackground Color optional
|
||||
* @uiDefault ToggleButton.hoverForeground Color optional
|
||||
* @uiDefault ToggleButton.pressedBackground Color optional
|
||||
* @uiDefault ToggleButton.pressedForeground Color optional
|
||||
* @uiDefault ToggleButton.selectedBackground Color
|
||||
* @uiDefault ToggleButton.selectedForeground Color
|
||||
* @uiDefault ToggleButton.disabledBackground Color optional
|
||||
* @uiDefault ToggleButton.disabledText Color
|
||||
* @uiDefault ToggleButton.disabledSelectedBackground Color
|
||||
* @uiDefault ToggleButton.disabledSelectedForeground Color optional
|
||||
* @uiDefault Button.paintShadow boolean default is false
|
||||
* @uiDefault Button.shadowWidth int default is 2
|
||||
* @uiDefault Button.shadowColor Color optional
|
||||
* @uiDefault ToggleButton.toolbar.hoverBackground Color
|
||||
* @uiDefault ToggleButton.toolbar.hoverForeground Color optional
|
||||
* @uiDefault ToggleButton.toolbar.pressedBackground Color
|
||||
* @uiDefault ToggleButton.toolbar.pressedForeground Color optional
|
||||
* @uiDefault ToggleButton.toolbar.selectedBackground Color
|
||||
* @uiDefault ToggleButton.toolbar.selectedForeground Color optional
|
||||
* @uiDefault ToggleButton.toolbar.disabledSelectedBackground Color optional
|
||||
* @uiDefault ToggleButton.toolbar.disabledSelectedForeground Color optional
|
||||
*
|
||||
* <!-- FlatToggleButtonUI -->
|
||||
*
|
||||
@@ -68,8 +78,11 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault ToggleButton.tab.underlineColor Color
|
||||
* @uiDefault ToggleButton.tab.disabledUnderlineColor Color
|
||||
* @uiDefault ToggleButton.tab.selectedBackground Color optional
|
||||
* @uiDefault ToggleButton.tab.selectedForeground Color optional
|
||||
* @uiDefault ToggleButton.tab.hoverBackground Color
|
||||
* @uiDefault ToggleButton.tab.hoverForeground Color optional
|
||||
* @uiDefault ToggleButton.tab.focusBackground Color
|
||||
* @uiDefault ToggleButton.tab.focusForeground Color optional
|
||||
*
|
||||
*
|
||||
* @author Karl Tauber
|
||||
@@ -81,8 +94,11 @@ public class FlatToggleButtonUI
|
||||
@Styleable(dot=true) protected Color tabUnderlineColor;
|
||||
@Styleable(dot=true) protected Color tabDisabledUnderlineColor;
|
||||
@Styleable(dot=true) protected Color tabSelectedBackground;
|
||||
/** @since 2.3 */ @Styleable(dot=true) protected Color tabSelectedForeground;
|
||||
@Styleable(dot=true) protected Color tabHoverBackground;
|
||||
/** @since 2.3 */ @Styleable(dot=true) protected Color tabHoverForeground;
|
||||
@Styleable(dot=true) protected Color tabFocusBackground;
|
||||
/** @since 2.3 */ @Styleable(dot=true) protected Color tabFocusForeground;
|
||||
|
||||
private boolean defaults_initialized = false;
|
||||
|
||||
@@ -115,8 +131,11 @@ public class FlatToggleButtonUI
|
||||
tabUnderlineColor = UIManager.getColor( "ToggleButton.tab.underlineColor" );
|
||||
tabDisabledUnderlineColor = UIManager.getColor( "ToggleButton.tab.disabledUnderlineColor" );
|
||||
tabSelectedBackground = UIManager.getColor( "ToggleButton.tab.selectedBackground" );
|
||||
tabSelectedForeground = UIManager.getColor( "ToggleButton.tab.selectedForeground" );
|
||||
tabHoverBackground = UIManager.getColor( "ToggleButton.tab.hoverBackground" );
|
||||
tabHoverForeground = UIManager.getColor( "ToggleButton.tab.hoverForeground" );
|
||||
tabFocusBackground = UIManager.getColor( "ToggleButton.tab.focusBackground" );
|
||||
tabFocusForeground = UIManager.getColor( "ToggleButton.tab.focusForeground" );
|
||||
|
||||
defaults_initialized = true;
|
||||
}
|
||||
@@ -143,6 +162,7 @@ public class FlatToggleButtonUI
|
||||
b.repaint();
|
||||
break;
|
||||
|
||||
case TAB_BUTTON_UNDERLINE_PLACEMENT:
|
||||
case TAB_BUTTON_UNDERLINE_HEIGHT:
|
||||
case TAB_BUTTON_UNDERLINE_COLOR:
|
||||
case TAB_BUTTON_SELECTED_BACKGROUND:
|
||||
@@ -164,11 +184,7 @@ public class FlatToggleButtonUI
|
||||
@Override
|
||||
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
|
||||
Map<String, Class<?>> infos = super.getStyleableInfos( c );
|
||||
Iterator<String> it = infos.keySet().iterator();
|
||||
while( it.hasNext() ) {
|
||||
if( it.next().startsWith( "help." ) )
|
||||
it.remove();
|
||||
}
|
||||
infos.keySet().removeIf( s -> s.startsWith( "help." ) );
|
||||
return infos;
|
||||
}
|
||||
|
||||
@@ -201,13 +217,42 @@ public class FlatToggleButtonUI
|
||||
|
||||
// paint underline if selected
|
||||
if( selected ) {
|
||||
int underlineHeight = UIScale.scale( clientPropertyInt( c, TAB_BUTTON_UNDERLINE_HEIGHT, tabUnderlineHeight ) );
|
||||
int underlineThickness = UIScale.scale( clientPropertyInt( c, TAB_BUTTON_UNDERLINE_HEIGHT, tabUnderlineHeight ) );
|
||||
g.setColor( c.isEnabled()
|
||||
? clientPropertyColor( c, TAB_BUTTON_UNDERLINE_COLOR, tabUnderlineColor )
|
||||
: tabDisabledUnderlineColor );
|
||||
g.fillRect( 0, height - underlineHeight, width, underlineHeight );
|
||||
int placement = clientPropertyInt( c, TAB_BUTTON_UNDERLINE_PLACEMENT, SwingConstants.BOTTOM );
|
||||
switch (placement) {
|
||||
case SwingConstants.TOP:
|
||||
g.fillRect( 0, 0, width, underlineThickness );
|
||||
break;
|
||||
case SwingConstants.LEFT:
|
||||
g.fillRect( 0, 0, underlineThickness, height );
|
||||
break;
|
||||
case SwingConstants.RIGHT:
|
||||
g.fillRect( width - underlineThickness, 0, underlineThickness, height );
|
||||
break;
|
||||
case SwingConstants.BOTTOM:
|
||||
default:
|
||||
g.fillRect( 0, height - underlineThickness, width, underlineThickness );
|
||||
}
|
||||
}
|
||||
} else
|
||||
super.paintBackground( g, c );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Color getForeground( JComponent c ) {
|
||||
if( isTabButton( c ) ) {
|
||||
if( !c.isEnabled() )
|
||||
return disabledText;
|
||||
|
||||
if( tabSelectedForeground != null && ((AbstractButton)c).isSelected() )
|
||||
return tabSelectedForeground;
|
||||
|
||||
return buttonStateColor( c, c.getForeground(), disabledText,
|
||||
tabFocusForeground, tabHoverForeground, null );
|
||||
} else
|
||||
return super.getForeground( c );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Map;
|
||||
import javax.swing.JComponent;
|
||||
@@ -31,6 +32,7 @@ import javax.swing.SwingConstants;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicToolBarSeparatorUI;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
@@ -47,7 +49,7 @@ import com.formdev.flatlaf.util.LoggingFacade;
|
||||
*/
|
||||
public class FlatToolBarSeparatorUI
|
||||
extends BasicToolBarSeparatorUI
|
||||
implements StyleableUI
|
||||
implements StyleableUI, PropertyChangeListener
|
||||
{
|
||||
private static final int LINE_WIDTH = 1;
|
||||
|
||||
@@ -56,7 +58,6 @@ public class FlatToolBarSeparatorUI
|
||||
|
||||
private final boolean shared;
|
||||
private boolean defaults_initialized = false;
|
||||
private PropertyChangeListener propertyChangeListener;
|
||||
private Map<String, Object> oldStyleValues;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
@@ -105,28 +106,33 @@ public class FlatToolBarSeparatorUI
|
||||
protected void installListeners( JSeparator s ) {
|
||||
super.installListeners( s );
|
||||
|
||||
propertyChangeListener = FlatStylingSupport.createPropertyChangeListener(
|
||||
s, () -> stylePropertyChange( s ), null );
|
||||
s.addPropertyChangeListener( propertyChangeListener );
|
||||
s.addPropertyChangeListener( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void uninstallListeners( JSeparator s ) {
|
||||
super.uninstallListeners( s );
|
||||
|
||||
s.removePropertyChangeListener( propertyChangeListener );
|
||||
propertyChangeListener = null;
|
||||
s.removePropertyChangeListener( this );
|
||||
}
|
||||
|
||||
private void stylePropertyChange( JSeparator s ) {
|
||||
if( shared && FlatStylingSupport.hasStyleProperty( s ) ) {
|
||||
// unshare component UI if necessary
|
||||
// updateUI() invokes installStyle() from installUI()
|
||||
s.updateUI();
|
||||
} else
|
||||
installStyle( s );
|
||||
s.revalidate();
|
||||
s.repaint();
|
||||
/** @since 2.0.1 */
|
||||
@Override
|
||||
public void propertyChange( PropertyChangeEvent e ) {
|
||||
switch( e.getPropertyName() ) {
|
||||
case FlatClientProperties.STYLE:
|
||||
case FlatClientProperties.STYLE_CLASS:
|
||||
JSeparator s = (JSeparator) e.getSource();
|
||||
if( shared && FlatStylingSupport.hasStyleProperty( s ) ) {
|
||||
// unshare component UI if necessary
|
||||
// updateUI() invokes installStyle() from installUI()
|
||||
s.updateUI();
|
||||
} else
|
||||
installStyle( s );
|
||||
s.revalidate();
|
||||
s.repaint();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
|
||||
@@ -256,11 +256,15 @@ public class FlatToolBarUI
|
||||
default: return;
|
||||
}
|
||||
|
||||
for( int i = focusedCompIndex + add; i != focusedCompIndex; i += add ) {
|
||||
int i = focusedCompIndex;
|
||||
for(;;) {
|
||||
i += add;
|
||||
if( i < 0 )
|
||||
i = count - 1;
|
||||
else if( i >= count )
|
||||
i = 0;
|
||||
if( i == focusedCompIndex )
|
||||
break;
|
||||
|
||||
Component c = toolBar.getComponentAtIndex( i );
|
||||
if( canBeFocusOwner( c ) ) {
|
||||
@@ -282,7 +286,7 @@ public class FlatToolBarUI
|
||||
return comboBox.getUI().isFocusTraversable( comboBox );
|
||||
}
|
||||
|
||||
// check whether component has a empty input map to skip components that
|
||||
// check whether component has an empty input map to skip components that
|
||||
// are focusable, but do nothing when focused (e.g. JLabel)
|
||||
// see LayoutFocusTraversalPolicy.accept()
|
||||
if( c instanceof JComponent ) {
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.awt.FontMetrics;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.List;
|
||||
import javax.swing.JComponent;
|
||||
@@ -49,9 +50,8 @@ import com.formdev.flatlaf.util.StringUtils;
|
||||
*/
|
||||
public class FlatToolTipUI
|
||||
extends BasicToolTipUI
|
||||
implements PropertyChangeListener
|
||||
{
|
||||
private static PropertyChangeListener sharedPropertyChangedListener;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return FlatUIUtils.createSharedUI( FlatToolTipUI.class, FlatToolTipUI::new );
|
||||
}
|
||||
@@ -68,24 +68,24 @@ public class FlatToolTipUI
|
||||
protected void installListeners( JComponent c ) {
|
||||
super.installListeners( c );
|
||||
|
||||
if( sharedPropertyChangedListener == null ) {
|
||||
sharedPropertyChangedListener = e -> {
|
||||
String name = e.getPropertyName();
|
||||
if( name == "tiptext" || name == "font" || name == "foreground" ) {
|
||||
JToolTip toolTip = (JToolTip) e.getSource();
|
||||
FlatLabelUI.updateHTMLRenderer( toolTip, toolTip.getTipText(), false );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
c.addPropertyChangeListener( sharedPropertyChangedListener );
|
||||
c.addPropertyChangeListener( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void uninstallListeners( JComponent c ) {
|
||||
super.uninstallListeners( c );
|
||||
|
||||
c.removePropertyChangeListener( sharedPropertyChangedListener );
|
||||
c.removePropertyChangeListener( this );
|
||||
}
|
||||
|
||||
/** @since 2.0.1 */
|
||||
@Override
|
||||
public void propertyChange( PropertyChangeEvent e ) {
|
||||
String name = e.getPropertyName();
|
||||
if( name == "tiptext" || name == "font" || name == "foreground" ) {
|
||||
JToolTip toolTip = (JToolTip) e.getSource();
|
||||
FlatLabelUI.updateHTMLRenderer( toolTip, toolTip.getTipText(), false );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -71,7 +71,7 @@ public class FlatUIUtils
|
||||
public static final boolean MAC_USE_QUARTZ = Boolean.getBoolean( "apple.awt.graphics.UseQuartz" );
|
||||
|
||||
private static boolean useSharedUIs = true;
|
||||
private static WeakHashMap<LookAndFeel, IdentityHashMap<Object, ComponentUI>> sharedUIinstances = new WeakHashMap<>();
|
||||
private static final WeakHashMap<LookAndFeel, IdentityHashMap<Object, ComponentUI>> sharedUIinstances = new WeakHashMap<>();
|
||||
|
||||
public static Rectangle addInsets( Rectangle r, Insets insets ) {
|
||||
return new Rectangle(
|
||||
@@ -245,7 +245,7 @@ public class FlatUIUtils
|
||||
isInActiveWindow( c, keyboardFocusManager.getActiveWindow() );
|
||||
}
|
||||
|
||||
private static boolean isInActiveWindow( Component c, Window activeWindow ) {
|
||||
static boolean isInActiveWindow( Component c, Window activeWindow ) {
|
||||
Window window = SwingUtilities.windowForComponent( c );
|
||||
return window == activeWindow ||
|
||||
(window != null && window.getType() == Window.Type.POPUP && window.getOwner() == activeWindow);
|
||||
@@ -777,8 +777,8 @@ public class FlatUIUtils
|
||||
* {@link SwingConstants#WEST} or {@link SwingConstants#EAST})
|
||||
* @param chevron {@code true} for chevron arrow, {@code false} for triangle arrow
|
||||
* @param arrowSize the width of the painted arrow (for vertical direction) (will be scaled)
|
||||
* @param xOffset a offset added to the x coordinate of the arrow to paint it out-of-center. Usually zero. (will be scaled)
|
||||
* @param yOffset a offset added to the y coordinate of the arrow to paint it out-of-center. Usually zero. (will be scaled)
|
||||
* @param xOffset an offset added to the x coordinate of the arrow to paint it out-of-center. Usually zero. (will be scaled)
|
||||
* @param yOffset an offset added to the y coordinate of the arrow to paint it out-of-center. Usually zero. (will be scaled)
|
||||
*
|
||||
* @since 1.1
|
||||
*/
|
||||
@@ -786,13 +786,15 @@ public class FlatUIUtils
|
||||
int direction, boolean chevron, int arrowSize, float xOffset, float yOffset )
|
||||
{
|
||||
// compute arrow width/height
|
||||
int aw = UIScale.scale( arrowSize + (chevron ? 0 : 1) );
|
||||
int ah = UIScale.scale( (arrowSize / 2) + (chevron ? 0 : 1) );
|
||||
// - make chevron arrows one pixel smaller because coordinates are based on center of pixels (0.5/0.5)
|
||||
// - make triangle arrows one pixel taller (and round height up) to make them look stronger
|
||||
float aw = UIScale.scale( arrowSize + (chevron ? -1 : 0) );
|
||||
float ah = chevron ? (aw / 2) : UIScale.scale( (arrowSize / 2) + 1 );
|
||||
|
||||
// rotate arrow width/height for horizontal directions
|
||||
boolean vert = (direction == SwingConstants.NORTH || direction == SwingConstants.SOUTH);
|
||||
if( !vert ) {
|
||||
int temp = aw;
|
||||
float temp = aw;
|
||||
aw = ah;
|
||||
ah = temp;
|
||||
}
|
||||
@@ -804,19 +806,19 @@ public class FlatUIUtils
|
||||
// compute arrow location
|
||||
float ox = ((width - (aw + extra)) / 2f) + UIScale.scale( xOffset );
|
||||
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 ));
|
||||
float ax = x + ((direction == SwingConstants.WEST) ? -Math.round( -(ox + aw) ) - aw : Math.round( ox ));
|
||||
float ay = y + ((direction == SwingConstants.NORTH) ? -Math.round( -(oy + ah) ) - ah : Math.round( oy ));
|
||||
|
||||
// paint arrow
|
||||
g.translate( ax, ay );
|
||||
/*debug
|
||||
debugPaintArrow( g, Color.red, vert, aw + extra, ah + extra );
|
||||
debugPaintArrow( g, Color.red, vert, Math.round( aw + extra ), Math.round( ah + extra ) );
|
||||
debug*/
|
||||
Shape arrowShape = createArrowShape( direction, chevron, aw, ah );
|
||||
if( chevron ) {
|
||||
Stroke oldStroke = g.getStroke();
|
||||
g.setStroke( new BasicStroke( UIScale.scale( 1f ) ) );
|
||||
g.draw( arrowShape );
|
||||
drawShapePure( g, arrowShape );
|
||||
g.setStroke( oldStroke );
|
||||
} else {
|
||||
// triangle
|
||||
@@ -828,7 +830,7 @@ debug*/
|
||||
/**
|
||||
* Creates a chevron or triangle arrow shape for the given direction and size.
|
||||
* <p>
|
||||
* The chevron shape is a open path that can be painted with {@link Graphics2D#draw(Shape)}.
|
||||
* The chevron shape is an open path that can be painted with {@link Graphics2D#draw(Shape)}.
|
||||
* The triangle shape is a close path that can be painted with {@link Graphics2D#fill(Shape)}.
|
||||
*
|
||||
* @param direction the arrow direction ({@link SwingConstants#NORTH}, {@link SwingConstants#SOUTH}
|
||||
@@ -880,7 +882,7 @@ debug*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a open or closed path for the given points.
|
||||
* Creates an open or closed path for the given points.
|
||||
*/
|
||||
public static Path2D createPath( boolean close, double... points ) {
|
||||
Path2D path = new Path2D.Float();
|
||||
@@ -892,6 +894,23 @@ debug*/
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the given shape with disabled stroke normalization.
|
||||
* The x/y coordinates of the shape are translated by a half pixel.
|
||||
*
|
||||
* @since 2.1
|
||||
*/
|
||||
public static void drawShapePure( Graphics2D g, Shape shape ) {
|
||||
Object oldStrokeControl = g.getRenderingHint( RenderingHints.KEY_STROKE_CONTROL );
|
||||
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE );
|
||||
|
||||
g.translate( 0.5, 0.5 );
|
||||
g.draw( shape );
|
||||
g.translate( -0.5, -0.5 );
|
||||
|
||||
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, oldStrokeControl );
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the given string at the specified location.
|
||||
* The provided component is used to query text properties and anti-aliasing hints.
|
||||
|
||||
@@ -18,8 +18,8 @@ package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
import java.lang.reflect.Method;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.JViewport;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicViewportUI;
|
||||
@@ -43,15 +43,28 @@ public class FlatViewportUI
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update( Graphics g, JComponent c ) {
|
||||
Component view = ((JViewport)c).getView();
|
||||
if( c.isOpaque() && view instanceof JTable ) {
|
||||
// paint viewport background in same color as table background
|
||||
g.setColor( view.getBackground() );
|
||||
g.fillRect( 0, 0, c.getWidth(), c.getHeight() );
|
||||
public void paint( Graphics g, JComponent c ) {
|
||||
super.paint( g, c );
|
||||
|
||||
paint( g, c );
|
||||
} else
|
||||
super.update( g, c );
|
||||
Component view = ((JViewport)c).getView();
|
||||
if( view instanceof JComponent ) {
|
||||
try {
|
||||
Method m = view.getClass().getMethod( "getUI" );
|
||||
Object ui = m.invoke( view );
|
||||
if( ui instanceof ViewportPainter )
|
||||
((ViewportPainter)ui).paintViewport( g, (JComponent) view, (JViewport) c );
|
||||
} catch( Exception ex ) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---- interface ViewportPainter ------------------------------------------
|
||||
|
||||
/**
|
||||
* @since 2.3
|
||||
*/
|
||||
public interface ViewportPainter {
|
||||
void paintViewport( Graphics g, JComponent c, JViewport viewport );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.awt.Dialog;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Frame;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Toolkit;
|
||||
@@ -42,7 +43,9 @@ import javax.swing.JComponent;
|
||||
import javax.swing.JInternalFrame;
|
||||
import javax.swing.JLayeredPane;
|
||||
import javax.swing.JRootPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
@@ -231,8 +234,15 @@ public abstract class FlatWindowResizer
|
||||
{
|
||||
protected Window window;
|
||||
|
||||
private final boolean limitResizeToScreenBounds;
|
||||
|
||||
public WindowResizer( JRootPane rootPane ) {
|
||||
super( rootPane );
|
||||
|
||||
// On Linux, limit window resizing to screen bounds because otherwise
|
||||
// there would be a strange effect when the mouse is moved over a sidebar
|
||||
// while resizing and the opposite window side is also resized.
|
||||
limitResizeToScreenBounds = SystemInfo.isLinux;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -289,11 +299,19 @@ public abstract class FlatWindowResizer
|
||||
|
||||
@Override
|
||||
protected boolean limitToParentBounds() {
|
||||
return false;
|
||||
return limitResizeToScreenBounds && window != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Rectangle getParentBounds() {
|
||||
if( limitResizeToScreenBounds && window != null ) {
|
||||
GraphicsConfiguration gc = window.getGraphicsConfiguration();
|
||||
Rectangle bounds = gc.getBounds();
|
||||
Insets insets = window.getToolkit().getScreenInsets( gc );
|
||||
return new Rectangle( bounds.x + insets.left, bounds.y + insets.top,
|
||||
bounds.width - insets.left - insets.right,
|
||||
bounds.height - insets.top - insets.bottom );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -385,7 +403,7 @@ public abstract class FlatWindowResizer
|
||||
|
||||
@Override
|
||||
protected Rectangle getParentBounds() {
|
||||
return getFrame().getParent().getBounds();
|
||||
return new Rectangle( getFrame().getParent().getSize() );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -504,7 +522,7 @@ debug*/
|
||||
|
||||
@Override
|
||||
public void mousePressed( MouseEvent e ) {
|
||||
if( !isWindowResizable() )
|
||||
if( !SwingUtilities.isLeftMouseButton( e ) || !isWindowResizable() )
|
||||
return;
|
||||
|
||||
int xOnScreen = e.getXOnScreen();
|
||||
@@ -533,7 +551,7 @@ debug*/
|
||||
|
||||
@Override
|
||||
public void mouseReleased( MouseEvent e ) {
|
||||
if( !isWindowResizable() )
|
||||
if( !SwingUtilities.isLeftMouseButton( e ) || !isWindowResizable() )
|
||||
return;
|
||||
|
||||
dragLeftOffset = dragRightOffset = dragTopOffset = dragBottomOffset = 0;
|
||||
@@ -559,7 +577,7 @@ debug*/
|
||||
|
||||
@Override
|
||||
public void mouseDragged( MouseEvent e ) {
|
||||
if( !isWindowResizable() )
|
||||
if( !SwingUtilities.isLeftMouseButton( e ) || !isWindowResizable() )
|
||||
return;
|
||||
|
||||
int xOnScreen = e.getXOnScreen();
|
||||
@@ -579,8 +597,8 @@ debug*/
|
||||
// top
|
||||
if( resizeDir == N_RESIZE_CURSOR || resizeDir == NW_RESIZE_CURSOR || resizeDir == NE_RESIZE_CURSOR ) {
|
||||
newBounds.y = yOnScreen - dragTopOffset;
|
||||
if( limitToParentBounds() && newBounds.y < 0 )
|
||||
newBounds.y = 0;
|
||||
if( limitToParentBounds() )
|
||||
newBounds.y = Math.max( newBounds.y, getParentBounds().y );
|
||||
newBounds.height += (oldBounds.y - newBounds.y);
|
||||
}
|
||||
|
||||
@@ -597,8 +615,8 @@ debug*/
|
||||
// left
|
||||
if( resizeDir == W_RESIZE_CURSOR || resizeDir == NW_RESIZE_CURSOR || resizeDir == SW_RESIZE_CURSOR ) {
|
||||
newBounds.x = xOnScreen - dragLeftOffset;
|
||||
if( limitToParentBounds() && newBounds.x < 0 )
|
||||
newBounds.x = 0;
|
||||
if( limitToParentBounds() )
|
||||
newBounds.x = Math.max( newBounds.x, getParentBounds().x );
|
||||
newBounds.width += (oldBounds.x - newBounds.x);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ import java.awt.Window;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
@@ -38,9 +37,7 @@ import javax.swing.Timer;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import javax.swing.event.EventListenerList;
|
||||
import com.formdev.flatlaf.FlatSystemProperties;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.NativeLibrary;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
|
||||
//
|
||||
@@ -84,7 +81,6 @@ class FlatWindowsNativeWindowBorder
|
||||
private Color colorizationColor;
|
||||
private int colorizationColorBalance;
|
||||
|
||||
private static NativeLibrary nativeLibrary;
|
||||
private static FlatWindowsNativeWindowBorder instance;
|
||||
|
||||
static FlatNativeWindowBorder.Provider getInstance() {
|
||||
@@ -96,31 +92,8 @@ class FlatWindowsNativeWindowBorder
|
||||
if( !SystemInfo.isX86 && !SystemInfo.isX86_64 )
|
||||
return null;
|
||||
|
||||
// load native library
|
||||
if( nativeLibrary == null ) {
|
||||
if( !SystemInfo.isJava_9_orLater ) {
|
||||
// In Java 8, load jawt.dll (part of JRE) explicitly because it
|
||||
// is not found when running application with <jdk>/bin/java.exe.
|
||||
// When using <jdk>/jre/bin/java.exe, it is found.
|
||||
// jawt.dll is located in <jdk>/jre/bin/.
|
||||
// Java 9 and later does not have this problem.
|
||||
try {
|
||||
System.loadLibrary( "jawt" );
|
||||
} catch( UnsatisfiedLinkError ex ) {
|
||||
// log error only if native library jawt.dll not already loaded
|
||||
String message = ex.getMessage();
|
||||
if( message == null || !message.contains( "already loaded in another classloader" ) )
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
} catch( Exception ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
}
|
||||
|
||||
nativeLibrary = createNativeLibrary();
|
||||
}
|
||||
|
||||
// check whether native library was successfully loaded
|
||||
if( !nativeLibrary.isLoaded() )
|
||||
if( !FlatNativeLibrary.isLoaded() )
|
||||
return null;
|
||||
|
||||
// create new instance
|
||||
@@ -129,23 +102,6 @@ class FlatWindowsNativeWindowBorder
|
||||
return instance;
|
||||
}
|
||||
|
||||
private static NativeLibrary createNativeLibrary() {
|
||||
String libraryName = "flatlaf-windows-x86";
|
||||
if( SystemInfo.isX86_64 )
|
||||
libraryName += "_64";
|
||||
|
||||
String libraryPath = System.getProperty( FlatSystemProperties.NATIVE_LIBRARY_PATH );
|
||||
if( libraryPath != null ) {
|
||||
File libraryFile = new File( libraryPath, libraryName + ".dll" );
|
||||
if( libraryFile.exists() )
|
||||
return new NativeLibrary( libraryFile, true );
|
||||
else
|
||||
LoggingFacade.INSTANCE.logSevere( "Did not find external library " + libraryFile + ", using extracted library instead", null );
|
||||
}
|
||||
|
||||
return new NativeLibrary( "com/formdev/flatlaf/natives/" + libraryName, null, true );
|
||||
}
|
||||
|
||||
private FlatWindowsNativeWindowBorder() {
|
||||
}
|
||||
|
||||
@@ -155,7 +111,7 @@ class FlatWindowsNativeWindowBorder
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell the window whether the application wants use custom decorations.
|
||||
* Tell the window whether the application wants to use custom decorations.
|
||||
* If {@code true}, the Windows 10 title bar is hidden (including minimize,
|
||||
* maximize and close buttons), but not the resize borders (including drop shadow).
|
||||
*/
|
||||
|
||||
@@ -195,11 +195,13 @@ public class JBRCustomDecorations
|
||||
{
|
||||
private static JBRWindowTopBorder instance;
|
||||
|
||||
private final Color defaultActiveBorder = new Color( 0x707070 );
|
||||
private final Color activeLightColor = new Color( 0x707070 );
|
||||
private final Color activeDarkColor = new Color( 0x2D2E2F );
|
||||
private final Color inactiveLightColor = new Color( 0xaaaaaa );
|
||||
private final Color inactiveDarkColor = new Color( 0x494A4B );
|
||||
|
||||
private boolean colorizationAffectsBorders;
|
||||
private Color activeColor = defaultActiveBorder;
|
||||
private Color activeColor;
|
||||
|
||||
static JBRWindowTopBorder getInstance() {
|
||||
if( instance == null )
|
||||
@@ -250,7 +252,7 @@ public class JBRCustomDecorations
|
||||
|
||||
private Color calculateActiveBorderColor() {
|
||||
if( !colorizationAffectsBorders )
|
||||
return defaultActiveBorder;
|
||||
return null;
|
||||
|
||||
Color colorizationColor = getColorizationColor();
|
||||
if( colorizationColor != null ) {
|
||||
@@ -284,16 +286,12 @@ public class JBRCustomDecorations
|
||||
@Override
|
||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||
Window window = SwingUtilities.windowForComponent( c );
|
||||
boolean active = (window != null) ? window.isActive() : false;
|
||||
boolean active = window != null && window.isActive();
|
||||
boolean dark = FlatLaf.isLafDark();
|
||||
|
||||
// paint top border
|
||||
// - in light themes
|
||||
// - in dark themes only for active windows if colorization affects borders
|
||||
boolean paintTopBorder = !FlatLaf.isLafDark() || (active && colorizationAffectsBorders);
|
||||
if( !paintTopBorder )
|
||||
return;
|
||||
|
||||
g.setColor( active ? activeColor : inactiveLightColor );
|
||||
g.setColor( active
|
||||
? (activeColor != null ? activeColor : (dark ? activeDarkColor : activeLightColor))
|
||||
: (dark ? inactiveDarkColor : inactiveLightColor) );
|
||||
HiDPIUtils.paintAtScale1x( (Graphics2D) g, x, y, width, height, this::paintImpl );
|
||||
}
|
||||
|
||||
|
||||
@@ -143,8 +143,8 @@ public class MigLayoutVisualPadding
|
||||
//---- class FlatMigInsets ------------------------------------------------
|
||||
|
||||
/**
|
||||
* Marker class to identify our visual paddings and leaf paddings,
|
||||
* which were set from outside, untouched.
|
||||
* Marker class to identify our visual paddings and leave paddings
|
||||
* set from outside untouched.
|
||||
*/
|
||||
private static class FlatMigInsets
|
||||
extends Insets
|
||||
|
||||
@@ -59,7 +59,7 @@ import com.formdev.flatlaf.util.Animator.Interpolator;
|
||||
* </pre>
|
||||
*
|
||||
* Animation works only if the component passed to {@link #paintIcon(Component, Graphics, int, int)}
|
||||
* is a instance of {@link JComponent}.
|
||||
* is an instance of {@link JComponent}.
|
||||
* A client property is set on the component to store the animation state.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
@@ -68,7 +68,7 @@ public interface AnimatedIcon
|
||||
extends Icon
|
||||
{
|
||||
@Override
|
||||
public default void paintIcon( Component c, Graphics g, int x, int y ) {
|
||||
default void paintIcon( Component c, Graphics g, int x, int y ) {
|
||||
AnimationSupport.paintIcon( this, c, g, x, y );
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ public class DerivedColor
|
||||
Color result = ColorFunctions.applyFunctions( baseColor, functions );
|
||||
|
||||
// if the result is equal to the default color, then the original base color
|
||||
// was passed and we can cache this to avoid color calculations
|
||||
// was passed, and we can cache this to avoid color calculations
|
||||
if( !hasBaseOfDefaultColor && result.getRGB() == this.getRGB() ) {
|
||||
hasBaseOfDefaultColor = true;
|
||||
baseOfDefaultColorRGB = baseColor.getRGB();
|
||||
|
||||
@@ -76,7 +76,7 @@ public class HSLColor
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a HSLColor object using an an array containing the
|
||||
* Create a HSLColor object using an array containing the
|
||||
* individual HSL values and with a default alpha value of 1.
|
||||
*
|
||||
* @param hsl array containing HSL values
|
||||
@@ -87,7 +87,7 @@ public class HSLColor
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a HSLColor object using an an array containing the
|
||||
* Create a HSLColor object using an array containing the
|
||||
* individual HSL values.
|
||||
*
|
||||
* @param hsl array containing HSL values
|
||||
@@ -291,7 +291,7 @@ public class HSLColor
|
||||
|
||||
// Calculate the Saturation
|
||||
|
||||
float s = 0;
|
||||
float s;
|
||||
|
||||
if (max == min)
|
||||
s = 0;
|
||||
@@ -386,7 +386,7 @@ public class HSLColor
|
||||
s /= 100f;
|
||||
l /= 100f;
|
||||
|
||||
float q = 0;
|
||||
float q;
|
||||
|
||||
if (l < 0.5)
|
||||
q = l * (1 + s);
|
||||
|
||||
@@ -31,7 +31,7 @@ import com.formdev.flatlaf.FlatSystemProperties;
|
||||
public class HiDPIUtils
|
||||
{
|
||||
public interface Painter {
|
||||
public void paint( Graphics2D g, int x, int y, int width, int height, double scaleFactor );
|
||||
void paint( Graphics2D g, int x, int y, int width, int height, double scaleFactor );
|
||||
}
|
||||
|
||||
public static void paintAtScale1x( Graphics2D g, JComponent c, Painter painter ) {
|
||||
@@ -48,30 +48,55 @@ public class HiDPIUtils
|
||||
*/
|
||||
public static void paintAtScale1x( Graphics2D g, int x, int y, int width, int height, Painter painter ) {
|
||||
// save original transform
|
||||
AffineTransform transform = g.getTransform();
|
||||
AffineTransform t = g.getTransform();
|
||||
|
||||
// get scale X/Y and shear X/Y
|
||||
double scaleX = t.getScaleX();
|
||||
double scaleY = t.getScaleY();
|
||||
double shearX = t.getShearX();
|
||||
double shearY = t.getShearY();
|
||||
|
||||
// check whether rotated
|
||||
// (also check for negative scale X/Y because shear X/Y are zero for 180 degrees rotation)
|
||||
boolean rotated = (shearX != 0 || shearY != 0 || scaleX <= 0 || scaleY <= 0);
|
||||
if( rotated ) {
|
||||
// resulting scale X/Y values are always positive
|
||||
scaleX = Math.hypot( scaleX, shearX );
|
||||
scaleY = Math.hypot( scaleY, shearY );
|
||||
} else {
|
||||
// make scale X/Y positive
|
||||
scaleX = Math.abs( scaleX );
|
||||
scaleY = Math.abs( scaleY );
|
||||
}
|
||||
|
||||
// check whether scaled
|
||||
if( transform.getScaleX() == 1 && transform.getScaleY() == 1 ) {
|
||||
if( scaleX == 1 && scaleY == 1 ) {
|
||||
painter.paint( g, x, y, width, height, 1 );
|
||||
return;
|
||||
}
|
||||
|
||||
// scale rectangle
|
||||
Rectangle2D.Double scaledRect = scale( transform, x, y, width, height );
|
||||
Rectangle2D.Double scaledRect = scale( scaleX, scaleY, t, x, y, width, height );
|
||||
|
||||
try {
|
||||
// unscale to factor 1.0 and move origin (to whole numbers)
|
||||
g.setTransform( new AffineTransform( 1, 0, 0, 1,
|
||||
Math.floor( scaledRect.x ), Math.floor( scaledRect.y ) ) );
|
||||
// unscale to factor 1.0, keep rotation and move origin (to whole numbers)
|
||||
AffineTransform t1x;
|
||||
if( rotated ) {
|
||||
t1x = new AffineTransform( t.getScaleX(), t.getShearY(), t.getShearX(), t.getScaleY(),
|
||||
Math.floor( scaledRect.x ), Math.floor( scaledRect.y ) );
|
||||
t1x.scale( 1. / scaleX, 1. / scaleY );
|
||||
} else
|
||||
t1x = new AffineTransform( 1, 0, 0, 1, Math.floor( scaledRect.x ), Math.floor( scaledRect.y ) );
|
||||
g.setTransform( t1x );
|
||||
|
||||
int swidth = (int) scaledRect.width;
|
||||
int sheight = (int) scaledRect.height;
|
||||
|
||||
// paint
|
||||
painter.paint( g, 0, 0, swidth, sheight, transform.getScaleX() );
|
||||
painter.paint( g, 0, 0, swidth, sheight, scaleX );
|
||||
} finally {
|
||||
// restore original transform
|
||||
g.setTransform( transform );
|
||||
g.setTransform( t );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,20 +105,16 @@ public class HiDPIUtils
|
||||
* sun.java2d.pipe.PixelToParallelogramConverter.fillRectangle(),
|
||||
* which is used by Graphics.fillRect().
|
||||
*/
|
||||
private static Rectangle2D.Double scale( AffineTransform transform, int x, int y, int width, int height ) {
|
||||
double dx1 = transform.getScaleX();
|
||||
double dy2 = transform.getScaleY();
|
||||
double px = x * dx1 + transform.getTranslateX();
|
||||
double py = y * dy2 + transform.getTranslateY();
|
||||
dx1 *= width;
|
||||
dy2 *= height;
|
||||
private static Rectangle2D.Double scale( double scaleX, double scaleY, AffineTransform t, int x, int y, int width, int height ) {
|
||||
double px = (x * scaleX) + t.getTranslateX();
|
||||
double py = (y * scaleY) + t.getTranslateY();
|
||||
|
||||
double newx = normalize( px );
|
||||
double newy = normalize( py );
|
||||
dx1 = normalize( px + dx1 ) - newx;
|
||||
dy2 = normalize( py + dy2 ) - newy;
|
||||
double newX = normalize( px );
|
||||
double newY = normalize( py );
|
||||
double newWidth = normalize( px + (width * scaleX) ) - newX;
|
||||
double newHeight = normalize( py + (height * scaleY) ) - newY;
|
||||
|
||||
return new Rectangle2D.Double( newx, newy, dx1, dy2 );
|
||||
return new Rectangle2D.Double( newX, newY, newWidth, newHeight );
|
||||
}
|
||||
|
||||
private static double normalize( double value ) {
|
||||
@@ -114,7 +135,7 @@ public class HiDPIUtils
|
||||
* painted too far down on some operating systems.
|
||||
* The higher the system scale factor is, the more.
|
||||
* <p>
|
||||
* This methods computes a correction value for the Y position.
|
||||
* This method computes a correction value for the Y position.
|
||||
*/
|
||||
public static float computeTextYCorrection( Graphics2D g ) {
|
||||
if( !useTextYCorrection() || !SystemInfo.isWindows )
|
||||
|
||||
@@ -89,7 +89,7 @@ public class JavaCompatibility
|
||||
getClippedStringMethod = cls.getMethod( SystemInfo.isJava_9_orLater
|
||||
? "getClippedString"
|
||||
: "clipStringIfNecessary",
|
||||
new Class[] { JComponent.class, FontMetrics.class, String.class, int.class } );
|
||||
JComponent.class, FontMetrics.class, String.class, int.class );
|
||||
} catch( Exception ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
throw new RuntimeException( ex );
|
||||
|
||||
@@ -72,7 +72,7 @@ public class MultiResolutionImageSupport
|
||||
* <p>
|
||||
* The given dimensions array is only used for {@link #getResolutionVariants(Image)}.
|
||||
* The producer function may be invoked with any dimension (that is not contained in
|
||||
* dimensions array) and is expected to produce a image for the passed in dimension.
|
||||
* dimensions array) and is expected to produce an image for the passed in dimension.
|
||||
*
|
||||
* @param baseImageIndex index of the base image in the dimensions array
|
||||
* @param dimensions dimensions of resolution variants (sorted by size; smallest first)
|
||||
@@ -92,7 +92,7 @@ public class MultiResolutionImageSupport
|
||||
* for "disabled" state.
|
||||
*
|
||||
* @param image a multi-resolution image that is mapped using the given mapper function
|
||||
* @param mapper mapper function that maps a single resolution variant to a new image (e.g. applying an filter)
|
||||
* @param mapper mapper function that maps a single resolution variant to a new image (e.g. applying a filter)
|
||||
* @return a multi-resolution image on Java 9 or later; a mapped image on Java 8
|
||||
*/
|
||||
public static Image map( Image image, Function<Image, Image> mapper ) {
|
||||
@@ -104,7 +104,7 @@ public class MultiResolutionImageSupport
|
||||
* <p>
|
||||
* If the given image is a multi-resolution image then invokes
|
||||
* {@code java.awt.image.MultiResolutionImage.getResolutionVariant(destImageWidth, destImageHeight)}.
|
||||
* Otherwise returns the given image.
|
||||
* Otherwise, returns the given image.
|
||||
*/
|
||||
public static Image getResolutionVariant( Image image, int destImageWidth, int destImageHeight ) {
|
||||
return image;
|
||||
@@ -115,7 +115,7 @@ public class MultiResolutionImageSupport
|
||||
* <p>
|
||||
* If the given image is a multi-resolution image then invokes
|
||||
* {@code java.awt.image.MultiResolutionImage.getResolutionVariants()}.
|
||||
* Otherwise returns a list containing only the given image.
|
||||
* Otherwise, returns a list containing only the given image.
|
||||
*/
|
||||
public static List<Image> getResolutionVariants( Image image ) {
|
||||
return Collections.singletonList( image );
|
||||
|
||||
@@ -143,16 +143,19 @@ public class NativeLibrary
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add prefix and suffix to library name.
|
||||
* <ul>
|
||||
* <li>Windows: libraryName + ".dll"
|
||||
* <li>macOS: "lib" + libraryName + ".dylib"
|
||||
* <li>Linux: "lib" + libraryName + ".so"
|
||||
* </ul>
|
||||
*/
|
||||
private static String decorateLibraryName( String libraryName ) {
|
||||
if( SystemInfo.isWindows )
|
||||
return libraryName.concat( ".dll" );
|
||||
|
||||
String suffix = SystemInfo.isMacOS ? ".dylib" : ".so";
|
||||
|
||||
int sep = libraryName.lastIndexOf( '/' );
|
||||
return (sep >= 0)
|
||||
? libraryName.substring( 0, sep + 1 ) + "lib" + libraryName.substring( sep + 1 ) + suffix
|
||||
: "lib" + libraryName + suffix;
|
||||
? libraryName.substring( 0, sep + 1 ) + System.mapLibraryName( libraryName.substring( sep + 1 ) )
|
||||
: System.mapLibraryName( libraryName );
|
||||
}
|
||||
|
||||
private static void log( String msg, Throwable thrown ) {
|
||||
@@ -195,7 +198,7 @@ public class NativeLibrary
|
||||
// for loaded native libraries, they will be deleted on next application startup.
|
||||
// The default temporary directory may contain hundreds or thousands of files.
|
||||
// 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 subdirectory that contains only our temporary native libraries.
|
||||
tmpdir += "\\flatlaf.temp";
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ public class SystemInfo
|
||||
public static final long javaVersion;
|
||||
public static final boolean isJava_9_orLater;
|
||||
public static final boolean isJava_11_orLater;
|
||||
/** @since 2.3 */ public static final boolean isJava_12_orLater;
|
||||
public static final boolean isJava_15_orLater;
|
||||
/** @since 2 */ public static final boolean isJava_17_orLater;
|
||||
/** @since 2 */ public static final boolean isJava_18_orLater;
|
||||
@@ -66,6 +67,9 @@ public class SystemInfo
|
||||
/** @since 1.1.2 */ public static final boolean isWebswing;
|
||||
/** @since 1.1.1 */ public static final boolean isWinPE;
|
||||
|
||||
// features
|
||||
/** @since 2.3 */ public static final boolean isMacFullWindowContentSupported;
|
||||
|
||||
static {
|
||||
// platforms
|
||||
String osName = System.getProperty( "os.name" ).toLowerCase( Locale.ENGLISH );
|
||||
@@ -92,6 +96,7 @@ public class SystemInfo
|
||||
javaVersion = scanVersion( System.getProperty( "java.version" ) );
|
||||
isJava_9_orLater = (javaVersion >= toVersion( 9, 0, 0, 0 ));
|
||||
isJava_11_orLater = (javaVersion >= toVersion( 11, 0, 0, 0 ));
|
||||
isJava_12_orLater = (javaVersion >= toVersion( 12, 0, 0, 0 ));
|
||||
isJava_15_orLater = (javaVersion >= toVersion( 15, 0, 0, 0 ));
|
||||
isJava_17_orLater = (javaVersion >= toVersion( 17, 0, 0, 0 ));
|
||||
isJava_18_orLater = (javaVersion >= toVersion( 18, 0, 0, 0 ));
|
||||
@@ -108,6 +113,12 @@ public class SystemInfo
|
||||
isProjector = Boolean.getBoolean( "org.jetbrains.projector.server.enable" );
|
||||
isWebswing = (System.getProperty( "webswing.rootDir" ) != null);
|
||||
isWinPE = isWindows && "X:\\Windows\\System32".equalsIgnoreCase( System.getProperty( "user.dir" ) );
|
||||
|
||||
// features
|
||||
// available since Java 12; backported to Java 11.0.8 and 8u292
|
||||
isMacFullWindowContentSupported =
|
||||
javaVersion >= toVersion( 11, 0, 8, 0 ) ||
|
||||
(javaVersion >= toVersion( 1, 8, 0, 292 ) && !isJava_9_orLater);
|
||||
}
|
||||
|
||||
public static long scanVersion( String version ) {
|
||||
|
||||
@@ -103,7 +103,7 @@ public class UIScale
|
||||
// Java 9 and later supports per-monitor scaling
|
||||
jreHiDPI = true;
|
||||
} else if( SystemInfo.isJetBrainsJVM ) {
|
||||
// IntelliJ IDEA ships its own JetBrains Java 8 JRE that may supports per-monitor scaling
|
||||
// IntelliJ IDEA ships its own JetBrains Java 8 JRE that may support per-monitor scaling
|
||||
// see com.intellij.ui.JreHiDpiUtil.isJreHiDPIEnabled()
|
||||
try {
|
||||
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
|
||||
@@ -411,7 +411,7 @@ public class UIScale
|
||||
* Scales the given dimension with the user scale factor.
|
||||
* <p>
|
||||
* If user scale factor is 1, then the given dimension is simply returned.
|
||||
* Otherwise a new instance of {@link Dimension} or {@link DimensionUIResource}
|
||||
* Otherwise, a new instance of {@link Dimension} or {@link DimensionUIResource}
|
||||
* is returned, depending on whether the passed dimension implements {@link UIResource}.
|
||||
*/
|
||||
public static Dimension scale( Dimension dimension ) {
|
||||
@@ -427,7 +427,7 @@ public class UIScale
|
||||
* Scales the given insets with the user scale factor.
|
||||
* <p>
|
||||
* If user scale factor is 1, then the given insets is simply returned.
|
||||
* Otherwise a new instance of {@link Insets} or {@link InsetsUIResource}
|
||||
* Otherwise, a new instance of {@link Insets} or {@link InsetsUIResource}
|
||||
* is returned, depending on whether the passed dimension implements {@link UIResource}.
|
||||
*/
|
||||
public static Insets scale( Insets insets ) {
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#
|
||||
# NOTE: Avoid copying the whole content of this file to own properties files.
|
||||
# This will make upgrading to newer FlatLaf versions complex and error-prone.
|
||||
# Instead copy and modify only those properties that you need to alter.
|
||||
# Instead, copy and modify only those properties that you need to alter.
|
||||
#
|
||||
|
||||
# Colors and style mostly based on Darcula theme from IntelliJ IDEA Community Edition,
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#
|
||||
# NOTE: Avoid copying the whole content of this file to own properties files.
|
||||
# This will make upgrading to newer FlatLaf versions complex and error-prone.
|
||||
# Instead copy and modify only those properties that you need to alter.
|
||||
# Instead, copy and modify only those properties that you need to alter.
|
||||
#
|
||||
|
||||
# Colors and style mostly based on Darcula theme from IntelliJ IDEA Community Edition,
|
||||
@@ -240,6 +240,7 @@ MenuBar.borderColor = $Separator.foreground
|
||||
#---- PasswordField ----
|
||||
|
||||
PasswordField.capsLockIconColor = #ffffff64
|
||||
PasswordField.revealIconColor = @foreground
|
||||
|
||||
|
||||
#---- Popup ----
|
||||
@@ -251,6 +252,7 @@ Popup.dropShadowOpacity = 0.25
|
||||
#---- PopupMenu ----
|
||||
|
||||
PopupMenu.borderColor = tint(@background,17%)
|
||||
PopupMenu.hoverScrollArrowBackground = lighten(@background,5%)
|
||||
|
||||
|
||||
#---- ProgressBar ----
|
||||
@@ -304,6 +306,7 @@ SplitPaneDivider.draggingColor = $Component.borderColor
|
||||
#---- TabbedPane ----
|
||||
|
||||
TabbedPane.underlineColor = @accentUnderlineColor
|
||||
TabbedPane.inactiveUnderlineColor = mix(@accentUnderlineColor,$TabbedPane.background,60%)
|
||||
TabbedPane.disabledUnderlineColor = lighten(@background,23%)
|
||||
TabbedPane.hoverColor = darken($TabbedPane.background,5%,derived noAutoInverse)
|
||||
TabbedPane.focusColor = mix(@selectionBackground,$TabbedPane.background,25%)
|
||||
@@ -322,7 +325,7 @@ TabbedPane.closePressedForeground = $TabbedPane.closeHoverForeground
|
||||
|
||||
#---- Table ----
|
||||
|
||||
Table.gridColor = lighten($Table.background,5%)
|
||||
Table.gridColor = lighten($Table.background,8%)
|
||||
|
||||
|
||||
#---- TableHeader ----
|
||||
@@ -367,6 +370,6 @@ Tree.hash = lighten($Tree.background,5%)
|
||||
focusable: false; \
|
||||
toolbar.margin: 1,1,1,1; \
|
||||
toolbar.spacingInsets: 1,1,1,1; \
|
||||
toolbar.hoverBackground: fade(Actions.GreyInline,30%,lazy); \
|
||||
toolbar.pressedBackground: fade(Actions.GreyInline,40%,lazy); \
|
||||
toolbar.selectedBackground: fade(Actions.GreyInline,50%,lazy)
|
||||
toolbar.hoverBackground: lighten($TextField.background,5%); \
|
||||
toolbar.pressedBackground: lighten($TextField.background,10%); \
|
||||
toolbar.selectedBackground: lighten($TextField.background,15%)
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#
|
||||
# NOTE: Avoid copying the whole content of this file to own properties files.
|
||||
# This will make upgrading to newer FlatLaf versions complex and error-prone.
|
||||
# Instead copy and modify only those properties that you need to alter.
|
||||
# Instead, copy and modify only those properties that you need to alter.
|
||||
#
|
||||
|
||||
# Colors and style mostly based on IntelliJ theme from IntelliJ IDEA Community Edition,
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#
|
||||
# NOTE: Avoid copying the whole content of this file to own properties files.
|
||||
# This will make upgrading to newer FlatLaf versions complex and error-prone.
|
||||
# Instead copy and modify only those properties that you need to alter.
|
||||
# Instead, copy and modify only those properties that you need to alter.
|
||||
#
|
||||
|
||||
#---- typography / fonts ----
|
||||
@@ -64,7 +64,7 @@ light.font = +0
|
||||
semibold.font = +0
|
||||
|
||||
# monospaced
|
||||
[win]monospaced.font = Consolas, "Courier New", Monospaced
|
||||
[win]monospaced.font = Monospaced
|
||||
[mac]monospaced.font = Menlo, Monospaced
|
||||
[linux]monospaced.font = "Liberation Mono", "Ubuntu Mono", Monospaced
|
||||
monospaced.font = Monospaced
|
||||
@@ -332,6 +332,7 @@ FileView.fileIcon = com.formdev.flatlaf.icons.FlatFileViewFileIcon
|
||||
FileView.computerIcon = com.formdev.flatlaf.icons.FlatFileViewComputerIcon
|
||||
FileView.hardDriveIcon = com.formdev.flatlaf.icons.FlatFileViewHardDriveIcon
|
||||
FileView.floppyDriveIcon = com.formdev.flatlaf.icons.FlatFileViewFloppyDriveIcon
|
||||
FileView.fullRowSelection = true
|
||||
|
||||
|
||||
#---- FormattedTextField ----
|
||||
@@ -487,7 +488,6 @@ PasswordField.showCapsLock = true
|
||||
PasswordField.showRevealButton = false
|
||||
PasswordField.capsLockIcon = com.formdev.flatlaf.icons.FlatCapsLockIcon
|
||||
PasswordField.revealIcon = com.formdev.flatlaf.icons.FlatRevealIcon
|
||||
PasswordField.revealIconColor = lazy(Actions.Grey)
|
||||
|
||||
|
||||
#---- Popup ----
|
||||
@@ -501,6 +501,7 @@ Popup.dropShadowInsets = -4,-4,4,4
|
||||
PopupMenu.border = com.formdev.flatlaf.ui.FlatPopupMenuBorder
|
||||
PopupMenu.borderInsets = 4,1,4,1
|
||||
PopupMenu.background = @menuBackground
|
||||
PopupMenu.scrollArrowColor = @buttonArrowColor
|
||||
|
||||
|
||||
#---- PopupMenuSeparator ----
|
||||
@@ -555,6 +556,7 @@ RootPane.honorDialogMinimumSizeOnResize = true
|
||||
#---- ScrollBar ----
|
||||
|
||||
ScrollBar.width = 10
|
||||
ScrollBar.minimumButtonSize = 12,12
|
||||
ScrollBar.minimumThumbSize = 10,10
|
||||
ScrollBar.maximumThumbSize = 100000,100000
|
||||
ScrollBar.trackInsets = 0,0,0,0
|
||||
@@ -787,11 +789,16 @@ TitlePane.noIconLeftGap = 8
|
||||
TitlePane.iconSize = 16,16
|
||||
TitlePane.iconMargins = 3,8,3,8
|
||||
TitlePane.titleMargins = 3,0,3,0
|
||||
TitlePane.titleMinimumWidth = 60
|
||||
TitlePane.buttonSize = 44,30
|
||||
TitlePane.buttonMinimumWidth = 30
|
||||
TitlePane.buttonMaximizedHeight = 22
|
||||
TitlePane.centerTitle = false
|
||||
TitlePane.centerTitleIfMenuBarEmbedded = true
|
||||
TitlePane.menuBarTitleGap = 20
|
||||
TitlePane.showIconBesideTitle = false
|
||||
TitlePane.menuBarTitleGap = 40
|
||||
TitlePane.menuBarTitleMinimumGap = 12
|
||||
TitlePane.menuBarResizeHeight = 4
|
||||
TitlePane.closeIcon = com.formdev.flatlaf.icons.FlatWindowCloseIcon
|
||||
TitlePane.iconifyIcon = com.formdev.flatlaf.icons.FlatWindowIconifyIcon
|
||||
TitlePane.maximizeIcon = com.formdev.flatlaf.icons.FlatWindowMaximizeIcon
|
||||
@@ -827,6 +834,7 @@ ToggleButton.tab.underlineHeight = 2
|
||||
ToggleButton.tab.underlineColor = $TabbedPane.underlineColor
|
||||
ToggleButton.tab.disabledUnderlineColor = $TabbedPane.disabledUnderlineColor
|
||||
ToggleButton.tab.selectedBackground = $?TabbedPane.selectedBackground
|
||||
ToggleButton.tab.selectedForeground = $?TabbedPane.selectedForeground
|
||||
ToggleButton.tab.hoverBackground = $TabbedPane.hoverColor
|
||||
ToggleButton.tab.focusBackground = $TabbedPane.focusColor
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#
|
||||
# NOTE: Avoid copying the whole content of this file to own properties files.
|
||||
# This will make upgrading to newer FlatLaf versions complex and error-prone.
|
||||
# Instead copy and modify only those properties that you need to alter.
|
||||
# Instead, copy and modify only those properties that you need to alter.
|
||||
#
|
||||
|
||||
# Colors and style mostly based on IntelliJ theme from IntelliJ IDEA Community Edition,
|
||||
@@ -247,6 +247,7 @@ MenuBar.borderColor = $Separator.foreground
|
||||
#---- PasswordField ----
|
||||
|
||||
PasswordField.capsLockIconColor = #00000064
|
||||
PasswordField.revealIconColor = tint(@foreground,40%)
|
||||
|
||||
|
||||
#---- Popup ----
|
||||
@@ -258,6 +259,7 @@ Popup.dropShadowOpacity = 0.15
|
||||
#---- PopupMenu ----
|
||||
|
||||
PopupMenu.borderColor = shade(@background,28%)
|
||||
PopupMenu.hoverScrollArrowBackground = darken(@background,5%)
|
||||
|
||||
|
||||
#---- ProgressBar ----
|
||||
@@ -311,6 +313,7 @@ SplitPaneDivider.draggingColor = $Component.borderColor
|
||||
#---- TabbedPane ----
|
||||
|
||||
TabbedPane.underlineColor = @accentUnderlineColor
|
||||
TabbedPane.inactiveUnderlineColor = mix(@accentUnderlineColor,$TabbedPane.background,50%)
|
||||
TabbedPane.disabledUnderlineColor = darken(@background,28%)
|
||||
TabbedPane.hoverColor = darken($TabbedPane.background,7%,derived)
|
||||
TabbedPane.focusColor = mix(@selectionBackground,$TabbedPane.background,10%)
|
||||
@@ -329,7 +332,7 @@ TabbedPane.closePressedForeground = $TabbedPane.closeHoverForeground
|
||||
|
||||
#---- Table ----
|
||||
|
||||
Table.gridColor = darken($Table.background,5%)
|
||||
Table.gridColor = darken($Table.background,8%)
|
||||
|
||||
|
||||
#---- TableHeader ----
|
||||
@@ -374,6 +377,6 @@ Tree.hash = darken($Tree.background,10%)
|
||||
focusable: false; \
|
||||
toolbar.margin: 1,1,1,1; \
|
||||
toolbar.spacingInsets: 1,1,1,1; \
|
||||
toolbar.hoverBackground: fade(Actions.GreyInline,10%,lazy); \
|
||||
toolbar.pressedBackground: fade(Actions.GreyInline,20%,lazy); \
|
||||
toolbar.selectedBackground: fade(Actions.GreyInline,30%,lazy)
|
||||
toolbar.hoverBackground: darken($TextField.background,4%); \
|
||||
toolbar.pressedBackground: darken($TextField.background,8%); \
|
||||
toolbar.selectedBackground: darken($TextField.background,12%)
|
||||
|
||||
@@ -67,6 +67,11 @@ Button.default.hoverBorderColor = null
|
||||
[dark]CheckBoxMenuItem.icon.checkmarkColor=#fff9
|
||||
|
||||
|
||||
#---- Component ----
|
||||
|
||||
Component.accentColor = lazy(ProgressBar.foreground)
|
||||
|
||||
|
||||
#---- HelpButton ----
|
||||
|
||||
HelpButton.hoverBorderColor = null
|
||||
@@ -77,6 +82,13 @@ HelpButton.hoverBorderColor = null
|
||||
Slider.focusedColor = fade($Component.focusColor,40%,derived)
|
||||
|
||||
|
||||
#---- TabbedPane ----
|
||||
|
||||
# colors from JBUI.CurrentTheme.DefaultTabs.inactiveUnderlineColor()
|
||||
[light]TabbedPane.inactiveUnderlineColor = #9ca7b8
|
||||
[dark]TabbedPane.inactiveUnderlineColor = #747a80
|
||||
|
||||
|
||||
#---- ToggleButton ----
|
||||
|
||||
ToggleButton.startBackground = $ToggleButton.background
|
||||
@@ -91,36 +103,37 @@ ToggleButton.endBackground = $ToggleButton.background
|
||||
@ijMenuCheckBackgroundL20 = lighten(@selectionBackground,20%,derived noAutoInverse)
|
||||
@ijMenuCheckBackgroundD10 = darken(@selectionBackground,10%,derived noAutoInverse)
|
||||
|
||||
[Arc_Theme]CheckBoxMenuItem.foreground = lazy(MenuItem.foreground)
|
||||
[Arc_Theme]PopupMenu.foreground = lazy(MenuItem.foreground)
|
||||
[Arc_Theme]RadioButtonMenuItem.foreground = lazy(MenuItem.foreground)
|
||||
[Arc_Theme]CheckBoxMenuItem.foreground = lazy(MenuItem.foreground)
|
||||
[Arc_Theme]PopupMenu.foreground = lazy(MenuItem.foreground)
|
||||
[Arc_Theme]RadioButtonMenuItem.foreground = lazy(MenuItem.foreground)
|
||||
[Arc_Theme]ProgressBar.selectionBackground = #000
|
||||
[Arc_Theme]ProgressBar.selectionForeground = #fff
|
||||
[Arc_Theme]List.selectionInactiveForeground = #fff
|
||||
[Arc_Theme]Table.selectionInactiveForeground = #fff
|
||||
[Arc_Theme]Tree.selectionInactiveForeground = #fff
|
||||
|
||||
[Arc_Theme_-_Orange]CheckBoxMenuItem.foreground = lazy(MenuItem.foreground)
|
||||
[Arc_Theme_-_Orange]PopupMenu.foreground = lazy(MenuItem.foreground)
|
||||
[Arc_Theme_-_Orange]RadioButtonMenuItem.foreground = lazy(MenuItem.foreground)
|
||||
[Arc_Theme_-_Orange]CheckBoxMenuItem.foreground = lazy(MenuItem.foreground)
|
||||
[Arc_Theme_-_Orange]PopupMenu.foreground = lazy(MenuItem.foreground)
|
||||
[Arc_Theme_-_Orange]RadioButtonMenuItem.foreground = lazy(MenuItem.foreground)
|
||||
[Arc_Theme_-_Orange]ProgressBar.selectionBackground = #000
|
||||
[Arc_Theme_-_Orange]ProgressBar.selectionForeground = #fff
|
||||
[Arc_Theme_-_Orange]List.selectionInactiveForeground = #fff
|
||||
[Arc_Theme_-_Orange]Table.selectionInactiveForeground = #fff
|
||||
[Arc_Theme_-_Orange]Tree.selectionInactiveForeground = #fff
|
||||
|
||||
[Arc_Theme_Dark]CheckBoxMenuItem.foreground = lazy(MenuItem.foreground)
|
||||
[Arc_Theme_Dark]PopupMenu.foreground = lazy(MenuItem.foreground)
|
||||
[Arc_Theme_Dark]RadioButtonMenuItem.foreground = lazy(MenuItem.foreground)
|
||||
[Arc_Theme_Dark]CheckBoxMenuItem.foreground = lazy(MenuItem.foreground)
|
||||
[Arc_Theme_Dark]PopupMenu.foreground = lazy(MenuItem.foreground)
|
||||
[Arc_Theme_Dark]RadioButtonMenuItem.foreground = lazy(MenuItem.foreground)
|
||||
[Arc_Theme_Dark]ProgressBar.selectionBackground = #ddd
|
||||
[Arc_Theme_Dark]ProgressBar.selectionForeground = #ddd
|
||||
|
||||
[Arc_Theme_Dark_-_Orange]CheckBoxMenuItem.foreground = lazy(MenuItem.foreground)
|
||||
[Arc_Theme_Dark_-_Orange]PopupMenu.foreground = lazy(MenuItem.foreground)
|
||||
[Arc_Theme_Dark_-_Orange]RadioButtonMenuItem.foreground = lazy(MenuItem.foreground)
|
||||
[Arc_Theme_Dark_-_Orange]CheckBoxMenuItem.foreground = lazy(MenuItem.foreground)
|
||||
[Arc_Theme_Dark_-_Orange]PopupMenu.foreground = lazy(MenuItem.foreground)
|
||||
[Arc_Theme_Dark_-_Orange]RadioButtonMenuItem.foreground = lazy(MenuItem.foreground)
|
||||
[Arc_Theme_Dark_-_Orange]ProgressBar.selectionBackground = #ddd
|
||||
[Arc_Theme_Dark_-_Orange]ProgressBar.selectionForeground = #fff
|
||||
|
||||
[Cobalt_2]Component.accentColor = lazy(Component.focusColor)
|
||||
[Cobalt_2]CheckBox.icon.background = #002946
|
||||
[Cobalt_2]CheckBox.icon.checkmarkColor = #002946
|
||||
[Cobalt_2]MenuItem.checkBackground = @ijMenuCheckBackgroundL10
|
||||
@@ -129,37 +142,50 @@ ToggleButton.endBackground = $ToggleButton.background
|
||||
[Cyan_light]MenuItem.checkBackground = @ijMenuCheckBackgroundL20
|
||||
[Cyan_light]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL20
|
||||
|
||||
[Dark_Flat_Theme]Component.accentColor = lazy(List.selectionBackground)
|
||||
[Dark_Flat_Theme]TableHeader.background = #3B3B3B
|
||||
|
||||
[Dark_purple]Slider.focusedColor = fade($Component.focusColor,70%,derived)
|
||||
|
||||
[Dracula---Zihan_Ma]Component.accentColor = lazy(Component.focusColor)
|
||||
[Dracula---Zihan_Ma]ProgressBar.selectionBackground = #fff
|
||||
[Dracula---Zihan_Ma]ProgressBar.selectionForeground = #fff
|
||||
|
||||
[Gradianto_Dark_Fuchsia]MenuItem.checkBackground = @ijMenuCheckBackgroundL10
|
||||
[Gradianto_Dark_Fuchsia]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
|
||||
|
||||
[Gruvbox_Dark_Hard]Component.accentColor = lazy(TabbedPane.underlineColor)
|
||||
[Gruvbox_Dark_Hard]ToggleButton.selectedBackground = $ToggleButton.selectedBackground
|
||||
[Gruvbox_Dark_Hard]ToggleButton.toolbar.selectedBackground = $ToggleButton.toolbar.selectedBackground
|
||||
|
||||
[Gruvbox_Dark_Medium]Component.accentColor = lazy(TabbedPane.underlineColor)
|
||||
[Gruvbox_Dark_Medium]ToggleButton.selectedBackground = $ToggleButton.selectedBackground
|
||||
[Gruvbox_Dark_Medium]ToggleButton.toolbar.selectedBackground = $ToggleButton.toolbar.selectedBackground
|
||||
|
||||
[Gruvbox_Dark_Soft]Component.accentColor = lazy(TabbedPane.underlineColor)
|
||||
[Gruvbox_Dark_Soft]MenuItem.checkBackground = @ijMenuCheckBackgroundL10
|
||||
[Gruvbox_Dark_Soft]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
|
||||
[Gruvbox_Dark_Soft]ToggleButton.selectedBackground = $ToggleButton.selectedBackground
|
||||
[Gruvbox_Dark_Soft]ToggleButton.toolbar.selectedBackground = $ToggleButton.toolbar.selectedBackground
|
||||
|
||||
[Hiberbee_Dark]TabbedPane.focusColor = #5A5A5A
|
||||
[Hiberbee_Dark]ToggleButton.selectedBackground = $ToggleButton.selectedBackground
|
||||
[Hiberbee_Dark]TabbedPane.selectedBackground = #434241
|
||||
[Hiberbee_Dark]TabbedPane.selectedForeground = #70D7FF
|
||||
[Hiberbee_Dark]ToggleButton.selectedBackground = $ToggleButton.selectedBackground
|
||||
[Hiberbee_Dark]ToggleButton.toolbar.selectedBackground = $ToggleButton.toolbar.selectedBackground
|
||||
|
||||
[High_contrast]Component.accentColor = lazy(Component.focusColor)
|
||||
[High_contrast]ToggleButton.selectedBackground = #fff
|
||||
[High_contrast]ToggleButton.selectedForeground = #000
|
||||
[High_contrast]ToggleButton.disabledSelectedBackground = #444
|
||||
[High_contrast]ToggleButton.toolbar.selectedBackground = #fff
|
||||
[High_contrast][style]Button.inTextField = \
|
||||
toolbar.hoverBackground: #444; \
|
||||
toolbar.pressedBackground: #666; \
|
||||
toolbar.selectedBackground: #fff
|
||||
[High_contrast][style]ToggleButton.inTextField = $[High_contrast][style]Button.inTextField
|
||||
|
||||
[Light_Flat]Component.accentColor = lazy(TabbedPane.underlineColor)
|
||||
[Light_Flat]TableHeader.background = #E5E5E9
|
||||
|
||||
[Monocai]MenuItem.checkBackground = @ijMenuCheckBackgroundL10
|
||||
@@ -175,6 +201,8 @@ ToggleButton.endBackground = $ToggleButton.background
|
||||
[Monocai]RadioButtonMenuItem.acceleratorForeground = @Monocai.acceleratorForeground
|
||||
[Monocai]RadioButtonMenuItem.acceleratorSelectionForeground = @Monocai.acceleratorSelectionForeground
|
||||
|
||||
[Monokai_Pro]TitledBorder.titleColor = @foreground
|
||||
|
||||
[Nord]MenuItem.checkBackground = @ijMenuCheckBackgroundL10
|
||||
[Nord]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
|
||||
|
||||
@@ -182,8 +210,12 @@ ToggleButton.endBackground = $ToggleButton.background
|
||||
[One_Dark]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
|
||||
[One_Dark]Slider.focusedColor = fade(#568af2,40%)
|
||||
|
||||
[Solarized_Dark---4lex4]Component.accentColor = lazy(TabbedPane.underlineColor)
|
||||
[Solarized_Dark---4lex4]Slider.focusedColor = fade($Component.focusColor,80%,derived)
|
||||
|
||||
[Solarized_Light---4lex4]Component.accentColor = lazy(TabbedPane.underlineColor)
|
||||
|
||||
[vuesion-theme]Component.accentColor = lazy(Button.default.endBackground)
|
||||
[vuesion-theme]MenuItem.checkBackground = @ijMenuCheckBackgroundL10
|
||||
[vuesion-theme]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
|
||||
[vuesion-theme]Slider.trackValueColor = #ececee
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,65 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
#---- FileChooser ----
|
||||
|
||||
#fields
|
||||
FileChooser.lookInLabel.textAndMnemonic = Buscar &en:
|
||||
FileChooser.saveInLabelText = Guardar en:
|
||||
FileChooser.fileNameLabel.textAndMnemonic = &Nombre de fichero:
|
||||
FileChooser.folderNameLabel.textAndMnemonic = &Nombre de carpeta:
|
||||
FileChooser.filesOfTypeLabel.textAndMnemonic = Ficheros de &Tipo:
|
||||
|
||||
# toolbar
|
||||
FileChooser.upFolderToolTipText = Subir un nivel
|
||||
FileChooser.upFolderAccessibleName = Subir
|
||||
FileChooser.homeFolderToolTipText = Inicio
|
||||
FileChooser.homeFolderAccessibleName = Inicio
|
||||
FileChooser.newFolderToolTipText = Crear nueva carpeta
|
||||
FileChooser.newFolderAccessibleName = Nueva carpeta
|
||||
FileChooser.listViewButtonToolTipText = Lista
|
||||
FileChooser.listViewButtonAccessibleName = Lista
|
||||
FileChooser.detailsViewButtonToolTipText = Detalles
|
||||
FileChooser.detailsViewButtonAccessibleName = Detalles
|
||||
|
||||
# details table header
|
||||
FileChooser.fileNameHeaderText = Nombre
|
||||
FileChooser.fileSizeHeaderText = Tama\u00F1o
|
||||
FileChooser.fileTypeHeaderText = Tipo
|
||||
FileChooser.fileDateHeaderText = Modificado
|
||||
FileChooser.fileAttrHeaderText = Atributos
|
||||
|
||||
# popup menu
|
||||
FileChooser.viewMenuLabelText = Ver
|
||||
FileChooser.refreshActionLabelText = Refrescar
|
||||
FileChooser.newFolderActionLabelText = Nueva carpeta
|
||||
FileChooser.listViewActionLabelText = Lista
|
||||
FileChooser.detailsViewActionLabelText = Detalles
|
||||
|
||||
|
||||
#---- SplitPaneDivider ----
|
||||
|
||||
SplitPaneDivider.collapseLeftToolTipText = Contraer Panel Izquierdo
|
||||
SplitPaneDivider.collapseRightToolTipText = Contraer panel Derecho
|
||||
SplitPaneDivider.collapseTopToolTipText = Contraer panel Superior
|
||||
SplitPaneDivider.collapseBottomToolTipText = Contraer Panel Inferior
|
||||
SplitPaneDivider.expandLeftToolTipText = Expandir Panel Izquierdo
|
||||
SplitPaneDivider.expandRightToolTipText = Expandir Panel Derecho
|
||||
SplitPaneDivider.expandTopToolTipText = Expandir Panel Superior
|
||||
SplitPaneDivider.expandBottomToolTipText = Expandir Panel Inferior
|
||||
|
||||
|
||||
#---- TabbedPane ----
|
||||
|
||||
TabbedPane.moreTabsButtonToolTipText = Mostrar Pesta\u00F1as Ocultas
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2022 FormDev Software GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.icons;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.image.BufferedImage;
|
||||
import javax.swing.Icon;
|
||||
import com.formdev.flatlaf.ui.TestUtils;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
|
||||
class TestFlatIconPaintingNullComponent
|
||||
{
|
||||
static Graphics graphics;
|
||||
|
||||
@BeforeAll
|
||||
static void setup() {
|
||||
TestUtils.setup( false );
|
||||
graphics = new BufferedImage( 32, 32, BufferedImage.TYPE_INT_ARGB ).getGraphics();
|
||||
graphics.setColor( Color.white );
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void cleanup() {
|
||||
TestUtils.cleanup();
|
||||
graphics = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
void flatHelpButtonIcon() {
|
||||
paintWithoutException( new FlatHelpButtonIcon() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void flatMenuArrowIcon() {
|
||||
paintWithoutException( new FlatMenuArrowIcon() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void flatSearchIcon() {
|
||||
paintWithoutException( new FlatSearchIcon() );
|
||||
}
|
||||
|
||||
private void paintWithoutException( Icon icon ) {
|
||||
graphics.clearRect( 0, 0, 32, 32 );
|
||||
assertDoesNotThrow( () -> icon.paintIcon( null, graphics, 0, 0 ) );
|
||||
}
|
||||
}
|
||||
@@ -96,19 +96,26 @@ public class TestFlatStyleableInfo
|
||||
"minimumWidth", int.class,
|
||||
|
||||
"focusedBackground", Color.class,
|
||||
"focusedForeground", Color.class,
|
||||
"hoverBackground", Color.class,
|
||||
"hoverForeground", Color.class,
|
||||
"pressedBackground", Color.class,
|
||||
"pressedForeground", Color.class,
|
||||
"selectedBackground", Color.class,
|
||||
"selectedForeground", Color.class,
|
||||
"disabledBackground", Color.class,
|
||||
"disabledText", Color.class,
|
||||
"disabledSelectedBackground", Color.class,
|
||||
"disabledSelectedForeground", Color.class,
|
||||
|
||||
"default.background", Color.class,
|
||||
"default.foreground", Color.class,
|
||||
"default.focusedBackground", Color.class,
|
||||
"default.focusedForeground", Color.class,
|
||||
"default.hoverBackground", Color.class,
|
||||
"default.hoverForeground", Color.class,
|
||||
"default.pressedBackground", Color.class,
|
||||
"default.pressedForeground", Color.class,
|
||||
"default.boldText", boolean.class,
|
||||
|
||||
"paintShadow", boolean.class,
|
||||
@@ -118,8 +125,13 @@ public class TestFlatStyleableInfo
|
||||
|
||||
"toolbar.spacingInsets", Insets.class,
|
||||
"toolbar.hoverBackground", Color.class,
|
||||
"toolbar.hoverForeground", Color.class,
|
||||
"toolbar.pressedBackground", Color.class,
|
||||
"toolbar.pressedForeground", Color.class,
|
||||
"toolbar.selectedBackground", Color.class,
|
||||
"toolbar.selectedForeground", Color.class,
|
||||
"toolbar.disabledSelectedBackground", Color.class,
|
||||
"toolbar.disabledSelectedForeground", Color.class,
|
||||
|
||||
"buttonType", String.class,
|
||||
"squareSize", boolean.class,
|
||||
@@ -422,6 +434,10 @@ public class TestFlatStyleableInfo
|
||||
FlatPopupMenuUI ui = (FlatPopupMenuUI) c.getUI();
|
||||
|
||||
Map<String, Class<?>> expected = expectedMap(
|
||||
"arrowType", String.class,
|
||||
"scrollArrowColor", Color.class,
|
||||
"hoverScrollArrowBackground", Color.class,
|
||||
|
||||
"borderInsets", Insets.class,
|
||||
"borderColor", Color.class
|
||||
);
|
||||
@@ -539,6 +555,7 @@ public class TestFlatStyleableInfo
|
||||
"maximumThumbSize", Dimension.class,
|
||||
"allowsAbsolutePositioning", boolean.class,
|
||||
|
||||
"minimumButtonSize", Dimension.class,
|
||||
"trackInsets", Insets.class,
|
||||
"thumbInsets", Insets.class,
|
||||
"trackArc", int.class,
|
||||
@@ -688,6 +705,7 @@ public class TestFlatStyleableInfo
|
||||
"selectedBackground", Color.class,
|
||||
"selectedForeground", Color.class,
|
||||
"underlineColor", Color.class,
|
||||
"inactiveUnderlineColor", Color.class,
|
||||
"disabledUnderlineColor", Color.class,
|
||||
"hoverColor", Color.class,
|
||||
"focusColor", Color.class,
|
||||
@@ -857,8 +875,11 @@ public class TestFlatStyleableInfo
|
||||
"tab.underlineColor", Color.class,
|
||||
"tab.disabledUnderlineColor", Color.class,
|
||||
"tab.selectedBackground", Color.class,
|
||||
"tab.selectedForeground", Color.class,
|
||||
"tab.hoverBackground", Color.class,
|
||||
"tab.focusBackground", Color.class
|
||||
"tab.hoverForeground", Color.class,
|
||||
"tab.focusBackground", Color.class,
|
||||
"tab.focusForeground", Color.class
|
||||
);
|
||||
|
||||
// FlatToggleButtonUI extends FlatButtonUI
|
||||
|
||||
@@ -221,19 +221,26 @@ public class TestFlatStyling
|
||||
ui.applyStyle( b, "minimumWidth: 100" );
|
||||
|
||||
ui.applyStyle( b, "focusedBackground: #fff" );
|
||||
ui.applyStyle( b, "focusedForeground: #fff" );
|
||||
ui.applyStyle( b, "hoverBackground: #fff" );
|
||||
ui.applyStyle( b, "hoverForeground: #fff" );
|
||||
ui.applyStyle( b, "pressedBackground: #fff" );
|
||||
ui.applyStyle( b, "pressedForeground: #fff" );
|
||||
ui.applyStyle( b, "selectedBackground: #fff" );
|
||||
ui.applyStyle( b, "selectedForeground: #fff" );
|
||||
ui.applyStyle( b, "disabledBackground: #fff" );
|
||||
ui.applyStyle( b, "disabledText: #fff" );
|
||||
ui.applyStyle( b, "disabledSelectedBackground: #fff" );
|
||||
ui.applyStyle( b, "disabledSelectedForeground: #fff" );
|
||||
|
||||
ui.applyStyle( b, "default.background: #fff" );
|
||||
ui.applyStyle( b, "default.foreground: #fff" );
|
||||
ui.applyStyle( b, "default.focusedBackground: #fff" );
|
||||
ui.applyStyle( b, "default.focusedForeground: #fff" );
|
||||
ui.applyStyle( b, "default.hoverBackground: #fff" );
|
||||
ui.applyStyle( b, "default.hoverForeground: #fff" );
|
||||
ui.applyStyle( b, "default.pressedBackground: #fff" );
|
||||
ui.applyStyle( b, "default.pressedForeground: #fff" );
|
||||
ui.applyStyle( b, "default.boldText: true" );
|
||||
|
||||
ui.applyStyle( b, "paintShadow: true" );
|
||||
@@ -243,8 +250,13 @@ public class TestFlatStyling
|
||||
|
||||
ui.applyStyle( b, "toolbar.spacingInsets: 1,2,3,4" );
|
||||
ui.applyStyle( b, "toolbar.hoverBackground: #fff" );
|
||||
ui.applyStyle( b, "toolbar.hoverForeground: #fff" );
|
||||
ui.applyStyle( b, "toolbar.pressedBackground: #fff" );
|
||||
ui.applyStyle( b, "toolbar.pressedForeground: #fff" );
|
||||
ui.applyStyle( b, "toolbar.selectedBackground: #fff" );
|
||||
ui.applyStyle( b, "toolbar.selectedForeground: #fff" );
|
||||
ui.applyStyle( b, "toolbar.disabledSelectedBackground: #fff" );
|
||||
ui.applyStyle( b, "toolbar.disabledSelectedForeground: #fff" );
|
||||
|
||||
ui.applyStyle( b, "buttonType: help" );
|
||||
ui.applyStyle( b, "squareSize: true" );
|
||||
@@ -565,6 +577,10 @@ public class TestFlatStyling
|
||||
JPopupMenu c = new JPopupMenu();
|
||||
FlatPopupMenuUI ui = (FlatPopupMenuUI) c.getUI();
|
||||
|
||||
ui.applyStyle( "arrowType: chevron" );
|
||||
ui.applyStyle( "scrollArrowColor: #fff" );
|
||||
ui.applyStyle( "hoverScrollArrowBackground: #fff" );
|
||||
|
||||
ui.applyStyle( "borderInsets: 1,2,3,4" );
|
||||
ui.applyStyle( "borderColor: #fff" );
|
||||
|
||||
@@ -684,6 +700,7 @@ public class TestFlatStyling
|
||||
ui.applyStyle( "maximumThumbSize: 1,2" );
|
||||
ui.applyStyle( "allowsAbsolutePositioning: true" );
|
||||
|
||||
ui.applyStyle( "minimumButtonSize: 1,2" );
|
||||
ui.applyStyle( "trackInsets: 1,2,3,4" );
|
||||
ui.applyStyle( "thumbInsets: 1,2,3,4" );
|
||||
ui.applyStyle( "trackArc: 5" );
|
||||
@@ -857,6 +874,7 @@ public class TestFlatStyling
|
||||
ui.applyStyle( "selectedBackground: #fff" );
|
||||
ui.applyStyle( "selectedForeground: #fff" );
|
||||
ui.applyStyle( "underlineColor: #fff" );
|
||||
ui.applyStyle( "inactiveUnderlineColor: #fff" );
|
||||
ui.applyStyle( "disabledUnderlineColor: #fff" );
|
||||
ui.applyStyle( "hoverColor: #fff" );
|
||||
ui.applyStyle( "focusColor: #fff" );
|
||||
@@ -1067,8 +1085,11 @@ public class TestFlatStyling
|
||||
ui.applyStyle( b, "tab.underlineColor: #fff" );
|
||||
ui.applyStyle( b, "tab.disabledUnderlineColor: #fff" );
|
||||
ui.applyStyle( b, "tab.selectedBackground: #fff" );
|
||||
ui.applyStyle( b, "tab.selectedForeground: #fff" );
|
||||
ui.applyStyle( b, "tab.hoverBackground: #fff" );
|
||||
ui.applyStyle( b, "tab.hoverForeground: #fff" );
|
||||
ui.applyStyle( b, "tab.focusBackground: #fff" );
|
||||
ui.applyStyle( b, "tab.focusForeground: #fff" );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -38,8 +38,8 @@ import com.formdev.flatlaf.FlatLightLaf;
|
||||
import com.formdev.flatlaf.demo.HintManager.Hint;
|
||||
import com.formdev.flatlaf.demo.extras.*;
|
||||
import com.formdev.flatlaf.demo.intellijthemes.*;
|
||||
import com.formdev.flatlaf.extras.FlatDesktop;
|
||||
import com.formdev.flatlaf.extras.FlatAnimatedLafChange;
|
||||
import com.formdev.flatlaf.extras.FlatDesktop;
|
||||
import com.formdev.flatlaf.extras.FlatSVGIcon;
|
||||
import com.formdev.flatlaf.extras.FlatUIDefaultsInspector;
|
||||
import com.formdev.flatlaf.extras.components.FlatButton;
|
||||
@@ -82,13 +82,33 @@ class DemoFrame
|
||||
if( tabIndex >= 0 && tabIndex < tabbedPane.getTabCount() && tabIndex != tabbedPane.getSelectedIndex() )
|
||||
tabbedPane.setSelectedIndex( tabIndex );
|
||||
|
||||
// hide some menu items on macOS
|
||||
// macOS (see https://www.formdev.com/flatlaf/macos/)
|
||||
if( SystemInfo.isMacOS ) {
|
||||
// hide menu items that are in macOS application menu
|
||||
exitMenuItem.setVisible( false );
|
||||
aboutMenuItem.setVisible( false );
|
||||
|
||||
// do not use HTML text on macOS
|
||||
// do not use HTML text in menu items because this is not supported in macOS screen menu
|
||||
htmlMenuItem.setText( "some text" );
|
||||
|
||||
if( SystemInfo.isMacFullWindowContentSupported ) {
|
||||
// expand window content into window title bar and make title bar transparent
|
||||
getRootPane().putClientProperty( "apple.awt.fullWindowContent", true );
|
||||
getRootPane().putClientProperty( "apple.awt.transparentTitleBar", true );
|
||||
|
||||
// hide window title
|
||||
if( SystemInfo.isJava_17_orLater )
|
||||
getRootPane().putClientProperty( "apple.awt.windowTitleVisible", false );
|
||||
else
|
||||
setTitle( null );
|
||||
|
||||
// add gap to left side of toolbar
|
||||
toolBar.add( Box.createHorizontalStrut( 70 ), 0 );
|
||||
}
|
||||
|
||||
// enable full screen mode for this window (for Java 8 - 10; not necessary for Java 11+)
|
||||
if( !SystemInfo.isJava_11_orLater )
|
||||
getRootPane().putClientProperty( "apple.awt.fullscreenable", true );
|
||||
}
|
||||
|
||||
// integrate into macOS screen menu
|
||||
@@ -322,8 +342,8 @@ class DemoFrame
|
||||
// add font families
|
||||
fontMenu.addSeparator();
|
||||
ArrayList<String> families = new ArrayList<>( Arrays.asList(
|
||||
"Arial", "Cantarell", "Comic Sans MS", "Courier New", "DejaVu Sans",
|
||||
"Dialog", "Liberation Sans", "Monospaced", "Noto Sans", "Roboto",
|
||||
"Arial", "Cantarell", "Comic Sans MS", "DejaVu Sans",
|
||||
"Dialog", "Liberation Sans", "Noto Sans", "Roboto",
|
||||
"SansSerif", "Segoe UI", "Serif", "Tahoma", "Ubuntu", "Verdana" ) );
|
||||
if( !families.contains( currentFamily ) )
|
||||
families.add( currentFamily );
|
||||
@@ -433,9 +453,9 @@ class DemoFrame
|
||||
lafClass == FlatIntelliJLaf.class ||
|
||||
lafClass == FlatDarculaLaf.class;
|
||||
|
||||
accentColorLabel.setEnabled( isAccentColorSupported );
|
||||
accentColorLabel.setVisible( isAccentColorSupported );
|
||||
for( int i = 0; i < accentColorButtons.length; i++ )
|
||||
accentColorButtons[i].setEnabled( isAccentColorSupported );
|
||||
accentColorButtons[i].setVisible( isAccentColorSupported );
|
||||
}
|
||||
|
||||
private void initComponents() {
|
||||
@@ -464,6 +484,7 @@ class DemoFrame
|
||||
JMenuItem projectViewMenuItem = new JMenuItem();
|
||||
JMenuItem structureViewMenuItem = new JMenuItem();
|
||||
JMenuItem propertiesViewMenuItem = new JMenuItem();
|
||||
scrollingPopupMenu = new JMenu();
|
||||
JMenuItem menuItem2 = new JMenuItem();
|
||||
htmlMenuItem = new JMenuItem();
|
||||
JRadioButtonMenuItem radioButtonMenuItem1 = new JRadioButtonMenuItem();
|
||||
@@ -668,6 +689,12 @@ class DemoFrame
|
||||
}
|
||||
viewMenu.add(menu1);
|
||||
|
||||
//======== scrollingPopupMenu ========
|
||||
{
|
||||
scrollingPopupMenu.setText("Scrolling Popup Menu");
|
||||
}
|
||||
viewMenu.add(scrollingPopupMenu);
|
||||
|
||||
//---- menuItem2 ----
|
||||
menuItem2.setText("Disabled Item");
|
||||
menuItem2.setEnabled(false);
|
||||
@@ -889,8 +916,17 @@ class DemoFrame
|
||||
copyMenuItem.addActionListener( new DefaultEditorKit.CopyAction() );
|
||||
pasteMenuItem.addActionListener( new DefaultEditorKit.PasteAction() );
|
||||
|
||||
if( FlatLaf.supportsNativeWindowDecorations() ) {
|
||||
windowDecorationsCheckBoxMenuItem.setSelected( FlatLaf.isUseNativeWindowDecorations() );
|
||||
scrollingPopupMenu.add( "Large menus are scrollable" );
|
||||
scrollingPopupMenu.add( "Use mouse wheel to scroll" );
|
||||
scrollingPopupMenu.add( "Or use up/down arrows at top/bottom" );
|
||||
for( int i = 1; i <= 100; i++ )
|
||||
scrollingPopupMenu.add( "Item " + i );
|
||||
|
||||
if( FlatLaf.supportsNativeWindowDecorations() || (SystemInfo.isLinux && JFrame.isDefaultLookAndFeelDecorated()) ) {
|
||||
if( SystemInfo.isLinux )
|
||||
unsupported( windowDecorationsCheckBoxMenuItem );
|
||||
else
|
||||
windowDecorationsCheckBoxMenuItem.setSelected( FlatLaf.isUseNativeWindowDecorations() );
|
||||
menuBarEmbeddedCheckBoxMenuItem.setSelected( UIManager.getBoolean( "TitlePane.menuBarEmbedded" ) );
|
||||
unifiedTitleBarMenuItem.setSelected( UIManager.getBoolean( "TitlePane.unifiedBackground" ) );
|
||||
showTitleBarIconMenuItem.setSelected( UIManager.getBoolean( "TitlePane.showIcon" ) );
|
||||
@@ -931,6 +967,7 @@ class DemoFrame
|
||||
|
||||
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
|
||||
private JMenuItem exitMenuItem;
|
||||
private JMenu scrollingPopupMenu;
|
||||
private JMenuItem htmlMenuItem;
|
||||
private JMenu fontMenu;
|
||||
private JMenu optionsMenu;
|
||||
|
||||
@@ -282,6 +282,13 @@ new FormModel {
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "menuItemActionPerformed", true ) )
|
||||
} )
|
||||
} )
|
||||
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
|
||||
name: "scrollingPopupMenu"
|
||||
"text": "Scrolling Popup Menu"
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JMenuItem" ) {
|
||||
name: "menuItem2"
|
||||
"text": "Disabled Item"
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
package com.formdev.flatlaf.demo;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.SwingUtilities;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.extras.FlatInspector;
|
||||
@@ -34,7 +36,7 @@ public class FlatLafDemo
|
||||
static boolean screenshotsMode = Boolean.parseBoolean( System.getProperty( "flatlaf.demo.screenshotsMode" ) );
|
||||
|
||||
public static void main( String[] args ) {
|
||||
// macOS
|
||||
// macOS (see https://www.formdev.com/flatlaf/macos/)
|
||||
if( SystemInfo.isMacOS ) {
|
||||
// enable screen menu bar
|
||||
// (moves menu bar from JFrame window to top of screen)
|
||||
@@ -49,9 +51,17 @@ public class FlatLafDemo
|
||||
// - "system": use current macOS appearance (light or dark)
|
||||
// - "NSAppearanceNameAqua": use light appearance
|
||||
// - "NSAppearanceNameDarkAqua": use dark appearance
|
||||
// (needs to be set on main thread; setting it on AWT thread does not work)
|
||||
System.setProperty( "apple.awt.application.appearance", "system" );
|
||||
}
|
||||
|
||||
// Linux
|
||||
if( SystemInfo.isLinux ) {
|
||||
// enable custom window decorations
|
||||
JFrame.setDefaultLookAndFeelDecorated( true );
|
||||
JDialog.setDefaultLookAndFeelDecorated( true );
|
||||
}
|
||||
|
||||
if( FlatLafDemo.screenshotsMode && !SystemInfo.isJava_9_orLater && System.getProperty( "flatlaf.uiScale" ) == null )
|
||||
System.setProperty( "flatlaf.uiScale", "2x" );
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ public class IJThemesClassGenerator
|
||||
markdownTable.append( "-----|------\n" );
|
||||
|
||||
for( IJThemeInfo ti : themesManager.bundledThemes ) {
|
||||
if( ti.sourceCodeUrl == null || ti.sourceCodePath == null )
|
||||
if( ti.sourceCodeUrl == null )
|
||||
continue;
|
||||
|
||||
generateClass( ti, toPath, allInfos, markdownTable );
|
||||
@@ -77,7 +77,7 @@ public class IJThemesClassGenerator
|
||||
themeName += " (Material)";
|
||||
|
||||
StringBuilder buf = new StringBuilder();
|
||||
for( String n : name.split( " " ) ) {
|
||||
for( String n : name.split( "[ \\-]" ) ) {
|
||||
if( n.length() == 0 || n.equals( "-" ) )
|
||||
continue;
|
||||
|
||||
|
||||
@@ -178,6 +178,13 @@
|
||||
"sourceCodeUrl": "https://github.com/bmikaili/intellij-monocai-theme",
|
||||
"sourceCodePath": "blob/master/resources/Monocai.theme.json"
|
||||
},
|
||||
"Monokai_Pro.default.theme.json": {
|
||||
"name": "Monokai Pro",
|
||||
"dark": true,
|
||||
"license": "MIT",
|
||||
"licenseFile": "Monokai_Pro.LICENSE.txt",
|
||||
"sourceCodeUrl": "https://github.com/subtheme-dev/monokai-pro"
|
||||
},
|
||||
"nord.theme.json": {
|
||||
"name": "Nord",
|
||||
"dark": true,
|
||||
@@ -225,6 +232,14 @@
|
||||
"sourceCodeUrl": "https://github.com/vuesion/intellij-theme",
|
||||
"sourceCodePath": "blob/master/resources/META-INF/vuesion_theme.theme.json"
|
||||
},
|
||||
"Xcode-Dark.theme.json": {
|
||||
"name": "Xcode-Dark",
|
||||
"dark": true,
|
||||
"license": "MIT",
|
||||
"licenseFile": "Xcode-Dark.LICENSE.txt",
|
||||
"sourceCodeUrl": "https://github.com/antelle/intellij-xcode-dark-theme",
|
||||
"sourceCodePath": "blob/master/resources/Xcode-Dark.theme.json"
|
||||
},
|
||||
|
||||
"material-theme-ui-lite/Arc Dark.theme.json": {
|
||||
"name": "Material Theme UI Lite / Arc Dark",
|
||||
|
||||
@@ -65,6 +65,7 @@ import javax.swing.plaf.UIResource;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
import com.formdev.flatlaf.ui.MigLayoutVisualPadding;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
@@ -113,6 +114,7 @@ public class FlatInspector
|
||||
private int inspectParentLevel;
|
||||
private boolean wasModifierKeyPressed;
|
||||
private boolean showClassHierarchy;
|
||||
private long lastWhen;
|
||||
|
||||
private JComponent highlightFigure;
|
||||
private Popup popup;
|
||||
@@ -131,8 +133,22 @@ public class FlatInspector
|
||||
(((KeyEvent)e).getModifiersEx() & KEY_MODIFIERS_MASK) == (keyStroke.getModifiers() & KEY_MODIFIERS_MASK) )
|
||||
{
|
||||
Window activeWindow = KeyboardFocusManager.getCurrentKeyboardFocusManager().getActiveWindow();
|
||||
if( activeWindow instanceof RootPaneContainer ) {
|
||||
JRootPane rootPane = ((RootPaneContainer)activeWindow).getRootPane();
|
||||
RootPaneContainer rootPaneContainer = null;
|
||||
if( activeWindow instanceof RootPaneContainer )
|
||||
rootPaneContainer = (RootPaneContainer) activeWindow;
|
||||
else {
|
||||
// search for root pain container in children
|
||||
// (e.g. for Swing embedded into SWT)
|
||||
for( Component child : activeWindow.getComponents() ) {
|
||||
if( child instanceof RootPaneContainer ) {
|
||||
rootPaneContainer = (RootPaneContainer) child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( rootPaneContainer != null ) {
|
||||
JRootPane rootPane = rootPaneContainer.getRootPane();
|
||||
FlatInspector inspector = (FlatInspector) rootPane.getClientProperty( FlatInspector.class );
|
||||
if( inspector == null ) {
|
||||
inspector = new FlatInspector( rootPane );
|
||||
@@ -172,6 +188,11 @@ public class FlatInspector
|
||||
if( keyCode == KeyEvent.VK_CONTROL || keyCode == KeyEvent.VK_SHIFT || keyCode == KeyEvent.VK_ALT )
|
||||
wasModifierKeyPressed = true;
|
||||
} else if( id == KeyEvent.KEY_RELEASED && wasModifierKeyPressed ) {
|
||||
// ignore duplicate events (for Swing embedded into SWT)
|
||||
if( (keyEvent.getWhen() - lastWhen) <= 5 )
|
||||
return;
|
||||
lastWhen = keyEvent.getWhen();
|
||||
|
||||
if( keyCode == KeyEvent.VK_CONTROL ) {
|
||||
inspectParentLevel++;
|
||||
int parentLevel = inspect( lastX, lastY );
|
||||
@@ -464,6 +485,15 @@ public class FlatInspector
|
||||
if( margin != null )
|
||||
appendRow( buf, "Margin", toString( margin ) );
|
||||
|
||||
if( c instanceof JComponent ) {
|
||||
Object value = ((JComponent)c).getClientProperty( MigLayoutVisualPadding.VISUAL_PADDING_PROPERTY );
|
||||
Insets visualPadding = (value instanceof int[])
|
||||
? new Insets( ((int[])value)[0], ((int[])value)[1], ((int[])value)[2], ((int[])value)[3] )
|
||||
: (value instanceof Insets ? (Insets) value : null);
|
||||
if( visualPadding != null )
|
||||
appendRow( buf, "Mig visual padding", toString( visualPadding ) );
|
||||
}
|
||||
|
||||
Dimension prefSize = c.getPreferredSize();
|
||||
Dimension minSize = c.getMinimumSize();
|
||||
Dimension maxSize = c.getMaximumSize();
|
||||
|
||||
@@ -284,6 +284,20 @@ public class FlatSVGIcon
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a copy of the given icon.
|
||||
* <p>
|
||||
* If the icon has a color filter, then it is shared with the new icon.
|
||||
*
|
||||
* @since 2.0.1
|
||||
*/
|
||||
public FlatSVGIcon( FlatSVGIcon icon ) {
|
||||
this( icon.name, icon.width, icon.height, icon.scale, icon.disabled, icon.classLoader, icon.uri );
|
||||
colorFilter = icon.colorFilter;
|
||||
diagram = icon.diagram;
|
||||
dark = icon.dark;
|
||||
}
|
||||
|
||||
protected FlatSVGIcon( String name, int width, int height, float scale, boolean disabled, ClassLoader classLoader, URI uri ) {
|
||||
this.name = name;
|
||||
this.width = width;
|
||||
@@ -466,7 +480,7 @@ public class FlatSVGIcon
|
||||
|
||||
if( url == null ) {
|
||||
loadFailed = true;
|
||||
LoggingFacade.INSTANCE.logSevere( "FlatSVGIcon: resource '" + name + "' not found (if using Java modules, check whether icon package is opened in module-info.java)", null );
|
||||
LoggingFacade.INSTANCE.logConfig( "FlatSVGIcon: resource '" + name + "' not found (if using Java modules, check whether icon package is opened in module-info.java)", null );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ package com.formdev.flatlaf.extras.components;
|
||||
|
||||
import static com.formdev.flatlaf.FlatClientProperties.*;
|
||||
import java.awt.Color;
|
||||
import javax.swing.JToggleButton;
|
||||
import javax.swing.*;
|
||||
import com.formdev.flatlaf.extras.components.FlatButton.ButtonType;
|
||||
|
||||
/**
|
||||
@@ -116,16 +116,37 @@ public class FlatToggleButton
|
||||
putClientProperty( OUTLINE, outline );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns placement of underline if toggle button type is {@link ButtonType#tab}.
|
||||
* If underline placement is not specified, returns {@link #BOTTOM} as the default
|
||||
* value.
|
||||
*
|
||||
* @since 2.3
|
||||
*/
|
||||
public int getTabUnderlinePlacement() {
|
||||
return getClientPropertyInt( TAB_BUTTON_UNDERLINE_PLACEMENT, BOTTOM );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns height of underline if toggle button type is {@link ButtonType#tab}.
|
||||
* Specifies placement of underline if toggle button type is {@link ButtonType#tab}.
|
||||
*
|
||||
* @param placement One of the following constants defined in SwingConstants:
|
||||
* {@link #TOP}, {@link #LEFT}, {@link #BOTTOM}, or {@link #RIGHT}.
|
||||
* @since 2.3
|
||||
*/
|
||||
public void setTabUnderlinePlacement( int placement ) {
|
||||
putClientProperty( TAB_BUTTON_UNDERLINE_PLACEMENT, (placement >= 0) ? placement : null );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns thickness of underline if toggle button type is {@link ButtonType#tab}.
|
||||
*/
|
||||
public int getTabUnderlineHeight() {
|
||||
return getClientPropertyInt( TAB_BUTTON_UNDERLINE_HEIGHT, "ToggleButton.tab.underlineHeight" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies height of underline if toggle button type is {@link ButtonType#tab}.
|
||||
* Specifies thickness of underline if toggle button type is {@link ButtonType#tab}.
|
||||
*/
|
||||
public void setTabUnderlineHeight( int tabUnderlineHeight ) {
|
||||
putClientProperty( TAB_BUTTON_UNDERLINE_HEIGHT, (tabUnderlineHeight >= 0) ? tabUnderlineHeight : null );
|
||||
|
||||
@@ -65,12 +65,14 @@ Name | Class
|
||||
[Light Flat](https://github.com/nerzhulart/LightFlatTheme) | `com.formdev.flatlaf.intellijthemes.FlatLightFlatIJTheme`
|
||||
[Material Design Dark](https://github.com/xinkunZ/NotReallyMDTheme) | `com.formdev.flatlaf.intellijthemes.FlatMaterialDesignDarkIJTheme`
|
||||
[Monocai](https://github.com/bmikaili/intellij-monocai-theme) | `com.formdev.flatlaf.intellijthemes.FlatMonocaiIJTheme`
|
||||
[Monokai Pro](https://github.com/subtheme-dev/monokai-pro) | `com.formdev.flatlaf.intellijthemes.FlatMonokaiProIJTheme`
|
||||
[Nord](https://github.com/arcticicestudio/nord-jetbrains) | `com.formdev.flatlaf.intellijthemes.FlatNordIJTheme`
|
||||
[One Dark](https://github.com/one-dark/jetbrains-one-dark-theme) | `com.formdev.flatlaf.intellijthemes.FlatOneDarkIJTheme`
|
||||
[Solarized Dark](https://github.com/4lex4/intellij-platform-solarized) | `com.formdev.flatlaf.intellijthemes.FlatSolarizedDarkIJTheme`
|
||||
[Solarized Light](https://github.com/4lex4/intellij-platform-solarized) | `com.formdev.flatlaf.intellijthemes.FlatSolarizedLightIJTheme`
|
||||
[Spacegray](https://github.com/mturlo/intellij-spacegray) | `com.formdev.flatlaf.intellijthemes.FlatSpacegrayIJTheme`
|
||||
[Vuesion](https://github.com/vuesion/intellij-theme) | `com.formdev.flatlaf.intellijthemes.FlatVuesionIJTheme`
|
||||
[Xcode-Dark](https://github.com/antelle/intellij-xcode-dark-theme) | `com.formdev.flatlaf.intellijthemes.FlatXcodeDarkIJTheme`
|
||||
|
||||
Material Theme UI Lite:
|
||||
|
||||
|
||||
@@ -52,12 +52,14 @@ public class FlatAllIJThemes
|
||||
new FlatIJLookAndFeelInfo( "Light Flat", "com.formdev.flatlaf.intellijthemes.FlatLightFlatIJTheme", false ),
|
||||
new FlatIJLookAndFeelInfo( "Material Design Dark", "com.formdev.flatlaf.intellijthemes.FlatMaterialDesignDarkIJTheme", true ),
|
||||
new FlatIJLookAndFeelInfo( "Monocai", "com.formdev.flatlaf.intellijthemes.FlatMonocaiIJTheme", true ),
|
||||
new FlatIJLookAndFeelInfo( "Monokai Pro", "com.formdev.flatlaf.intellijthemes.FlatMonokaiProIJTheme", true ),
|
||||
new FlatIJLookAndFeelInfo( "Nord", "com.formdev.flatlaf.intellijthemes.FlatNordIJTheme", true ),
|
||||
new FlatIJLookAndFeelInfo( "One Dark", "com.formdev.flatlaf.intellijthemes.FlatOneDarkIJTheme", true ),
|
||||
new FlatIJLookAndFeelInfo( "Solarized Dark", "com.formdev.flatlaf.intellijthemes.FlatSolarizedDarkIJTheme", true ),
|
||||
new FlatIJLookAndFeelInfo( "Solarized Light", "com.formdev.flatlaf.intellijthemes.FlatSolarizedLightIJTheme", false ),
|
||||
new FlatIJLookAndFeelInfo( "Spacegray", "com.formdev.flatlaf.intellijthemes.FlatSpacegrayIJTheme", true ),
|
||||
new FlatIJLookAndFeelInfo( "Vuesion", "com.formdev.flatlaf.intellijthemes.FlatVuesionIJTheme", true ),
|
||||
new FlatIJLookAndFeelInfo( "Xcode-Dark", "com.formdev.flatlaf.intellijthemes.FlatXcodeDarkIJTheme", true ),
|
||||
new FlatIJLookAndFeelInfo( "Arc Dark (Material)", "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatArcDarkIJTheme", true ),
|
||||
new FlatIJLookAndFeelInfo( "Arc Dark Contrast (Material)", "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatArcDarkContrastIJTheme", true ),
|
||||
new FlatIJLookAndFeelInfo( "Atom One Dark (Material)", "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatAtomOneDarkIJTheme", true ),
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.intellijthemes;
|
||||
|
||||
//
|
||||
// DO NOT MODIFY
|
||||
// Generated with com.formdev.flatlaf.demo.intellijthemes.IJThemesClassGenerator
|
||||
//
|
||||
|
||||
import com.formdev.flatlaf.IntelliJTheme;
|
||||
|
||||
/**
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatMonokaiProIJTheme
|
||||
extends IntelliJTheme.ThemeLaf
|
||||
{
|
||||
public static final String NAME = "Monokai Pro";
|
||||
|
||||
public static boolean setup() {
|
||||
try {
|
||||
return setup( new FlatMonokaiProIJTheme() );
|
||||
} catch( RuntimeException ex ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void installLafInfo() {
|
||||
installLafInfo( NAME, FlatMonokaiProIJTheme.class );
|
||||
}
|
||||
|
||||
public FlatMonokaiProIJTheme() {
|
||||
super( Utils.loadTheme( "Monokai_Pro.default.theme.json" ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return NAME;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.intellijthemes;
|
||||
|
||||
//
|
||||
// DO NOT MODIFY
|
||||
// Generated with com.formdev.flatlaf.demo.intellijthemes.IJThemesClassGenerator
|
||||
//
|
||||
|
||||
import com.formdev.flatlaf.IntelliJTheme;
|
||||
|
||||
/**
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatXcodeDarkIJTheme
|
||||
extends IntelliJTheme.ThemeLaf
|
||||
{
|
||||
public static final String NAME = "Xcode-Dark";
|
||||
|
||||
public static boolean setup() {
|
||||
try {
|
||||
return setup( new FlatXcodeDarkIJTheme() );
|
||||
} catch( RuntimeException ex ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void installLafInfo() {
|
||||
installLafInfo( NAME, FlatXcodeDarkIJTheme.class );
|
||||
}
|
||||
|
||||
public FlatXcodeDarkIJTheme() {
|
||||
super( Utils.loadTheme( "Xcode-Dark.theme.json" ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return NAME;
|
||||
}
|
||||
}
|
||||
@@ -127,7 +127,11 @@
|
||||
"secondaryForeground": "#7ac2cc"
|
||||
},
|
||||
|
||||
"List.background": "#eef0f4",
|
||||
"List": {
|
||||
"background": "#eef0f4",
|
||||
"hoverBackground": "#dae6eb",
|
||||
"hoverInactiveBackground": "#dae6eb"
|
||||
},
|
||||
|
||||
"Notification": {
|
||||
"MoreButton.innerBorderColor": "#bec5cd",
|
||||
@@ -143,6 +147,12 @@
|
||||
}
|
||||
},
|
||||
|
||||
"NotificationsToolwindow": {
|
||||
"newNotification.background": "#dae6ebB3",
|
||||
"newNotification.hoverBackground": "#dae6eb",
|
||||
"Notification.hoverBackground": "#dae6eb"
|
||||
},
|
||||
|
||||
"PasswordField.background": "#FFFFFF",
|
||||
|
||||
"Plugins": {
|
||||
@@ -151,7 +161,8 @@
|
||||
"SectionHeader.foreground": "#808080",
|
||||
"SectionHeader.background": "#edeef2",
|
||||
"Tab.selectedBackground": "#cacccf",
|
||||
"Tab.hoverBackground": "#cacccf"
|
||||
"Tab.hoverBackground": "#cacccf",
|
||||
"hoverBackground": "#e6eef2"
|
||||
},
|
||||
|
||||
"Popup": {
|
||||
@@ -249,7 +260,12 @@
|
||||
}
|
||||
},
|
||||
|
||||
"Tree.background": "#eef0f4",
|
||||
"Tree": {
|
||||
"background": "#eef0f4",
|
||||
"hoverBackground": "#dae6eb",
|
||||
"hoverInactiveBackground": "#dae6eb",
|
||||
"hash": "#d0d5db"
|
||||
},
|
||||
|
||||
"WelcomeScreen": {
|
||||
"Details.background": "#eef0f4",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user