Compare commits

...

1290 Commits

Author SHA1 Message Date
Karl Tauber
4d7a6ff331 AnimatedPainter:
Some checks failed
CI / build (1.8) (push) Has been cancelled
CI / build (11) (push) Has been cancelled
CI / build (14) (push) Has been cancelled
CI / build (15) (push) Has been cancelled
CI / build (9) (push) Has been cancelled
CI / snapshot (push) Has been cancelled
CI / release (push) Has been cancelled
- renamed `getValues()` to `getAnimatableValues()`
- renamed `getClientPropertyKey()` to `getAnimationClientPropertyKey()`
- AnimatedPainterSupport improvements
2025-03-13 11:46:14 +01:00
Karl Tauber
23fc3674c9 LineChartPanel:
- support "synchron" charts
- reworked to make code easier to understand/maintain
- added some JavaBean properties to make it configurable in JFormDesigner
- fixes some bugs

removed `FlatAnimatorTest.LineChartPanel` and replaced it with `LineChartPanel`
2025-03-12 18:35:56 +01:00
Karl Tauber
34a7214dd8 LineChartPanel copied from branch smooth-scrolling, commit 44a04cca2c 2025-03-11 19:33:36 +01:00
Karl Tauber
26d7008c04 AnimatedPainter: support individual animation duration, resolution and interpolator depending on value(s) 2021-11-22 22:07:45 +01:00
Karl Tauber
3b489e8e1a AnimatedPainter: support independent animation of multiple values 2021-11-22 22:07:20 +01:00
Karl Tauber
ccbf577f46 AnimatedBorder: demo for labeled material border 2021-11-21 23:20:47 +01:00
Karl Tauber
b903f18130 FlatAnimatorTest:
- support synchronized line chart
- LineChartPanel: added slider to change horizontal scaling
- FlatAnimatedIconTest: added line chart panel
- FlatAnimatedBorderTest: added line chart panel
2021-11-21 12:27:31 +01:00
Karl Tauber
9523c89c51 FlatAnimatorTest: added standard-easing and line chart
(line chart copied from `FlatSmoothScrollingTest.LineChartPanel` in branch `smooth-scrolling` commit 331ab06b0087d3a70f7c131368b88e5e7c92102f)
2021-11-20 15:14:03 +01:00
Karl Tauber
aa6fb2fcce AnimatedPainter added (refactored from AnimatedBorder and AnimatedIcon)
(checked API compatibility of AnimatedIcon with gradle task sigtestCheck)
2021-11-20 11:13:06 +01:00
Karl Tauber
e4fa2e28ea AnimatedBorder:
- support repainting only necessary region while animating
- use AbstractBorder in test app and fixed insets
2021-11-19 18:02:54 +01:00
Karl Tauber
b2245e2246 AnimatedBorder added (for future animations) (issue #66) 2021-11-19 18:02:54 +01:00
Karl Tauber
13a6b92e47 Merge PR #429: Window title bar improvements (Windows 10/11 only) 2021-11-19 18:01:34 +01:00
Karl Tauber
9ba008002b Merge PR #396: Typography 2021-11-19 14:57:36 +01:00
Karl Tauber
8914cf78a1 Typography: Theme Editor: added h1.regular, h2.regular and h3.regular to preview 2021-11-19 11:37:46 +01:00
Karl Tauber
d360375b4f Typography:
- use semibold for `h1`, `h2` and `h3`
- added `h1.regular`, `h2.regular` and `h3.regular`
2021-11-19 11:13:32 +01:00
Karl Tauber
1caab194af TabbedPane:
- added styling support for properties added in PR #343
- updated change log
2021-11-18 18:01:07 +01:00
Karl Tauber
31754eba5d Merge PR #343: New tabbed pane active tab border painting style 2021-11-18 17:27:23 +01:00
Karl Tauber
3cfa16b8b7 TabbedPane: completed review of PR #343 (active tab border painting style)
- replaced `activeTabBorder` with `tabType`
- added `TabbedPane.cardTabSelectionHeight`
2021-11-18 16:47:21 +01:00
Karl Tauber
f80d2bacf4 Typography: use light and semibold in FlatTypographyTest 2021-11-17 19:39:51 +01:00
Karl Tauber
5df3717d94 Typography: added "Material Design 3" to FlatTypographyTest 2021-11-17 00:25:38 +01:00
Karl Tauber
68897f04a2 Typography: removed thin font/style because
- there is no thin font available on Windows
- previously used "Segoe UI Light" for `thin.font` and "Segoe UI Semilight" for `light.font`, but "Segoe UI Semilight" is too close to regular font so that it is better to use "Segoe UI Light" for `light.font` and drop `thin.font`
- the usefulness of having thin font in addition to light font is low

on macOS use "HelveticaNeue-Thin" for `light.font` (instead of "HelveticaNeue-Light")
2021-11-17 00:23:54 +01:00
Karl Tauber
4cb6aeae36 OptionPane: hide window icon by default; can be shown via UI default OptionPane.showIcon = true (issue #416) 2021-11-16 21:20:01 +01:00
Karl Tauber
0a765a35bf Merge remote-tracking branch 'origin/release-1.6.4' into main
# Conflicts:
#	CHANGELOG.md
2021-11-16 15:52:15 +01:00
Karl Tauber
6c0b122fbc release 1.6.4 2021-11-16 15:37:19 +01:00
Karl Tauber
4da2bd90cb ComboBox: fixed regression in FlatLaf 1.6.3 that makes selected item invisible in popup list if DefaultListCellRenderer is used as renderer (issue #426) 2021-11-16 15:36:14 +01:00
Karl Tauber
f0275192c6 Demo: added "Options > Show window title bar icon" to menu 2021-11-16 11:08:04 +01:00
Karl Tauber
df905a1d73 Demo: made hint popups look nicer (balloon with arrow and shadow) 2021-11-16 10:49:53 +01:00
Karl Tauber
ad8ad06f44 Window decorations: FlatTitlePane: fixed size of hit test spot on right side of menu bar if it contains a glue and a stretching component (e.g. progress bar)
removed HIT_TEST_SPOT_GROW because it is no longer necessary since commit 54e6cefa67
2021-11-15 20:43:25 +01:00
Karl Tauber
d6b9e2df62 RootPane: give the root pane useful background, foreground and font
(fixes wrong background in title bar and menu bar when switching from Nimbus to FlatLaf)
2021-11-15 16:58:44 +01:00
Karl Tauber
5c9b36556f Window decorations: FlatMenuBarBorder: use same conditions for bottom separator painting as for menu bar background painting (fixes/improves previous commit) 2021-11-15 01:00:10 +01:00
Karl Tauber
80a8348a99 Window decorations:
- enabled `TitlePane.unifiedBackground` by default (because seems to be standard on Windows 11)
- no longer paint a bottom separator for the menu bar (if unified background is enabled)
2021-11-15 01:00:10 +01:00
Karl Tauber
005c9f471e Window decorations:
- option to hide window icon (via client property or UI default)
- no longer show the Java "duke/cup" icon if no window icon image is set (issue #416)
2021-11-15 01:00:10 +01:00
Karl Tauber
b40532a830 UI defaults inspector: fixed color value renderer for some 3rd party Lafs 2021-11-15 00:59:13 +01:00
Karl Tauber
fc7a4408e9 FlatWindowDecorationsTest: update decoration style radio buttons from window 2021-11-15 00:35:19 +01:00
Karl Tauber
93b5f0081d Window decorations: reduced number of FlatTitlePane.updateNativeTitleBarHeightAndHitTestSpots() invokations 2021-11-15 00:24:56 +01:00
Karl Tauber
ce049ea3ee Window decorations: fixed exception in SwingUtilities.convertPoint() when doing new JDialog( (Window) null )
regression since commits 54e6cefa67 and
fb37be5734
2021-11-15 00:20:04 +01:00
Karl Tauber
fcc39b2db5 Merge branch 'release-1.6.3' into main
# Conflicts:
#	CHANGELOG.md
#	flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTreeUI.java
2021-11-14 23:23:29 +01:00
Karl Tauber
cb70fb4e82 GitHub Actions: run Gradle wrapper validation only once
(to reduce risk of connection timeout)
2021-11-14 23:06:23 +01:00
Karl Tauber
2593a43d72 release 1.6.3 2021-11-14 22:42:10 +01:00
Karl Tauber
e44ff5b72a Tree: Fixed editing cell issue with custom cell renderer and cell editor that use same component for rendering and editing (fixes #385)
(cherry picked from commit 161ee090a8)
2021-11-14 22:34:28 +01:00
Karl Tauber
22cb1b50a6 ComboBox (not editable): fixed regression that may display text in non-editable combo boxes in bold (issue #423)
fixes commits 02f3239669
and 0b6df8be1c
2021-11-14 22:11:19 +01:00
Karl Tauber
a42c413705 Testing: added modular app 2021-11-12 17:28:04 +01:00
Karl Tauber
d59d38dc7c added method FlatLaf.registerCustomDefaultsSource(URL packageUrl) for JPMS (issue #325) 2021-11-12 17:00:26 +01:00
Karl Tauber
77582be7fd Demo: fixed exception if hint is shown and switching to a non-FlatLaf L&F 2021-11-12 11:39:33 +01:00
Karl Tauber
0cb50355b7 added hint to FlatLaf.registerCustomDefaultsSource() javadoc that the package must be opened in module-info.java (issue #325) 2021-11-12 11:16:53 +01:00
Karl Tauber
a2d66e91ff Extras: FlatSVGIcon and FlatSVGUtils: use soft cache for SVG diagrams to allow freeing memory if no longer used 2021-11-12 10:49:02 +01:00
Karl Tauber
ccdb981917 refactored private class UIDefaultsLoader.Cache to public class SoftCache and implement the Map interface 2021-11-12 10:12:34 +01:00
Karl Tauber
d80b581ace Extras: FlatSVGUtils: support loading SVG from URL (for JPMS) (issue #325) 2021-11-12 09:28:24 +01:00
Karl Tauber
53efb6711d Extras: FlatSVGIcon: support loading SVG from URL (for JPMS), URI, File or InputStream (issues #419 and #325)
also improved error handling and javadoc
2021-11-12 09:27:04 +01:00
Karl Tauber
1de6e875f9 Merge branch 'release-1.6.2' into main
# Conflicts:
#	CHANGELOG.md
2021-11-11 13:05:33 +01:00
Karl Tauber
95a15c3cf8 release 1.6.2 2021-11-11 12:45:50 +01:00
Karl Tauber
ab320684f5 Native window decorations: fixed layout loop (issue #420)
(cherry picked from commit d3355eda65)
2021-11-11 12:35:51 +01:00
Karl Tauber
a284b69a1e FileChooser: workaround for crash on Windows with Java 17 32bit (issue #403)
(cherry picked from commits 44d8545c09 and 33b25c1129)
2021-11-11 12:35:16 +01:00
Karl Tauber
b590f41254 Linux: fixed NPE when using java.awt.TrayIcon (issue #405)
(cherry picked from commit 16a769ea61)
2021-11-11 12:31:14 +01:00
Karl Tauber
a97076ead5 ComboBox: fix NPE in CellPaddingBorder.install() (issue #408)
(cherry picked from commit d48b98f582)
2021-11-11 12:30:10 +01:00
Karl Tauber
0b6df8be1c ComboBox (not editable): fixed background painted outside of border if round edges are enabled (similar to issue #382; regression since fixing #330 in FlatLaf 1.4)
(cherry picked from commit 02f3239669)
2021-11-11 12:26:09 +01:00
Karl Tauber
150bab0b57 Table: do not select text in cell editor when it gets focus (when JTable.surrendersFocusOnKeystroke is true) and TextComponent.selectAllOnFocusPolicy is once (the default) or always (issue #395)
(cherry picked from commit f8b9f4c1fa)
2021-11-11 12:19:58 +01:00
Karl Tauber
d3355eda65 Native window decorations: fixed layout loop (issue #420) 2021-11-11 11:49:39 +01:00
Karl Tauber
fbf10e553d Native window decorations: updated DLLs (issues #397 and #407)
built by GitHub Actions:
https://github.com/JFormDesigner/FlatLaf/actions/runs/1440605430
2021-11-09 18:35:55 +01:00
Karl Tauber
fb37be5734 Native window decorations: show (system) tooltips for minimize/maximize/close buttons on Windows 10 and for minimize/close buttons on Windows 11 (issues #397 and #407) 2021-11-09 18:21:17 +01:00
Karl Tauber
54e6cefa67 Native window decorations: show Windows 11 snap layouts menu when hovering the mouse over the maximize button (issues #397 and #407) 2021-11-09 15:36:21 +01:00
Karl Tauber
33b25c1129 FileChooser: updated CHANGELOG.md for previous commit (issue #403) 2021-11-06 00:34:06 +01:00
Karl Tauber
44d8545c09 FileChooser: workaround for crash on Windows with Java 17 32bit (issue #403) 2021-11-06 00:03:17 +01:00
Karl Tauber
7a2808243c Typography: Demo: make typography/fonts visible in "screen shot" mode; hide password fields and labels 2021-11-04 14:54:01 +01:00
Karl Tauber
1be84de26b Typography: added thin/light/semibold fonts to demo 2021-11-04 12:48:46 +01:00
Karl Tauber
78e37f7ab4 Typography: since there is no thin font available on Windows, use "Segoe UI Light" (which looks thin IMHO) for thin.font and "Segoe UI Semilight" for light.font 2021-11-04 12:16:11 +01:00
Karl Tauber
e49459fd8b UIDefaultsLoader: do not add properties with empty values to UI defaults (value was an empty string) 2021-11-04 00:21:57 +01:00
Karl Tauber
52f6e7fc32 Theme Editor: Switches" preview:
- zoom 2x, 3x and 4x icons via toolbar
- hide indeterminate state for checkboxes via toolbar
2021-11-04 00:17:24 +01:00
Karl Tauber
c8ea61dc79 Merge PR #414: CheckBox and RadioButton improvements 2021-11-04 00:08:07 +01:00
Karl Tauber
16a769ea61 Linux: fixed NPE when using java.awt.TrayIcon (issue #405) 2021-11-03 23:37:37 +01:00
Karl Tauber
475781db91 Extras: FlatDesktop: fixed javadoc issues 2021-11-03 15:22:41 +01:00
Karl Tauber
4dae082cd5 fixed unit tests, which fail now on GitHub Actions, but did work a few days ago... 2021-11-03 15:21:52 +01:00
Karl Tauber
57405b2f56 CheckBox and RadioButton: derive CheckBox.icon.disabledCheckmarkColor from CheckBox.icon.checkmarkColor in light themes (as in dark themes) 2021-11-03 14:29:56 +01:00
Karl Tauber
88576f68fd CheckBox and RadioButton: added RadioButton.icon.style (similar to CheckBox.icon.style) to support different styles for checkbox and radiobutton
(e.g. Material design uses filled checkboxes, but outlined radiobuttons)
2021-11-03 11:27:18 +01:00
Karl Tauber
aa4e013097 CheckBox and RadioButton: made focused icon better recognizable in **FlatLaf Light** and **Dark** themes by painting a 1px focus border; **Darcula** and **IntelliJ** themes are not changed 2021-11-03 11:15:17 +01:00
Karl Tauber
d67cfc911b CheckBox and RadioButton:
- added `CheckBox.icon.selectedBorderWidth`
- added `CheckBox.icon.disabledSelectedBorderWidth`
- added `CheckBox.icon.disabledSelectedBorderColor`
- added `CheckBox.icon.disabledSelectedBackground`
- changed `CheckBox.icon.focusWidth` from `int` `float`
2021-11-03 10:59:39 +01:00
Karl Tauber
00a3ad738f CheckBox and RadioButton: made selected icon better recognizable in **FlatLaf Light** (use blue border), **Dark** and **Darcula** (use lighter border) themes; **IntelliJ** theme is not changed 2021-10-31 18:26:31 +01:00
Karl Tauber
1d39d34d7c CheckBox and RadioButton:
- added `CheckBox.icon.hoverCheckmarkColor`
- added `CheckBox.icon.selectedHoverBorderColor`
- added `CheckBox.icon.pressedBorderColor`
- added `CheckBox.icon.selectedPressedBorderColor`
- added `CheckBox.icon.pressedCheckmarkColor`
- renamed `CheckBox.icon.selectedFocusedBorderColor` to `CheckBox.icon.focusedSelectedBorderColor`
- renamed `CheckBox.icon.selectedFocusedBackground` to `CheckBox.icon.focusedSelectedBackground`
- renamed `CheckBox.icon.selectedFocusedCheckmarkColor` to `CheckBox.icon.focusedCheckmarkColor`
- renamed `CheckBox.icon.selectedHoverBackground` to `CheckBox.icon.hoverSelectedBackground`
- renamed `CheckBox.icon.selectedPressedBackground` to `CheckBox.icon.pressedSelectedBackground`
- renamed `CheckBox.icon[filled].selectedFocusedBorderColor` to `CheckBox.icon[filled].focusedSelectedBorderColor`
- renamed `CheckBox.icon[filled].selectedFocusedBackground` to `CheckBox.icon[filled].focusedSelectedBackground`
- renamed `CheckBox.icon[filled].selectedFocusedCheckmarkColor` to `CheckBox.icon[filled].focusedCheckmarkColor`
- renamed `CheckBox.icon[filled].selectedHoverBackground` to `CheckBox.icon[filled].hoverSelectedBackground`
- renamed `CheckBox.icon[filled].selectedPressedBackground` to `CheckBox.icon[filled].pressedSelectedBackground`

(Note: this are incompatible changes!)
2021-10-31 17:39:48 +01:00
Karl Tauber
5f6013edd4 Theme Editor: Switches" preview:
- show indeterminate state for checkboxes
- removed "text" from checkboxes and radio buttons
2021-10-31 11:17:37 +01:00
Karl Tauber
3e198ecd28 JIDE: RangeSlider: support specifying width of thumb borders (fixes compile error in commit dd806144) 2021-10-30 20:37:12 +02:00
Karl Tauber
d48b98f582 ComboBox: fix NPE in CellPaddingBorder.install() (issue #408) 2021-10-30 20:25:57 +02:00
Karl Tauber
9b839231f7 ToggleButton: use UI values from Button 2021-10-30 14:04:31 +02:00
Karl Tauber
dd80614465 ComboBox, Spinner, TextField and subclasses, CheckBox, RadioButton and Slider: support specifying width of borders 2021-10-30 14:02:49 +02:00
Karl Tauber
8c2be1b406 FlatButtonBorder: removed fields that override fields from FlatBorder 2021-10-29 14:09:58 +02:00
Karl Tauber
8152b7dad6 UIDefaultsLoader: further reduced need for value type prefixes in properties files and in CSS styles 2021-10-29 13:55:28 +02:00
Karl Tauber
fb4fe175d9 UIDefaultsLoader: reduced need for {float} in properties files and in CSS styles 2021-10-29 13:33:55 +02:00
Karl Tauber
5e03eb9b51 UIDefaultsDump: removed Java 8 patch version from dump file names 2021-10-28 21:01:16 +02:00
Karl Tauber
ef25575f85 ignore internal UI keys in dumps and in UI defaults inspector 2021-10-28 20:47:47 +02:00
Karl Tauber
b77b338c7a Styling: support using variables (defined in properties files) in CSS styles 2021-10-28 19:03:13 +02:00
Karl Tauber
0e4fe4e9bb Theme Editor: support platform and light/dark specific properties in preview 2021-10-26 18:46:08 +02:00
Karl Tauber
f742f83834 Typography: added thin font/style 2021-10-26 13:16:52 +02:00
Karl Tauber
e6e4e53a73 Typography: added light and semibold font/style 2021-10-25 13:27:40 +02:00
Karl Tauber
7c594ba7a9 Typography: UIDefaultsDump: dumps updated on macOS Big Sur 2021-10-25 13:06:34 +02:00
Karl Tauber
0156a9a9d5 Merge PR #401: Text components: double/triple-click-and-drag selection improvements 2021-10-24 20:06:06 +02:00
Karl Tauber
3facbc0900 macOS: improved macOS support of Demo and Theme Editor:
- set application name that is used in screen menu bar
- enable dark window title bars if macOS is in dark mode
2021-10-24 17:05:50 +02:00
Karl Tauber
78cef1b3c7 Theme Editor:
- use class `FlatDesktop`
- hide "File > Exit" and "Help > About" on macOS
- enable macOS screen menu bar
2021-10-24 11:49:48 +02:00
Karl Tauber
d907c469ed Theme Editor: renamed class FlatThemeEditor to FlatLafThemeEditor because this name is shown in macOS screen menu bar (and to be consistent with FlatLafDemo) 2021-10-24 11:43:28 +02:00
Karl Tauber
cc238d3e34 Extras: added class FlatDesktop for easy integration into macOS screen menu (About, Preferences and Quit) when using Java 8
Demo:
- use class `FlatDesktop`
- hide "File > Exit" and "Help > About" on macOS
2021-10-24 09:44:34 +02:00
Karl Tauber
0f9b38895e FlatComponents2Test: allow enabling tree editing 2021-10-23 09:20:53 +02:00
Karl Tauber
8fa1eae352 TextComponents: triple-click-and-drag now extends selection by whole lines
triple-click-and-drag does not work in theme editor because drag is enabled, anyway a triple-click now selects the whole line before dragging starts
2021-10-22 13:14:01 +02:00
Karl Tauber
e13fb25f14 TextComponents: keep selection when switching theme 2021-10-21 22:57:28 +02:00
Karl Tauber
e36f942129 TextComponents: double-click-and-drag now extends selection by whole words 2021-10-21 13:24:07 +02:00
Karl Tauber
d34619824c Typography: support deriving font from any other font (was always from defaultFont) (issue #384) 2021-10-17 16:54:05 +02:00
Karl Tauber
80297f113f UIDefaultsLoader: detect string values, that start and end with '"', after determining value type from key to allow font values like "Roboto Mono" 2021-10-17 14:59:18 +02:00
Karl Tauber
80f51bfe1e Theme Editor: fixed StackOverflowError when setting "defaultFont" to non-font value (e.g. defaultFont = #fff) 2021-10-17 14:43:12 +02:00
Karl Tauber
f8b9f4c1fa Table: do not select text in cell editor when it gets focus (when JTable.surrendersFocusOnKeystroke is true) and TextComponent.selectAllOnFocusPolicy is once (the default) or always (issue #395) 2021-10-16 23:32:08 +02:00
Karl Tauber
587f431ef4 Typography: added FlatFontsTest to quickly view all available fonts on the current system 2021-10-16 18:56:53 +02:00
Karl Tauber
65a4f66d2c Merge branch 'release-1.6.1' into main
# Conflicts:
#	CHANGELOG.md
2021-10-14 22:50:44 +02:00
Karl Tauber
a253b6c0cf release 1.6.1 2021-10-14 22:35:33 +02:00
Karl Tauber
efcbc1fbdb Native window decorations: catch UnsatisfiedLinkError when trying to load jawt.dll to avoid an application crash (Java 8 on Windows 10 only) 2021-10-14 18:59:26 +02:00
Karl Tauber
e560f9cbd6 Typography: added typography/fonts preview to theme editor 2021-10-13 15:47:55 +02:00
Karl Tauber
80235d53f4 Typography: added FlatTypographyTest, which was used to compare various typography systems 2021-10-13 14:29:57 +02:00
Karl Tauber
892b9a732e Typography: added typography/fonts to demo 2021-10-13 14:17:40 +02:00
Karl Tauber
d8a0a015e4 Typography: Extras: add labelType property to FlatLabel 2021-10-13 13:48:03 +02:00
Karl Tauber
e60e3b9fae Typography: added monospaced font/style 2021-10-13 13:46:43 +02:00
Karl Tauber
6715f01b8c Typography: use typography styles in demo, theme editor, etc 2021-10-13 11:48:28 +02:00
Karl Tauber
465af9bc41 Typography: added fonts/styles for headings and various text sizes 2021-10-13 10:53:37 +02:00
Karl Tauber
d10bcfc72f Theme Editor: fixed StackOverflowError when adding "defaultFont" key to properties file 2021-10-12 23:50:45 +02:00
Karl Tauber
942e5b9cd1 IntelliJ Themes: do not ignore UI keys prefixed with [style] to allow using styles 2021-10-12 22:29:38 +02:00
Karl Tauber
51a90d32f8 support defining "defaultFont" in FlatLaf properties files (issue #384) 2021-10-12 11:13:40 +02:00
Karl Tauber
ac46632e73 UIDefaultsLoader: do not detect string values that start and end with '"', but also contain ", as string (e.g. font value "Roboto Mono", "Ubuntu Mono") 2021-10-10 17:59:00 +02:00
Karl Tauber
1192bef1ae Styling: use cache for parsed fonts, which is mostly used for fonts in CSS styles (e.g. font: bold +4) (issue 384) 2021-10-08 22:08:37 +02:00
Karl Tauber
b9ec382589 support defining fonts in FlatLaf properties files (issue #384) 2021-10-08 20:23:54 +02:00
Karl Tauber
5ecf19ef4f Styling: added styling properties that are likewise to client properties
(e.g. `buttonType: help` on `JButton` does the same as setting client property `JButton.buttonType` to `help`)
2021-10-07 14:22:47 +02:00
Karl Tauber
9636809b4d CHANGELOG.md: added PR #388 (style classes) 2021-10-06 12:25:17 +02:00
Karl Tauber
ba1c1ed952 ToolBar: added arrowKeysOnlyNavigation to unit tests (issue #346) 2021-10-06 00:04:49 +02:00
Karl Tauber
7452390614 ToolBar: support non-button components in arrow-keys-only navigation (issue #346) 2021-10-05 23:11:53 +02:00
Karl Tauber
69042e42b7 ToolBar: support arrow-keys-only navigation within focusable buttons of toolbar:
- arrow keys move focus within toolbar (provided by `BasicToolBarUI`)
- tab-key moves focus out of toolbar
- if moving focus into the toolbar, focus recently focused toolbar button

(issue #346)
2021-10-05 16:36:50 +02:00
Karl Tauber
1e93deab2a ToolBar: fixed focus moving to next button when switching Laf and focusable buttons are enabled via CSS style focusableButtons: true
also avoid unnecessary invokation of `c.setFocusable()`
2021-10-05 15:34:23 +02:00
Karl Tauber
16ea809bb3 ToolBar: skip components with empty input map (e.g. JLabel) when using arrow keys to navigate in focusable buttons (related to issue #346) 2021-10-05 12:15:51 +02:00
Karl Tauber
78aa4343b7 ColorFunctions: added lighten(), darken(), saturate(), desaturate() and spin() 2021-10-04 22:56:10 +02:00
Karl Tauber
6815109e15 ColorFunctions: moved methods applyFunctions() and clamp() down to nested classes 2021-10-04 22:41:32 +02:00
Karl Tauber
e34fbcec58 ToolBar: foolbars are no longer floatable by default 2021-10-04 15:31:55 +02:00
Karl Tauber
bb2a21270b Theme Editor: added "Pick Color from Screen" action to "Edit" menu that allows picking a color from anywhere on screen and insert/change it at caret position 2021-10-04 12:44:03 +02:00
Karl Tauber
49b9ec9025 Theming improvements: updated CHANGELOG.md 2021-10-04 12:00:29 +02:00
Karl Tauber
a2e896e102 Merge PR #390: Theming improvements 2021-10-04 11:55:18 +02:00
Karl Tauber
2e1ef647a9 Theming improvements:
- renamed `MenuItemCheckBox.icon.checkmarkColor` to `CheckBoxMenuItem.icon.checkmarkColor`
- renamed `MenuItemCheckBox.icon.disabledCheckmarkColor` to `CheckBoxMenuItem.icon.disabledCheckmarkColor`

(Note: this are incompatible changes!)
2021-10-03 23:28:53 +02:00
Karl Tauber
f0c314df80 Theming improvements:
- renamed `@disabledText` to `@disabledForeground`
- renamed `@textComponentBackground` to `@componentBackground`
- renamed `@textComponentMargin` to `@componentMargin`
- added `@disabledBackground`

(Note: this are incompatible changes!)
2021-10-03 23:15:51 +02:00
Karl Tauber
4db39828ef Theming improvements: reordered variables and added comments 2021-10-02 00:53:54 +02:00
Karl Tauber
b2d40825ac Theming improvements:
- reworked core themes
- reduced explicit colors by using color functions
- made it easier to create new themes
- avoid using colors from one component type for another component type
  (except when useful; e.g. `Separator.foreground` is also used for other separators)
- HelpButton: use colors from Button (instead of from CheckBox.icon)
- ToolBar: improved "docking" and "floating" colors
2021-10-01 23:48:46 +02:00
Karl Tauber
6df5d3334e Styling: test if() and contrast() functions in unit tests 2021-10-01 15:08:17 +02:00
Karl Tauber
0e982df90c Styling:
- check for duplicate keys in StyleableInfos to find "overlapping" fields/properties (e.g. `borderColor` in `FlatBorder` and in `FlatComboBoxUI`)
- Button and ToggleButton: fixed styling `toolbar.spacingInsets`
2021-10-01 13:49:38 +02:00
Karl Tauber
3834d93c9d ComboBox and Spinner:
- added `buttonSeparatorColor` and `buttonDisabledSeparatorColor`
- fixed styling of `borderColor` and `disabledBorderColor`
2021-10-01 13:43:24 +02:00
Karl Tauber
16920a5b82 Styling: added slider properties to tests 2021-09-30 11:39:02 +02:00
Karl Tauber
d66e35fdde Styling: support enums 2021-09-30 10:40:43 +02:00
Karl Tauber
d93dde0a03 StringUtils:
- use new StringUtils.split(..., boolean trim, boolean excludeEmpty) where possible
- added substringTrimmed() and isTrimmedEmpty() to avoid temporary string  allocation
2021-09-30 01:14:45 +02:00
Karl Tauber
2d232124dd Merge PR #388: Styling: basic support for "classes" (similar to CSS classes) 2021-09-30 00:06:34 +02:00
Karl Tauber
ac6702fcf7 Styling: Extras: add styleClass getter and setter to component classes 2021-09-29 23:56:41 +02:00
Karl Tauber
c4b016c9c8 Styling: support specifying multiple style classes in single string 2021-09-29 23:49:40 +02:00
Karl Tauber
6baa583a28 ColorFunctions: improved performance of mix(), tint() and shade() color functions
(used UIDefaultsDump to verify whether results are the same as before)
2021-09-28 19:48:54 +02:00
Karl Tauber
82df2ecfa9 ComboBox: paint focus border if combobox component itself is focused (instead of internal text field) or if client property JComponent.focusOwner is set
Theme Editor:
- do not set client property `JComponent.focusOwner` on internal components of combobox and spinner
- repaint preview on window activation (necessary because if something changed in editor and switching to another app, the editor is saved and the preview is updated while the editor window is not-active, which hides all focus indicators)
2021-09-28 19:34:53 +02:00
Karl Tauber
06b3de720a Merge PR #375: Accent colors
# Conflicts:
#	flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java
#	flatlaf-core/src/main/java/com/formdev/flatlaf/UIDefaultsLoader.java
2021-09-28 15:13:25 +02:00
Karl Tauber
b0edd5659f Accent color: made accent focus border colors lighter/darker in IntelliJ/Darcula themes
(issue #233)
2021-09-28 14:18:34 +02:00
Karl Tauber
bb5c2eea10 Accent color:
- added `Component.accentColor`
- dark themes: changed threshold for contrast() from 39% down to 25% for better readability of text
- Demo: added "Default" accent color and changed "Blue" to lighter color

(issue #233)
2021-09-28 11:12:17 +02:00
Karl Tauber
e31e4dfe3a Accent color: avoid that @accentXYZ variables depend on other @accentXYZ variables to allow independent modification
(issue #233)
2021-09-27 12:31:49 +02:00
Karl Tauber
caf2cd8487 Accent color: fixed text colors if using light accent color
(issue #233)
2021-09-27 12:24:45 +02:00
Karl Tauber
15c6f11a5e Accent color:
- introduced @accentBaseColor variable that is now used as base for accent colors in Light/Dark/IntelliJ/Darcula themes, which use variations of the accent color
- @accentColor is now `null` by default, but if set to a color, then it is used unmodified for all accents

(issue #233)
2021-09-26 23:56:56 +02:00
Karl Tauber
a4ea88f4be UIDefaultsLoader: added if() function (inspired by Less CSS) 2021-09-26 23:54:06 +02:00
Karl Tauber
36d5747fbf Accent color: changed javadoc since version from 1.6 to 2 2021-09-25 23:53:57 +02:00
Karl Tauber
3d8c535ffa Styling: catch runtime exceptions while applying styles (and log them) to avoid that wrong/invalid styles could result in "damaged" UI 2021-09-25 19:34:46 +02:00
Karl Tauber
1c067d0284 behaviour --> behavior 2021-09-25 18:32:11 +02:00
Karl Tauber
b6be0462a5 Styling: basic support for "classes" (similar to CSS classes) using client property FlatLaf.styleClass 2021-09-25 14:34:21 +02:00
Karl Tauber
cce91ea16d changed multi-line javadoc since tags to single-line 2021-09-25 13:27:26 +02:00
Karl Tauber
d756041b06 Styling: fixed "Illegal reflective access" warning on stdout for BasicMenuItemUI fields when running on Java 9+ 2021-09-22 23:40:10 +02:00
Karl Tauber
2d0eb0a05b Styling: fixed build error on GitHub Actions 2021-09-22 23:15:00 +02:00
Karl Tauber
02f3239669 ComboBox (not editable): fixed background painted outside of border if round edges are enabled (similar to issue #382; regression since fixing #330 in FlatLaf 1.4) 2021-09-16 22:55:05 +02:00
Karl Tauber
14a9240c45 FlatUIUtils: joined the 3 component painting methods (for focus border, border and background) into a single method paintOutlinedComponent()
- this allows optimized painting if focus color and border color are equal
- avoids duplicate code
- support focusWidthFraction for future animations
2021-09-16 18:09:32 +02:00
Karl Tauber
c659638fb4 Styling: support styling for recently merged PR #378 2021-09-15 23:43:41 +02:00
Karl Tauber
fd15b63044 Merge PR #378: TextField: leading and trailing icons
# Conflicts:
#	flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPasswordFieldUI.java
#	flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextFieldUI.java
2021-09-15 23:32:57 +02:00
Karl Tauber
263e6c34b5 Merge PR #341: Styling individual components 2021-09-15 20:00:06 +02:00
Karl Tauber
eb62a3dc17 UI defaults inspector: avoid NPE if DerivedColorKeys.properties missing 2021-09-15 19:44:09 +02:00
Karl Tauber
161ee090a8 Tree: Fixed editing cell issue with custom cell renderer and cell editor that use same component for rendering and editing (fixes #385) 2021-09-15 19:39:44 +02:00
Karl Tauber
560ec437b9 Styling: avoid duplicate applying styles to buttons, labels and separators (which use shared UI delegates) 2021-09-15 10:57:52 +02:00
Karl Tauber
ccd0597b35 Styling: support styling for recently merged changes 2021-09-14 22:43:44 +02:00
Karl Tauber
c5c0a3768a Merge remote-tracking branch 'origin/main' into styling 2021-09-14 19:02:21 +02:00
Karl Tauber
5aa2d24d58 added sigtest to flatlaf-core subproject to check for incompatible API changes in packages com.formdev.flatlaf and com.formdev.flatlaf.util
added FlatLaf 1.6 API signature (generated in clean workspace with gradle task `sigtestGenerate`)
2021-09-14 18:14:21 +02:00
Karl Tauber
ae28c595f9 release 1.6 2021-09-14 15:00:29 +02:00
Karl Tauber
1d08ddda60 InternalFrame: added missing since 1.6 2021-09-14 14:56:21 +02:00
Karl Tauber
578379fd00 Table and TableHeader: renamed UI keys Table[Header].showLastVerticalLine to Table[Header].showTrailingVerticalLine (issue #332) 2021-09-14 14:31:17 +02:00
Karl Tauber
7c9f550d4c ComboBox: fixed popup location if shown above of combo box (Java 8 only) 2021-09-14 14:16:53 +02:00
Karl Tauber
84d4510d70 ComboBox: fixed popup border painting on HiDPI screens (e.g. at 150% scaling) 2021-09-14 12:46:51 +02:00
Karl Tauber
fa194ec258 TableHeader: fixed missing trailing vertical separator line if used in upper left corner of scroll pane (issue #332) 2021-09-14 00:52:59 +02:00
Karl Tauber
fd56de403d Slider: fixed calculation of baseline (see also PR #214) 2021-09-13 22:05:48 +02:00
Karl Tauber
85fde46504 Testing: FlatSingleComponentTest: revalidate and repaint when changing component orientation using Alt+R 2021-09-13 10:11:09 +02:00
Karl Tauber
b283178979 Spinner: fixed painting of border corners on left side (issue #382; regression since FlatLaf 1.4)
ComboBox (editable): fixed wrong border of internal text field under special circumstances
2021-09-10 16:37:07 +02:00
Karl Tauber
e0dddfceba Styling: Menu: support top-level underline selection 2021-09-08 14:55:41 +02:00
Karl Tauber
bddef38a7c Theme Editor: preview: added "editable" check box for text components 2021-09-08 00:22:02 +02:00
Karl Tauber
b5f2f77944 Theme Editor: layout of "All" preview tab improvements:
- right align "enabled" and "focused" check boxes
- two columns for controls
- removed help button
- JTextArea, JEditorPane and JTextPane in single line
- reduced some vertical gaps
2021-09-08 00:10:53 +02:00
Karl Tauber
fca0718ed0 Native window decorations: fixed unwanted uninstall of native window border when using JInternalFrame (which has its own JRootPane) and invoking updateUI() on internal frame (e.g. in preview of FlatLaf Theme Editor) 2021-09-07 17:55:45 +02:00
Karl Tauber
0d44ade6ea Theme Editor: preview improvements:
- remember state of "enabled", "focused" and "buttonType" and sync it with all editors
- added "_" button near "JMenuBar" label to test menu underline selection
2021-09-07 14:31:09 +02:00
Karl Tauber
08ca2aa266 Styling:
- support references in color functions
- added test for using color functions in styling
2021-09-06 22:53:04 +02:00
Karl Tauber
fe15758e59 Styling: updated "since" javadoc tags 2021-09-06 15:39:19 +02:00
Karl Tauber
674efae184 Styling: Extras: add style getters and setters to component classes 2021-09-06 15:23:15 +02:00
Karl Tauber
4a65bc88d5 Theme Editor: highlight selected editor tab 2021-09-05 23:25:16 +02:00
Karl Tauber
a8f3d59729 Merge remote-tracking branch 'origin/main' into styling
# Conflicts:
#	flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatListUI.java
#	flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTableUI.java
2021-09-05 23:12:38 +02:00
Karl Tauber
6018f83a22 Theme Editor: center some labels and help buttons in preview 2021-09-05 22:15:49 +02:00
Karl Tauber
0b6247851b Theme Editor: fixed preview of focused list and table selection 2021-09-05 22:05:21 +02:00
Karl Tauber
8640dee053 Theme Editor: preview improvements:
- added "focused" checkbox to "All" tab to preview focused components
- added "button type" selector to "Buttons" tab
- added "unfocused"/"focused" header labels to "Buttons" and "Switches" tabs
- use local variables instead of fields where possible
2021-09-05 21:08:36 +02:00
Karl Tauber
824db2e3bd Table and TableHeader: added UI defaults to show last vertical line (issue #332) 2021-09-05 11:51:28 +02:00
Karl Tauber
c2c79c4676 Theme Editor:
- remember last used preview tab
- sync selected preview tab with all editors
2021-09-05 11:13:29 +02:00
Karl Tauber
4795fe5687 Theme Editor:
- added preview of buttons, checkboxes, radiobuttons, etc in various states (hover, pressed, focused, selected, disabled)
  (copied from `FlatComponentStateTest`)
- moved components preview panel from FlatThemePreview.jfd` to FlatThemePreviewAll.jfd`
- added tabs at top of preview area
2021-09-05 10:55:51 +02:00
Karl Tauber
d508f339c1 TableHeader: do not show resize cursor for last column if resizing last column is not possible because auto resize mode of table is not off (issue #332) 2021-09-04 18:20:21 +02:00
Karl Tauber
c7054537e7 Testing: FlatSingleComponentTest: support changing component orientation using Alt+R 2021-09-04 13:28:02 +02:00
Karl Tauber
b98b904023 added missing UI defaults to javadoc 2021-09-04 13:24:19 +02:00
Karl Tauber
253df9325d Extras: FlatAnimatedLafChange: made animated Laf change transition smoother 2021-09-04 13:19:12 +02:00
Karl Tauber
78a9cc1d0c Theme Editor: fixed: editor was not focused after startup or when switching directory 2021-09-03 17:32:59 +02:00
Karl Tauber
b25fcc3381 OptionPane: fixed rendering of longer HTML text if it is passed as StringBuilder, StringBuffer, or any other object that returns HTML text in method toString() (similar to issue #12) 2021-09-03 11:26:30 +02:00
Karl Tauber
a2c0df5891 TextField: consider widths of leading and trailing icons for minimum/preferred text field size 2021-09-03 11:01:44 +02:00
Karl Tauber
dc33c26960 TextField: support leading and trailing icons (issue #368) 2021-09-02 17:45:33 +02:00
Karl Tauber
51d7bc2c37 TextField, FormattedTextField, PasswordField and ComboBox: fixed alignment of placeholder text in right-to-left component orientation 2021-09-02 16:18:53 +02:00
Karl Tauber
cdbdccf1ad Styling: support styling any component property that has public getter and setter methods 2021-09-01 13:32:31 +02:00
Karl Tauber
397c369114 Styling: renamed class FlatStyleSupport to FlatStylingSupport 2021-09-01 00:21:47 +02:00
Karl Tauber
6f9bbb184a Styling: support specifying explicit value type for parsing CSS values (for future use) 2021-08-31 23:53:12 +02:00
Karl Tauber
b12c818862 Styling: support styling for recently merged changes 2021-08-31 16:12:03 +02:00
Karl Tauber
9118dcf925 Merge remote-tracking branch 'origin/main' into styling
# Conflicts:
#	flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatButtonUI.java
#	flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatInternalFrameUI.java
#	flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextFieldUI.java
2021-08-31 15:41:46 +02:00
Karl Tauber
d333d0c9e4 Accent color:
- Demo: added accent color switching to toolbar
- added `FlatLaf.setGlobalExtraDefaults()` for easy setting accent color at runtime

(issue #233)
2021-08-31 14:06:41 +02:00
Karl Tauber
7f9cf6f45c UIDefaultsLoader: added contrast() color function (inspired by Less CSS), which is useful to choose a foreground color that is readable, based on the luma (perceptual brightness) of a background color 2021-08-30 23:58:37 +02:00
Karl Tauber
9b465cb550 Accent color: added FlatLaf.setExtraDefaults() for easy setting accent color at runtime (issue #233) 2021-08-30 23:06:06 +02:00
Karl Tauber
9144b7206e Accent color:
- added @accentXYZ variables that define all blueish accent colors
- all blueish accent colors are calculated based on @accentColor

(issue #233)
2021-08-30 23:06:06 +02:00
Karl Tauber
dd14843f2e Accent color: reduced number of individual blueish accent colors with color functions (issue #233) 2021-08-30 23:06:06 +02:00
Karl Tauber
09a18b2305 Theme Editor:
- highlight opened directory in history combobox list
- support removing directories from history ('x' button in combobox list)
2021-08-29 18:39:40 +02:00
Karl Tauber
31f2feee2e Theme Editor:
- special renderer for directory history combobox list that dimes path parts
- disable menu items and buttons if no directory or editor is open
- set editor font size when opening new editor if increased/decreased
2021-08-29 16:06:50 +02:00
Karl Tauber
218bb62bfd Theme Editor:
- fixed increasing layout and wrong top border color of find/replace bar when switching Laf
- fixed duplicate keys in reference auto-completion
2021-08-29 14:28:11 +02:00
Karl Tauber
694c2ad767 Theme Editor: preview improvements:
- added JSplitPane (contains JList and JTree)
- sort first column in JTable to have preview of sort direction arrow
- fixed background color of JEditorPane and JTextPane when enabling/disabling
- keep first JMenu enabled, but disable the menu items
2021-08-29 11:44:38 +02:00
Karl Tauber
97943fcd38 Theme Editor: changed main class to com.formdev.flatlaf.themeeditor.FlatThemeEditor 2021-08-28 17:38:51 +02:00
Karl Tauber
77f33467d2 Theme Editor: fixed endless look in "replace all" when replacing e.g. "a" with "aa" 2021-08-28 17:37:02 +02:00
Karl Tauber
651454170d Theme Editor:
- fixed duplicate lines action if selection includes line separator at the end
- preview: do not disable internal components of JInternalFrame
2021-08-28 14:30:11 +02:00
Karl Tauber
7ca48bd136 Theme Editor:
- support lazy values and icon colors in overlay color preview
- support icon colors in preview
- support icon colors in reference auto-completion
- support changing preview theme when editing FlatLaf.properties via adding `@baseTheme = dark|darcula|intellij`
2021-08-28 14:18:11 +02:00
Karl Tauber
968e508bb5 Theme Editor:
- change border color of find field to red if noting found/matches
- update search match highlighting after reloading file on external change
2021-08-27 22:53:04 +02:00
Karl Tauber
a6d318a197 Theme Editor: fixed missing keys (e.g. Button.foreground) in reference auto-completion, which are defined as wildcards or have some prefix 2021-08-27 22:32:59 +02:00
Karl Tauber
cd20f4086b Theme Editor: fixed preview of focused button in FlatDarkLaf (and probably other null value related issues) 2021-08-27 18:32:42 +02:00
Karl Tauber
ebd5905947 Theme Editor: preview improvements:
- added JToolBar, JProgressBar with string painted, JDesktopPane and JInternalFrame
- placed text components side-by-side to save vertical space
- changed button texts and removed tooltips
- fixed painting of table cell focus border
- added missing add.svg
2021-08-27 16:10:10 +02:00
Karl Tauber
817a3c62bb Theme Editor: preview improvements:
- fixed table header borders (runWithUIDefaultsGetter() in paint())
- cache lazy values
- use runWithUIDefaultsGetter() in layout(), validateTree() and paint()
2021-08-24 22:32:48 +02:00
Karl Tauber
f8f58400fe Theme Editor: added list, tree and table to preview 2021-08-24 21:49:09 +02:00
Karl Tauber
ef06840649 Theme Editor: basic README.md with shapshot download link 2021-08-24 18:38:21 +02:00
Karl Tauber
b17c14d62e Theme Editor: use UTF-8 encoding to load properties files 2021-08-24 17:50:03 +02:00
Karl Tauber
19dba94064 IntelliJ Themes: removed deprecated install() methods
but keep them in the flatlaf-core for API compatibility in NetBeans plugin
2021-08-24 17:38:19 +02:00
Karl Tauber
601e24f9e7 Theme Editor: fixed "..." in menus 2021-08-24 16:52:45 +02:00
Karl Tauber
c7f323ee13 Theme Editor: added window icon 2021-08-24 16:49:55 +02:00
Karl Tauber
e4522f3af4 Theme Editor: added "About" dialog
Demo: updated "About" dialog
2021-08-24 16:40:17 +02:00
Karl Tauber
79af461a5b Theme Editor: instead of creating empty FlatLightLaf.properties and FlatDarkLaf.properties, add some how-to-use description to those files 2021-08-24 15:38:15 +02:00
Karl Tauber
2e8e07faf6 Theme Editor: auto-completion for keys improved:
- now also contains variables and keys defined in current and base themes
- appended " = "
- removes some unsupported keys (fonts and input maps)
2021-08-24 15:13:30 +02:00
Karl Tauber
ecdb000818 Theme Editor: avoid changing editor text (and adding item to undo history) when simply pressing OK button in "Insert Color" dialog without changing anything 2021-08-23 23:56:27 +02:00
Karl Tauber
999fd0d4da Theme Editor: generate .java file when creating new theme 2021-08-23 23:52:22 +02:00
Karl Tauber
705dd9558f Theme Editor:
- added "New Properties File" action to "File" menu
- added "+" button to tabbed pane
- ask to create .properties files when opening a directory that does not contain .properties files
- fixed Darcula baseTheme/preview
2021-08-23 23:02:41 +02:00
Karl Tauber
97ca866ffa OptionPane: fixed OptionPane.sameSizeButtons, which did not work as expected when setting to false 2021-08-23 16:53:23 +02:00
Karl Tauber
543b977db7 updated SVG icons from IntelliJ IDEA Community Edition to latest versions that include license header; added license header to SVGs where it were missing 2021-08-23 15:57:26 +02:00
Karl Tauber
ebb8a6d025 Theme Editor: ignore custom UI delegates in preview 2021-08-23 15:00:28 +02:00
Karl Tauber
506543281e Theme Editor: "Insert Color" dialog now immediately updates editor with new color, which updates "live" preview; also save/restore location of dialog 2021-08-23 14:41:53 +02:00
Karl Tauber
60322be22a Theme Editor: added "Insert Color" action to "Edit" menu that opens a color chooser dialog and inserts/edits a color at caret position 2021-08-23 14:06:18 +02:00
Karl Tauber
e1f30f24a8 Theme Editor: to toggle comment, add Ctrl+7 for German keyboards where Ctrl+/ does not work 2021-08-22 17:34:18 +02:00
Karl Tauber
1759f6b25c Theme Editor: increment/decrement color parts (red, green, blue or alpha) at caret using Ctrl+UP/Ctrl+DOWN 2021-08-22 17:26:29 +02:00
Karl Tauber
6578f25cc9 GitHub Actions: upload theme editor 2021-08-22 16:10:29 +02:00
Karl Tauber
8c26e0323f Theme Editor: increment/decrement numbers at caret using Ctrl+UP/Ctrl+DOWN 2021-08-22 15:33:29 +02:00
Karl Tauber
a5575894ab Theme Editor:
- update preview after 300ms (was 500ms)
- added separator between editor and preview
2021-08-22 14:26:18 +02:00
Karl Tauber
357823a027 Theme Editor: added "Show HSL/RGB colors" menu items to "View" menu to control display of color models in overlay color preview 2021-08-22 12:34:48 +02:00
Karl Tauber
a6d3f6b3eb Theme Editor: added menu components to preview 2021-08-22 11:19:47 +02:00
Karl Tauber
ae4c69e75c Theme Editor: fixed preview when switching Laf 2021-08-22 11:13:05 +02:00
Karl Tauber
31cadc532b Theme Editor:
- F12 now activates editor if focus is in preview or in find/replace
- changed accelerators for light/dark themes from F11/F12 to Alt+F1/F2
2021-08-22 00:33:34 +02:00
Karl Tauber
6e8443473b Theme Editor: special order for tabs: first core themes, then other themes 2021-08-21 23:27:43 +02:00
Karl Tauber
cca4ab3cd8 Theme Editor: fixed tabbed pane "more tabs" popup in preview 2021-08-21 18:24:57 +02:00
Karl Tauber
dab0ee3306 Theme Editor: added "live" preview 2021-08-21 18:09:59 +02:00
Karl Tauber
c6d1ed91a7 Menus: fixed missing modifiers flags in ActionEvent (issue #371; regression since FlatLaf 1.3) 2021-08-13 20:32:07 +02:00
Karl Tauber
a613a244f4 InternalFrame: double-click on icon in internal frame title bar now closes the internal frame (issue #374) 2021-08-13 19:11:03 +02:00
Karl Tauber
268fe15004 Tree: improved support for JTree.getPathForLocation(int x, int y) in wide selection (issue #373)
this is experimental and disabled by default; enable with:
`UIManager.put( "FlatLaf.experimental.tree.widePathForLocation", true );`
2021-08-13 00:19:34 +02:00
Karl Tauber
7bc9be686f FlatLaf: use larger initial capacity for UI defaults table to avoid resizing hash table and to save some memory 2021-08-13 00:13:54 +02:00
Karl Tauber
751919ec5a Theme Editor: find/replace improvements:
- while typing in find field, select match near caret and scroll to it
- PageUp/PageDown keys scroll editor if find/replace fields have focus
2021-08-12 22:05:08 +02:00
Karl Tauber
da913b426e Theme Editor: paint current line highlight always in the line where the caret is, which makes it easier to locate current match when using find/replace
RSyntaxTextArea paints line highlight only if selection is empty (caret dot == mark)
2021-08-11 23:59:33 +02:00
Karl Tauber
d8ef99cd8f Theme Editor: support resolving properties that use wildcards 2021-08-11 23:24:55 +02:00
Karl Tauber
d08a6d7dd3 Theme Editor: support loading/resolving base properties from core themes 2021-08-11 22:38:35 +02:00
Karl Tauber
896e9bca8e Theme Editor: re-implemented support loading/resolving base properties from other editors in opened directory 2021-08-11 21:53:10 +02:00
Karl Tauber
1df9597bb1 Theme Editor: support Ctrl+PageDown/PageUp to switch to next/previous editor 2021-08-09 10:19:24 +02:00
Karl Tauber
eaf55f2099 Theme Editor: store unscaled window bounds in preferences so that using Java 8 or 9+ results in same size on screen 2021-08-08 19:15:10 +02:00
Karl Tauber
5018a1f9eb Theme Editor: increase/decrease editor font size 2021-08-08 19:14:46 +02:00
Karl Tauber
71ba8f55a7 Theme Editor:
- support dark theme (menu "View > Dark Laf")
- moved RSyntaxTextArea theme config from XML to properties files
- bracket matching enabled
- highlight selected tab background
2021-08-08 17:43:59 +02:00
Karl Tauber
b65db707ed Theme Editor: auto-completion improved: support auto-activate after spaces, tabs or ',' 2021-08-07 14:59:20 +02:00
Karl Tauber
ed62266a43 Theme Editor: always select all text in find/replace text fields 2021-08-07 12:55:25 +02:00
Karl Tauber
49913b7dad Theme Editor: duplicate lines with Ctrl+Alt+Up or Ctrl+Alt+Down 2021-08-07 12:51:00 +02:00
Karl Tauber
3eeeb9e00b Theme Editor: update RSyntaxTextArea from 3.1.2 to 3.1.3 2021-08-07 11:18:00 +02:00
Karl Tauber
bfb1642284 UIDefaultsDump: dump HSL color values 2021-08-06 10:45:57 +02:00
Karl Tauber
0544a605c3 UIDefaultsLoader: added tint() and shade() color functions (inspired by Less CSS) 2021-08-05 23:37:42 +02:00
Karl Tauber
3f5acda132 UI defaults inspector: round HSL values (as also done in theme editor) 2021-08-05 18:49:03 +02:00
Karl Tauber
02b1ba2926 UIDefaultsLoader: added mix() color function (inspired by Less CSS) 2021-08-05 18:19:42 +02:00
Karl Tauber
7f7f9e3c7c UIDefaultsLoader: added changeHue(), changeSaturation(), changeLightness() and changeAlpha() color functions (inspired by Sass CSS color.change() function) 2021-08-05 17:08:20 +02:00
Karl Tauber
6fcee03752 release 1.5 2021-08-04 15:13:58 +02:00
Karl Tauber
5782ceeb5d README.md: added descriptions to addons 2021-08-04 14:27:57 +02:00
Karl Tauber
f752db5892 FileChooser: fixed missing (localized) texts when FlatLaf is loaded in special classloader
(e.g. plugin system in Apache NetBeans)

https://issues.apache.org/jira/browse/NETBEANS-5865
2021-08-04 11:15:18 +02:00
Karl Tauber
bce58bc97b SwingX: added search and clear icons to JXSearchField (issue #359) 2021-08-03 17:52:49 +02:00
Karl Tauber
d373687bc4 Testing: added FlatSingleComponentTest to easier test/debug single components 2021-08-03 15:16:04 +02:00
Karl Tauber
e5e510c825 Demo: fixed inconsistent behavior when first changing font size and then font family, which did loose user scale factor on Windows in Java 9+ (issue #352) 2021-08-02 19:16:38 +02:00
Karl Tauber
29064ec72f Button and TextComponent: do not apply minimum width/height if margins are set (issue #364) 2021-08-02 18:36:10 +02:00
Karl Tauber
953eee1dc8 TableHeader: made getRolloverColumn() public to allow usage in custom renderers (issue #336) 2021-08-02 18:01:08 +02:00
Karl Tauber
75f76f4875 ComboBox and Spinner: limit arrow button width if component has large preferred height (issue #361) 2021-08-02 15:27:25 +02:00
Karl Tauber
ecfbe68c33 Native window decorations: updated DLLs (issues #357 and #339)
built by GitHub Actions:
https://github.com/JFormDesigner/FlatLaf/actions/runs/1085691279
2021-07-31 21:22:09 +02:00
Karl Tauber
7f02eb9cf0 Native window decorations: when window is initially shown, fill background with window background color (instead of white), which avoids flickering in dark themes (issue #339) 2021-07-31 21:05:01 +02:00
Karl Tauber
4ab90065dc Native window decorations: when resizing a window to the right or to the bottom, then first fill the new space with the window background color (instead of black) before the layout is updated (issue #339) 2021-07-31 18:02:10 +02:00
Karl Tauber
d3e39a1359 Native window decorations: fixed occasional application crash on Windows 10 in flatlaf-windows.dll (issue #357) 2021-07-30 23:06:09 +02:00
Karl Tauber
60e5861de4 InternalFrame: limit internal frame bounds to parent bounds on resize; honor maximum size of internal frame (issue #362) 2021-07-29 16:44:50 +02:00
Karl Tauber
ca7f5045ae Popup: fixed incorrectly placed drop shadow for medium-weight popups in maximized windows (issue #358) 2021-07-29 15:39:16 +02:00
Karl Tauber
299bd67151 Styling: support PopupMenu 2021-07-23 08:54:50 +02:00
Karl Tauber
4d4bb3fd7f Styling: added StyleableUI.getStyleableInfos() for tooling (e.g. GUI builder) 2021-07-21 11:51:19 +02:00
Karl Tauber
7fd64a1b73 Styling: support InternalFrame 2021-07-20 08:57:21 +02:00
Karl Tauber
e3e8765b91 Styling: support MenuBar 2021-07-19 14:39:57 +02:00
Karl Tauber
b0997fb5d2 release 1.4 2021-07-13 11:02:10 +02:00
Karl Tauber
435cf05f9f TabbedPane: reviewed PR #343 (active tab border painting style)
- moved focus listener to class `Handler`
- instead of repainting content border in `repaintContentBorder()`, increase size of repaint region in `repaintTab()` to include part of content border
- simplified `paintContentBorder()` by using `getTabBounds()` and `Rectangle2D.intersect()` to compute gap rectangle
- slightly make code smaller
- minor formatting, renaming, ...
2021-07-12 13:37:24 +02:00
Karl Tauber
37dab9fb22 TabbedPane: fixed rendering of tab separators in scroll layout if scaled on HiDPI screens 2021-07-12 11:48:34 +02:00
Karl Tauber
943dfe0619 Styling: support styling for recently merged changes 2021-07-11 01:41:52 +02:00
Karl Tauber
be7114d3e6 Merge remote-tracking branch 'origin/main' into styling
# Conflicts:
#	flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatButtonBorder.java
#	flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatToolBarUI.java
2021-07-11 01:26:11 +02:00
Karl Tauber
fb44c8fbe4 TextField: fixed location of placeholder text if paddings are used (e.g. in ComboBox) (for commit a9dcf09d13) 2021-07-10 21:05:26 +02:00
Karl Tauber
94375b7d36 Extras: added support for client property JTextField.padding (for commit a9dcf09d13) 2021-07-10 20:59:34 +02:00
Karl Tauber
8b585deb78 ToolBar: support focusable buttons in toolbar (issue #346)
fixed focusable state when switching to/from other Laf
2021-07-10 13:32:30 +02:00
Karl Tauber
4d8b544aed UIDefaultsKeysDump: also use FlatTestLaf, which adds missing keys to FlatLafUIKeys.txt 2021-07-10 13:28:02 +02:00
Karl Tauber
548d651d29 PasswordField: move the lower bar of the caps lock icon up a half pixel 2021-07-10 11:03:13 +02:00
Karl Tauber
0b342acec9 PasswordField: paint caps lock icon on left side in right-to-left component orientation 2021-07-09 15:14:29 +02:00
Karl Tauber
cc6d3c1b1a PasswordField: Caps lock icon no longer painted over long text (issue #172) 2021-07-09 15:03:16 +02:00
Karl Tauber
74a748d92e use LoggingFacade instead of printStackTrace() in flatlaf-extras and flatlaf-demo 2021-07-09 13:22:37 +02:00
Karl Tauber
1de81d0af5 ComboBox: fixed StackOverflowError when using single renderer instance in multiple comboboxes (regression since commit 4507ce359d) 2021-07-09 11:39:35 +02:00
Karl Tauber
ff9ef21f67 OptionPane: align wrapped lines to the right if component orientation is right-to-left (issue #350) 2021-07-08 17:53:44 +02:00
Karl Tauber
266a546478 Window decorations: window title bar width is no longer considered when calculating preferred/minimum width of window (issue #351) 2021-07-08 16:54:34 +02:00
Karl Tauber
87407ca832 Table and PopupFactory: use StackWalker in Java 9+ for better performance (issue #334) 2021-07-08 14:02:50 +02:00
Karl Tauber
90282d4436 UI defaults dumps updated for issue #335 2021-07-08 00:02:33 +02:00
Karl Tauber
abbe6d6c1f ToolBar: paint focus indicator for focused button in toolbar (issue #346) 2021-07-07 18:17:45 +02:00
Karl Tauber
a28f701e6f OptionPane: do not make child components, which are derived from JPanel, non-opaque (issue #349) 2021-07-07 10:57:54 +02:00
Karl Tauber
4cdc995a7f ComboBox: simplified code in configureEditor() 2021-07-05 23:14:05 +02:00
Karl Tauber
713a01bfa9 Styling: set "shared" flag to true when shared icon is assigned 2021-07-05 23:12:45 +02:00
Karl Tauber
ac291b688d Styling: fixed detection of value type if key prefix ix given (e.g. [light]padding) 2021-07-05 22:40:55 +02:00
Karl Tauber
84f7e244f2 Styling:
- support ComboBox.padding
- fixed updating of Spinner.padding
2021-07-05 22:36:57 +02:00
Karl Tauber
4a8207f367 Styling: use TestUtils.setup() in unit tests; 2021-07-05 21:58:48 +02:00
Karl Tauber
9cfd4d27e9 Styling: renamed unit tests (so that all unit test classes start with Test) 2021-07-05 21:48:41 +02:00
Karl Tauber
1b23cfd747 Merge remote-tracking branch 'origin/main' into styling
# Conflicts:
#	flatlaf-core/build.gradle.kts
#	flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java
#	flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPasswordFieldUI.java
2021-07-05 21:38:07 +02:00
Karl Tauber
c708205593 TestFlatComponentSizes: shortened combobox text because unit tests on GitHub Actions use font size 15 2021-07-05 20:06:07 +02:00
Karl Tauber
a22c6c8013 ComboBox (not editable):
- increased size of internal renderer pane to the component border so that it can paint within the whole component
- increase combo box size if a custom renderer uses a border with insets that are larger than the default combo box padding (`2,6,2,6`)
2021-07-05 18:41:17 +02:00
Karl Tauber
b576f473e5 fixed component heights at 1.25x, 1.75x and 2.25x scaling factors (Java 8 only) so that Button, ComboBox, Spinner and TextField components (including subclasses) have same heights 2021-07-05 15:15:37 +02:00
Karl Tauber
0b127caa83 ComboBox: fixed minimum width if focusWidth > 0 (to be equal with button minimum width)
added some unit tests to compare component sizes
2021-07-05 11:07:32 +02:00
Karl Tauber
5801bf3bdf Styling: use FlatLightLaf in unit tests and get UI delegates from components 2021-07-04 10:43:08 +02:00
Karl Tauber
4507ce359d ComboBox: reworked uninstall of CellPaddingBorder, which is temporary used for cell renderers, to make it easier to understand and reliable
(tested using FlatCustomBordersTest, FlatNetBeansTest, etc)
2021-07-03 10:43:55 +02:00
Karl Tauber
3e14f28dc2 ComboBox (editable) and Spinner: increased size of internal text field to the component border so that it behaves like plain text field (issue #330) 2021-07-02 18:43:37 +02:00
Karl Tauber
a9dcf09d13 TextField: support adding extra padding
(for #172, #173 and #330)
2021-07-02 15:38:45 +02:00
Karl Tauber
c8998c2bcf PasswordField: UI delegate FlatPasswordFieldUI now extends FlatTextFieldUI (instead of BasicPasswordFieldUI) to avoid duplicate code and for easier extensibility (e.g. for #173 and #341) 2021-07-02 14:03:54 +02:00
Karl Tauber
10bf1295bc CHANGELOG.md: fixed UI key ComboBox.popupFocusedBackground to ComboBox.popupBackground 2021-07-02 10:52:30 +02:00
Karl Tauber
1e869973d4 release 1.3 2021-07-02 10:40:27 +02:00
Karl Tauber
731c8962c9 added missing since 1.3 2021-07-02 10:21:55 +02:00
Karl Tauber
294b8bb789 Extras: FlatInspector: fixed border value when class hierarchy is enabled 2021-07-02 10:14:51 +02:00
Karl Tauber
4f9b819f48 Spinner: reduced gap between up and down arrows, which was increased by previous commit (issue #329) 2021-06-30 18:57:54 +02:00
Karl Tauber
5318d5fa8e ScrollBar: fixed left/top arrow icon location (if visible) (issue #329)
(tested using FlatPaintingTest)
2021-06-30 18:47:16 +02:00
Karl Tauber
98b156bdde TextComponents: use focusedBackground also if not editable (but enabled)
(PR #338)
2021-06-30 00:01:33 +02:00
Karl Tauber
511dd02107 JIDE: build using latest version of JIDE library com.formdev:jide-oss:3.7.12 2021-06-29 22:58:42 +02:00
Karl Tauber
f1f7a2e7b6 Extras: FlatInspector: fixed missing "UI" row on Java 9+ 2021-06-27 23:19:36 +02:00
Karl Tauber
d557cf5427 FlatTestFrame: do not print stack trace if lafs.properties does not exist 2021-06-27 21:36:49 +02:00
Karl Tauber
2b1c55ee67 Styling: support TabbedPane 2021-06-27 17:12:46 +02:00
Karl Tauber
925ddaa63a Styling: update MigLayout visual padding 2021-06-25 21:40:19 +02:00
Karl Tauber
2b60b18d47 Styling: support ScrollPane 2021-06-25 21:39:52 +02:00
Karl Tauber
d502406fa2 Styling: support borders of ComboBox and Spinner
reduced code size of Button, TextField and PasswordField
2021-06-25 21:38:39 +02:00
Karl Tauber
afdbf711f7 Styling: support Help button 2021-06-25 14:27:44 +02:00
Karl Tauber
39d2941099 removed duplicate ; 2021-06-25 10:48:00 +02:00
Karl Tauber
b4f7b1d71d Styling: support ToolBar and ToolBar.Separator 2021-06-24 20:06:00 +02:00
Karl Tauber
69061cd41c Styling: support TableHeader 2021-06-24 17:57:12 +02:00
Karl Tauber
8ba7f7f961 Styling: reduce duplicate code in list and table cell borders 2021-06-24 17:53:19 +02:00
Karl Tauber
5e5aa17e14 Styling: add property change listener only for FlatLaf.style (where possible) 2021-06-24 14:05:24 +02:00
Karl Tauber
551f5fc929 Styling: support Label 2021-06-24 14:02:32 +02:00
Karl Tauber
4e7b0d11d0 Styling: support Tree icons 2021-06-24 13:43:19 +02:00
Karl Tauber
06bc53692a Styling: support cell borders of List and Table 2021-06-24 10:45:48 +02:00
Karl Tauber
007ee38cb4 Styling: support List, Table and Tree 2021-06-22 17:59:55 +02:00
Karl Tauber
2a732306a1 ComboBox: renamed UI key ComboBox.popupFocusedBackground to ComboBox.popupBackground 2021-06-22 08:59:11 +02:00
Karl Tauber
82192bef91 Styling: clear field oldStyleValues on UI delegate uninstall 2021-06-21 21:06:39 +02:00
Karl Tauber
0c51dfe19c Styling: support ComboBox 2021-06-21 20:58:04 +02:00
Karl Tauber
24a9fa1ccc Styling: renamed "update" methods 2021-06-21 20:49:31 +02:00
Karl Tauber
14b06507cb Styling: support Spinner 2021-06-21 19:45:42 +02:00
Karl Tauber
b46233087b Styling: use FlatStyleSupport.createPropertyChangeListener() where possible/useful 2021-06-21 17:27:46 +02:00
Karl Tauber
28fb2e2a08 Styling: support Menu, MenuItem, CheckBoxMenuItem and RadioButtonMenuItem 2021-06-21 17:24:45 +02:00
DUDSS
943e211cf1 TabbedPane: ActiveTabBorder: Added handling for thick content separators and 0 height selection indicator. Fixed scaling issues (presumably). 2021-06-20 14:01:01 +02:00
DUDSS
ad0a13004e TabbedPane: Changed name in demo and added separator repaint on focus gained. 2021-06-20 02:56:19 +02:00
DUDSS
04bb6a5275 TabbedPane: Adjustements 2021-06-20 02:14:31 +02:00
DUDSS
d3c917eac1 TabbedPane: Added the new style option to the flatlaf demo. 2021-06-20 02:14:27 +02:00
DUDSS
4c13271a5b TabbedPane: Added activeTabBorder option to tabbed panes. Changes the active tab design to more closely resemble classic tabbed pane designs. 2021-06-20 02:13:54 +02:00
Karl Tauber
20027c2db7 Styling: support platform and light/dark theme specific styling with key prefixes [win], [mac], [linux], [light] and [dark]
e.g. `mySlider.putClientProperty( "FlatLaf.style", "[light]trackColor: #00f; [dark]trackColor: #f00" );`
2021-06-19 23:24:04 +02:00
Karl Tauber
6affc70a66 Styling: support Button and ToggleButton (including border) 2021-06-19 22:31:21 +02:00
Karl Tauber
ab4c9bdeda Styling: renamed client property JComponent.style to FlatLaf.style 2021-06-19 11:16:14 +02:00
Karl Tauber
b4a9c9b7f5 Styling: support styling disabledBackground and inactiveBackground of text components 2021-06-19 11:11:57 +02:00
Karl Tauber
5e20d50abf Styling: support TextArea, TextPane and EditorPane 2021-06-18 14:21:17 +02:00
Karl Tauber
53abbbbe56 Styling: support TextField, FormattedTextField and PasswordField 2021-06-18 13:22:19 +02:00
Karl Tauber
1938cb586d Styling: support SplitPane 2021-06-17 20:59:09 +02:00
Karl Tauber
50490ece84 Styling: support Separator and PopupMenu.Separator 2021-06-17 15:21:19 +02:00
Karl Tauber
f291cc2bd3 Styling: support ProgressBar 2021-06-17 14:57:10 +02:00
Karl Tauber
2542c8bd53 Styling: support ScrollBar 2021-06-17 13:56:38 +02:00
Karl Tauber
b457fd634e Styling: (try to) fix errors on GitHub Actions 2021-06-16 22:59:00 +02:00
Karl Tauber
041fd0e0cd Styling: fixed javadoc error 2021-06-16 22:57:56 +02:00
Karl Tauber
a983edde1e Styling: support CheckBox and RadioButton icons 2021-06-16 22:31:56 +02:00
Karl Tauber
7eb642dd13 Styling: added simple unit tests 2021-06-16 21:28:51 +02:00
Karl Tauber
e0bc93371e Styling: use annotation on fields to apply style properties (to avoid boilerplate code) 2021-06-16 21:21:33 +02:00
Karl Tauber
db56486506 Styling: support CheckBox and RadioButton (without icons) 2021-06-16 12:07:13 +02:00
Karl Tauber
c99be13697 Styling: support using java.util.Map as style
e.g. `mySlider.putClientProperty( "JComponent.style", Collections.singletonMap( "thumbSize", new Dimension( 8, 24 ) ) );`
2021-06-15 23:23:11 +02:00
Karl Tauber
0830c78728 Styling: support using simple references to UI defaults
e.g. `mySlider.putClientProperty( "JComponent.style", "thumbColor: $TextField.background; thumbBorderColor: $Component.borderColor" );`
2021-06-15 23:20:33 +02:00
Karl Tauber
edade93054 Styling: basic implementation of styling support using client property JComponent.style and CSS syntax
only for JSlider (at the moment)

e.g. `mySlider.putClientProperty( "JComponent.style", "trackValueColor: #00f; trackColor: #f00; thumbColor: #0f0; trackWidth: 6; thumbSize: 40,20; focusWidth: 20" );`

(issues #117 and #340)
2021-06-15 14:35:26 +02:00
Karl Tauber
8a72b30cbc Merge pull request #338 from Chrriis/focusedBackground
Issue #335: allow a different background on focus
2021-06-15 11:57:17 +02:00
Karl Tauber
ed9cb0f918 Spinner: support Spinner.focusedBackground
ComboBox:
- prefer explicit set background color over focusedBackground
- if ComboBox.buttonFocusedBackground is not specified use ComboBox.focusedBackground
- added ComboBox.popupFocusedBackground

(issue #335)
2021-06-15 11:50:30 +02:00
Karl Tauber
7e0915cb9c FlatBorder: refractored ComboBox, ScrollPane and Spinner focus owner checking to UI delegates (for later usage) 2021-06-13 11:21:55 +02:00
Karl Tauber
a51294d570 TextComponents:
- use focusedBackground only if editable (and enabled)
- prefer explicit set background color over focusedBackground
- added FlatTextFieldUI.getBackground() used by all text components
- support EditorPane.focusedBackground
- support TextPane.focusedBackground

(issue #335)
2021-06-12 20:46:59 +02:00
Karl Tauber
d962f218a1 ToolTip: fixed positioning of huge tooltips (issue #333) 2021-06-11 20:53:09 +02:00
Karl Tauber
7b248427f0 fixed white lines at bottom and right side of window (in dark themes on HiDPI screens with scaling enabled) 2021-06-11 16:16:41 +02:00
Christopher Deckers
b99fb8b11f Use focused background color for combo popups. 2021-06-09 09:56:50 +02:00
Christopher Deckers
26250e790f Issue #335: allow a different background on focus. 2021-06-08 10:12:59 +02:00
Karl Tauber
b26dbe81f4 README.md: changed deprecated FlatLightLaf.install() to FlatLightLaf.setup() 2021-06-01 16:23:54 +02:00
Karl Tauber
903212345b .gitbugtraq added (for SmartGit) 2021-06-01 16:21:58 +02:00
Karl Tauber
025f6564dc release 1.2 2021-05-18 18:23:41 +02:00
Karl Tauber
35f97368fa Native window decorations: double-click at upper-left corner of maximized frame did not close window (issue #326) 2021-05-18 18:00:53 +02:00
Karl Tauber
09e5c86488 FlatLaf.getDisabledIcon() now returns a instanceof UIResource for disabled SVG icons to allow recreation of disabled icons when switching to another Laf 2021-05-15 17:51:33 +02:00
Karl Tauber
8998371cae Extras: FlatSVGUtils.createWindowIconImages(): return multi-resolution image only on Windows because Java implementations for macOS and Linux do not support multi-resolution images for window title icons
(issue #323)
2021-05-14 17:33:40 +02:00
Karl Tauber
29e1dc6b55 FlatTitlePaneIcon: use getResolutionVariant(width, height) instead of getResolutionVariants() to allow creation of requested size on demand and to avoids creation of all resolution variants
Extras: `FlatSVGUtils.createWindowIconImages()` now returns a single multi-resolution image that creates requested image sizes on demand from SVG

(issue #323)
2021-05-14 16:43:47 +02:00
Karl Tauber
439e63b52f Native window decorations: updated DLLs (issue #283)
built by GitHub Actions:
https://github.com/JFormDesigner/FlatLaf/actions/runs/838543378
2021-05-13 13:43:45 +02:00
Karl Tauber
eea341fb33 Native window decorations: fixed broken maximizing window (under special conditions) when restoring frame state at startup (issue #283) 2021-05-13 12:10:11 +02:00
Karl Tauber
359eedf773 Native window decorations: fixed slow application startup under particular conditions (issue #319) 2021-05-13 00:54:22 +02:00
Karl Tauber
866751ffc1 Extras: FlatInspector: show class hierarchies when pressing Alt key and prettified class names (dimmed package name) 2021-05-12 19:03:13 +02:00
Karl Tauber
38a3a0768d Tree: fill cell background if DefaultTreeCellRenderer.setBackgroundNonSelectionColor(Color) was used (issue #322) 2021-05-12 15:45:36 +02:00
Karl Tauber
03b42749cd replaced deprecated (since Java 9) KeyEvent.*_MASK with KeyEvent.*_DOWN_MASK 2021-05-12 14:03:16 +02:00
Karl Tauber
60fd78e082 build.gradle.kts: removed unnecessary mapOf() and fixed formatting 2021-05-12 13:59:50 +02:00
Karl Tauber
9edaf58929 Linux: fixed/improved detection of user font settings (issue #309) 2021-05-04 22:41:00 +02:00
Karl Tauber
5000186f85 Linux: enable text anti-aliasing if no Gnome or KDE Desktop properties are available (issue #218) 2021-05-04 22:11:15 +02:00
Karl Tauber
cacf0ea987 ComboBox: support using as cell renderer (e.g. in JTable) 2021-05-04 21:39:08 +02:00
Karl Tauber
067501cbe7 Native window decorations: avoid double window title bar if enabling native window border failed (issue #315) 2021-04-23 21:12:40 +02:00
Karl Tauber
9fe0cf496b Native window decorations: updated DLLs (issue #315)
built by GitHub Actions:
https://github.com/JFormDesigner/FlatLaf/actions/runs/778322373
2021-04-23 18:23:44 +02:00
Karl Tauber
9d0823038e Native window decorations: fixed occasional double window title bar when creating many frames or dialogs (issue #315) 2021-04-23 18:14:00 +02:00
Karl Tauber
5a05efefdd build.gradle.kts:
- moved javadoc options from subprojects to root project
- removed "API" from titles in HTML files
- added subproject name and version to header and footer
- use links to Java 11 API
2021-04-22 23:00:28 +02:00
Karl Tauber
988d171bdd fixed javadoc warnings/errors when building with Java 15 2021-04-22 16:20:50 +02:00
Karl Tauber
e6f72bf343 fixed some deprecation warnings when compiling with Java 11 2021-04-22 15:53:02 +02:00
Karl Tauber
89c5a0c57b FlatSVGIcon: fixed javadoc issues 2021-04-22 14:27:14 +02:00
Karl Tauber
d97146393c renamed Flat*Laf.install() methods to Flat*Laf.setup() to avoid confusion with UIManager.installLookAndFeel(LookAndFeelInfo info); the old Flat*Laf.install() methods are still there, but marked as deprecated 2021-04-22 14:20:09 +02:00
Karl Tauber
1c52f1f76c CheckBox and RadioButton: do not fill background if used as cell renderer, except if cell is selected or has different background color (issue #311) 2021-04-22 00:14:42 +02:00
Karl Tauber
9bd3a68115 update miglayout-swing from 5.3-SNAPSHOT to 5.3 2021-04-20 21:01:55 +02:00
Karl Tauber
f58780d36b FlatSVGIcon: share color filter in derived icons 2021-04-18 18:30:56 +02:00
Karl Tauber
6eb15ab437 FlatSVGIcon: added missing javadoc and updated CHANGELOG.md 2021-04-18 17:43:12 +02:00
Karl Tauber
00dc7004f5 Merge pull request #303 from xDUDSSx/extras-svg-icon-filter
FlatSVGIcon color filters
2021-04-18 17:31:01 +02:00
Karl Tauber
8ec0e57235 FlatSVGIcon: use fluent API for color filter 2021-04-18 17:05:22 +02:00
Karl Tauber
d75dc9e70c FlatSVGIcon: support light and dark mappings in single color filter 2021-04-18 16:37:24 +02:00
Karl Tauber
ec2fccbb0e FlatSVGIcon: if icon has color filter and did change the color, then do not apply global color filter 2021-04-16 23:25:22 +02:00
Karl Tauber
34861166e8 Demo: ExtrasPanel: added "Toggle RED" button 2021-04-16 23:03:38 +02:00
Karl Tauber
584fa0a26e Demo: ExtrasPanel:
- animate "rainbow" icon only if extras tab is visible
- recreated added components in JFormDesigner
2021-04-16 22:56:44 +02:00
Karl Tauber
6c48489d89 FlatSVGIcon:
- added getters for all fields passed to constructors
- preserve disabled state in derive() methods
- ColorFilter: create hash maps only if needed/used
2021-04-16 21:53:15 +02:00
Karl Tauber
ba9c884a0c FlatSVGIcon:
- renamed FlatSVGIcon.setFilter(...) to setColorFilter()
- renamed ColorFilter.setFilter(Function) to setMapper(Function)
- replaced ColorFilter.createGrayFilterFunction(int,int,int) with universal createRGBImageFilterFunction(RGBImageFilter)
- ColorFilter: use default color palette mapping only in global filter
2021-04-16 21:33:23 +02:00
Karl Tauber
360f0bafe0 Extras: FlatInspector: always show tooltip over highlight figures 2021-04-16 15:12:55 +02:00
Karl Tauber
4327c13dca FlatTestFrame: moved 3rd party lafs to lafs.properties 2021-04-16 14:57:43 +02:00
Karl Tauber
4f2256f713 TableHeader: Moved table header column border painting from FlatTableHeaderUI to new border FlatTableHeaderBorder to improve compatibility with custom table header implementations (issue #228) 2021-04-14 19:34:44 +02:00
Karl Tauber
5167cd368f JIDE: JideTabbedPane: updated CHANGELOG.md 2021-04-13 16:32:20 +02:00
Karl Tauber
ef7289d11a Merge pull request #306 from JFormDesigner/jidetabbedpane
JideTabbedPane improvements
2021-04-13 16:29:49 +02:00
Karl Tauber
cb11d98bf7 JIDE: JideTabbedPane: hide tab selection and tab area separator for tabbedPane.setHideOneTab(true) if tabbed pane contains only one tab 2021-04-13 12:20:11 +02:00
Karl Tauber
992349da8c JIDE: JideTabbedPane: fixed close button in tab area, which was visible even if shown on tabs (regression in previous commit) 2021-04-13 12:06:28 +02:00
Karl Tauber
2e7637f274 JIDE: JideTabbedPane: fixed close button in tab area 2021-04-13 11:25:42 +02:00
Karl Tauber
1f8eaf4a64 JIDE: JideTabbedPane: fixed scroll and list buttons 2021-04-13 10:51:04 +02:00
Karl Tauber
46ac7a9dc7 IntelliJ Themes: fixed background colors of DesktopPane and DesktopIcon in all themes 2021-04-11 19:39:47 +02:00
Karl Tauber
0d86d39217 IntelliJ Themes: minor fixes to text in progress bars for some themes 2021-04-11 18:59:23 +02:00
Karl Tauber
1f591f3d1b IntelliJ Themes: added "Material Theme UI Lite / GitHub Dark" theme 2021-04-11 17:42:57 +02:00
Karl Tauber
30c6ddba37 IntelliJ Themes: updated themes to newest versions (used IJThemesUpdater) 2021-04-11 17:35:25 +02:00
Karl Tauber
406eeaec96 PopupFactory: fixed occasional NullPointerException in FlatPopupFactory.fixToolTipLocation() (issue #305) 2021-04-11 16:00:36 +02:00
Karl Tauber
2fe5652bc6 DesktopPane: automatically layout icons in dock (without invoking from DesktopManager), which eliminates the need for FlatDesktopManager 2021-04-11 15:10:59 +02:00
Karl Tauber
39bf68a6bd DesktopIcon: automatically update preview (without invoking from DesktopManager) 2021-04-11 14:58:20 +02:00
Karl Tauber
a7a4a19824 DesktopIcon: use derived color for icon background, based on background color of JDesktopPane 2021-04-11 14:48:19 +02:00
Karl Tauber
7f906ba0ea DesktopPane: fixed empty minimized icon when switching LaF (regression since commit ab1ce7fab16597c518dd00a4c4e86320d98410c1; see PR #294) 2021-04-10 15:53:45 +02:00
Karl Tauber
07bf6e4506 DesktopPane: on HiDPI screens, use high-resolution images for preview of iconified internal frames in dock 2021-04-10 14:36:46 +02:00
Karl Tauber
a331760321 DesktopPane: made private methods/fields protected to allow overriding 2021-04-10 13:36:44 +02:00
Karl Tauber
d9c240d729 DesktopPane: fixed incomplete minimized icon when switching LaF 2021-04-10 12:46:13 +02:00
Karl Tauber
d9526c19e7 DesktopPane: improved layout of iconified internal frames in dock 2021-04-10 12:39:26 +02:00
Karl Tauber
1798ccd284 Merge pull request #294 from lsimediasarl/main
Fixed JInternalFrame iconified content snapshot for already installed DesktopManager
2021-04-10 00:05:02 +02:00
Karl Tauber
ab1ce7fab1 DesktopPane: avoid using two instances of DefaultDesktopManager if a custom desktop manager is used/wrapped (see PR #294) 2021-04-09 18:17:15 +02:00
DUDSS
e9b2f17171 FlatSVGIcon: Fixed an oversight 2021-04-09 13:41:08 +02:00
DUDSS
d3bf4433b7 FlatSVGIcon: Removed unnecessary getInstance method. Changed the demo a little and added a utility method to ColorFilter to easily create a brightness/contrast/alpha filter. 2021-04-09 13:36:49 +02:00
DUDSS
ba0f43455b Reworked how the FlatSVGIcon filters work. Filters are now set using the ColorFilter class and can work globally too. Added related demo components to flatlaf-demo extras tab. 2021-04-09 13:36:49 +02:00
DUDSS
638af4bcd7 Added an option to specify an RGBImageFilter to a FlatSVGIcon 2021-04-09 13:36:48 +02:00
Karl Tauber
5eab843d97 Button and ToggleButton:
- updated CHANGELOG.md for #276
- FlatComponentsTest: use FlatButton and FlatToggleButton
- FlatButtonUI: avoid unnecessary reading client property if shadowColor is null, which is the case in most themes
2021-04-09 11:44:59 +02:00
Karl Tauber
c55f0e239e Merge pull request #276 from ingokegel/border_less_button
Added ButtonType.borderLess
2021-04-09 11:17:11 +02:00
Ingo Kegel
32d9381745 Renamed borderLess to borderless 2021-04-08 22:36:42 +02:00
Karl Tauber
77fc564e70 TabbedPane: fixed actions scrollTabsForwardAction and scrollTabsBackwardAction when used from outside (e.g. in NetBeans) 2021-04-08 01:15:29 +02:00
Karl Tauber
3b84314c45 client/system properties: javadoc fixes 2021-04-07 16:25:24 +02:00
Karl Tauber
5729c20386 release 1.1.2 2021-04-07 11:53:18 +02:00
Karl Tauber
a4d70d8095 FlatTextComponentsTest: fixed compiler warnings (for previous commit) 2021-04-07 10:34:11 +02:00
Karl Tauber
8fcce349d5 ComboBox and Spinner: fixed too wide arrow button if component is higher than preferred (issue #302) 2021-04-07 01:39:29 +02:00
Karl Tauber
5a94676a3a Merge pull request #269 from SchiopuMatei/main
Added option for downscaling
2021-04-07 00:24:18 +02:00
Karl Tauber
f32d72ee62 UIScale:
- allow scale factors less than 100% for system property `flatlaf.uiScale`
- no longer round scale factor of system property `flatlaf.uiScale` to 1/4
- renamed system property `flatlaf.uiDowncale.enabled` to `flatlaf.uiScale.allowScaleDown`
- round smaller scale factors to 1/10
- absolute minimum user scale factor is now 0.1
2021-04-07 00:21:15 +02:00
Karl Tauber
e35fc8620c JIDE: fixed null font in other Lafs if (wrongly) using LookAndFeelFactory.addUIDefaultsInitializer() or LookAndFeelFactory.addUIDefaultsCustomizer() (issue #288) 2021-04-06 18:35:48 +02:00
Karl Tauber
277c288952 IntelliJ Themes: fixed system colors 2021-04-06 11:29:55 +02:00
Karl Tauber
240b08e55c IntelliJ Themes: fixed window title bar background if unified background is enabled 2021-04-06 11:04:52 +02:00
Karl Tauber
fe7f345661 Native window decorations: support changing title bar background and foreground colors per window (via client property) also if unified window title bar is enabled 2021-04-06 10:46:28 +02:00
Karl Tauber
c8db01c958 SplitPane: fixed JSplitPane.setContinuousLayout(false) (issue #301) 2021-04-05 14:24:49 +02:00
Karl Tauber
f456185f7d Native window decorations: support changing title bar background and foreground colors per window (via client property) 2021-04-05 14:19:41 +02:00
Karl Tauber
801b555835 Window decorations: fixed random window title bar background for unified backgrounds in cases were background is not filled by custom window/rootpane components (issue #254) 2021-04-04 11:47:15 +02:00
Karl Tauber
eee177e64b Window decorations: enabling/disabling menu bar embedding via system and client properties now works the same way as for window decorations
(previously it was only possible to disable menu bar embedding)
2021-04-03 16:19:11 +02:00
Karl Tauber
63639f8e96 Native window decorations: cleaned-up/simplified JetBrains Runtime custom window decorations "enabled" checking:
- `FlatSystemProperties.USE_WINDOW_DECORATIONS` is now also used for JBR custom window decorations
- `FlatSystemProperties.USE_JETBRAINS_CUSTOM_DECORATIONS` is now only used to disable JBR custom window decorations; then FlatLaf native window decorations are used
- JBR custom window decorations are now disabled when running in JetBrains Projector, Webswing or WinPE
2021-04-03 13:32:46 +02:00
Karl Tauber
de1b0b1bb6 MenuBar: do not use TitlePane.unifiedBackground if window decorations are disabled for the window 2021-04-03 11:51:45 +02:00
Karl Tauber
bbdd7fc2b4 Demo:
- keep "Options > Window decorations" selected for JetBrains Runtime
- disable "Options > Use underline menu selection" on macOS
- added font size `11`
2021-04-03 11:49:57 +02:00
Karl Tauber
6addb5c4b4 Native window decorations:
- API to check whether current platform supports window decorations `FlatLaf.supportsNativeWindowDecorations()`
- API to toggle window decorations of all windows `FlatLaf.setUseNativeWindowDecorations(boolean)`
- `FlatClientProperties.USE_WINDOW_DECORATIONS` can now used to toggle window decorations for single window
- cleaned-up/fixed/simplified window decorations "enabled" checking:
  1. if `FlatSystemProperties.USE_WINDOW_DECORATIONS` is set, its value is used
  2. if `FlatClientProperties.USE_WINDOW_DECORATIONS` is set, its value is used
  3. use value of UI default `TitlePane.useWindowDecorations`
2021-04-03 11:13:57 +02:00
Karl Tauber
b47e0c88d6 Merge pull request #298 from Bios-Marcel/fix-demo-menu-item-states
Fix selected states for native window border related menu items
2021-04-02 16:13:36 +02:00
Marcel Schramm
d06993d940 Add comment explaining why the use of JBR results in not having custom decorations 2021-04-01 22:14:39 +02:00
Karl Tauber
d31f167b9e TabbedPane: fixed NPE when creating/modifying in another thread (issue #299) 2021-04-01 12:35:50 +02:00
Karl Tauber
f12ee6c167 added dummy class to empty opend module packages 2021-04-01 09:40:22 +02:00
Karl Tauber
983b341f33 Native window decorations: fixed loading of native library when using JPMS for application (issue #289) 2021-04-01 01:07:35 +02:00
Karl Tauber
f3e6642f05 Button and ToggleButton: simplified/unified code of FlatButtonUI.getBackground() (issue #292) 2021-03-31 23:14:45 +02:00
Karl Tauber
0a63990d21 Button and ToggleButton: do not paint background of disabled (and unselected) toolBar buttons (issue #292; regression since fixing #112) 2021-03-31 22:28:43 +02:00
Karl Tauber
6909bb4b03 Native window decorations: removed superfluous pixel-line at top of screen when window is maximized (issue #296) 2021-03-31 20:56:17 +02:00
Marcel Schramm
620aa8bcee Fix selected states for native window border related menu items
The menu items for custom window decorations and embeded menu bar aren't selected anymore if the feature isn't supported.
On top of that, there's now a tooltip indicating that these aren't supported.
2021-03-31 19:59:29 +02:00
Stephan Bodmer
6db39d1860 Implemented desktop manager wrapper for already installed desktop manager so the iconifyFrame with small
content snapshot are still available

Signed-off-by: Stephan Bodmer <sbodmer@lsi-media.ch>
2021-03-31 13:58:25 +02:00
Stephan Bodmer
1762ead89f s
Signed-off-by: Stephan Bodmer <sbodmer@lsi-media.ch>
2021-03-31 13:54:40 +02:00
Karl Tauber
d13ddeb944 use larger font when running on WinPE (issue #279) 2021-03-30 11:00:27 +02:00
Karl Tauber
1b5da0e1d1 Window decorations: support enabling/disabling unified title bar backgrounds at runtime without FlatLaf.updateUI() 2021-03-30 01:34:34 +02:00
Karl Tauber
7a2d0e7fcb fixed crash when running in Webswing (issue #290) 2021-03-30 01:06:30 +02:00
Karl Tauber
477c3b6b1e README.md: added link to FlatLaf 1.0 announcement on Reddit 2021-03-28 18:44:21 +02:00
Karl Tauber
95312c3650 release 1.1.1 2021-03-28 16:04:14 +02:00
Karl Tauber
98a3c4b0f5 JIDE: JideTabbedPane: fixed disabled tab text, which was unreadable in dark themes 2021-03-27 19:19:17 +01:00
Karl Tauber
6e990a7e31 JIDE: JideTabbedPane: fixed hover background of close button on selected tab 2021-03-27 18:46:37 +01:00
Karl Tauber
8e49904f8d JIDE: JideTabbedPane: fixed location of tab title editing box 2021-03-27 18:22:10 +01:00
Karl Tauber
69f52c8abd JIDE: JideTabbedPane: scale tab gripper 2021-03-27 17:48:58 +01:00
Karl Tauber
d7b0754327 JIDE: JideTabbedPane: tab layout fixes for compact resize mode 2021-03-27 17:03:49 +01:00
Karl Tauber
2a00de11f1 JIDE: JideTabbedPane: fixed tab icon and title locations in vertical tabs 2021-03-27 14:28:21 +01:00
Karl Tauber
923cc51f3e JIDE: JideTabbedPane: FlatJideOssContainerTest updated (based on FlatContainerTest) 2021-03-27 12:18:06 +01:00
Karl Tauber
c8f7478170 JIDE: JideTabbedPane:
- use `FlatTabbedPaneCloseIcon` for tab close buttons
- scale close buttons
- fix close buttons location
2021-03-27 11:02:33 +01:00
Karl Tauber
9006e835c6 natives.yml: exclude ~/.gradle/caches/modules-2/modules-2.lock from Gradle cache 2021-03-26 21:52:28 +01:00
Karl Tauber
f801d61929 support running on WinPE (issue #279) 2021-03-26 21:51:11 +01:00
Karl Tauber
a143e5777c Extras: FlatInspector: fixed InaccessibleObjectException when running in Java 16 2021-03-26 21:44:41 +01:00
Karl Tauber
bffac60bf8 JIDE: JideTabbedPane:
- support selected tab background
- support tab separators
2021-03-25 18:49:16 +01:00
Karl Tauber
bf500e46e7 Window decorations: fixed wrong/missing window icon when application replaces InternalFrame.icon (issue #284) 2021-03-25 16:14:41 +01:00
Karl Tauber
4a2f79f390 Native window decorations: updated DLLs (issues #282 and #283)
built by GitHub Actions:
https://github.com/JFormDesigner/FlatLaf/actions/runs/686023039
2021-03-25 11:10:13 +01:00
Karl Tauber
c24ce7c5bc Native window decorations: fixed broken maximizing window when restoring frame state at startup (issue #283) 2021-03-25 10:32:24 +01:00
Karl Tauber
8a6a0c7971 Native window decorations: fixed missing animations when minimizing, maximizing or restoring a window using window title bar buttons (issue #282) 2021-03-24 23:59:59 +01:00
Karl Tauber
de6e5bd800 fixed missing focus indicators in heavy-weight popups (issue #273) 2021-03-24 11:43:06 +01:00
Karl Tauber
e18a04f9e6 Merge pull request #278 from ingokegel/native_provider_setter
Add a setter for the native provider
2021-03-24 11:34:22 +01:00
Karl Tauber
14fc652f4b Window decorations: fixed right aligned progress bar in embedded menu bar was overlapping window title (issue #272) 2021-03-23 19:23:18 +01:00
Ingo Kegel
9a876e747a Added setter for native provider
This makes it possible to support situations where the extraction of a DLL at runtime is not possible
2021-03-23 16:47:08 +01:00
Karl Tauber
f8ee8b27fb InternalFrame: fixed translucent internal frame menu bar background if TitlePane.unifiedBackground is true (issue #274) 2021-03-23 15:08:01 +01:00
Karl Tauber
ce1a1487aa support menu bars in JDialog 2021-03-23 14:58:53 +01:00
Karl Tauber
fe1e364a1d Native window decorations: support disabling native window decorations per window via client property (issue #277) 2021-03-23 13:18:07 +01:00
Karl Tauber
eabb052107 Native window decorations: fixed double window title bar when first disposing a window and then showing it again (issue #277) 2021-03-23 10:07:43 +01:00
Karl Tauber
734f3621f1 Window decorations: Fixed NPE in FlatTitlePane.findHorizontalGlue() (issue #275) 2021-03-22 18:47:53 +01:00
Ingo Kegel
ae8323e2f8 Added ButtonType.borderLess for buttons that look like toolbar buttons but have a focus indicator.
This behavior can be achieved with JideButton, but it would be preferable to use FlatButton instead.
2021-03-22 16:45:37 +01:00
Karl Tauber
9612a81f2e release 1.1 2021-03-21 14:03:36 +01:00
Karl Tauber
2945a36cef added since 1.1 2021-03-21 13:53:57 +01:00
Karl Tauber
b84dc5bfcc JIDE and SwingX: README.md: added links to dependencies on maven central 2021-03-21 13:29:23 +01:00
Karl Tauber
60486fd880 JIDE: build using latest version of JIDE library com.formdev:jide-oss:3.7.11.1 2021-03-20 19:19:33 +01:00
Karl Tauber
891091cebc SwingX: fixed compiling module-info (broken since previous commit) 2021-03-19 17:06:23 +01:00
Karl Tauber
1493ddcf41 SwingX: the library on Maven Central no longer depends on org.swinglabs.swingx:swingx-all:1.6.5-1 to avoid problems when another SwingX library should be used 2021-03-19 16:23:29 +01:00
Karl Tauber
4299c50537 JIDE: the library on Maven Central no longer depends on com.jidesoft:jide-oss:3.6.18 to avoid problems when another JIDE library should be used (issue #270) 2021-03-19 16:22:24 +01:00
Karl Tauber
14577c396d JIDE: fixed hover/selection background colors of JideSplitButton and JideSplitToggleButton 2021-03-19 15:59:59 +01:00
Karl Tauber
e9b566241d JIDE: support JideSplitButton and JideSplitToggleButton 2021-03-19 15:39:32 +01:00
Karl Tauber
d39b08c035 FlatArrowButton: refactored arrow painting to FlatUIUtils.paintArrow() so that it can be easily used other components (e.g. JideSplitButton) 2021-03-19 01:21:19 +01:00
Karl Tauber
69ac683c8c Support running in JetBrains Projector (https://jetbrains.com/projector/) 2021-03-17 00:43:08 +01:00
Karl Tauber
eafd0b3d06 use lambdas for listeners (where possible) instead of extending Basic*UI.*Handler classes
some of those `Basic*UI.*Handler` classes may be deprecated in a future Java version (see https://github.com/openjdk/jdk/pull/1958)

this should also avoid loading of those `Basic*UI.*Handler` classes at runtime
2021-03-17 00:34:35 +01:00
Karl Tauber
310a4989dc JIDE: made used fonts "active" and restored fonts modified in LookAndFeelFactory.installJideExtension() 2021-03-16 23:23:40 +01:00
Karl Tauber
3d0df51839 JIDE: support JideLabel to fix wrong text colors in dark themes 2021-03-16 22:52:13 +01:00
Karl Tauber
ede02aaaa5 TabbedPane: use float arc for tab area button background 2021-03-16 22:20:46 +01:00
Karl Tauber
beff149004 JIDE: support JideButton and JideToggleButton 2021-03-16 22:15:32 +01:00
Karl Tauber
07db6e8fb0 Extras: FlatInspector: fixed NPE if component class is in default package 2021-03-16 13:46:25 +01:00
Karl Tauber
46852c0780 JIDE: invoke LookAndFeelFactory.installJideExtension() early in FlatJidePopupMenuUI to be sure that Jide extensions are installed 2021-03-16 13:26:36 +01:00
Karl Tauber
a5e41c573f JIDE: UIDefaultsDump: dump UI defaults added by LookAndFeelFactory.installJideExtension() 2021-03-16 11:38:49 +01:00
SchiopuMatei
ed91aa4648 Added option for downscaling 2021-03-15 20:41:40 +02:00
Karl Tauber
9a94395d30 JIDE: split FlatJideOssTest (moved JideTabbedPane to FlatJideOssContainerTest`) 2021-03-15 17:40:31 +01:00
Karl Tauber
04aa61c2bb Merge pull request #268 from title-pane-improvements
Title pane improvements (Windows 10 only)
2021-03-14 17:39:50 +01:00
Karl Tauber
035a13df54 Window decorations: support unified backgrounds for window title bar, menu bar and main content (issue #254) 2021-03-14 15:13:26 +01:00
Karl Tauber
e8a6f0ca3d Native window decorations: added flatlaf-windows-x86.dll and updated flatlaf-windows-x86_64.dll
built by GitHub Actions:
https://github.com/JFormDesigner/FlatLaf/actions/runs/650060630
2021-03-14 00:20:22 +01:00
Karl Tauber
1fc519b9de natives.yml: run "Native Libraries" also when natives.yml changed 2021-03-14 00:02:01 +01:00
Karl Tauber
2bcf38e2e3 natives.yml: run "Native Libraries" on any change in native project (e.g. when changing Gradle build script) 2021-03-13 23:59:30 +01:00
Karl Tauber
8eb44a68cb Native window decorations: support 32-bit JREs 2021-03-13 23:41:38 +01:00
Karl Tauber
30c7b442a8 Window decorations:
- support customizing of window title alignment: left aligned or centered (default is left without embedded menubar and centered with embedded menubar)
- improved centering of window title with embedded menubar (issue #252)
2021-03-13 17:08:47 +01:00
Karl Tauber
cee2211108 Demo: added "users" icon to right side of menu bar to demonstrate this feature 2021-03-13 11:14:51 +01:00
Karl Tauber
b7bcbccd45 Window decorations: support right aligned extra components in JFrame title pane with embedded menu bar 2021-03-13 11:10:50 +01:00
Karl Tauber
d2ccb97eba Native window decorations: use LoggingFacade 2021-03-12 23:18:13 +01:00
Karl Tauber
39d56f2603 Merge pull request #267 from native-window-decorations
Native window decorations for Windows 10 (using JNI)
2021-03-12 23:15:19 +01:00
Karl Tauber
83e904dd2d Merge pull request #262 from native-window-decorations-jna
Native window decorations for Windows 10 (using JNA)
2021-03-12 23:08:35 +01:00
Karl Tauber
110c787eba Merge pull request #265 from ingokegel:optional_logging
Make the module dependency on java.logging optional
2021-03-12 22:57:04 +01:00
Karl Tauber
7c7ff289de removed module java.logging from module-info.javas 2021-03-12 22:52:59 +01:00
Karl Tauber
617a35c51b LoggingFacade:
- make LoggingFacadeImpl classes package private
- added missing @Override
- minor formatting changes
2021-03-12 21:16:57 +01:00
Karl Tauber
73487ccf65 Native window decorations:
- enabled by default (via UI property `TitlePane.useWindowDecorations`)
- dropped system property `flatlaf.useNativeWindowDecorations` and replaced with `flatlaf.useWindowDecorations`
- old functionality of system property `flatlaf.useWindowDecorations` removed
2021-03-11 10:54:23 +01:00
Ingo Kegel
712bff9c99 Use System.Logger for logging with Java 9+ 2021-03-10 17:56:27 +01:00
Ingo Kegel
eedfcf86aa LoggingFacade: moved to com.formdev.flatlaf.util, added license header, fixed NPEs in logging calls and removed overloads of logSevere 2021-03-10 17:06:12 +01:00
Karl Tauber
f730848928 Native window decorations: added flatlaf-windows-x86_64.dll
built by GitHub Actions:
https://github.com/JFormDesigner/FlatLaf/actions/runs/636694710
2021-03-10 16:16:50 +01:00
Karl Tauber
61d0574c5c Native window decorations: added READMEs 2021-03-09 19:08:53 +01:00
Karl Tauber
2f01e01ec1 Native window decorations: delete temporary DLLs on next startup (same approach as used in JNA) 2021-03-07 00:10:15 +01:00
Karl Tauber
cbcf66df7f Native window decorations: fixed enabled items is system menu 2021-03-06 16:23:10 +01:00
Karl Tauber
cfaeea039b Native window decorations: fixed enabled items is system menu 2021-03-06 16:21:22 +01:00
Karl Tauber
a891d1eb54 Native window decorations: never build :flatlaf-natives-windows:jar because it is not used/needed 2021-03-06 15:26:18 +01:00
Karl Tauber
4372052ef0 Native window decorations: do not try to build native library (on Windows) if no C++ compiler is available 2021-03-06 15:18:23 +01:00
Karl Tauber
8734b062dc Native window decorations: avoid using C-runtime, which reduces the DLL size from 100kb to 8kb 2021-03-06 12:01:49 +01:00
Ingo Kegel
343451de65 Make the module dependency on java.logging optional
Currently, FlatLaf has the following module dependencies:

$ jdeps --list-deps --multi-release 9 flatlaf-1.0.jar
   java.base
   java.desktop
   java.logging

This commit makes the java.logging dependency optional and hides logging behind a facade that falls back to printing to stderr if the java.logging module is not available.

To test, create a reduced JRE with a command like

jdk-15/bin/jlink.exe --module-path jdk-15/jmods --add-modules java.desktop --add-modules java.instrument --output jre-15-desktop-only

(adding java.instrument, so the FlatLafDemo main class can be started from IntelliJ IDEA)
2021-03-05 16:44:08 +01:00
Karl Tauber
144d65c776 Native window decorations: initial implementation in C++ using JNI 2021-03-05 10:31:31 +01:00
Karl Tauber
a6815574f7 Native window decorations: renamed project flatlaf-native-jna to flatlaf-natives/flatlaf-natives-jna
removed module-info.java because this JAR is not released/published
2021-03-04 11:04:47 +01:00
Karl Tauber
e5a116a0d4 Extras: FlatInspector: removed println (fixes #263) 2021-02-25 16:54:05 +01:00
Karl Tauber
0beef6b108 README.md: new applications using FlatLaf:
- install4j
2021-02-25 00:00:30 +01:00
Karl Tauber
7341008449 Native window decorations: fixed missing top border line 2021-02-24 23:17:41 +01:00
Karl Tauber
49bd53194a Native window decorations: show window system menu when left-clicking on application icon, close window on left-double-click on app icon 2021-02-23 23:31:36 +01:00
Karl Tauber
baf4437efc Native window decorations: show window system menu when right-clicking on caption 2021-02-23 01:10:59 +01:00
Karl Tauber
b244f80f81 Native window decorations: support autohide taskbar 2021-02-22 22:57:43 +01:00
Karl Tauber
e41c91a42b Native window decorations: fixed exception when switching Laf after closing a dialog 2021-02-22 09:56:40 +01:00
Karl Tauber
b9a2e3ceac Native window decorations: initial implementation (using JNA; will be replaced with JNI later) 2021-02-21 17:51:19 +01:00
Karl Tauber
fa7dd3bdc4 GitHub Actions: upload all built libs 2021-02-21 17:18:59 +01:00
Karl Tauber
9a8c68b846 GitHub Actions: renamed master to main 2021-02-19 16:38:25 +01:00
Karl Tauber
698e33ddf4 IntelliJ Themes: fixed text color of CheckBoxMenuItem and RadioButtonMenuItem in all "Arc" themes (issue #259) 2021-02-19 11:33:15 +01:00
Karl Tauber
909258ba14 README.md: added "Getting started" and direct links to documentation 2021-02-14 12:32:56 +01:00
Karl Tauber
2ad6bd1d23 release 1.0 2021-02-13 13:42:04 +01:00
Karl Tauber
510ffd41d8 PopupFactory: fixed NullPointerException when PopupFactory.getPopup() is invoked with parameter owner set to null 2021-02-13 13:31:30 +01:00
Karl Tauber
4f00591c4e Table: fixed wrong grid line thickness in dragged column on HiDPI screens on Java 9+ (issue #236) 2021-02-12 11:32:12 +01:00
Karl Tauber
5b65ed87cd FileChooser: fixed display of date in details view if current user is selected in "Look in" combobox (Windows 10 only; issue #249) 2021-02-12 11:10:25 +01:00
Karl Tauber
b0121c422d GitHub Actions: added Gradle wrapper validation 2021-02-11 23:52:11 +01:00
Karl Tauber
a9e9fad222 Extras: FlatInspector: tooltip is no longer limited to window bounds 2021-02-11 18:23:01 +01:00
Karl Tauber
b5fc07acc7 TabbedPane: custom TabbedPane.selectedForeground color did not work when TabbedPane.foreground has also custom color (issue #257) 2021-02-11 12:04:36 +01:00
Karl Tauber
140ebfdb92 release 1.0-rc3 2021-02-06 23:31:53 +01:00
Karl Tauber
37d0179de1 GitHub Actions: upload demo (was removed in previous commit) 2021-02-06 23:27:39 +01:00
Karl Tauber
823d4b0fe2 dropped usage of bintray, jcenter and jfrog artifactory
deploy to Sonatype OSSRH

snapshots are now here:
https://oss.sonatype.org/content/repositories/snapshots/com/formdev/
2021-02-06 19:02:32 +01:00
Karl Tauber
dd1eacf4f0 update to Gradle 6.8.2
./gradlew wrapper --gradle-version=6.8.2
2021-02-06 11:35:35 +01:00
Karl Tauber
86c33dd686 fixed javadoc syntax error 2021-02-06 11:26:57 +01:00
Karl Tauber
c6757cc61b UI defaults inspector: filter by colors with alpha and derived colors 2021-02-06 01:32:32 +01:00
Karl Tauber
a38cf284dd UI defaults inspector: show color functions in value tooltips 2021-02-06 01:31:34 +01:00
Karl Tauber
575b8e3f7f UI defaults inspector: for derived colors, no longer change Item.value from Color to Color[] because this could cause problems if there is a UI value of type Color[] 2021-02-06 01:01:48 +01:00
Karl Tauber
bc443f47f1 Theme Editor: fixed NPE (caused by no longer implemented base files support) 2021-02-05 23:33:26 +01:00
Karl Tauber
b631bcc0db UIDefaultsLoader: check for endless recursion in parsing color functions (e.g. abc = darken($abc,10%)) 2021-02-05 23:30:48 +01:00
Karl Tauber
5ccd92ece6 CheckBox: fixed background of check boxes in JIDE CheckBoxTree (broken since commit dd8ab242fb) 2021-02-04 19:41:14 +01:00
Karl Tauber
2f3c8868a7 IntelliJ Themes: fixed table header background when dragging column in "Dark Flat" and "Light Flat" themes 2021-02-04 19:18:06 +01:00
Karl Tauber
6f7b5e8005 README.md: removed JCenter and replaced download links to bintray with Maven Central 2021-02-04 16:48:53 +01:00
Karl Tauber
10d1e4b798 UIDefaultsDump: dump color value in same format as used in FlatLaf properties files; also dump alpha as percentage 2021-02-04 15:24:50 +01:00
Karl Tauber
9d5934df14 Extras: FlatInspector: use HTML in tooltip 2021-02-04 15:19:33 +01:00
Karl Tauber
be507de6c1 Label and ToolTip: made inserting BASE_SIZE rule into HTML text more reliable 2021-02-04 15:10:27 +01:00
Karl Tauber
e5d3c08821 Fixed color of <address> tag in HTML text 2021-02-04 12:58:14 +01:00
Karl Tauber
027b4ab7da Label and ToolTip: fixed font sizes for <code>, <kbd>, <big>, <small> and <samp> tags in HTML text
ToolTip: update font size if `tiptext` property changes
2021-02-04 12:56:18 +01:00
Karl Tauber
fefea0d7ec IntelliJ Themes: updated themes to newest versions (used IJThemesUpdater) 2021-02-02 18:00:17 +01:00
Karl Tauber
33f30bfd19 README.md: new applications using FlatLaf:
- DbVisualizer
- MagicPlot
- Thermo-Calc
- Burp Suite
- BurpCustomizer
- IGMAS+
2021-02-01 21:58:18 +01:00
Karl Tauber
e9d4b9961a README.md: made "commercial" bold 2021-02-01 15:14:07 +01:00
Karl Tauber
b94248fe79 README.md: removed "new" badge from projects using FlatLaf 2021-02-01 14:58:44 +01:00
Karl Tauber
225975e0dd FlatTestFrame: added 5x and 6x scale factors 2021-02-01 13:57:36 +01:00
Karl Tauber
eac7492143 FlatAnimatedIconTest: made animation of switch smooth on high scale factors 2021-02-01 12:55:14 +01:00
Karl Tauber
b3c40bf448 release 1.0-rc2 2021-02-01 01:39:52 +01:00
Karl Tauber
02f7cd77f4 FlatBorder: fixed wrong round edge of focused components in themes without outer focus border (Flat Light/Dark) 2021-02-01 01:30:52 +01:00
Karl Tauber
7f8f3aa99b Button: undone most style changes done in previous commit related to focused and default buttons:
- default button: white background and wide border
- focused button: light blue background and thin border

(the light blue default button did not look beautiful IMHO)
2021-02-01 01:08:20 +01:00
Karl Tauber
0bcdc14909 - Button:
- In "Flat Light" theme, changed styles of focused and default buttons to
    avoid confusion with all other themes. Focused buttons now have a white
    background (was light blue) and a slightly wider border. The default button
    now has a light blue background (was white) and a thin border. In all other
    themes the default button also has colored background.
  - In "Flat Dark" theme, use slightly wider border for focused buttons.
- CheckBox and RadioButton: In "Flat Dark" theme, use blueish background for
  focused components.
2021-01-31 20:02:24 +01:00
Karl Tauber
526c25a02b FlatComponentStateTest: fixed insets 2021-01-31 18:51:28 +01:00
Karl Tauber
f48da9dab1 FlatComponentStateTest: added text field and combobox (for comparison) 2021-01-31 16:17:47 +01:00
Karl Tauber
2e8dfda12e FlatComponentStateTest: added help buttons 2021-01-31 00:55:29 +01:00
Karl Tauber
63da576d85 FlatComponentStateTest: added selected checkboxes and radiobuttons 2021-01-30 20:53:07 +01:00
Karl Tauber
0ab4206540 FlatComponentStateTest added 2021-01-30 18:43:11 +01:00
Karl Tauber
212ae90401 client property "JComponent.focusOwner" added to allow customizing detection of focused state (issue #185) 2021-01-30 17:54:47 +01:00
Karl Tauber
d4e5d0be45 javadoc fixes 2021-01-30 17:46:53 +01:00
Karl Tauber
3520a0f1fb TextComponents: border of focused non-editable text components had wrong color 2021-01-30 01:06:03 +01:00
Karl Tauber
036090a947 Button: fixed behavior of Enter key on focused button on Windows and Linux, which now clicks the focused button (instead of the default button) 2021-01-30 00:37:36 +01:00
Karl Tauber
dc570c683a UI defaults: added Java 8 and 9+ InputMap dumps of NimbusLookAndFeel, which are different on Linux (and macOS) than on Windows because they use GTK key bindings (see GTKKeybindings.installKeybindings(), invoked from NimbusLookAndFeel.getDefaults()) 2021-01-29 23:00:06 +01:00
Karl Tauber
9f85d34c91 JIDE: updated UI defaults dumps for commit 7d0f7e1c8e (support JidePopupMenu) 2021-01-29 22:06:01 +01:00
Karl Tauber
16bf1fb6c3 README.md: screenshots updated 2021-01-28 23:26:30 +01:00
Karl Tauber
47c4d508e0 Demo: updated screenshot mode 2021-01-28 23:26:16 +01:00
Karl Tauber
e5d9060623 UI defaults: added links to docs and note to properties files 2021-01-23 18:49:35 +01:00
Karl Tauber
fdf28fc385 javadoc and comment updates/fixes 2021-01-23 18:05:46 +01:00
Karl Tauber
9015a4d56b Window decorations: fixed top window border in dark themes when running in JetBrains Runtime (issue #244)
fixed/improved calculation of active border color
2021-01-23 16:59:53 +01:00
Karl Tauber
38301454a6 CHANGELOG.md: added recently merged PRs #245 2021-01-22 11:10:04 +01:00
Karl Tauber
9b3a22c4ca FlatComponents2Test: simplified layout and reduced frame size 2021-01-21 23:58:22 +01:00
Karl Tauber
548dbc3649 Merge pull request #245 from ingokegel/tree_wide_selection
Added a per-tree wide selection setting
2021-01-21 23:19:33 +01:00
Karl Tauber
3474129812 Tree:
- paint non-wide selection in FlatTreeUI.paintRow() instead of using reflection to change private field in DefaultTreeCellRenderer
- use DefaultTreeCellRenderer.getBackgroundSelectionColor() as selection color (if possible)
- added boolean client property JTree.paintSelection to disable selection painting in FlatTreeUI.paintRow()
- FlatComponents2Test:
  - added checkboxes for wideSelection and paintSelection client properties
  - added possibility to test various kinds of tree cell renderers
  - added JXTree, JIDE CheckBoxTree

(PR #245)
2021-01-21 17:38:20 +01:00
Karl Tauber
63193feebe JIDE: JidePopupMenu:
- added test to FlatJideOssTest
- updated README.md and CHANGELOG.md

(PR #246)
2021-01-21 00:14:42 +01:00
Karl Tauber
51f22bfe75 Merge pull request #246 from ingokegel/jide_popup_menu_ui
Added UI for JidePopupMenu
2021-01-21 00:05:32 +01:00
Ingo Kegel
7d0f7e1c8e Added UI for JidePopupMenu 2021-01-20 16:18:48 +01:00
Karl Tauber
dd8ab242fb CheckBox and RadioButton: fill component background as soon as background color is different to default background color, even if component is not opaque (which is the default). This paints selection if using the component as cell renderer a Table, Tree or List (better fix for #77) 2021-01-19 19:13:20 +01:00
Ingo Kegel
60f3428da7 Added a per-tree wide selection setting 2021-01-19 17:46:41 +01:00
Karl Tauber
c6fec0a131 release 1.0-rc1 2021-01-18 23:34:37 +01:00
Karl Tauber
fdc43fc0d3 Slider: improved thumb hover and pressed colors
Also changed auto-inverse threshold from 50% to 65% for increase and 35% for decrease, because this gives much better results for slider hover and pressed colors. This does not change other colors in core themes, but few colors in some IntelliJ themes (usually checkbox hover/pressed).
2021-01-18 23:20:25 +01:00
Karl Tauber
0b880aa335 TabbedPane: fixed scrolling tabs with touchpads and high-resolution mouse wheels 2021-01-18 18:34:21 +01:00
Karl Tauber
74f50ec992 IntelliJ Themes: fixed menu accelerator colors in Monocai theme (issue #243) 2021-01-18 12:15:12 +01:00
Karl Tauber
1bdf4532db UI defaults inspector: support wildcard matching in filter 2021-01-16 12:56:25 +01:00
Karl Tauber
f97783ddef Window decorations: RootPane.activeBorderColor and RootPane.inactiveBorderColor fixes:
- FlatDarkLaf.properties: changed darken() to lighten(), which does not change real colors due to autoInverse mechanism
- FlatLightLaf.properties: use also derived colors (to be consistent with FlatDarkLaf.properties and fix warning in UIDefaultsDump)
2021-01-16 01:01:36 +01:00
Karl Tauber
1024d6fc07 UIDefaultsDump: use DerivedColorKeys.properties to compute and dump derived colors and verify them 2021-01-16 00:39:36 +01:00
Karl Tauber
3ec59d0c58 UI defaults inspector:
- no longer show color values as decimal rgb
- use black for color value text if color is translucent
- fix derived color tooltip
- improved filter performance
2021-01-15 19:44:45 +01:00
Karl Tauber
c43249316c UI defaults inspector:
- show computed derived colors
- also show base colors and default colors
- indicate derived colors with magenta bar on right side in value column
2021-01-15 19:07:44 +01:00
Karl Tauber
ed5180ffd6 Theme Editor:
- save/restore selection when reloading file (if changed outside)
- select all text in find field when pressing Ctrl+F
- use lighter color for operators (e.g. '=')
2021-01-15 16:15:05 +01:00
Karl Tauber
e9ec769340 CHANGELOG.md: added recently merged PRs #237, #239 and #241 2021-01-15 16:00:11 +01:00
Karl T
5e16ff8dff Merge pull request #241 from ingokegel/macos_text_aa
The fix for text anti-aliasing in 50d36fe9 should only apply on macOS
2021-01-15 14:39:00 +01:00
Ingo Kegel
364b6631ea The fix for text anti-aliasing in 50d36fe9 should only apply on macOS 2021-01-15 14:31:58 +01:00
Karl T
48a18e53e3 Merge pull request #240 from ingokegel/table_header_column_borders
Made paintColumnBorders protected to help with implementing derived table header UIs
2021-01-15 14:15:27 +01:00
Karl T
bcc8282d73 Merge pull request #239 from ingokegel/macos_text_aa
Switched from sub-pixel to greyscale text anti-aliasing on macOS when running with a JetBrains JRE
2021-01-15 14:04:40 +01:00
Ingo Kegel
15017ed49c Made paintColumnBorders protected to help with implementing derived table header UIs
To implement FlatLaf UIs for CellStyleTableHeaderUI and SortableTableHeaderUI from the Jide Grids library, access to the paintColumnBorders method is required
2021-01-15 13:09:10 +01:00
Ingo Kegel
50d36fe91b Switched from sub-pixel to greyscale text anti-aliasing on macOS when running with a JetBrains JRE.
Sub-pixel anti-aliasing (VALUE_TEXT_ANTIALIAS_LCD_HRGB) causes font rendering with too much weight with a JetBrains JREs (both 8 and 11). This can be seen when comparing the text rendering of UI elements between IntelliJ IDEA and FlatLaf.

This commits aligns FlatLaf's behavior with IntelliJ IDEA which disables sub-pixel anti-aliasing on macOS for its IDE anti-aliasing setting and uses greyscale anti-aliasing by default (see com.intellij.ide.ui.AntialiasingType.canUseSubpixelAAForIDE).
2021-01-14 18:59:54 +01:00
Karl Tauber
23e67a2908 Slider: support per component custom thumb and track colors 2021-01-14 13:50:42 +01:00
Karl Tauber
0dab1b73cc JIDE: RangeSlider: fixed slider focused colors in IntelliJ themes (see commit 1fb0783808) 2021-01-14 13:36:01 +01:00
Karl T
3c086a92e2 Merge pull request #237 from ingokegel/macos_font
JetBrains Runtime 11 has support for displaying the .AppleSystemUIFont font.
2021-01-14 13:22:16 +01:00
Ingo Kegel
647d72514b JetBrains Runtime 11 has support for displaying the .AppleSystemUIFont font.
This font should be used for UI elements since macOS 10.15.
See https://youtrack.jetbrains.com/issue/JBR-1915 for more information.

Other JREs, including JetBrains Runtime 8 do not handle kerning for that font correctly.
2021-01-14 10:18:39 +01:00
Karl Tauber
15328b4fd7 ToggleButton: tab style buttons now respect explicitly set background color 2021-01-13 17:52:05 +01:00
Karl Tauber
b49a498f9c Button and ToggleButton: ToolBar buttons now respect explicitly set background color. If no background color is set, then the button background is not painted anymore (issue #191) 2021-01-13 17:22:09 +01:00
Karl Tauber
8d14d5f87c Button: disabled Button.defaultButtonFollowsFocus on Windows (as on other platforms, IntelliJ IDEA and other Lafs) 2021-01-13 10:32:15 +01:00
Karl Tauber
a6db352ecd IntelliJ Themes:
- fixed menu item check colors
- fixed MenuItem.underlineSelectionColor
- fixed List, Tree and Table selectionInactiveForeground in light Arc themes
- fixed List and Table background colors in Material UI Lite themes
2021-01-13 10:11:29 +01:00
Karl Tauber
ccbb26c176 IntelliJ Themes: added hover and pressed feedback to Button, CheckBox, RadioButton and ToggleButton (issue #176) 2021-01-12 14:15:44 +01:00
Karl Tauber
8f6af73541 CheckBox and RadioButton:
- use `CheckBox.icon.selectedBackground` as base color for derived "selected" colors
- use derived colors for `CheckBox.icon[filled].selectedHoverBackground` and `CheckBox.icon[filled].selectedPressedBackground`
- removed unnecessary `CheckBox.icon.selectedFocusedBorderColor`from FlatDarkLaf.properties
- added missing keys to FlatLafUIKeys.txt

(preparation for #176)
2021-01-12 10:43:57 +01:00
Karl Tauber
a59f17fdb2 UIDefaultsKeysDump: extend existing keys file (instead of replacing it) to allow manual adding of optional keys, which are not defined in UI defaults 2021-01-11 14:00:14 +01:00
Karl Tauber
14222e40ad TabbedPane: fixed IndexOutOfBoundsException when using tooltip text on close buttons and closing last/rightmost tab (issue #235) 2021-01-10 18:28:30 +01:00
Karl Tauber
7d48bf06fe Button and ToggleButton: Threat Unicode surrogate character pair as single character and make button square (issue #234) 2021-01-09 23:46:56 +01:00
Karl Tauber
1d06a2c2e8 IntelliJ Themes: updated "Material Theme UI Lite" themes; added "Material Theme UI Lite / Moonlight" theme 2021-01-09 17:55:09 +01:00
Karl Tauber
cf141f0e55 IntelliJ Themes: updated "Dracula" and "Gradianto" themes 2021-01-09 17:35:13 +01:00
Karl Tauber
9113c31612 UI defaults inspector: support copy key/value to clipboard 2021-01-09 11:13:17 +01:00
Karl Tauber
00b4e0a6fd UI defaults inspector: support embedding into any window 2021-01-09 00:38:46 +01:00
Karl Tauber
e3cac95d37 UI defaults:
- moved some common properties from FlatLightLaf.properties and FlatDarkLaf.properties to FlatLaf.properties
- use color functions for more properties
2021-01-08 18:24:39 +01:00
Karl Tauber
64d850c583 build.gradle.kts: added more information to pom 2021-01-08 11:47:48 +01:00
Karl Tauber
2fe1b9e726 ScrollPane: smooth scrolling:
- scroll at least one pixel to avoid "hanging"
- limit scroll increment to visible width/height
- no longer use block increment because had width/height of view (IOW was too large and had no effect)

(issue #27)
2021-01-08 11:20:55 +01:00
Karl Tauber
1315d847b9 removed dummy pom.xml for GitHub dependency graph 2021-01-07 14:09:55 +01:00
Karl Tauber
b5954102b6 README.md: added maven-central badge 2021-01-05 15:09:52 +01:00
Karl Tauber
1c8ba0c538 added dummy root pom.xml for GitHub dependency graph 2021-01-05 11:58:02 +01:00
Karl Tauber
be18317a6d moved flatlaf-extras/pom.xml (for GitHub dependency graph) to another folder to check whether GitHub recognizes it there 2021-01-05 11:48:50 +01:00
Karl Tauber
88d2b8266e README.md: reordered chapters 2021-01-03 11:59:44 +01:00
Karl Tauber
949ca5ddff JIDE: auto-initialize JIDE extensions (issue #230) 2021-01-03 11:55:09 +01:00
Karl Tauber
3eb53b9648 Theme Editor: save/restore window size (basic implementation; ignoring maximized state and screen number) 2021-01-02 15:44:37 +01:00
Karl Tauber
e4a03ede1f added dummy pom.xml for GitHub dependency graph for flatlaf-extras 2021-01-02 14:05:10 +01:00
Karl Tauber
cb65dc0e9d added dummy pom.xml for GitHub dependency graph 2021-01-02 13:09:31 +01:00
Karl Tauber
8ec907050e Theme Editor:
- "Open Directory" action added
- remember recently opened directories
- remember recently selected file
2021-01-01 17:43:05 +01:00
Karl Tauber
15ba00a902 Theme Editor: use selected text in editor for searching when pressing Ctrl+F 2021-01-01 12:56:29 +01:00
Karl Tauber
89d0c301c2 Theme Editor: "replace" and "replace all" added; focus editor with F12 key 2020-12-31 23:22:45 +01:00
Karl Tauber
2f47466f3b Theme Editor:
- fixed broken (mouse-wheel) scrolling caused by the additional JPanel
- fixed broken slide-in animation of "find bar"
2020-12-31 22:29:09 +01:00
Karl Tauber
d70eca9774 Theme Editor: added "error strip" to right side; removed scroll pane border 2020-12-31 18:15:20 +01:00
Karl Tauber
95ce92fa18 Theme Editor: find previous/next with UP/DOWN keys 2020-12-31 17:34:16 +01:00
Karl Tauber
b3db52b2ed Theme Editor: mark occurrence while typing; disable previous/next occurrence buttons if searchFor is empty 2020-12-31 16:23:04 +01:00
Karl Tauber
c40912013d Theme Editor: use markAll() (instead of find()) to avoid that selection jumps to next occurrence when showing find bar or when changing options 2020-12-31 16:11:22 +01:00
Karl Tauber
1c08e98c1c Theme Editor: show/hide highlighted matches when showing/hiding "find bar" 2020-12-31 15:55:22 +01:00
Karl Tauber
3f202a7cdc Theme Editor: transfer focus to editor when hiding "find bar" 2020-12-31 15:24:32 +01:00
Karl Tauber
6f3aea8fc1 Theme Editor: basic "find bar" added 2020-12-31 15:08:14 +01:00
Karl Tauber
0896143838 Theme Editor: support navigating to next/previous editor with Ctrl+Tab/Ctrl+Shift+Tab 2020-12-30 14:03:41 +01:00
Karl Tauber
ea94899a28 Extras: added missing export of package com.formdev.flatlaf.extras.components to Java 9 module descriptor (issue #117) 2020-12-30 11:23:51 +01:00
Karl Tauber
d2109cef86 Theme Editor: update open tabs when .properties files were added or removed to directory (on window activation) 2020-12-29 23:12:23 +01:00
Karl Tauber
cda146366c Theme Editor: auto-reload .properties files on window activation, if modified outside 2020-12-29 18:30:52 +01:00
Karl Tauber
678b879a01 Theme Editor:
- open all .properties files in passed directory in tabs
- basic menu bar added (Save, Exit)
- auto-save files on window deactivation and app exit
2020-12-28 20:38:48 +01:00
Karl Tauber
4c885c5e7b CHANGELOG.md: added PR #229 2020-12-23 12:31:16 +01:00
Karl Tauber
d5002b1c33 Merge pull request #229
TextField Placeholder now honors the right inset
2020-12-23 12:18:33 +01:00
Karl Tauber
4f8b6d6b28 UIDefaultsLoader:
- changed "globals" to "wildcard replacements"
- strict checking for background/foreground keys
2020-12-23 11:14:26 +01:00
Karl Tauber
66dab41539 properties: added spaces around '=' for easier reading 2020-12-23 10:52:42 +01:00
Niklas
9e4940228d TextField now honours right component inset
If the placeholder can't be drawn fully, we clip it by adding an
ellipse.
2020-12-23 09:26:30 +01:00
Karl Tauber
cbb11ebb03 ComboBox, Spinner and SplitPaneDivider: support "pressed" feedback on arrow buttons 2020-12-23 00:02:58 +01:00
Karl Tauber
073a25f381 release 0.46 2020-12-20 18:42:23 +01:00
Karl Tauber
40592ab876 FlatUIUtils: fixed javadoc warnings 2020-12-20 18:34:13 +01:00
Karl Tauber
bbfe624b51 Merge pull request #222 into master
AnimatedIcon
2020-12-20 18:26:09 +01:00
Karl Tauber
a2af9e4c65 JIDE: RangeSlider: clicking on track now immediately moves the thumb to mouse location and starts dragging the thumb 2020-12-20 18:24:40 +01:00
Karl Tauber
0123a8895f JIDE: updated UI defaults dumps for commit ef065d31a0 (support TristateCheckBox) 2020-12-20 17:33:42 +01:00
Karl Tauber
53854a4d13 Slider: snap to ticks is now done while dragging the thumb 2020-12-20 17:32:01 +01:00
Karl Tauber
4fdd44858f Slider: clicking on track now immediately moves the thumb to mouse location and starts dragging the thumb 2020-12-20 13:32:10 +01:00
Karl Tauber
3c58879ce5 Slider: fixed painting of colored track if JSlider.inverted is true 2020-12-19 17:01:34 +01:00
Karl Tauber
a7c6a881b3 Extras: FlatTriStateCheckBox reworked 2020-12-19 16:13:12 +01:00
Karl Tauber
ef065d31a0 JIDE: support TristateCheckBox 2020-12-19 13:34:53 +01:00
Karl Tauber
d059d6b448 README.md: new projects using FlatLaf:
- jEnTunnel
- JPass
- Linotte
- MEKA
- Shutter Encoder
- ThunderFocus
- lectureStudio
2020-12-18 16:05:56 +01:00
Karl Tauber
2d0a6f1bec README.md: new projects using FlatLaf:
- JOSM
- Novel-Grabber
- Android Tool
2020-12-18 16:04:43 +01:00
Karl Tauber
a3cc5a1938 README.md: added descriptions to projects using FlatLaf 2020-12-18 14:34:40 +01:00
Karl Tauber
435068515a always reset our graphics rendering hints
(this is usually not necessary because each component gets its own instance of Graphics when painting, but resetting may avoid side effects if our paint methods are invoked directly)
2020-12-18 13:35:17 +01:00
Karl Tauber
956001dbd7 avoid painting text with our rendering hints enabled to avoid antialiased text in some components if text antialiasing is disabled in system (issue #227) 2020-12-18 12:22:27 +01:00
Karl Tauber
460f0d9dee UIScale: fixed NPE in getSystemScaleFactor(Graphics2D) when using Batik SVGGraphics2D (issue #226) 2020-12-15 11:25:00 +01:00
Karl Tauber
5155ec93c9 ToolTip: fixed drop shadow for wide tooltips (issue #224; regression since fixed issue #142) 2020-12-15 11:19:30 +01:00
Karl Tauber
8bb8883e22 IntelliJ Themes: added flag whether a theme is dark to FlatAllIJThemes.INFOS. (issue #221) 2020-12-12 18:54:42 +01:00
Karl Tauber
ffb7a6dfbb README.md:
- added demo download section
- added link to javadoc of extras components
2020-12-12 14:45:08 +01:00
Karl Tauber
176de6f245 README.md: simplified download sections of subprojects 2020-12-12 14:21:07 +01:00
Karl Tauber
11f9740dbf Extras: added support for JComponent.outline client property (issue #117) 2020-12-12 13:59:58 +01:00
Karl Tauber
42a91ba26c Extras: renamed SVG utility class from com.formdev.flatlaf.extras.SVGUtils to com.formdev.flatlaf.extras.FlatSVGUtils 2020-12-12 12:21:48 +01:00
Karl Tauber
234003e2b1 Extras: Renamed tri-state check box class from
`com.formdev.flatlaf.extras.TriStateCheckBox` to
`com.formdev.flatlaf.extras.components.FlatTriStateCheckBox`
2020-12-12 00:33:51 +01:00
Karl Tauber
534384438b Extras: added extension class for JTabbedPane (issue #117) 2020-12-11 23:44:52 +01:00
Karl Tauber
ab51f35d5d Extras: added extension classes for JEditorPane, JSpinner, JTextArea and JTextPane; added minimumWidth and roundRect properties (issue #117) 2020-12-11 18:05:58 +01:00
Karl Tauber
511a4044d7 Extras: added extension classes for JButton and JToggleButton (issue #117) 2020-12-11 17:18:35 +01:00
Karl Tauber
821efaff40 Extras: removed duplicate enums in text components (issue #117) 2020-12-11 14:01:42 +01:00
Karl Tauber
91bc994532 Extras: made enums in text components public (issue #117) 2020-12-11 13:39:51 +01:00
Karl Tauber
1323b46ac7 Extras: added extension class for JProgressBar (issue #117) 2020-12-11 13:28:55 +01:00
Karl Tauber
3a8b30ca8e Extras: removed extension interfaces and moved methods to components classes because:
- Javadoc for components that implement extension interfaces are useless because they do not include default methods from the extension interface
- GUI builders do not recognize default methods from the extension interface and it is not possible to edit extension properties in GUI builder
- the idea of adding the extension interface to own components can be also achieved by changing superclass of own component

(issue #117)
2020-12-11 13:24:14 +01:00
Karl Tauber
923d58519f Extras: added extension interfaces and classes for JComboBox, JFormattedTextField, JPasswordField, JScrollBar, JScrollPane and JTextField (issue #117) 2020-12-10 20:30:27 +01:00
Karl Tauber
eabb1f84f6 Table and TableHeader: fixed missing right vertical grid line if using table as row header in scroll pane (issues #152 and #46) 2020-12-09 23:04:04 +01:00
Karl Tauber
cfbe44b946 TableHeader: fixed position of column separators in right-to-left component orientation; do not paint anything if column count is zero 2020-12-09 00:33:01 +01:00
Karl Tauber
81c35eab46 SwingX: fixed striping background highlighting color (e.g. alternating table rows) in dark themes
Table: made grid lines slightly darker/lighter
2020-12-07 12:28:31 +01:00
Karl Tauber
a1c7c29113 FlatComponents2Test: added SwingX JXTable and JXTreeTable to test extended/customized tables 2020-12-07 12:21:34 +01:00
Karl Tauber
1293e2a074 AnimatedIcon added (for future animations) (issue #66) 2020-12-05 17:57:06 +01:00
Karl Tauber
b5deca7f22 release 0.45 2020-12-05 14:32:02 +01:00
Karl Tauber
604ba236c0 Merge pull request #217 into master
MenuBar.underlineSelectionColor
2020-12-05 12:00:50 +01:00
Karl Tauber
14df490b2a MenuBar: support different underline menu selection style UI defaults for MenuBar and MenuItem. (PR #217; issue #216) 2020-12-05 11:56:38 +01:00
Karl Tauber
dd2f73e8ad Merge pull request #214 into master
Slider redesign
2020-12-04 22:43:05 +01:00
Karl Tauber
56bfdc8ef9 Slider: updated CHANGELOG.md 2020-12-04 22:29:32 +01:00
Karl Tauber
91dbf1e144 Sider: text baseline layout in FlatComponentsTest 2020-12-04 21:08:12 +01:00
Karl Tauber
e07ae90d09 TabbedPane: no longer add (internal) tab close button component as child to JTabbedPane (issue #219) 2020-11-29 01:32:38 +01:00
Karl Tauber
5ef0c9aae1 Table: fixed unstable grid line thickness when scaled on HiDPI screens (issue #152) 2020-11-28 23:20:58 +01:00
Karl Tauber
aefed7c481 Table: do not paint last vertical grid line if auto-resize mode is not off (issue #46) 2020-11-28 23:15:37 +01:00
Karl Tauber
0d66d9f9a3 FlatCheckBoxIcon:
- added parameter `Component c` to all paint methods so that subclasses can access component states
- extracted methods to get colors and selected/indeterminate state
2020-11-28 12:29:13 +01:00
Karl Tauber
d0ffc4f979 TabbedPane: support hiding tab area if it contains only one tab 2020-11-28 11:21:46 +01:00
mmatessi
f149d2b7cd MenuBar.underlineSelectionColor 2020-11-27 19:14:28 +01:00
Karl Tauber
21a12b8dd4 added Flat*Laf.installLafInfo() methods to add a Laf to the set of available Lafs
uses `UIManager.installLookAndFeel( new UIManager.LookAndFeelInfo(...) )`
2020-11-23 22:14:42 +01:00
Karl Tauber
6c8b8e8949 Popup: allow forcing to heavy weight popup windows (issue #189) 2020-11-23 18:09:44 +01:00
Karl Tauber
539737d1c5 ScrollBar: fixed NPE in NetBeans GUI builder when using JCalendar component (issue #194) 2020-11-23 17:19:04 +01:00
Karl Tauber
33ff5828da IntelliJ Themes:
- added "Gradianto Nature Green" theme
- updated "Arc Dark", "Cyan", "Dark purple", "Gradianto", "Gray", "Gruvbox" and "One Dark" themes
2020-11-22 17:10:11 +01:00
Karl Tauber
1fb0783808 Slider: fixed slider colors in IntelliJ themes 2020-11-21 18:18:06 +01:00
Karl Tauber
b5e7aa8553 Slider: fixed painting issues:
- needle of directional thumb was not painted while dragging
- artifacts on HiDPI screen while dragging
- cut off focus indicator on HiDPI screen
2020-11-21 18:18:06 +01:00
Karl Tauber
1d3ce76b27 Slider: replaced Slider.thumbWidth with Slider.thumbSize to support non-square sized thumbs (as used in Windows 10) 2020-11-21 18:18:06 +01:00
Karl Tauber
0101171159 UIDefaultsLoader: added fadein(), fadeout(), fade() and spin() color functions (inspired by Less CSS) 2020-11-21 18:18:06 +01:00
Karl Tauber
8b8ed0b9ff Slider:
- compute useful baseline for horizontal orientation so that the track is vertically centered
- no baseline for vertical orientation
2020-11-21 18:18:06 +01:00
Karl Tauber
413b60e630 Slider:
- changed default color to bluish
- made track thinner (2px, was 3px)
- made thumb larger (12px, was 11px)
- added thumb outline focus indicator (4px wide)
- slider component height increased from 11px to 20px
- support painting thumb border
- support different colors for thumb background and colored track
2020-11-21 18:18:06 +01:00
Karl Tauber
10b2a94c70 JIDE: RangeSlider: avoid that middle track is painted over first thumb 2020-11-21 18:18:06 +01:00
Karl Tauber
e337e5bbd8 JIDE: RangeSlider:
- updated with latest changes from FlatSliderUI
- use static FlatSliderUI methods for thumb painting
- hover/pressed feedback on single thumb
- hover/pressed feedback on middle track and both thumbs
- added JSlider components to FlatRangeSliderTest for easier testing/comparing
2020-11-21 18:18:06 +01:00
Karl Tauber
6e55e0a183 Slider:
- hover feedback only when mouse is over thumb
- pressed feedback added
- separate disabled colors for track and thumb
- made private fields protected
2020-11-21 18:18:06 +01:00
Karl Tauber
8ee1d26935 Merge branch into master 2020-11-21 17:53:17 +01:00
Karl Tauber
80bdf69eaf GitHub Actions: build on all branches; produce snapshots only on master branch; disable Travis CI 2020-11-21 17:31:52 +01:00
Karl Tauber
18e838bffd GitHub Actions: exclude javadoc and sources from build artifacts 2020-11-21 15:21:33 +01:00
Karl Tauber
d95b1b0ec4 GitHub Actions: upload build artifacts 2020-11-21 15:08:07 +01:00
Karl Tauber
d16a3c117b GitHub Actions: 3rd attempt to test release job without publishing 2020-11-21 14:45:02 +01:00
Karl Tauber
d04ec982ab GitHub Actions: 2nd attempt to test release job without publishing 2020-11-21 14:42:09 +01:00
Karl Tauber
cce99c803e GitHub Actions: test release job without publishing 2020-11-21 14:32:36 +01:00
Karl Tauber
19ed538573 GitHub Actions: added secrets for snapshot and release jobs 2020-11-21 14:24:56 +01:00
Karl Tauber
a1f78345e6 GitHub Actions: use separate jobs for snapshots and releases to be sure that build succeeded for all Java versions 2020-11-21 14:04:32 +01:00
Karl Tauber
f8c7ccf064 GitHub Actions: run if tags are pushed 2020-11-21 13:38:21 +01:00
Karl Tauber
4d5242cd61 GitHub Actions: fixed typo in snapshot step condition 2020-11-21 12:06:18 +01:00
Karl Tauber
7ad176f98d GitHub Actions: info step added 2020-11-21 12:02:08 +01:00
Karl Tauber
57df7d28b5 GitHub Actions: added steps for snapshots and releases 2020-11-21 11:51:41 +01:00
Karl Tauber
f784ff2c84 GitHub Actions: test also against Java 9 2020-11-21 01:57:37 +01:00
Karl Tauber
a0f6affb68 GitHub Actions: cache gradle wrapper; fixed key for caching gradle cache 2020-11-21 01:37:28 +01:00
Karl Tauber
0c679167fa GitHub Actions: cache gradle dependencies 2020-11-21 00:48:27 +01:00
Karl Tauber
4fe707e519 GitHub Actions: initial commit 2020-11-21 00:19:46 +01:00
Karl Tauber
d83704b7cb FlatPaintingTest: added test case for circular components 2020-11-20 11:57:24 +01:00
Karl Tauber
2177ee45cc FlatUIUtils: replaced quadratic curves with bezier curves in createRoundRectanglePath() to get perfect circle when using large arcs
(currently only used for SwingX)
2020-11-20 11:50:03 +01:00
Karl Tauber
ccd4f99aea Window decorations: removed 1px window border if window is in full-screen mode (issue #212) 2020-11-20 10:12:28 +01:00
Karl Tauber
cd6b55c846 Demo: Alt+UP and Alt+DOWN now switch to previous/next theme 2020-11-20 00:40:10 +01:00
Karl Tauber
d923c8df81 Window decorations: title bar was not hidden if window is in full-screen mode (issue #212) 2020-11-18 23:31:04 +01:00
Karl Tauber
59879f493e FlatTestFrame: fixed exception when using FlatPropertiesLaf and changing scale factor, which re-sets the current Laf 2020-11-18 18:45:13 +01:00
Karl Tauber
06cab0d4b5 updated svgSalamander to version 1.1.2.4 2020-11-18 18:34:12 +01:00
Karl Tauber
a16db38a6f Testing: FlatBaselineTest added 2020-11-18 18:32:08 +01:00
Karl Tauber
de93e19a80 JIDE: RangeSlider: updated UI defaults dumps 2020-11-17 12:13:01 +01:00
Karl Tauber
47bb7d0de7 JIDE: RangeSlider: added to CHANGELOG.md and README.md 2020-11-16 22:26:49 +01:00
Karl Tauber
896e808db4 JIDE: RangeSlider: removed nested panel from FlatRangeSliderTest 2020-11-16 22:19:09 +01:00
Karl Tauber
6fe6d1ffa0 JIDE: RangeSlider: reordered methods and slightly changed formatting to make it easier to compare with FlatRangeSliderUI 2020-11-16 22:04:08 +01:00
Karl Tauber
4c6f7a66e2 Merge pull request #209 into master
Add RangeSlider support
2020-11-16 21:25:50 +01:00
Karl Tauber
4b5646ec88 release 0.44 2020-11-15 11:29:07 +01:00
Karl Tauber
66a5f350da Merge pull request #211 into master
TabbedPane: scroll buttons on both sides of the tab area
2020-11-15 11:20:43 +01:00
Karl Tauber
f9e34cbab7 TabbedPane: support specifying default tab layout policy for all tabbed panes via UI value TabbedPane.tabLayoutPolicy 2020-11-14 18:46:39 +01:00
Karl Tauber
634f7b5ba3 CHANGELOG.md: added/updated latest TabbedPane changes 2020-11-14 00:48:37 +01:00
Karl Tauber
7dbc6ff8a3 TabbedPane: fixes
- avoid that tab area "jump" to the right/top when backward button becomes hidden
- scroll arrow buttons were not always hidden in right-to-left horizontal layout
2020-11-14 00:24:38 +01:00
Karl Tauber
afccdc4749 Demo: "Tabs" tab: improved demo of leading and trailing tab area components by using toolbars 2020-11-13 23:25:19 +01:00
Karl Tauber
c98ec041d4 Demo: "Tabs" tab: added "Scroll buttons policy", "Scroll buttons placement" and "Tabs popup policy" configuration for PR #211 2020-11-13 22:26:14 +01:00
Karl Tauber
9e0c62092e TabbedPane: updated UI defaults dumps for previous checkins 2020-11-13 22:23:28 +01:00
Karl Tauber
9aea006f50 TabbedPane: fixed typo in previous commit 2020-11-13 18:20:00 +01:00
Karl Tauber
c16c3759cf TabbedPane:
- support forward/backward scroll buttons on both sides of the tab area (new default)
- optionally: not applicable scroll buttons are hidden (new default)
- changed configuration
  - removed TabbedPane.hiddenTabsNavigation
  - added TabbedPane.tabsPopupPolicy, TabbedPane.scrollButtonsPolicy and TabbedPane.scrollButtonsPlacement
- made scroll arrows larger

(issue #40; replaces PR #195)
2020-11-13 17:34:46 +01:00
Karl Tauber
cbc1fe27ef TabbedPane: more fallbacks to find tab name for "more tabs" popup in case that tab title is not set (issue #207; PR #190) 2020-11-13 11:48:03 +01:00
mmatessi
f57dbf94c8 FlatJideOssDefaultsAddon reformat 2020-11-13 09:47:32 +01:00
mmatessi
c0f15d2e6f FlatRangeSliderUI fix change label foreground 2020-11-13 09:42:26 +01:00
mmatessi
cb525fafb6 FlatSliderUI extends BasicSliderUI 2020-11-12 13:02:16 +01:00
mmatessi
5cae3a8141 add RangeSlider support 2020-11-11 16:57:40 +01:00
Karl Tauber
8594e78287 TabbedPane: search for label or text component in custom tab component and use its text in "more tabs" popup (issue #207; PR #190) 2020-11-10 15:28:25 +01:00
Karl Tauber
5b8f922273 FlatSVGIcon: getImage() now returns a multi-resolution image (on Java 9+) for HiDPI disabled icons in other LaFs that support multi-resolution images when producing disabled icons in LookAndFeel.getDisabledIcon() (e.g. Windows or Nimbus Laf) (issue #205) 2020-11-10 11:56:59 +01:00
Karl Tauber
847b41752c FlatSVGIcon: icons were not painted in disabled labels and disabled tabs (issue #205) 2020-11-10 11:22:34 +01:00
Karl Tauber
7c08489cb3 UIDefaultsLoader: minor optimization (avoid String.substring() and avoid double searching for '.') 2020-11-06 23:47:06 +01:00
Karl Tauber
605c77ecbc IntelliJ Themes: added getName() method to all InttelliJ Laf classes so that they return same name as defined in class FlatAllIJThemes (issue #201) 2020-11-06 19:13:11 +01:00
Karl Tauber
fd0c2a5cd1 IntelliJ Themes: added suffix "(Material)" to names of all Material UI Lite themes to avoid duplicate theme names (issue #201) 2020-11-06 18:38:21 +01:00
Karl Tauber
a80790fc8e TabbedPane:
- use rounded rectangles for buttons in tab area
- "pressed" background for buttons in tab area
- fill background of buttons in tab area
- use derived colors for hover and pressed
- fixed missing arrow in "more tabs" button at larger scaling
2020-11-06 17:30:29 +01:00
Karl Tauber
206d449d0d FlatLaf.properties: added "allowed values" as comments 2020-11-05 19:19:13 +01:00
Karl Tauber
2323dc099f TabbedPane: always use chevron arrows (even in IntelliJ and Darcula themes) 2020-11-05 18:59:28 +01:00
Karl Tauber
642583479f default arrow type changed from "triangle" to "chevron" (does not change any theme) 2020-11-05 18:55:08 +01:00
Karl Tauber
082e5842d0 removed FlatClientProperties.clientPropertyChoice() 2020-11-05 18:35:36 +01:00
Karl Tauber
c67ba02839 UI defaults dumps updated for PR #202 2020-11-05 17:12:21 +01:00
Karl Tauber
4c6cb7618f Merge pull request #202 into master
TextField: allow select all on mouse click
2020-11-05 17:07:29 +01:00
basix86
c15100f129 Update FlatLaf.properties
fixed previous behavior selectAllOnMouseClick
2020-11-05 10:47:47 +01:00
basix86
6dfb3cc84e Update FlatCaret.java
missing space
2020-11-05 10:46:12 +01:00
Karl Tauber
18d8c7d086 SplitPane: added grip to divider (issue #179) 2020-11-04 11:52:50 +01:00
mmatessi
ab3adf4ae3 selectAllOnMouseClick 2020-11-04 10:16:23 +01:00
basix86
7e6619af00 Merge pull request #1 from JFormDesigner/master
update fork
2020-11-04 09:48:40 +01:00
Karl Tauber
a7e2a10403 TabbedPane: support horizontal alignment of tab title and icon 2020-11-03 22:20:55 +01:00
Karl Tauber
3a784375d0 SplitPane: support tooltip texts in splitpane client properties (issue #198) 2020-11-02 15:07:57 +01:00
Karl Tauber
b8c9433259 SplitPane: added tooltips to expand/collapse buttons (issue #198) 2020-11-02 12:13:06 +01:00
Karl Tauber
815d9d6012 SplitPane: hide not applicable expand/collapse buttons (issue #198) 2020-11-02 11:51:51 +01:00
Karl Tauber
feb91aa056 Demo: re-designed "Tabs" tab to show features added in PRs #187, #190, #192, #193 and #199 2020-11-01 21:36:46 +01:00
Karl Tauber
cd264586ca TabbedPane: fixed missing arrow in "more tabs" button when changing tabPlacement to left/right and back to top/bottom (PR #190) 2020-11-01 17:19:12 +01:00
Karl Tauber
c6d561f2df Demo: moved split panes from "SplitPane & Tabs" tab to "More Components" tab (to make room for more tabbed pane features) 2020-11-01 16:45:05 +01:00
Karl Tauber
6167c5f855 TabbedPane: calculate correct preferred size for tabbed panes without any content 2020-11-01 16:38:28 +01:00
Karl Tauber
1a31cb96b8 TabbedPane: disable wheel scrolling if application has added its own mouse wheel listener (PR #187) 2020-11-01 16:22:05 +01:00
Karl Tauber
9b8df64c35 FlatContainerTest: always use for-loop to modify all tabbed panes 2020-11-01 15:59:47 +01:00
Karl Tauber
a47565afec Merge pull request #199 into master
TabbedPane: tab area alignment; min/max tab widths; tab icon placement; tab width mode
2020-11-01 15:56:10 +01:00
Karl Tauber
c2ee815cbe TabbedPane: fixed clipping when painting tab selection in scroll layout 2020-10-31 14:20:35 +01:00
Karl Tauber
e45a2df6b6 FlatContainerTest: test disabled tab icons 2020-10-31 11:30:06 +01:00
Karl Tauber
a19979c233 FlatContainerTest: test HTML tab titles 2020-10-30 10:50:17 +01:00
Karl Tauber
e2a297fa40 TabbedPane: support left, right, top and bottom tab icon placement 2020-10-30 01:47:14 +01:00
Karl Tauber
df13b338b2 TabbedPane: support specifying tab area insets via client property 2020-10-29 22:42:41 +01:00
Karl Tauber
da9d7a0dee TabbedPane: support equal and compact tab width modes 2020-10-29 19:26:09 +01:00
Karl Tauber
0374c65159 TabbedPane: support alignment of tab area (leading, trailing, center or fill) 2020-10-29 16:11:30 +01:00
Karl Tauber
71b1e07ba6 TabbedPane: support minimum and maximum tab widths 2020-10-29 16:10:27 +01:00
Karl Tauber
c3781dc4b5 CHANGELOG.md: added PR references 2020-10-27 17:16:25 +01:00
Karl Tauber
dc92d0913c TabbedPane: trailing component now fills all available horizontal space (PR #192) 2020-10-27 16:29:58 +01:00
Karl Tauber
a5adf29001 FlatContainerTest:
- reorganized tabbed pane control panel
- added "tab area insets" checkbox
- made text of leading component shorter
2020-10-27 14:07:14 +01:00
Karl Tauber
8861bfe4fa FlatContainerTest:
- replaced "more tabs" checkbox and spinner with "tab count" spinner
- avoid right-to-left for tabbed pane control panel
- use other color for trailing component
2020-10-27 10:44:14 +01:00
Karl Tauber
c8d280f418 TabbedPane: improved/fixed placement of tab close button on smaller tab insets or smaller tab height (PR #193) 2020-10-26 23:37:02 +01:00
Karl Tauber
09c98359af fixed javadoc warnings and errors 2020-10-26 15:16:37 +01:00
Karl Tauber
6f8a7471c2 SVGUtils: support creating window images from SVG files that are not 16x16 (issue #196) 2020-10-26 15:13:37 +01:00
Karl Tauber
4c141fe47c FlatSVGIcon now allows specifying icon width and height in constructors (issue #196) 2020-10-26 13:53:25 +01:00
Karl T
b37ff348fb Merge pull request #197 from kingthorin/patch-1
Minor correction
2020-10-26 11:17:54 +01:00
kingthorin
09798d33b0 Minor correction
“not be” vs “be not”.

Just noticed while browsing around.
2020-10-24 16:22:21 -04:00
Karl Tauber
717ab95fbe Merge pull request #193 into master
TabbedPane closable tabs
2020-10-22 22:40:30 +02:00
Karl Tauber
3f616e3608 TabbedPane: for right-to-left always use "more tabs" button for horizontal scrolling because methods scrollForward() and scrollBackward() in class BasicTabbedPaneUI.ScrollableTabSupport do not work for right-to-left 2020-10-22 11:07:42 +02:00
Karl Tauber
c590157561 TabbedPane: support specifying tooltip text for tab close buttons via client property 2020-10-21 23:13:01 +02:00
Karl Tauber
2b50431081 TabbedPane: fixed scaling of client property "JTabbedPane.tabHeight"; avoid storing scaled values in UI delegate 2020-10-21 11:24:06 +02:00
Karl Tauber
6d38e44f91 TabbedPane: support specifying tab insets via client property 2020-10-21 01:14:26 +02:00
Karl Tauber
9bc656a5c5 TabbedPane: fixed NPE in scroll layout when removing last tab 2020-10-20 10:37:31 +02:00
Karl Tauber
700bb9b567 TabbedPane: support closable tabs (issue #40) 2020-10-20 09:37:28 +02:00
Karl Tauber
8ccda81d9a Merge pull request #192 into master
TabbedPane custom components on left and right sides of tabs area
2020-10-19 23:35:17 +02:00
Karl Tauber
3818790ced TabbedPane: support adding custom components to left and right sides of tabs area if wrap layout is used (issue #40) 2020-10-17 18:17:45 +02:00
Karl Tauber
c34ce389a4 TabbedPane: do not include preferred/minimum size of leading/trailing components in calculating preferred/minimum size of tabbed pane, because the largest tab content determines the size 2020-10-17 16:46:56 +02:00
Karl Tauber
15718cdb46 TabbedPane: support adding custom components to left and right sides of tabs area if scroll backward/foreward buttons are used (issue #40)
this also fixes some minor layout issues when using tabAreaInsets and arrow buttons
2020-10-17 15:19:39 +02:00
Karl Tauber
10746a454a TabbedPane: support adding custom components to left and right sides of tabs area if "more tabs" button is used (issue #40) 2020-10-17 11:30:04 +02:00
Karl Tauber
f0fd02e81f Merge pull request #190 into master
Tabbedpane "Show Hidden Tabs" button
2020-10-16 23:10:49 +02:00
Karl Tauber
bfaac6d164 TabbedPane: fixed: content separator was painted at wrong position if using TabbedPane.tabAreaInsets (regression since changing TabbedPane.tabsOverlapBorder to false in commit c58f5a6ca7)
exit paintContentBorder() early if content separator is not painted
2020-10-16 21:13:06 +02:00
Karl Tauber
a909f1012a TabbedPane: finally get rid of the cropped edge (issue #40) 2020-10-16 12:25:04 +02:00
Karl Tauber
201581a07c TabbedPane: support right-to-left if "more tabs" button is used (issue #40) 2020-10-16 00:24:02 +02:00
Karl Tauber
8cef5ecf7e popups using JToolTip components did not respect their location (fixes #188; regression in 0.42 in fix for #164) 2020-10-15 17:49:34 +02:00
Karl Tauber
2c1075f471 TabbedPane: do not clip title on left tabs when scrolled 2020-10-15 14:53:42 +02:00
Karl Tauber
1f5e08fdc6 TabbedPane: fixed clipping title if "more tabs" button is used (issue #40) 2020-10-15 13:16:21 +02:00
Karl Tauber
c0408045ef TabbedPane: support specifying hiddenTabsNavigation type per tabbedpane via client property (issue #40) 2020-10-15 10:41:45 +02:00
Karl Tauber
c58f5a6ca7 TabbedPane: replaced forward/backward scrolling arrow buttons with "Show Hidden Tabs" button (issue #40) 2020-10-15 00:10:07 +02:00
Karl Tauber
ae445c9343 Merge pull request #187 into master
TabbedPane wheel scrolling
2020-10-14 22:43:02 +02:00
Karl Tauber
ad7ff2ba0b support painting separator line between window title and content (issue #184) 2020-10-14 22:08:20 +02:00
Karl Tauber
4b7ef6e853 FlatWindowDecorationsTest: added "menu bar visible" checkbox (for testing previous commit) 2020-10-14 13:37:28 +02:00
Karl Tauber
87f2acc2d9 Window decorations: not visible menu bar is now ignored in layout 2020-10-14 13:05:39 +02:00
Karl Tauber
ec2fef02ed Demo: if disabling window decoration ("Options > Window decorations") , which changes the main window, also invoke JDialog.setDefaultLookAndFeelDecorated() to disable window decorations for dialogs 2020-10-14 10:50:54 +02:00
Karl Tauber
ebe0d74dbe FlatInspector: make sure that glass pane is not opaque, which is not the case in all Lafs 2020-10-14 10:36:29 +02:00
Karl Tauber
029dc51f8b Testing: updated 3rd party Lafs 2020-10-14 10:30:44 +02:00
Karl Tauber
3fc85cd7b2 TabbedPane: support precise scrolling tabs with trackpad (issue #40) 2020-10-12 00:33:23 +02:00
Karl Tauber
a46bdef079 Animator: reuse timer instance
(cherry picked from commit 0888fd8fb5d18c36886bf958ac5a5e44bf75618d)
2020-10-11 22:51:33 +02:00
Karl Tauber
3de489f693 TabbedPane:
- fixed jittery animated scrolling tabs
- support disabling animated scrolling with "ScrollPane.smoothScrolling=false"
2020-10-09 16:27:52 +02:00
Karl Tauber
eddb9eee46 TabbedPane: make sure that tab stays hover highlighted when mouse is moved to custom tab component that handles mouse events (e.g. a close button)
refactored PropertyChangeListener to class Handler
2020-10-09 10:19:17 +02:00
Karl Tauber
5b0c96cd6d TabbedPane: avoid scrolling selected tab back into visible area (after wheel scrolling) if the mouse is over a custom tab component that handles mouse events (e.g. a close button) 2020-10-08 23:46:43 +02:00
Karl Tauber
15ac77107f TabbedPane: increased size of scroll arrow buttons (issue #40) 2020-10-07 19:09:19 +02:00
Karl Tauber
a7c906091c TabbedPane: use animation for scrolling tabs with mouse wheel (issue #40) 2020-10-07 17:54:12 +02:00
Karl Tauber
de870c546c TabbedPane: repeat scrolling as long as arrow buttons are pressed (issue #40) 2020-10-07 16:05:26 +02:00
Karl Tauber
2f3427e6ad TabbedPane: scroll selected tab into visible area (500ms delayed) if mouse exits scroll viewport after wheel scrolling (issue #40) 2020-10-07 13:29:15 +02:00
Karl Tauber
203426bd55 TabbedPane: support scrolling tabs with mouse wheel (if tabLayoutPolicy is SCROLL_TAB_LAYOUT) (issue #40) 2020-10-07 12:25:46 +02:00
Karl Tauber
16242080e0 README.md: screenshots of dark themes updated 2020-10-06 13:37:37 +02:00
Karl Tauber
57655d8859 release 0.43 2020-10-05 14:36:54 +02:00
Karl Tauber
62ffd57108 Windows: made scaling compatible with Windows OS scaling, which distinguish between "screen scaling" and "text scaling" (issue #175) 2020-10-05 13:14:44 +02:00
Karl Tauber
8db05f47b5 FlatChooserTest: grow file chooser when resizing window 2020-10-04 23:59:28 +02:00
Karl Tauber
c684761eef ComboBox: limit popup width to screen width for very long items (issue #182) 2020-10-04 18:59:54 +02:00
Karl Tauber
0a8ece8c9c no longer use static fields for shared instances of UI delegates because this makes problems in GUI builders that support Laf switching and use more than one FlatLaf theme at the same time 2020-10-04 14:21:00 +02:00
Karl Tauber
01058bde1b UI defaults inspector: fixed key rendering for Nimbus Laf 2020-10-04 14:03:39 +02:00
Karl Tauber
9c2c03cddb Spinner: fixed NullPointerException in case that arrow buttons were removed to create button-less spinner (issue #181) 2020-10-04 13:58:23 +02:00
Karl Tauber
f0778a83a0 CheckBoxMenuItem and RadioButtonMenuItem: improved checkmark background colors of selected menu items that have also an icon 2020-09-25 00:07:25 +02:00
Karl Tauber
b86ae1f122 FileChooser: fixed localizing special Windows folders (e.g. "Documents") and enabled hiding known file extensions (if enabled in Windows Explorer) (issue #178) 2020-09-24 22:27:10 +02:00
Karl Tauber
dfd6831b02 ComboBox: if using own JTextField as editor, default text field border is now removed to avoid duplicate border 2020-09-24 22:17:10 +02:00
Karl Tauber
a4ddc13c1a TabbedPane: added some missing UI defaults 2020-09-24 22:05:07 +02:00
Karl Tauber
fd63a1b7c2 TabbedPane: support hiding separator between tabs and content area via client property 2020-09-24 22:03:39 +02:00
Karl Tauber
d83c3689d0 TabbedPane:
- made tabs separator color lighter in dark themes so that it is easier to recognize the tabbed pane
- added top and bottom tab insets to avoid that large tab icons are painted over active tab underline
2020-09-24 15:18:45 +02:00
Karl Tauber
d52bf9d318 FlatScreenInfo: output warning if screens intersect (issue #177) 2020-09-23 21:44:00 +02:00
Karl Tauber
80f56dec15 travis: added openjdk15 2020-09-23 19:03:53 +02:00
Karl Tauber
358c226b96 update to Gradle 6.6.1
./gradlew wrapper --gradle-version=6.6.1
2020-09-23 18:42:12 +02:00
Karl Tauber
9de9983416 laf.dark flag added to UI defaults 2020-09-20 10:59:50 +02:00
Karl Tauber
c9da4fcaf1 UI defaults: dumps moved out of resources folder to dumps/uidefaults folder 2020-09-18 14:41:15 +02:00
Karl Tauber
932ca6f9d4 FlatDesktopPropertiesDump tool added
developed to find out whether it is possible to detect Windows screen scaling and text scaling factors in Java 8, which seems to be possible by using "win.defaultGUI.font" desktop property

issue #175
2020-09-18 14:24:30 +02:00
Karl Tauber
4487c9985c release 0.42 2020-09-17 15:51:27 +02:00
Karl Tauber
a53ce99977 PasswordField: support disabling Caps Lock warning icon (issue #172) 2020-09-17 15:34:57 +02:00
Karl Tauber
5444719895 Extras: added screenshots to README.md and instructions for using UI inspectors 2020-09-17 14:20:59 +02:00
Karl Tauber
b66139281d FlatHtmlTest: fixed labels and added HTML tooltips 2020-09-17 13:50:56 +02:00
Karl Tauber
8925c27eb9 ToolTip: avoid that tooltip hides owner component (issue #164) 2020-09-17 13:32:28 +02:00
Karl Tauber
99be346387 FlatWindowDecorationsTest: disable "add/remove/change menu" buttons if shown in dialog, which does not have a menubar 2020-09-17 13:28:02 +02:00
Karl Tauber
81d46ba8ee Demo: show simple dialog for "File > New"
(used to test previous commit)
2020-09-17 13:26:45 +02:00
Karl Tauber
ef4c467b20 fixed occasional wrong positioning of heavy weight popups when using multiple screens with different scaling factors (issue #166)
workaround for https://bugs.openjdk.java.net/browse/JDK-8224608
2020-09-17 11:43:20 +02:00
Karl Tauber
44d196fb8c Demo: menu item "Options > Window decorations" did exit Demo
(regression in commit ee6a1da709)
2020-09-16 22:52:19 +02:00
Karl Tauber
867c4fff58 fixed compiling flatlaf-extras on Java 9+ 2020-09-15 18:06:56 +02:00
Karl Tauber
5643546117 UI defaults inspector:
- add placeholder text to filter field
- fixed menu item text in Demo
2020-09-15 17:56:20 +02:00
Karl Tauber
549832ba96 UI defaults inspector:
- fixed: indicate when a LaF UI value was overridden with UIManager.put(key,value)
- auto-refresh if UIManager.put(key,value) was invoked
2020-09-15 17:30:13 +02:00
Karl Tauber
a8744b2bb4 made disabled text color slightly lighter in dark themes for better readability (issue #174) 2020-09-15 15:47:12 +02:00
Karl Tauber
e292d3444c UI defaults inspector: avoid that restored window bounds are outside of screens 2020-09-15 15:09:03 +02:00
Karl Tauber
ee6a1da709 Demo: exit even if UI defaults inspector window is shown 2020-09-15 13:44:00 +02:00
Karl Tauber
8c15bc746b UI defaults inspector: render values of type Border, GrayFilter, Object[] and int[]; paint icons with light gray background 2020-09-15 13:16:01 +02:00
Karl Tauber
aebb083180 UI defaults inspector: indicate when a LaF UI value was overridden with UIManager.put(key,value) 2020-09-15 12:02:51 +02:00
Karl Tauber
5438549b6d UI defaults inspector: horizontally align rgb() and hsl() in color values 2020-09-15 10:56:28 +02:00
Karl Tauber
0077708235 UI defaults inspector: install it in FlatTestFrame and FlatThemeFileEditor 2020-09-15 00:32:04 +02:00
Karl Tauber
2fd99ec9f3 UI defaults inspector: support sorting 2020-09-15 00:16:57 +02:00
Karl Tauber
0d266c4990 UI defaults inspector: use short format for hex colors if possible; use uppercase hex 2020-09-14 23:53:54 +02:00
Karl Tauber
0982675b5f UI defaults inspector: support filter by value
this is also a preparation to support sort by value
2020-09-14 23:13:44 +02:00
Karl Tauber
3bac5d3c80 UI defaults inspector:
- update table if LaF was switched or F5 key pressed
- added LaF name to window title
- close window with ESC key
2020-09-14 21:18:52 +02:00
Karl Tauber
58338f4848 UI defaults inspector: scroll with Up, Down, PageUp and PageDown keys if filter field is focused 2020-09-14 20:35:41 +02:00
Karl Tauber
9c261d3a3f UI defaults inspector: support filter by key and by value type 2020-09-14 18:17:05 +02:00
Karl Tauber
5441ac6640 UI defaults inspector: added separator between component groups and draw component name with lighter color 2020-09-14 15:18:10 +02:00
Karl Tauber
015b04a29a UI defaults inspector: initial commit with basic functionality 2020-09-14 15:16:16 +02:00
Karl Tauber
12ec0abf54 UI defaults: moved some common properties from FlatLightLaf.properties and FlatDarkLaf.properties to FlatLaf.properties 2020-09-12 22:00:17 +02:00
Karl Tauber
c8d461cdee UI defaults: moved "globals" from FlatLightLaf.properties and FlatDarkLaf.properties to FlatLaf.properties 2020-09-12 20:53:23 +02:00
Karl Tauber
faecffeadd TextComponents: fixed text color of disabled text components in dark themes (issue #174) 2020-09-12 18:45:40 +02:00
Karl Tauber
b3c76c21b4 UIDefaultsLoader: moved some code to where it belongs (for previous commit) 2020-09-12 18:38:35 +02:00
Karl Tauber
1697735162 UIDefaultsLoader: changed processing of "globals" so that they are first added to the properties table (instead of directly modifying defaults table), which is then parsed and copied to defaults table
this has the advantage that they can be referenced in other values, which did not work before (because they only existed in `defaults` table)

used for Tree.textForeground
verified with UIDefaultsDump that there are no side effects
2020-09-12 18:13:34 +02:00
Karl Tauber
ecb94bac6d use short color format #RGB (instead of #RRGGBB) where possible 2020-09-11 21:24:00 +02:00
Karl Tauber
7ebeacf16e UIDefaultsDump: dump FlatTestLaf 2020-09-11 21:08:07 +02:00
Karl Tauber
d0079ab66b UIDefaultsLoader: use class loader from FlatLaf.registerCustomDefaultsSource(String, ClassLoader) also for instantiating classes specified in values
see commit b208017117
2020-09-11 17:58:12 +02:00
Karl Tauber
147e400bd6 FlatInspector: limit parent level to real depth at mouse location (issue #169) 2020-09-11 17:37:40 +02:00
Karl Tauber
c44905ea5e InternalFrame: support draggable border for resizing frame inside of the visible frame border (issue #121) 2020-09-04 22:59:09 +02:00
Karl Tauber
98b9df06fe Window decorations: fixed wrong window bounds when resizing window to another screen with different scaling factor (issue #166) 2020-09-04 09:46:12 +02:00
Karl Tauber
02473080a5 Window decorations: fixed wrong window placement when moving window to another screen with different scaling factor (issue #166) 2020-09-03 19:26:52 +02:00
Karl Tauber
c6beb9dc0a Demo: menu items "File > Open" and "File > Save As" now show file choosers 2020-09-03 18:16:28 +02:00
Karl Tauber
dcce14b122 FlatScreenInfo tool added 2020-09-03 15:55:12 +02:00
Karl Tauber
a2ac24ac74 Demo: "SplitPane & Tabs" tab improved 2020-09-03 15:09:28 +02:00
Karl Tauber
600f812f45 Demo: removed too large gap between content panel and control bar 2020-09-03 12:01:49 +02:00
Karl Tauber
e945f46f25 Demo: "Data components" tab: added checkboxes to control table grid and selection 2020-09-03 11:53:50 +02:00
Karl Tauber
c78c653b0a FlatComponents2Test: moved table checkboxes into tableOptionsPanel 2020-09-03 11:26:16 +02:00
Karl Tauber
e0b3663239 FlatComponents2Test: support testing large amount of list/tree/table rows 2020-09-03 11:12:00 +02:00
Karl Tauber
3cc9c98040 Demo:
- "Data components" tab: increase component height if frame is made larger
- "SplitPane & Tabs" tab: increased some gaps and renamed TabbedPane option checkboxes
- "Option Pane" and "Extras" tabs: minor layout improvements
2020-09-02 19:08:24 +02:00
Karl Tauber
ec8213b891 release 0.41 2020-09-02 11:23:43 +02:00
Karl Tauber
ae61383742 README.md: screenshots updated; removed unused screenshots 2020-09-01 18:50:26 +02:00
Karl Tauber
cc90a2ad75 Demo: reworked "More Components" tab and added screenshot mode 2020-09-01 17:24:26 +02:00
Karl Tauber
28634cda56 README.md: screenshots updated 2020-09-01 12:20:40 +02:00
Karl Tauber
3b71fcd690 Demo: fixed too large gap between themes list and control bar 2020-08-31 18:25:01 +02:00
Karl Tauber
5923ac65df smoother transition from old to new theme, independent of UI complexity, when using animated theme change 2020-08-31 18:10:54 +02:00
Karl Tauber
faffc9393d fixed sub-pixel text rendering in animated theme change; use weak hash map for static map to avoid memory leak for the case that something went wrong 2020-08-31 18:07:37 +02:00
Karl Tauber
6da220f36c IntelliJ Themes: updated themes to newest versions (used IJThemesUpdater) 2020-08-27 00:05:29 +02:00
Karl Tauber
21d78671d6 Demo: show hint popups to guide users to some features of the FlatLaf Demo application; added "Options > Show hints" menu item 2020-08-26 23:17:55 +02:00
Karl Tauber
af5a0ec0b7 Window decorations: fixed title pane background color in IntelliJ themes if window is inactive 2020-08-26 16:13:44 +02:00
Karl Tauber
ff214455a3 Window decorations: fixed iconify, maximize and close icon colors if window is inactive 2020-08-26 15:03:26 +02:00
Karl Tauber
3e941e3e42 Demo: fixed restoring last used theme on startup (regression in 0.39 since commit a8f4c8e843) 2020-08-26 12:35:26 +02:00
Karl Tauber
2f876d553f List and Table: fixed possible NPE in unusual cases 2020-08-26 12:16:11 +02:00
Karl Tauber
b208017117 added API to register packages or folders where FlatLaf searches for application specific properties files with custom UI defaults 2020-08-26 12:07:00 +02:00
Karl Tauber
a1dab94a61 TextArea: update background color property if enabled or editable state changes in the same way as Swing does it for all other text components (issue #147) 2020-08-25 19:15:53 +02:00
Karl Tauber
e55b2afd60 Button: show "selected" state (issue #161) 2020-08-25 16:41:40 +02:00
Karl Tauber
535c3ddf6c FlatSVGIcon now allows specifying ClassLoader that is used to load SVG file (issue #163) 2020-08-24 23:31:18 +02:00
Karl Tauber
3008d99fcd updated svgSalamander to version 1.1.2.3 2020-08-24 22:45:35 +02:00
Karl Tauber
fd37339e2f TableHeader: fixed NPE for the (unusual) case that JTableHeader is used without JTable 2020-08-13 17:07:44 +02:00
Karl Tauber
e29eca203c Theme Editor: build fat jar (includes all dependencies) (issue #160) 2020-08-12 14:02:04 +02:00
Karl Tauber
f1fd6dcdd2 release 0.40 2020-08-11 11:32:05 +02:00
Karl Tauber
2975ed2eae FlatComponents2Test: added checkboxes to enable/configure table grid lines 2020-08-07 22:46:26 +02:00
Karl Tauber
5a27d03faa IntelliJ Themes: fixed NPE in Solarized themes on scroll bar hover 2020-08-07 17:34:23 +02:00
Karl Tauber
8bcf9dbcaf - Table: detect whether component is used in cell editor and automatically disable round border style and reduce cell editor outer border width (used for focus indicator) to zero
- ComboBox, Spinner and TextField: support disabling round border style per component, if globally enabled
(issue #148)
2020-08-07 11:27:27 +02:00
Karl Tauber
56ebd26361 Window decorations: make embedded menu bar make smaller if horizontal space is rare to avoid that embedded menu bar overlaps buttons 2020-08-06 23:10:54 +02:00
Karl Tauber
b0426b81a7 Window decorations: embedded menu bar did not always respond to mouse events after adding menus and when running in JetBrains Runtime (issue #151) 2020-08-06 11:45:47 +02:00
Karl Tauber
368fbcdeb0 release 0.39 2020-08-03 16:20:57 +02:00
Karl Tauber
30747b7776 UIScale: added system property "flatlaf.uiScale.enabled" (replaces "hidpi" property) to disable user scaling mode 2020-08-02 14:08:18 +02:00
Karl Tauber
4eb4ddf5d8 FlatTestFrame: do not use sun.java2d.uiScale for user scale factor 2020-08-02 11:43:46 +02:00
Karl Tauber
b1d24680b2 ToolTip: fixed truncated text in HTML formatted tooltip on HiDPI displays (issue #142) 2020-08-01 22:53:09 +02:00
Karl Tauber
ef38f3805e IntelliJ Themes: fixed text colors in ProgressBar (issue #138) 2020-08-01 00:31:20 +02:00
Karl Tauber
2f5ca20ca4 fixed compile error caused by previous checkin (issue #143) 2020-07-31 19:28:58 +02:00
Karl Tauber
f29d3d84d4 FileChooser: fixed too small text field when renaming a file/directory in Flat IntelliJ/Darcula themes (issue #143) 2020-07-31 19:17:49 +02:00
Karl Tauber
02132c5fcd MenuItem on macOS: removed plus characters from accelerator text and made modifier key order conform with macOS standard (issue #141) 2020-07-31 13:02:01 +02:00
Karl Tauber
7057e3c6ad IntelliJ Themes: added "Carbon" and "Cobalt 2" themes 2020-07-30 23:11:37 +02:00
Karl Tauber
a8f4c8e843 Demo: added combo box above themes list to show only light or dark themes 2020-07-30 19:41:56 +02:00
Karl Tauber
a2b6e66a13 CHANGELOG.md: split change log of last version into "New features" and "Fixed bugs" sections 2020-07-30 19:26:50 +02:00
Karl Tauber
e3b3cc2896 IntelliJ Themes: replaced "Solarized" themes with much better ones from 4lex4 2020-07-30 16:30:56 +02:00
Karl Tauber
a5b2c50f24 IntelliJ Themes:
- added "Arc Dark" and "Arc Dark - Orange" themes
- updated themes to newest versions (used IJThemesUpdater)
2020-07-30 15:00:31 +02:00
Karl Tauber
5ebdf64d30 ComboBox: fixed width of popup, which was too small if popup is wider than combo box and vertical scroll bar is visible (issue #137) 2020-07-30 13:30:50 +02:00
Karl Tauber
2640ab2e8b ComboBox: changed maximum row count of popup list to 15 (was 20) (issue #124) 2020-07-30 12:11:15 +02:00
Karl Tauber
e29436da04 Button: support specifying button border width 2020-07-28 23:51:02 +02:00
Karl Tauber
7b35325f9a Flat IntelliJ theme: use color functions for selected checkbox/radio button hover/pressed background 2020-07-28 22:14:08 +02:00
Karl Tauber
f2ab7fafcf ToolTip: do not show empty tooltip component if tooltip text is an empty string (issue #134) 2020-07-28 11:10:34 +02:00
Karl Tauber
e3cda9905a Table: allow disabling swapped behavior of Home/End and Ctrl+Home/End with Table.consistentHomeEndKeyBehavior=false (issue #95) 2020-07-27 17:55:31 +02:00
Karl Tauber
a8423f7741 ScrollBar: increased minimum thumb size on macOS and Linux to 18px and on Windows to 10px; also include ScrollBar.thumbInsets in minimum size calculation (issue #131) 2020-07-27 14:41:01 +02:00
Karl Tauber
5a9e620c17 Animator: added constructor that allows passing a runnable that is invoked at the end of the animation, which allows using lambdas in most cases 2020-07-25 10:53:06 +02:00
Karl Tauber
9f41ec3986 ScrollPane: support disabling smooth scrolling per component via client property "JScrollPane.smoothScrolling" 2020-07-25 10:27:06 +02:00
Karl Tauber
5a2c0672d4 Window decorations: avoid possible endless restore/maximize in WindowStateListener in case of behavior changes in Java (issue #129) 2020-07-23 10:43:24 +02:00
Karl Tauber
38d853b5b2 Window decorations: fixed maximized window bounds with Java 11.0.8 and 13.0.4, which has fixes backported from Java 15 (issue #129) 2020-07-22 23:23:46 +02:00
Karl Tauber
5166d4bb0f SystemInfo:
- renamed public fields from upper-case to mixed-case
- added public fields for osVersion and javaVersion
- fixed Mac -> MacOS
- added orLater to Mojave
2020-07-22 22:01:19 +02:00
Karl Tauber
2ffd5437a9 animated Laf changing added to flatlaf-extras, used in Demo 2020-07-22 12:56:42 +02:00
Karl Tauber
797830ff96 InternalFrame: title pane height was too small when iconify, maximize and close buttons are hidden (issue #132) 2020-07-21 18:23:57 +02:00
Karl Tauber
008ecabd21 animator and cubic bezier easing classes added (for future animations) (issue #66) 2020-07-21 17:53:53 +02:00
Karl Tauber
2cdcde8a5e Window decorations: fixed maximized window bounds when programmatically maximizing window before showing window (issue #129) 2020-07-18 14:21:19 +02:00
Karl Tauber
e7ec3988e2 Window decorations: fixed maximized window bounds when programmatically maximizing window (issue #129) 2020-07-17 00:08:21 +02:00
Karl Tauber
093dd9f3ef README.md: added jAlbum to list of projects that use FlatLaf 2020-07-15 19:37:47 +02:00
Karl Tauber
b491202ec7 UIDefaultsLoader: fixed NPE on syntax error in color function 2020-07-15 11:57:40 +02:00
Karl Tauber
8603ca827e Theme Editor: auto-completion improvements:
- include reference completions in value completions (if already entered text is empty)
- order completions: 1st color functions, 2nd @refs, 3rd $refs
- exclude platform specific keys from reference provider
2020-07-11 13:35:59 +02:00
Karl Tauber
6b148a59da Theme Editor: added auto-completion for "amount" and "options" parameters of color functions 2020-07-11 13:01:59 +02:00
Karl Tauber
de6d45fee6 Theme Editor: fixed NPE in FlatCompletionProvider.isAutoActivateOkay() 2020-07-10 16:10:43 +02:00
Karl Tauber
65e2071937 CHANGELOG.md: added regression note 2020-07-10 15:58:04 +02:00
Karl Tauber
8a6242d9ea release 0.38 2020-07-10 15:45:35 +02:00
Karl Tauber
82294b68eb CheckBox: fixed colors in light IntelliJ themes (issue #126) 2020-07-10 15:35:02 +02:00
Karl Tauber
c232de1996 Window decorations: fixed cursor of components (issue #125) 2020-07-10 11:39:17 +02:00
Karl Tauber
dc18c8178d Theme Editor: fixed typo 2020-07-10 10:54:09 +02:00
Karl Tauber
6662714277 Theme Editor: auto-completion improved:
- reference completion shows all keys defined in current and base files
- support auto-activate for value provider
- do not auto-complete single choices
2020-07-10 10:33:10 +02:00
Karl Tauber
c404a0d1a9 Theme Editor:
- auto-activate key completion on any letter
- special completion provider for references
2020-07-08 19:15:52 +02:00
Karl Tauber
990da2b412 Theme Editor:
- auto-activate completion popup when '$' is pressed
- use keys auto-complete in value if value contains '$'
- more fine grained detection what completion provider should be used
2020-07-08 18:07:37 +02:00
Karl Tauber
1b974379c8 UIDefaultsLoader: check for endless recursion in resolveValue() 2020-07-08 17:57:40 +02:00
Karl Tauber
835faf9773 Theme Editor: auto-completion depending on caret position (none for comments, keys and values); added color functions 2020-07-08 14:29:11 +02:00
Karl Tauber
80deecb73e Theme Editor: close input streams when reading base properties files 2020-07-08 10:59:40 +02:00
Karl Tauber
64328ab9cc UIDefaultsLoader: trim value in resolveValue() to ignore spaces at the end of references/variables 2020-07-08 10:47:36 +02:00
Karl Tauber
eafad942e7 Theme Editor: added basic auto-complete for keys 2020-07-08 10:43:24 +02:00
Karl Tauber
eb5a3168b9 Theme Editor: support loading/resolving base properties 2020-07-07 21:42:10 +02:00
Karl Tauber
ac8225d8fb Theme Editor: support saving file; added inspector 2020-07-07 16:17:31 +02:00
Karl Tauber
6f71e4ada0 Theme Editor: use deferred properties loading 2020-07-07 14:21:31 +02:00
Karl Tauber
7ed90cddf8 Theme Editor: support color preview for color functions
UIDefaultsLoader: made some private methods package private and return parsed valued type
2020-07-07 14:03:39 +02:00
Karl Tauber
283ba83cef Window decorations: use derived color for RootPane.inactiveBorderColor in FlatLightLaf.properties to be consistent with FlatDarkLaf.properties 2020-07-06 15:47:44 +02:00
Karl Tauber
468c66e842 Window decorations: hide window icon if InternalFrame.icon is null or its width or height is zero 2020-07-06 14:45:52 +02:00
Karl Tauber
f22862b0a4 InternalFrame: use default icon in internal frames (issue #122) 2020-07-06 14:41:17 +02:00
Karl Tauber
9e731cb67a Tree: fixed cell editor border 2020-07-06 12:01:53 +02:00
Karl Tauber
7f911b61a2 Window decorations: no longer honor minimum size of frames on resizing window, but still do for dialogs 2020-07-06 11:30:49 +02:00
Karl Tauber
cace4a9bfd Window decorations: center title if menu bar is embedded 2020-07-05 11:01:58 +02:00
Karl Tauber
0992e97a1a README.md: added Mapton, Pseudo Assembler IDE, Sound Analysis and RemoteLight to list of projects that use FlatLaf 2020-07-04 23:47:47 +02:00
Karl Tauber
eee101f279 Merge remote-tracking branch 'uwemock/patch-1' 2020-07-04 21:46:08 +02:00
Karl Tauber
4b9f204951 Tree: fixed selection colors when used as cell renderer in another component (e.g. in Rhino JavaScript debugger) (issue #120) 2020-07-04 17:51:13 +02:00
Karl Tauber
019804407b Window decorations: hide window border if window is maximized 2020-07-01 12:11:53 +02:00
Karl Tauber
65b54ced7a Window decorations: made most fields protected for extending/subclassing 2020-07-01 10:49:18 +02:00
Karl Tauber
a308114b2f Window decorations:
- use window border color from UI defaults
- support "active" and "inactive" window border colors
- better window border colors for dark themes
2020-07-01 10:37:08 +02:00
Karl Tauber
41da023bdd hide focus indicator when the containing window became inactive 2020-07-01 00:21:22 +02:00
Karl Tauber
19fcb6a82c refactored some anonymous classes into nested classes for easier extending/subclassing 2020-06-30 17:02:48 +02:00
Karl Tauber
14c837ad05 release 0.37 2020-06-29 17:03:06 +02:00
Karl Tauber
9da634e225 CHANGELOG.md: added custom window decorations 2020-06-29 17:00:28 +02:00
Karl Tauber
0d91116e62 Merge branch 'origin/custom-window-decorations' into master
# Conflicts:
#	flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.java
2020-06-29 15:59:38 +02:00
Karl Tauber
a31a8a03c1 Window decorations: made most classes/methods public/protected for extending/subclassing 2020-06-29 15:45:26 +02:00
Karl Tauber
e8d5210606 Window decorations: use default icon if no icon set on window 2020-06-29 12:20:57 +02:00
Karl Tauber
7b11e29122 Button and ToggleButton: support making buttons square (issue #118) 2020-06-29 10:49:07 +02:00
Karl Tauber
df7f693cf4 Demo: new window icon 2020-06-28 23:59:28 +02:00
Karl Tauber
14ddc2f629 Demo: use window decorations by default and added "Options > Window decorations" to menu 2020-06-28 12:12:58 +02:00
Karl Tauber
6669d0e59d Window decorations: support enabling/disabling embedding menu bar via UI value at runtime 2020-06-28 11:34:30 +02:00
Karl Tauber
8d80176a79 IntelliJ Themes: fixed menu bar and menu item margins in all Material UI Lite themes 2020-06-28 00:28:02 +02:00
Karl Tauber
e1dc302592 IntelliJ Themes: updated themes to newest versions (used IJThemesUpdater) 2020-06-27 23:09:00 +02:00
Karl Tauber
84dbe39185 FileChooser: increase maximum row count of directory combobox popup list to 20 (was 8) 2020-06-27 22:49:22 +02:00
Karl Tauber
4af2c31dab Eclipse code formatter: insert space in casts 2020-06-27 22:26:49 +02:00
Karl Tauber
332f05b6e1 Window decorations: allow enabling/disabling custom window decorations via system properties "flatlaf.useWindowDecorations", "flatlaf.useJetBrainsCustomDecorations" and "flatlaf.menuBarEmbedded" (all boolean) 2020-06-27 19:36:36 +02:00
Karl Tauber
8b4786ad18 added class FlatSystemProperties to define/document own system properties used in FlatLaf 2020-06-27 17:57:59 +02:00
Karl Tauber
7e8aaffb92 Window decorations:
- double-click on icon closes window
- after switching LaF is was not possible to move window when running in JetBrains Runtime
2020-06-26 10:49:49 +02:00
Karl Tauber
7720d42584 Window decorations: reworked/fixed initialization when running in JetBrains Runtime 2020-06-26 00:22:28 +02:00
Karl Tauber
293b76f04b Window decorations: FlatWindowDecorationsTest: added "undecorated" checkbox 2020-06-25 17:55:42 +02:00
Karl Tauber
a1b0c0bbd4 ComboBox: increase maximum row count of popup list to 20 (was 8) 2020-06-25 17:00:10 +02:00
Karl Tauber
46d3204bc3 MenuBar:
- use derived colors for menu bar hover
- use derived colors for menu item selected background
- top-level JMenu now uses foreground color from parent JMenuBar

This allows changing menu bar background to dark with:
  UIManager.put( "MenuBar.background", Color.DARK_GRAY );
  UIManager.put( "MenuBar.foreground", Color.WHITE );
or
  menuBar.setBackground( Color.DARK_GRAY );
  menuBar.setForeground( Color.WHITE );

(issue #117)
2020-06-25 11:36:36 +02:00
Karl Tauber
c25ff57b61 Button, CheckBox, RadioButton and ToggleButton: do not paint focus indicator if AbstractButton.isFocusPainted() returns false 2020-06-24 16:45:41 +02:00
Karl Tauber
71e61f8f27 made class FlatCaret public for subclassing (issue #113) 2020-06-24 13:02:25 +02:00
Karl Tauber
6914a6132c Button: prefer explicitly set background/foreground over focused background and "default" background/foreground (issue #116) 2020-06-24 12:43:49 +02:00
Karl Tauber
b72916187a Button: invoke FlatButtonUI.getForeground(c) also if component is disabled to be consistent with getBackground(c) 2020-06-23 12:45:25 +02:00
Karl Tauber
7c9bbe6aef Merge branch 'master' into branch 'custom-window-decorations' 2020-06-23 11:11:14 +02:00
Karl Tauber
27eeb0a636 Demo: use uppercase leading characters 2020-06-22 23:35:56 +02:00
Karl Tauber
cf436962f8 fixed/improved vertical position of HTML text when scaled on HiDPI screens on Windows 2020-06-22 23:31:01 +02:00
Karl Tauber
7fb7a1ac85 fixed/improved vertical position of text when scaled on HiDPI screens on Windows when running on Java 8 2020-06-22 21:05:11 +02:00
Karl Tauber
15a714faed fixed/improved vertical position of text when scaled on HiDPI screens on Windows when running on Java 9 or later 2020-06-22 13:45:56 +02:00
Karl Tauber
ea2412d3a7 Improved subclassing:
- reviewed all private methods and made them protected/public where it might be useful for subclasses
- ComboBox and Spinner: added protected getBackground() and getForeground() methods to allow subclasses to change colors
- TabbedPane: moved tab separator painting to own method

(issue #113)
2020-06-20 10:46:56 +02:00
Karl Tauber
40321856f2 Testing: updated 3rd party Lafs 2020-06-19 19:49:26 +02:00
Karl Tauber
262ae7865b ComboBox and Spinner: support changing arrow button style (issue #114) 2020-06-19 18:12:23 +02:00
Karl Tauber
84cc86bef7 CheckBox and RadioButton: support changing selected icon style from outline to filled
renamed CheckBox.icon.focusedColor to CheckBox.icon.focusColor
2020-06-19 15:36:49 +02:00
Karl Tauber
1ba27730d6 UIDefaultsDump: fixed order of removed values in diff dumps 2020-06-19 13:38:25 +02:00
Karl Tauber
6568cee2e8 UIDefaultsDump: dump IntelliJ and Darcula themes (as differences to Light/dark themes; Windows only) 2020-06-18 20:29:40 +02:00
Karl Tauber
5496a60f62 CheckBox: reordered icon colors (grouped by state) to make it easier to maintain
(nothing else changed)
2020-06-18 18:09:32 +02:00
Karl Tauber
5c7378cf94 Button and ToggleButton: paint disabled background by default (issue #112) 2020-06-18 12:02:02 +02:00
Karl Tauber
fe15f44e96 ScrollBar: support pressed track, thumb and button colors (issue #115) 2020-06-18 11:04:38 +02:00
Karl Tauber
273d762cd3 ScrollBar: avoid continuous repainting scrollbar when moving mouse pointer over track and ScrollBar.hoverThumbWithTrack is enabled (regression in fd208a3879) 2020-06-17 23:53:06 +02:00
Karl Tauber
211030b5b6 TableHeader: support top/bottom/left positioned sort arrow when using Glazed Lists (issue #113) 2020-06-16 18:52:59 +02:00
Karl Tauber
212c553904 Testing: added class FlatGlazedListsTest for testing Glazed Lists (https://github.com/glazedlists/glazedlists) table sorting (issue #113) 2020-06-16 16:48:00 +02:00
Karl Tauber
dffe4f4451 Button and ToggleButton: support disabled background color (issue #112) 2020-06-15 23:34:21 +02:00
Karl Tauber
fd99af5fe6 added Java code style formatter profile 'FlatLaf' for Eclipse projects (#71) 2020-06-10 00:25:19 +02:00
Karl Tauber
aee539bbef CHANGELOG.md: added missing change to scrollbars on macOS and Linux 2020-06-09 18:25:56 +02:00
Karl Tauber
e7cdc9cf8c release 0.36 2020-06-09 12:33:27 +02:00
Karl Tauber
2443547b3b FlatTestFrame: removed no longer needed nested JRootPane (was used for UI inspector) 2020-06-08 16:03:04 +02:00
Karl Tauber
8424300b5f Demo: faster repainting when enabling/disabling components 2020-06-08 15:58:52 +02:00
Karl Tauber
81822cf7f6 Demo: added UI inspector 2020-06-08 15:45:19 +02:00
Karl Tauber
907956994f Extras: FlatInspector:
- do not increase inspection level when activated with keyboard shortcut
- added some javadoc
- added to CHANGELOG.md and flatlaf-extras/README.md
2020-06-08 15:44:52 +02:00
Karl Tauber
9246cc0607 Extras: added FlatInspector (moved from flatlaf-testing) 2020-06-08 15:03:34 +02:00
Karl Tauber
9f81d147d1 Demo on macOS: enabled screen menu bar by default, except if explicitly disabled 2020-06-08 14:29:47 +02:00
Karl Tauber
b9bd26b2fb FlatSVGIcon: support mapping custom colors 2020-06-08 14:11:06 +02:00
Karl Tauber
1838174678 added "use" tab to javadoc 2020-06-08 12:53:48 +02:00
Karl Tauber
0880a3380c Window decorations: hide drag border components if frame is maximized 2020-06-07 23:22:57 +02:00
Karl Tauber
2aad301938 Spinner: fixed arrow positions 2020-06-07 18:27:55 +02:00
Karl Tauber
e18e8e3158 Popup: made Popup.show(), hide() and component listener more robust when used in unusual ways (issue #106) 2020-06-07 15:25:11 +02:00
Karl Tauber
ff55cc1a2a Window decorations: do not overwrite maximized bounds if controlled from the application 2020-06-07 11:57:05 +02:00
Karl Tauber
d081b9e182 Window decorations: do not restore maximized bounds in method maximize() because when restoring an iconified frame by clicking on the Windows 10 taskbar the maximize() method is not invoked and the frame size becomes full screen size and overlaps taskbar 2020-06-07 11:31:11 +02:00
Karl Tauber
5e5b9f0990 Window decorations: fixed maximized bounds on Java 15 (issues #47 and #82) 2020-06-07 11:03:22 +02:00
Karl Tauber
97577e835e Window decorations: fixed top border when running in JetBrains Runtime (issues #47 and #82) 2020-06-06 22:16:26 +02:00
Karl Tauber
732ca8be56 FlatLaf.isLafDark() added 2020-06-06 22:00:54 +02:00
Karl Tauber
1381a34752 FlatInspector: ignore FlatWindowResizer 2020-06-06 15:38:22 +02:00
Karl Tauber
dd96712c2a Menu: no longer add 1px to bottom insets of JMenu contained in JMenuBar to fix vertical alignment of JMenu text with FlatTitlePane title text on Java 9+ on HiDPI screens (due to rounding)
(this extra 1px was actually not necessary)
2020-06-06 15:31:11 +02:00
Karl Tauber
2ad0aba382 Window decorations: enable dark window appearance on macOS when running in JetBrains Runtime (issues #47 and #82) 2020-06-06 13:53:22 +02:00
Karl Tauber
8e77eb0519 Window decorations: support resizing window (issues #47 and #82) 2020-06-06 12:20:33 +02:00
Karl Tauber
049dae6584 Button: support non-square icon-only buttons (issue #110) 2020-06-03 15:55:14 +02:00
Karl Tauber
1fffc67d13 Window decorations: added border (issues #47 and #82) 2020-06-02 17:49:30 +02:00
Karl Tauber
8500781cd5 Merge branch 'master' into branch 'custom-window-decorations'
# Conflicts:
#	flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatRootPaneUI.java
2020-06-02 16:13:35 +02:00
Karl Tauber
6a8bf2acc5 FlatInspector: fixed highlight figure bounds of windows; limit used inspection level to existing components 2020-06-02 16:07:11 +02:00
Karl Tauber
c45a769aa3 update JFrame/JDialog background color when switching Laf 2020-06-02 15:46:36 +02:00
Karl Tauber
16d2e27d05 Window decorations: require Windows 10 (issues #47 and #82) 2020-05-31 15:31:28 +02:00
Karl Tauber
10c948d33c Window decorations: nested class FlatRootPaneUI.FlatRootLayout is no longer static (issues #47 and #82) 2020-05-31 14:53:13 +02:00
Karl Tauber
7ccd32dfbd Window decorations: fixed menu bar border if embedded (issues #47 and #82) 2020-05-31 14:45:44 +02:00
Karl Tauber
99c99b9218 Window decorations: support embedding menu bar into title pane (enabled by default) (issues #47 and #82) 2020-05-31 14:10:58 +02:00
Karl Tauber
e0b0617ad2 macOS Catalina: Use Helvetica Neue font 2020-05-30 21:44:52 +02:00
Karl Tauber
5add723852 Window decorations: support right-to-left component orientation (issues #47 and #82) 2020-05-30 18:33:22 +02:00
Karl Tauber
14ec6f6471 FlatInspector: increase/decrease inspection level with Ctrl/Shift keys 2020-05-30 17:35:54 +02:00
Karl Tauber
c4a1341aa9 FlatInspector:
- support ending inspection with ESC key
- inspect component at current mouse location when enabling inspector
2020-05-30 16:53:20 +02:00
Karl Tauber
fc68dfd7bc FlatInspector: support inspecting whole window including menubar and custom window decoration 2020-05-30 15:19:07 +02:00
Karl Tauber
436fc545c0 Window decorations: support native Windows 10 custom window decorations with JetBrains Runtime 11 (issues #47 and #82) 2020-05-29 16:44:33 +02:00
Karl Tauber
023d781daf Window decorations: set maximized title pane height to 22px (issues #47 and #82) 2020-05-29 11:17:46 +02:00
Karl Tauber
576c0048d0 Window decorations: make title pane height smaller when frame is maximized (issues #47 and #82) 2020-05-29 00:26:10 +02:00
Karl Tauber
4f79cdad50 Window decorations: support moving window (issues #47 and #82) 2020-05-28 23:49:46 +02:00
Karl Tauber
954cae8738 Window decorations: limit size of moximized windows so that they do not overlap the Windows task bar (issues #47 and #82) 2020-05-28 23:04:43 +02:00
Karl Tauber
b203ad63ee IntelliJ Themes: updated themes to newest versions (used IJThemesUpdater) 2020-05-28 12:17:46 +02:00
Karl Tauber
a560be11ed InternalFrame: renamed FlatInternalFrameMinimizeIcon to FlatInternalFrameRestoreIcon; added some missing @uiDefault to internal frame icons 2020-05-28 11:50:34 +02:00
Karl Tauber
506a1e6b62 Window decorations: iconify/maximize/restore/close button icons in Windows 10 style (issues #47 and #82) 2020-05-28 11:35:30 +02:00
Karl Tauber
626601f6aa Window decorations: added window icon (issues #47 and #82) 2020-05-27 11:40:41 +02:00
Karl Tauber
9ad32125c0 Window decorations: initial implementation (incomplete) (issues #47 and #82)
TODO
- move window
- resize window
- window icon
- window border
2020-05-26 23:35:05 +02:00
Karl Tauber
ebd6375672 Spinner: optimized up/down chevron arrow positions 2020-05-25 13:05:59 +02:00
Karl Tauber
502731d3b0 Spinner: optimized up/down arrow positions 2020-05-24 19:05:28 +02:00
Karl Tauber
283535c429 Demo: use Command modifier to change font size on macOS 2020-05-24 15:26:54 +02:00
Karl Tauber
5cef1f6730 Testing: added font size spinner to control bar; also support Ctrl+0, Ctrl++ and Ctrl+- to change font size 2020-05-24 15:26:07 +02:00
Karl Tauber
7d14fbe739 Testing: do not fail startup when LaF initialization throws UnsupportedClassVersionError (may occur when switching from Java 9+ to Java 8) 2020-05-24 14:48:05 +02:00
Karl Tauber
e9e1e350eb Spinner:
- repaint if JSpinner component gained/lost focus
- paint focus border if JSpinner component is focused
- if spinner gained focus, transfer it to the editor text field
2020-05-24 14:44:36 +02:00
Karl Tauber
566e42cc40 revalidate layout when minimum width client property is changed 2020-05-23 22:57:39 +02:00
Karl Tauber
0abfb5922a ComboBox: minimum width is now 72 pixels (was ~50 for non-editable and ~130 for editable comboboxes) 2020-05-23 22:25:18 +02:00
Karl Tauber
4af8d2f1c5 ComboBox: support custom borders in combobox editors (issue #102) 2020-05-23 18:26:59 +02:00
Karl Tauber
d2d4f73834 ScrollBar: use derived colors for track and thumb (issue #103) 2020-05-23 16:40:09 +02:00
Karl Tauber
53fce4e81d ScrollBar: rotate track/thumb insets for horizontal orientation because they are given for vertical orientation (issue #103) 2020-05-23 14:16:12 +02:00
Karl Tauber
08c439b46e ScrollBar: use rounded thumb on macOS (issue #103) 2020-05-23 13:58:05 +02:00
Karl Tauber
934eb9fc1d ScrollBar: use rounded thumb on Linux (issue #103) 2020-05-23 13:51:25 +02:00
Karl Tauber
fd208a3879 ScrollBar: made styling more flexible by supporting insets and arc for track and thumb (issue #103) 2020-05-23 13:32:31 +02:00
Karl Tauber
10b131e111 Demo: show Java vendor in bottom control bar 2020-05-23 11:28:28 +02:00
Karl Tauber
c4c6faa943 Ubuntu Linux: fixed poorly rendered font (2nd attempt) (issue #105) 2020-05-23 11:06:24 +02:00
Karl Tauber
c7a8d1e1b7 Linux: changing system font did not update FlatLaf font 2020-05-22 18:22:46 +02:00
Karl Tauber
b36ac1b824 UI defaults: added GTKLookAndFeel dump made on Fedora 31 (Adweita theme) 2020-05-21 18:38:46 +02:00
Karl Tauber
bc6cb492f1 Ubuntu Linux: fixed poorly rendered font (issue #105) 2020-05-21 17:11:58 +02:00
Karl Tauber
ce503cedc3 Demo: improved "Font" menu:
- add current font family and size to menu
- filter out unavailable fonts
- select active font family and size
- disable font menu items if non-FlatLaf LaF is active

also show current font in bottom control bar

(issue #105)
2020-05-21 12:24:40 +02:00
Karl Tauber
c900c9cc82 reduce derived colors calculations 2020-05-20 14:49:56 +02:00
Karl Tauber
87b73f26f5 replaced FlatUIUtils.setColor() with deriveColor() for more flexibility 2020-05-20 14:24:22 +02:00
uwemock
221a18c119 Update README.md
Added my project that uses FlatLaf
2020-05-20 07:20:42 +02:00
Karl Tauber
be529655d6 UIDefaultsLoader: on color functions use "autoInverse" option by default if "derived" option is set 2020-05-20 00:40:05 +02:00
Karl Tauber
2a0403a988 support CompoundBorder as component border with FlatBorder on the outside 2020-05-19 23:24:00 +02:00
Karl Tauber
815e23b930 ScrollBar: make hoverTrack and hoverThumb fields protected to allow subclasses implement own painting (issue #103) 2020-05-19 19:24:48 +02:00
Karl Tauber
f1c08e7769 FlatTestFrame: added Substance Business skin for testing light UI 2020-05-19 18:42:22 +02:00
Karl Tauber
571f028ca3 FlatComponentsTest: moved components that change something into own "control" panel 2020-05-19 11:31:52 +02:00
Karl Tauber
16d51fe6b4 ComboBox and Spinner: move arrow slightly to the left if round borders are used on the component 2020-05-18 23:26:34 +02:00
Karl Tauber
ddf9ed06ab release 0.35 2020-05-18 21:22:31 +02:00
Karl Tauber
1907f80024 Demo: fixed compiler warnings and improved error/warning hints 2020-05-18 21:07:11 +02:00
Karl Tauber
8c0ccdd227 Drop shadows on Windows: support medium-weight popups (issue #94) 2020-05-18 13:13:57 +02:00
Karl Tauber
dc098025b6 FileChooser: make top-right buttons look like toolbar buttons 2020-05-18 10:51:23 +02:00
Karl Tauber
c11222b5c7 FlatHtmlTest: added more HTML samples 2020-05-17 22:50:40 +02:00
Karl Tauber
03bc6eb69b FlatTestFrame: '2.0' --> '2' 2020-05-17 18:46:21 +02:00
Karl Tauber
1aa339de02 make component outline border wider if focus width is zero 2020-05-17 17:59:26 +02:00
Karl Tauber
531bb2a968 UIDefaultsDump: dump only differences for macOS
(to avoid the need for updating multiple dumps when changing UI defaults)
2020-05-17 17:52:12 +02:00
Karl Tauber
800dbf3ba9 support different component border colors to indicate errors, warnings or custom state (set client property JComponent.outline to error, warning or any java.awt.Color) 2020-05-17 13:43:19 +02:00
Karl Tauber
ff545e6ecd UIDefaultsLoader: support using a derived color function within another derived color function and create a derived color that joins the color functions 2020-05-17 12:14:14 +02:00
Karl Tauber
961fe38c7e UIDefaultsDump: dump color functions 2020-05-16 22:25:23 +02:00
Karl Tauber
19426394e2 UIDefaultsLoader: added saturate() and desaturate() color functions 2020-05-16 18:59:05 +02:00
Karl Tauber
069a4e8f0b ToolTip: fixed left/right insets of multi-line tooltips so that they are the same as in single-line tooltips (BasicToolTipUI adds 3 to the left and right) 2020-05-16 14:33:55 +02:00
Karl Tauber
a76b02b828 fixed broken FlatTestLaf.properties 2020-05-16 14:19:41 +02:00
Karl Tauber
fbb9bf5f0c Extras: TriStateCheckBox: fixed painting third state in LaFs that do not support third state 2020-05-16 12:29:35 +02:00
Karl Tauber
f632c355e8 FileChooser: scale file icons (issue #100) 2020-05-16 11:03:40 +02:00
Karl Tauber
e75caf5833 FileChooser: use system icons (issue #100) 2020-05-15 17:20:52 +02:00
Karl Tauber
b0c8f2cefd TextComponents: reduced duplicate code; fixed parameter order 2020-05-15 15:00:32 +02:00
Karl Tauber
2136d9f13d PasswordField: do not apply minimum width if columns property > 0 2020-05-15 14:06:33 +02:00
Karl Tauber
83fdeb7e0c ComboBox, Spinner and TextField: support round border style (set client property JComponent.roundRect to true) 2020-05-15 13:38:45 +02:00
Karl Tauber
26c77b3118 Button, ComboBox, TextField and DatePicker UI delegates now get Component.focusWidth and Button.arc/Component.arc/TextComponent.arc from component border 2020-05-15 11:32:53 +02:00
Karl Tauber
578d445ecb FlatBorder: moved scaling from getter methods to paintBorder() and getBorderInsets() 2020-05-14 23:35:11 +02:00
Karl Tauber
3bbc9517af Popup: fixed background flashing effect when drop shadows are disabled (issue #94) 2020-05-14 14:48:12 +02:00
Karl Tauber
a4d7f278cf Drop shadows on Windows: fix location of light weight popup in case it has left or top drop shadow (issue #94) 2020-05-14 11:44:00 +02:00
Karl Tauber
bf0ffc6ac2 Drop shadows: support enabling/disabling drop shadows per component (issue #94) 2020-05-14 11:39:09 +02:00
Karl Tauber
ace07cd9cb Drop shadows on Windows: fixed sub-pixel text rendering issue for heavy weight popups (issue #94) 2020-05-14 11:11:11 +02:00
Karl T
a341179426 Merge pull request #101 from cristatus/patch-2
Fix menu background flashing effect
2020-05-14 10:46:15 +02:00
Amit Mendapara
298f0dfd63 Fix menu background flashing effect
When using dark theme on light platform theme, there was a
background flashing effect on popups.

See #94
2020-05-14 11:43:59 +05:30
Karl Tauber
b8f953cd26 Drop shadows on Windows: use light weight popups by default (issue #94)
this fixes the sub-pixel text rendering issue (on Windows) for popups that fit into the owner window
2020-05-13 18:41:26 +02:00
Karl Tauber
a9cfe69ba7 FileChooser: fixed missing labels in file chooser when running on Java 9 or later (issue #98) 2020-05-13 12:50:41 +02:00
Karl Tauber
b3e0b99e8d Button and ToggleButton: support round button style (set client property JButton.buttonType to roundRect) 2020-05-13 11:45:01 +02:00
Karl Tauber
5bd40baed2 Extras: TriStateCheckBox: paint magenta rectangle when used in LaFs that do not support third state 2020-05-12 23:26:52 +02:00
Karl Tauber
d3a70b8bb2 CheckBox and RadioButton: Opaque flag is no longer ignored when checkbox is used as table cell renderer (issue #77)
this fix replaces/improves fix made in commit 3ba8133890
2020-05-12 22:35:05 +02:00
Karl Tauber
71e698603d ComboBox: fixed painting background outside of border if Component.arc is set to a large value 2020-05-12 22:29:59 +02:00
Karl Tauber
659ead903c TextField: avoid garbage in corners if TextComponent.arc is set to a large value 2020-05-12 18:58:17 +02:00
Karl Tauber
070c435f40 paint nicely rounded buttons, comboboxes, spinners and text fields when setting Button.arc, Component.arc or TextComponent.arc to a large value (e.g. 1000) 2020-05-12 17:48:35 +02:00
Karl Tauber
b668a526e3 changed "Flat" to "FlatLaf" in look and feel names and descriptions 2020-05-12 16:47:46 +02:00
Karl Tauber
01287d0669 Popup: allow disabling native drop shadows for popups on macOS 2020-05-12 16:42:55 +02:00
Karl T
ff481d759f Merge pull request #99 from cristatus/patch-1
Fix popup shadow issue on Linux

https://github.com/JFormDesigner/FlatLaf/issues/94#issuecomment-626344149
2020-05-10 19:25:17 +02:00
Amit Mendapara
71248f1708 Fix popup shadow issue on Linux
Linux adds drop shadow to heavy weight popups. So there is no
need to draw shadow manually.
2020-05-10 22:46:57 +05:30
Karl Tauber
0a0f834f23 Drop shadows:
- reworked drop shadows implementation to support 4-sided shadows
- use 4-sided shadow for internal frames
- made shadows configurable in UI defaults
- made shadows dark in dark themes

(issue #94)
2020-05-10 15:38:50 +02:00
Karl Tauber
06cad7ecd8 Popup: make sure that popup background is filled (issue #94) 2020-05-09 23:50:48 +02:00
Karl Tauber
ceba3e2f95 CHANGELOG.md: added Java 9 module descriptor to extras and swingx JARs 2020-05-09 15:59:29 +02:00
Karl Tauber
61c2fd8794 build.gradle.kts: use MigLayout 5.3-SNAPSHOT for better scaling
Demo: exclude module-info.class from fat JAR
2020-05-09 15:42:18 +02:00
Karl Tauber
db933fee4f build.gradle.kts: flatlaf-extras and flatlaf-swingx are now Java modules
flatlaf-jide-oss is not a Java module because jide-oss.jar does not run on the module path (tries to access private Windows LaF classes)
2020-05-09 15:32:25 +02:00
Karl Tauber
2656c2dc40 build.gradle.kts: moved publishing related configuration to precompiled script plugin 2020-05-09 13:54:16 +02:00
Karl Tauber
01cfe33865 build.gradle.kts: moved module-info and java9 related configuration to precompiled script plugins 2020-05-09 11:16:40 +02:00
Karl Tauber
d79a31cc79 build.gradle.kts: use withSourcesJar() and withJavadocJar()
this adds resources to sources.jar
2020-05-09 02:09:03 +02:00
Karl Tauber
9efab8b892 travis: added openjdk14 and removed openjdk13 2020-05-09 00:30:38 +02:00
Karl Tauber
aae845247a update to Gradle 6.4
./gradlew wrapper --gradle-version=6.4
2020-05-09 00:16:07 +02:00
Karl Tauber
3f45a9a75f Merge remote-tracking branch 'origin/drop-shadows' into master 2020-05-08 19:02:13 +02:00
Karl Tauber
c9016155ae Demo: added "Options > Always show mnemonics" to menu 2020-05-08 18:58:02 +02:00
Karl Tauber
1019e8f4af Extras: added FlatSVGIcon and download section 2020-05-08 18:50:02 +02:00
Karl Tauber
8e423b4552 release 0.34 2020-05-08 14:53:16 +02:00
Karl Tauber
0e288c955c Extras: added publishing tasks to build.gradle.kts 2020-05-08 14:44:41 +02:00
Karl Tauber
465dc8a66c Popup: added drop shadows to all popups (menu, combobox and tooltip) on all platforms (issue #94) 2020-05-08 11:02:20 +02:00
Karl Tauber
7e5c599cc0 added user scale factor to UI defaults to allow layout managers (e.g. MigLayout) to use it
(see https://github.com/mikaelgrev/miglayout/pull/76)
2020-05-07 23:28:57 +02:00
Karl Tauber
a961001a4b reorder entries in JAR file to fix issues #13 and #93 2020-05-07 14:45:22 +02:00
Karl Tauber
0a181f6407 InternalFrame: added drop shadows (issue #94)
also made borders of internal frames in dark themes darker
2020-05-07 00:07:02 +02:00
Karl Tauber
27a347db34 PopupMenu on macOS: enabled drop shadows for popup menus and combobox popups (issue #94) 2020-05-05 19:20:48 +02:00
Karl Tauber
b228dbb2df Demo on macOS: enabled screen menu bar by default 2020-05-05 19:10:57 +02:00
Karl Tauber
09cffc4340 UIDefaultsDump: avoid locale specific decimal separators in dumps 2020-05-05 18:53:31 +02:00
Karl Tauber
e79880d305 ToolTip: made border darker (to make it better and no longer paint disabled tips (issue #94) 2020-05-05 18:44:54 +02:00
Karl Tauber
34266761d1 UIDefaultsDump: dump FlatLineBorder parameters because they may be specified in properties files 2020-05-05 16:34:30 +02:00
Karl Tauber
77f17eaa3e FlatPropertiesLaf class added that allows creating FlatLaf theme from properties (issue #97) 2020-05-05 15:13:21 +02:00
Karl Tauber
ac70342cb3 Menus: made check background margin smaller (issue #96) 2020-05-05 13:56:41 +02:00
Karl Tauber
d2f16dcaf3 Menus:
- added 1px to menu item top and bottom margin
- changed gap between menu item icon and text from 4 to 6
- improved colors of checked menu items that have a icon

(issue #96)
2020-05-05 12:31:33 +02:00
Karl Tauber
abcce2bf68 Table: fixed inconsistent table selection / move shortcuts (issue #95) 2020-05-04 13:30:42 +02:00
Karl Tauber
514487074b Menus: after Alt+Tab to other window and back, activating menu with Alt key did not always work (issue #43) 2020-05-04 12:08:47 +02:00
Karl Tauber
f014e2473f Menus: on Windows, releasing Alt key now activates the menu bar (issue #43) 2020-05-04 10:57:10 +02:00
Karl Tauber
80981f7027 Demo: added "Extras" tab 2020-05-03 19:34:21 +02:00
Karl Tauber
8e6e971b51 IntelliJ Themes Demo: theme save and github buttons were not enabled when starting demo with active IntelliJ theme 2020-05-03 18:23:16 +02:00
Karl Tauber
4bd3b889dc FlatSVGIcon: support color filtering 2020-05-03 18:21:00 +02:00
Karl Tauber
464787dc1e FlatSVGIcon: use grayFilter and graphics proxy to paint disabled icons without bitmaps 2020-05-02 23:48:46 +02:00
Karl Tauber
a2541a9659 Menus: added gap between accelerator and arrow in menu items (issue #91) 2020-05-02 19:16:33 +02:00
Karl Tauber
099dd87241 UIDefaultsLoader: removed support for deprecated variable prefix '@@' 2020-05-02 16:20:17 +02:00
Karl Tauber
38eb914420 Mnemonics: scale underline; added mnemonic test app
FlatTestFrame: Metal Laf is now at F12 so that F10 is unused because F10 is a standard key to move focus to menu bar
2020-05-02 14:38:54 +02:00
Karl Tauber
162215b1cf UIDefaultsLoader:
- support percentage in rgb() and rgba() functions
- support rgba(color,alpha) to add alpha to any color
2020-05-02 11:52:53 +02:00
Karl Tauber
c6883f7a92 ToolTip: use BasicHTML.propertyKey to check whether tooltip contains HTML 2020-05-02 00:41:11 +02:00
Karl Tauber
584286b794 Demo: wrap OptionPanePanel in JPanel to avoid that JFormDesigner tries to convert it to a container when opening DemoFrame.jfd 2020-05-02 00:33:47 +02:00
Karl Tauber
a48713b7ca no longer always show mnemonics when a menu bar is active or a popup menu is visible (issue #43) 2020-05-01 00:22:04 +02:00
Karl Tauber
8f10c2d8bf Menus: removed now unused *.evenHeight from list of UI defaults 2020-04-30 22:33:42 +02:00
Karl Tauber
5c0de9aa1c macOS: Fixed NPE if using JMenuBar in JInternalFrame and macOS screen menu bar is enabled (issue #90) 2020-04-30 13:38:23 +02:00
Karl Tauber
5553fd6538 CHANGELOG.md: added changes made in 'menu-layout' branch 2020-04-30 00:54:36 +02:00
Karl Tauber
e3ed47b37c show mnemonics always when a menu bar is active or a popup menu is visible 2020-04-29 23:56:15 +02:00
Karl Tauber
976353d770 Menus: on Windows, pressing F10 now activates the menu bar without showing a menu popup 2020-04-29 23:29:34 +02:00
Karl Tauber
6fc216dff5 Menus: fixed text color of selected menu items that use HTML (issue #87) 2020-04-29 19:22:09 +02:00
Karl Tauber
3f3961d255 fixed broken FlatTestLaf.properties 2020-04-29 19:14:18 +02:00
Karl Tauber
875637bc6d Menus: support switching "underline" menu selection type at any time without updating UI (issue #49) 2020-04-29 14:46:33 +02:00
Karl Tauber
395333cb3d Merge branch 'origin/menu-layout' into master 2020-04-29 13:39:51 +02:00
Karl Tauber
870d039541 hide mnemonics if window is deactivated (e.g. Alt+Tab to another window) (issue #43) 2020-04-29 12:06:00 +02:00
Karl Tauber
e8c8bece3f Menus: support "underline" menu selection type (suggested in issue #49) 2020-04-29 00:26:25 +02:00
Karl Tauber
bd2f5dd6fe Menus: if checkbox/radiobutton menu item is selected and also has a custom icon, then use filled icon background to indicate selection (instead of using checkIcon) (issue #3) 2020-04-28 18:00:01 +02:00
Karl Tauber
73f78d47ae refactored mnemonic code into own class 2020-04-28 12:02:10 +02:00
Karl Tauber
dd2cf50a39 Menus: use simpler method to compute center offset (same as in SwingUtilities.layoutCompoundLabel()), which gives same results and avoids floats 2020-04-27 13:14:11 +02:00
Karl Tauber
06eeced5b2 Menus: made accelerator text in dark themes brighter; updated UI defaults dumps (issue #3) 2020-04-27 12:07:06 +02:00
Karl Tauber
be23e5709d Menus: support alignment and text position properties (issue #3) 2020-04-27 11:52:11 +02:00
Karl Tauber
2735185eb9 Menus: fixed icon in top-level JMenu (issue #3) 2020-04-26 14:20:09 +02:00
Karl Tauber
41dd0acfa3 Menus: use disabled and pressed icons (issue #3) 2020-04-26 11:27:59 +02:00
Karl Tauber
115a2df2b0 Menus: support HTML in new layout (issue #3) 2020-04-26 10:35:23 +02:00
Karl Tauber
fcbb3aeed1 Menus: new menu item layout and renderer
- stable left margin (always space for one icon)
- right aligned accelerators
- larger gap between text and accelerator

current limitations:
- no HTML text support
- text not vertically aligned with other menu items if icons have different sizes
- vertical/horizontal alignment/textPosition properties are ignored

(issues #3 and #54)
2020-04-26 10:13:52 +02:00
753 changed files with 121470 additions and 16431 deletions

4
.gitattributes vendored
View File

@@ -15,8 +15,12 @@
# BINARY FILES:
# Disable line ending normalize on checkin.
*.dll binary
*.dylib binary
*.gif binary
*.jar binary
*.lib binary
*.png binary
*.sketch binary
*.so binary
*.zip binary

8
.gitbugtraq Normal file
View File

@@ -0,0 +1,8 @@
# links issue numbers in git commit messages to issue tracker
# https://github.com/mstrap/bugtraq
# for SmartGit - https://www.syntevo.com/smartgit/
[bugtraq]
url = "https://github.com/JFormDesigner/FlatLaf/issues/%BUGID%"
loglinkregex = "#[0-9]{1,5}"
logregex = "[0-9]{1,5}"

175
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,175 @@
# https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
name: CI
on:
push:
branches:
- '*'
tags:
- '[0-9]*'
pull_request:
branches:
- '*'
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
# test against
# - Java 1.8 (minimum requirement)
# - Java 9 (first version with JPMS)
# - Java LTS versions (11, 17, ...)
# - lastest Java version(s)
java:
- 1.8
- 9
- 11 # LTS
- 14
- 15
steps:
- uses: actions/checkout@v2
- uses: gradle/wrapper-validation-action@v1
if: matrix.java == '1.8'
- name: Setup Java ${{ matrix.java }}
uses: actions/setup-java@v1
with:
java-version: ${{ matrix.java }}
- name: Cache Gradle wrapper
uses: actions/cache@v1
with:
path: ~/.gradle/wrapper
key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }}
- name: Cache Gradle cache
uses: actions/cache@v2
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}
restore-keys: ${{ runner.os }}-gradle
- name: Build with Gradle
run: ./gradlew build
- name: Upload artifacts
uses: actions/upload-artifact@v2
if: matrix.java == '11'
with:
name: FlatLaf-build-artifacts
path: |
flatlaf-*/build/libs
!**/*-javadoc.jar
!**/*-sources.jar
snapshot:
runs-on: ubuntu-latest
needs: build
if: |
github.event_name == 'push' &&
github.ref == 'refs/heads/main' &&
github.repository == 'JFormDesigner/FlatLaf'
steps:
- uses: actions/checkout@v2
- name: Setup Java 11
uses: actions/setup-java@v1
with:
java-version: 11
- name: Cache Gradle wrapper
uses: actions/cache@v1
with:
path: ~/.gradle/wrapper
key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }}
- name: Cache Gradle cache
uses: actions/cache@v2
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}
restore-keys: ${{ runner.os }}-gradle
- name: Publish snapshot to oss.sonatype.org
run: ./gradlew publish :flatlaf-theme-editor:build -Dorg.gradle.internal.publish.checksums.insecure=true
env:
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
- name: Upload theme editor
uses: sebastianpopp/ftp-action@releases/v2
with:
host: ${{ secrets.FTP_SERVER }}
user: ${{ secrets.FTP_USERNAME }}
password: ${{ secrets.FTP_PASSWORD }}
forceSsl: true
localDir: "flatlaf-theme-editor/build/libs"
remoteDir: "snapshots"
options: "--only-newer --no-recursion --verbose=1"
release:
runs-on: ubuntu-latest
needs: build
if: |
github.event_name == 'push' &&
startsWith( github.ref, 'refs/tags/' ) &&
github.repository == 'JFormDesigner/FlatLaf'
steps:
- uses: actions/checkout@v2
- name: Setup Java 11
uses: actions/setup-java@v1
with:
java-version: 11
- name: Cache Gradle wrapper
uses: actions/cache@v1
with:
path: ~/.gradle/wrapper
key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }}
- name: Cache Gradle cache
uses: actions/cache@v2
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}
restore-keys: ${{ runner.os }}-gradle
- name: Release a new stable version to Maven Central
run: ./gradlew publish :flatlaf-demo:build :flatlaf-theme-editor:build -Drelease=true
env:
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
SIGNING_KEY: ${{ secrets.SIGNING_KEY }}
SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }}
- name: Upload demo
uses: sebastianpopp/ftp-action@releases/v2
with:
host: ${{ secrets.FTP_SERVER }}
user: ${{ secrets.FTP_USERNAME }}
password: ${{ secrets.FTP_PASSWORD }}
forceSsl: true
localDir: "flatlaf-demo/build/libs"
remoteDir: "."
options: "--only-newer --no-recursion --verbose=1"
- name: Upload theme editor
uses: sebastianpopp/ftp-action@releases/v2
with:
host: ${{ secrets.FTP_SERVER }}
user: ${{ secrets.FTP_USERNAME }}
password: ${{ secrets.FTP_PASSWORD }}
forceSsl: true
localDir: "flatlaf-theme-editor/build/libs"
remoteDir: "."
options: "--only-newer --no-recursion --verbose=1"

58
.github/workflows/natives.yml vendored Normal file
View File

@@ -0,0 +1,58 @@
# https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
name: Native Libraries
on:
push:
branches:
- '*'
tags:
- '[0-9]*'
paths:
- 'flatlaf-natives/flatlaf-natives-windows/**'
- '.github/workflows/natives.yml'
pull_request:
branches:
- '*'
paths:
- 'flatlaf-natives/flatlaf-natives-windows/**'
- '.github/workflows/natives.yml'
jobs:
Windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- uses: gradle/wrapper-validation-action@v1
- name: Setup Java 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Cache Gradle wrapper
uses: actions/cache@v1
with:
path: ~/.gradle/wrapper
key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }}
- name: Cache Gradle cache
uses: actions/cache@v2
with:
path: |
~/.gradle/caches
!~/.gradle/caches/modules-2/modules-2.lock
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}
restore-keys: ${{ runner.os }}-gradle
- name: Build with Gradle
run: ./gradlew :flatlaf-natives-windows:build
- name: Upload artifacts
uses: actions/upload-artifact@v2
with:
name: FlatLaf-natives-windows-build-artifacts
path: |
flatlaf-natives/flatlaf-natives-windows/build

2
.gitignore vendored
View File

@@ -9,3 +9,5 @@ out/
*.iml
*.ipr
*.iws
.vs/
.vscode/

View File

@@ -1,39 +0,0 @@
language: java
sudo: false
jdk:
- openjdk8
- openjdk9
- openjdk11
- openjdk13
before_cache:
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
- rm -fr $HOME/.gradle/caches/*/plugin-resolution/
cache:
directories:
- $HOME/.gradle/caches/
- $HOME/.gradle/wrapper/
before_install:
- ./gradlew --version
- java -version
stages:
- name: test
- name: snapshot
if: branch = master AND type IN (push) AND tag IS blank
- name: release
if: type IN (push) AND tag IS present
jobs:
include:
# publish snapshot to oss.jfrog.org
- stage: snapshot
jdk: openjdk11
script: ./gradlew artifactoryPublish
# release a new stable version to bintray
- stage: release
jdk: openjdk11
script: ./gradlew bintrayUpload -Drelease=true

View File

@@ -1,6 +1,942 @@
FlatLaf Change Log
==================
## 2.0-SNAPSHOT
#### New features and improvements
- Styling:
- Styling individual components using string in CSS syntax or `java.util.Map`.
(PR #341)\
E.g.: `mySlider.putClientProperty( "FlatLaf.style", "trackWidth: 2" );`
- Style classes allow defining style rules at a single place (in UI defaults)
and use them in any component. (PR #388)\
E.g.: `mySlider.putClientProperty( "FlatLaf.styleClass", "myclass" );`
- Typography defines several font styles for headers and various text sizes,
which makes it easy to use consistent font styles across the application. (PR
#396)
- Native window decorations (Windows 10/11 only):
- Unified backgrounds for window title bar is now enabled by default (window
title bar has now same background color as window content). Bottom separator
for menu bars is no longer painted (if unified background is enabled).
- Show Windows 11 snap layouts menu when hovering the mouse over the maximize
button. (issues #397 and #407)
- 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
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)
- TextField, FormattedTextField and PasswordField: Support leading and trailing
icons (set client property `JTextField.leadingIcon` or
`JTextField.trailingIcon` to an `Icon`). (PR #378; issue #368)
- TextComponents: Double/triple-click-and-drag now extends selection by whole
words/lines.
- Theming improvements: Reworks core themes to make it easier to create new
themes (e.g. reduced explicit colors by using color functions). **Note**:
There are minor incompatible changes in FlatLaf properties files. (PR #390)
- ToolBar:
- Toolbars are no longer floatable by default (dots on left side of toolbar
that allows dragging toolbar). Use `UIManager.put( "ToolBar.floatable", true
)` if you want the old behavior.
- Skip components with empty input map (e.g. `JLabel`) when using arrow keys
to navigate in focusable buttons (if UI value `ToolBar.focusableButtons` is
`true`).
- Support arrow-keys-only navigation within focusable buttons of toolbar (if
UI value `ToolBar.focusableButtons` is `true`):
- arrow keys move focus within toolbar
- tab-key moves focus out of toolbar
- if moving focus into the toolbar, focus recently focused toolbar button
- ComboBox, Spinner, TextField and subclasses: Support specifying width of
border (see UI value `Component.borderWidth`).
- CheckBox and RadioButton:
- Made selected icon better recognizable in **FlatLaf Light** (use blue
border), **Dark** and **Darcula** (use lighter border) themes. **IntelliJ**
theme is not changed.
- Support specifying width of icon border (see UI value
`CheckBox.icon.borderWidth`).
- Reworked icon UI defaults and added missing ones. **Note**: There are minor
incompatible changes in FlatLaf properties files.
- Slider: Support specifying width of thumb border (see UI value
`Slider.thumbBorderWidth`).
- TabbedPane: Optionally paint selected tab as card. (PR #343)
- Added more color functions to class `ColorFunctions` for easy use in
applications: `lighten()`, `darken()`, `saturate()`, `desaturate()`, `spin()`,
`tint()`, `shade()` and `luma()`.
- Support defining fonts in FlatLaf properties files. (issue #384)
- Added method `FlatLaf.registerCustomDefaultsSource(URL packageUrl)` for JPMS.
(issue #325)
- Extras:
- Added class `FlatDesktop` for easy integration into macOS screen menu
(About, Preferences and Quit) when using Java 8.
- `FlatSVGIcon`: Support loading SVG from `URL` (for JPMS), `URI`, `File` or
`InputStream`. (issues #419 and #325)
- `FlatSVGUtils`: Support loading SVG from `URL` (for JPMS). (issue #325)
## 1.6.4
#### Fixed bugs
- ComboBox: Fixed regression in FlatLaf 1.6.3 that makes selected item invisible
in popup list if `DefaultListCellRenderer` is used as renderer. If using
default renderer, it works. (issue #426)
## 1.6.3
#### Fixed bugs
- ComboBox (not editable): Fixed regression in FlatLaf 1.6.2 that may display
text in non-editable combo boxes in bold. (issue #423)
- Tree: Fixed editing cell issue with custom cell renderer and cell editor that
use same component for rendering and editing. (issue #385)
## 1.6.2
#### Fixed bugs
- ComboBox (not editable): Fixed background painted outside of border if round
edges are enabled (client property `JComponent.roundRect` is `true`). (similar
to issue #382; regression since fixing #330 in FlatLaf 1.4)
- ComboBox: Fixed `NullPointerException`, which may occur under special
circumstances. (issue #408)
- Table: Do not select text in cell editor when it gets focus (when
`JTable.surrendersFocusOnKeystroke` is `true`) and
`TextComponent.selectAllOnFocusPolicy` is `once` (the default) or `always`.
(issue #395)
- Linux: Fixed NPE when using `java.awt.TrayIcon`. (issue #405)
- FileChooser: Workaround for crash on Windows with Java 17 32-bit (disabled
Windows icons). Java 17 64-bit is not affected. (issue #403)
- Native window decorations: Fixed layout loop, which may occur under special
circumstances and slows down the application. (issue #420)
## 1.6.1
#### Fixed bugs
- Native window decorations: Catch `UnsatisfiedLinkError` when trying to load
`jawt.dll` to avoid an application crash (Java 8 on Windows 10 only).
## 1.6
#### New features and improvements
- InternalFrame: Double-click on icon in internal frame title bar now closes the
internal frame. (issue #374)
- IntelliJ Themes: Removed deprecated `install()` methods.
#### Fixed bugs
- Menus: Fixed missing modifiers flags in `ActionEvent` (e.g. `Ctrl` key
pressed) when running in Java 9+ on Linux, macOS. Occurs also on Windows in
large popup menus that do not fit into the window. (issue #371; regression
since FlatLaf 1.3)
- OptionPane: Fixed `OptionPane.sameSizeButtons`, which did not work as expected
when setting to `false`.
- OptionPane: Fixed rendering of longer HTML text if it is passed as
`StringBuilder`, `StringBuffer`, or any other object that returns HTML text in
method `toString()`. (similar to issue #12)
- ComboBox: Fixed popup border painting on HiDPI screens (e.g. at 150% scaling).
- ComboBox: Fixed popup location if shown above of combo box (Java 8 only).
- ComboBox (editable): Fixed wrong border of internal text field under special
circumstances.
- Spinner: Fixed painting of border corners on left side. (issue #382;
regression since fixing #330 in FlatLaf 1.4)
- TableHeader: Do not show resize cursor for last column if resizing last column
is not possible because auto resize mode of table is not off. (issue #332)
- TableHeader: Fixed missing trailing vertical separator line if used in upper
left corner of scroll pane. (issue #332)
- TextField, FormattedTextField, PasswordField and ComboBox: Fixed alignment of
placeholder text in right-to-left component orientation.
- Slider: Fixed calculation of baseline, which was wrong under some
circumstances.
## 1.5
#### New features and improvements
- SwingX: Added search and clear icons to `JXSearchField`. (issue #359)
#### Fixed bugs
- Button and TextComponent: Do not apply minimum width/height if margins are
set. (issue #364)
- ComboBox and Spinner: Limit arrow button width if component has large
preferred height. (issue #361)
- FileChooser: Fixed missing (localized) texts when FlatLaf is loaded in special
classloader (e.g. plugin system in Apache NetBeans).
- InternalFrame: Limit internal frame bounds to parent bounds on resize. Also
honor maximum size of internal frame. (issue #362)
- Popup: Fixed incorrectly placed drop shadow for medium-weight popups in
maximized windows. (issue #358)
- Native window decorations (Windows 10 only):
- Fixed occasional application crash in `flatlaf-windows.dll`. (issue #357)
- When window is initially shown, fill background with window background color
(instead of white), which avoids flickering in dark themes. (issue 339)
- When resizing a window at the right/bottom edge, then first fill the new
space with the window background color (instead of black) before the layout
is updated.
- When resizing a window at the left/top edge, then first fill the new space
with the window background color (instead of garbage) before the layout is
updated.
## 1.4
#### New features and improvements
- TextField, FormattedTextField and PasswordField: Support adding extra padding
(set client property `JTextField.padding` to an `Insets`).
- PasswordField: UI delegate `FlatPasswordFieldUI` now extends `FlatTextFieldUI`
(instead of `BasicPasswordFieldUI`) to avoid duplicate code and for easier
extensibility.
- Table and PopupFactory: Use `StackWalker` in Java 9+ for better performance.
(issue #334)
- ToolBar: Paint focus indicator for focused button in toolbar. (issue #346)
- ToolBar: Support focusable buttons in toolbar (set UI value
`ToolBar.focusableButtons` to `true`). (issue #346)
#### Fixed bugs
- ComboBox (editable) and Spinner: Increased size of internal text field to the
component border so that it behaves like plain text field (mouse click to left
of text now positions caret to first character instead of opening ComboBox
popup; mouse cursor is now of type "text" within the whole component, except
for arrow buttons). (issue #330)
- ComboBox (not editable): Increased size of internal renderer pane to the
component border so that it can paint within the whole component. Also
increase combo box size if a custom renderer uses a border with insets that
are larger than the default combo box padding (`2,6,2,6`).
- Fixed component heights at `1.25x`, `1.75x` and `2.25x` scaling factors (Java
8 only) so that Button, ComboBox, Spinner and TextField components (including
subclasses) have same heights. This increases heights of Button and TextField
components by:
- `2px` at `1.75x` in **Light** and **Dark** themes
- `2px` at `1.25x` and `2.25x` in **IntelliJ** and **Darcula** themes
- OptionPane: Do not make child components, which are derived from `JPanel`,
non-opaque. (issue #349)
- OptionPane: Align wrapped lines to the right if component orientation is
right-to-left. (issue #350)
- PasswordField: Caps lock icon no longer painted over long text. (issue #172)
- PasswordField: Paint caps lock icon on left side in right-to-left component
orientation.
- Window decorations: Window title bar width is no longer considered when
calculating preferred/minimum width of window. (issue #351)
## 1.3
#### New features and improvements
- TextComponents, ComboBox and Spinner: Support different background color when
component is focused (use UI values `TextField.focusedBackground`,
`PasswordField.focusedBackground`, `FormattedTextField.focusedBackground`,
`TextArea.focusedBackground`, `TextPane.focusedBackground`,
`EditorPane.focusedBackground`, `ComboBox.focusedBackground`,
`ComboBox.buttonFocusedBackground`, `ComboBox.popupBackground` and
`Spinner.focusedBackground`). (issue #335)
#### Fixed bugs
- Fixed white lines at bottom and right side of window (in dark themes on HiDPI
screens with scaling enabled).
- ScrollBar: Fixed left/top arrow icon location (if visible). (issue #329)
- Spinner: Fixed up/down arrow icon location.
- ToolTip: Fixed positioning of huge tooltips. (issue #333)
## 1.2
#### New features and improvements
- Renamed `Flat*Laf.install()` methods to `Flat*Laf.setup()` to avoid confusion
with `UIManager.installLookAndFeel(LookAndFeelInfo info)`. The old
`Flat*Laf.install()` methods are still there, but marked as deprecated. They
will be removed in a future version.
- Button and ToggleButton: Support borderless button style (set client property
`JButton.buttonType` to `borderless`). (PR #276)
- ComboBox: Support using as cell renderer (e.g. in `JTable`).
- DesktopPane: Improved layout of iconified internal frames in dock:
- Always placed at bottom-left in desktop pane.
- Newly iconified frames are added to the right side of the dock.
- If frame is deiconified, dock is compacted (icons move to the left).
- If dock is wider than desktop width, additional rows are used.
- If desktop pane is resized, layout of dock is updated.
- TableHeader: Moved table header column border painting from
`FlatTableHeaderUI` to new border `FlatTableHeaderBorder` to improve
compatibility with custom table header implementations. (issue #228)
- Linux: Enable text anti-aliasing if no Gnome or KDE Desktop properties are
available. (issue #218)
- IntelliJ Themes: Added "Material Theme UI Lite / GitHub Dark" theme.
- JIDE Common Layer: Improved support for `JideTabbedPane`. (PR #306)
- Extras: `FlatSVGIcon` improvements:
- Each icon can now have its own color filter. (PR #303)
- Use mapper function in color filter to dynamically map colors. (PR #303)
- Color filter supports light and dark themes.
- Getters for icon name, classloader, etc.
- Extras: UI Inspector: Show class hierarchies when pressing <kbd>Alt</kbd> key
and prettified class names (dimmed package name).
- Extras: `FlatSVGUtils.createWindowIconImages()` now returns a single
multi-resolution image that creates requested image sizes on demand from SVG
(only on Windows with Java 9+).
#### Fixed bugs
- CheckBox and RadioButton: Do not fill background if used as cell renderer,
except if cell is selected or has different background color. (issue #311)
- DesktopPane:
- Fixed missing preview of iconified internal frames in dock when using a
custom desktop manager. (PR #294)
- Fixed incomplete preview of iconified internal frames in dock when switching
LaF.
- On HiDPI screens, use high-resolution images for preview of iconified
internal frames in dock.
- PopupFactory: Fixed occasional `NullPointerException` in
`FlatPopupFactory.fixToolTipLocation()`. (issue #305)
- Tree: Fill cell background if
`DefaultTreeCellRenderer.setBackgroundNonSelectionColor(Color)` was used.
(issue #322)
- IntelliJ Themes: Fixed background colors of DesktopPane and DesktopIcon in all
themes.
- Native window decorations:
- Fixed slow application startup under particular conditions. (e.g. incomplete
custom JRE) (issue #319)
- Fixed occasional double window title bar when creating many frames or
dialogs. (issue #315)
- Fixed broken maximizing window (under special conditions) when restoring
frame state at startup.
- Title icon: For multi-resolution images now use `getResolutionVariant(width,
height)` (instead of `getResolutionVariants()`) to allow creation of
requested size on demand. This also avoids creation of all resolution
variants.
- Double-click at upper-left corner of maximized frame did not close window.
(issue #326)
- Linux: Fixed/improved detection of user font settings. (issue #309)
## 1.1.2
#### New features and improvements
- Native window decorations: Added API to check whether current platform
supports window decorations (`FlatLaf.supportsNativeWindowDecorations()`) and
to toggle window decorations of all windows
(`FlatLaf.setUseNativeWindowDecorations(boolean)`).
- Native window decorations: Support changing title bar background and
foreground colors per window. (set client properties
`JRootPane.titleBarBackground` and `JRootPane.titleBarForeground` on root pane
to a `java.awt.Color`).
#### Fixed bugs
- Native window decorations: Fixed loading of native library when using Java
Platform Module System (JPMS) for application. (issue #289)
- Native window decorations: Removed superfluous pixel-line at top of screen
when window is maximized. (issue #296)
- Window decorations: Fixed random window title bar background in cases were
background is not filled by custom window or root pane components and unified
background is enabled.
- IntelliJ Themes: Fixed window title bar background if unified background is
enabled.
- IntelliJ Themes: Fixed system colors.
- Button and ToggleButton: Do not paint background of disabled (and unselected)
toolBar buttons. (issue #292; regression since fixing #112)
- ComboBox and Spinner: Fixed too wide arrow button if component is higher than
preferred. (issue #302)
- SplitPane: `JSplitPane.setContinuousLayout(false)` did not work. (issue #301)
- TabbedPane: Fixed NPE when creating/modifying in another thread. (issue #299)
- Fixed crash when running in Webswing. (issue #290)
## 1.1.1
#### New features and improvements
- Native window decorations: Support disabling native window decorations per
window. (set client property `JRootPane.useWindowDecorations` on root pane to
`false`).
- Support running on WinPE. (issue #279)
#### Fixed bugs
- Native window decorations: Fixed missing animations when minimizing,
maximizing or restoring a window using window title bar buttons. (issue #282)
- Native window decorations: Fixed broken maximizing window when restoring frame
state at startup. (issue #283)
- Native window decorations: Fixed double window title bar when first disposing
a window with `frame.dispose()` and then showing it again with
`frame.setVisible(true)`. (issue #277)
- Custom window decorations: Fixed NPE in `FlatTitlePane.findHorizontalGlue()`.
(issue #275)
- Custom window decorations: Fixed right aligned progress bar in embedded menu
bar was overlapping window title. (issue #272)
- Fixed missing focus indicators in heavy-weight popups. (issue #273)
- InternalFrame: Fixed translucent internal frame menu bar background if
`TitlePane.unifiedBackground` is `true`. (issue #274)
- Extras: UI Inspector: Fixed `InaccessibleObjectException` when running in Java 16.
## 1.1
#### New features and improvements
- Windows 10 only:
- Native window decorations for Windows 10 enables dark frame/dialog title bar
and embedded menu bar with all JREs, while still having native Windows 10
border drop shadows, resize behavior, window snapping and system window
menu. (PR #267)
- Custom window decorations: Support right aligned components in `JFrame`
title bar with embedded menu bar (using `Box.createHorizontalGlue()`). (PR
#268)
- Custom window decorations: Improved centering of window title with embedded
menu bar. (PR #268; issue #252)
- Custom window decorations: Support unified backgrounds for window title bar,
menu bar and main content. If enabled with `UIManager.put(
"TitlePane.unifiedBackground", true );` then window title bar and menu bar
use same background color as main content. (PR #268; issue #254)
- JIDE Common Layer: Support `JideButton`, `JideLabel`, `JideSplitButton`,
`JideToggleButton` and `JideToggleSplitButton`.
- JIDE Common Layer: The library on Maven Central no longer depends on
`com.jidesoft:jide-oss:3.6.18` to avoid problems when another JIDE library
should be used. (issue #270)
- SwingX: The library on Maven Central no longer depends on
`org.swinglabs.swingx:swingx-all:1.6.5-1` to avoid problems when another
SwingX library should be used.
- Support running in [JetBrains Projector](https://jetbrains.com/projector/).
#### Fixed bugs
- IntelliJ Themes: Fixed text color of CheckBoxMenuItem and RadioButtonMenuItem
in all "Arc" themes. (issue #259)
## 1.0
#### New features and improvements
- Extras: UI Inspector: Tooltip is no longer limited to window bounds.
#### Fixed bugs
- TabbedPane: Custom `TabbedPane.selectedForeground` color did not work when
`TabbedPane.foreground` has also custom color. (issue #257)
- FileChooser: Fixed display of date in details view if current user is selected
in "Look in" combobox. (Windows 10 only; issue #249)
- Table: Fixed wrong grid line thickness in dragged column on HiDPI screens on
Java 9+. (issue #236)
- PopupFactory: Fixed `NullPointerException` when `PopupFactory.getPopup()` is
invoked with parameter `owner` set to `null`.
## 1.0-rc3
#### New features and improvements
- Extras:
- UI Inspector: Use HTML in tooltip. Display color value in same format as
used in FlatLaf properties files. Added color preview.
#### Fixed bugs
- Label and ToolTip: Fixed font sizes for `<code>`, `<kbd>`, `<big>`, `<small>`
and `<samp>` tags in HTML text.
- Fixed color of `<address>` tag in HTML text.
- IntelliJ Themes: Fixed table header background when dragging column in "Dark
Flat" and "Light Flat" themes.
- CheckBox: Fixed background of check boxes in JIDE `CheckBoxTree`. (regression
in 1.0-rc2)
## 1.0-rc2
#### New features and improvements
- Button:
- In "Flat Light" theme, use a slightly thinner border for focused buttons
(because they already have light blue background).
- In "Flat Dark" theme, use slightly wider border for focused buttons.
- CheckBox and RadioButton: In "Flat Dark" theme, use blueish background for
focused components.
- Tree: Support disabling wide selection per component. (set client property
`JTree.wideSelection` to `false`). (PR #245)
- Tree: Support disabling selection painting per component. Then the tree cell
renderer is responsible for selection painting. (set client property
`JTree.paintSelection` to `false`).
- JIDE Common Layer: Support `JidePopupMenu`.
#### Fixed bugs
- Button: Fixed behavior of <kbd>Enter</kbd> key on focused button on Windows
and Linux, which now clicks the focused button (instead of the default
button).
- On Windows, this is a regression in 1.0-rc1.
- On macOS, the <kbd>Enter</kbd> key always clicks the default button, which
is the platform behavior.
- On all platforms, the default button can be always clicked with
<kbd>Ctrl+Enter</kbd> keys, even if another button is focused.
- CheckBox and RadioButton: Fill component background as soon as background
color is different to default background color, even if component is not
opaque (which is the default). This paints selection if using the component as
cell renderer in Table, Tree or List.
- TextComponents: Border of focused non-editable text components had wrong
color.
- Custom window decorations: Fixed top window border in dark themes when running
in JetBrains Runtime.
## 1.0-rc1
#### New features and improvements
- Button: Disabled `Button.defaultButtonFollowsFocus` on Windows (as on other
platforms). If you like to keep the old behavior in your application, use:
`if(SystemInfo.isWindows)
UIManager.put("Button.defaultButtonFollowsFocus",true);`.
- ComboBox, Spinner and SplitPaneDivider: Added pressed feedback to arrow
buttons.
- Slider: Support per component custom thumb and track colors via
`JSlider.setForeground(Color)` and `JSlider.setBackground(Color)`.
- Slider: Improved thumb hover and pressed colors.
- TextComponent: Clip placeholder text if it does not fit into visible area. (PR
#229)
- macOS: Improved font rendering on macOS when using JetBrains Runtime. (PRs
#237, #239 and #241)
- Extras: UI defaults inspector:
- Support embedding UI defaults inspector panel into any window. See
`FlatUIDefaultsInspector.createInspectorPanel()`.
- Copy selected keys and values into clipboard via context menu.
- Support wildcard matching in filter (`*` matches any number of characters,
`?` matches a single character, `^` beginning of line, `$` end of line).
- IntelliJ Themes:
- Added hover and pressed feedback to Button, CheckBox, RadioButton and
ToggleButton. (issue #176)
- Added "Material Theme UI Lite / Moonlight" theme.
- Updated "Dracula", "Gradianto" and "Material Theme UI Lite" themes.
#### Fixed bugs
- Button and ToggleButton: Threat Unicode surrogate character pair as single
character and make button square. (issue #234)
- Button and ToggleButton: ToolBar buttons now respect explicitly set background
color. If no background color is set, then the button background is not
painted anymore. (issue #191)
- ToggleButton: Tab style buttons (client property `JButton.buttonType` is
`tab`) now respect explicitly set background color.
- TabbedPane: Fixed `IndexOutOfBoundsException` when using tooltip text on close
buttons and closing last/rightmost tab. (issue #235)
- TabbedPane: Fixed scrolling tabs with touchpads and high-resolution mouse
wheels.
- Extras: Added missing export of package
`com.formdev.flatlaf.extras.components` to Java 9 module descriptor.
- JIDE Common Layer:
- Invoke `LookAndFeelFactory.installJideExtension()` when using FlatLaf UI
delegates. (issue #230)
- RangeSlider: Fixed slider focused colors in IntelliJ themes.
- IntelliJ Themes:
- Fixed menu item check colors.
- Fixed `MenuItem.underlineSelectionColor`.
- Fixed List, Tree and Table `selectionInactiveForeground` in light Arc
themes.
- Fixed List and Table background colors in Material UI Lite themes.
- Fixed menu accelerator colors in Monocai theme. (issue #243)
## 0.46
#### New features and improvements
- Slider and JIDE RangeSlider: Clicking on track now immediately moves the thumb
to mouse location and starts dragging the thumb. Use `UIManager.put(
"Slider.scrollOnTrackClick", true )` to enable old behavior that scrolls the
thumb when clicking on track.
- Slider: Snap to ticks is now done while dragging the thumb. Use
`UIManager.put( "Slider.snapToTicksOnReleased", true )` to enable old behavior
that snaps to ticks on mouse released.
- Extras: Added standard component extension classes that provides easy access
to FlatLaf specific client properties (see package
`com.formdev.flatlaf.extras.components`).
- Extras: Renamed tri-state check box class from
`com.formdev.flatlaf.extras.TriStateCheckBox` to
`com.formdev.flatlaf.extras.components.FlatTriStateCheckBox`. Also
changed/improved API and added javadoc.
- Extras: Renamed SVG utility class from `com.formdev.flatlaf.extras.SVGUtils`
to `com.formdev.flatlaf.extras.FlatSVGUtils`.
- IntelliJ Themes: Added flag whether a theme is dark to
`FlatAllIJThemes.INFOS`. (issue #221)
- JIDE Common Layer: Support `TristateCheckBox`.
#### Fixed bugs
- Slider: Fixed painting of colored track if `JSlider.inverted` is `true`.
- Table and TableHeader: Fixed missing right vertical grid line if using table
as row header in scroll pane. (issues #152 and #46)
- TableHeader: Fixed position of column separators in right-to-left component
orientation.
- ToolTip: Fixed drop shadow for wide tooltips on Windows and Java 9+. (issue
#224)
- SwingX: Fixed striping background highlighting color (e.g. alternating table
rows) in dark themes.
- Fixed: If text antialiasing is disabled (in OS system settings or via
`-Dawt.useSystemAAFontSettings=off`), then some components still did use
antialiasing to render text (not-editable ComboBox, ProgressBar, Slider,
TabbedPane and multiline ToolTip). (issue #227)
## 0.45
#### New features and improvements
- Slider: New design, added hover and pressed feedback and improved customizing.
(PR #214)
- JIDE Common Layer: Support `RangeSlider`. (PR #209)
- IntelliJ Themes:
- Added "Gradianto Nature Green" theme.
- Updated "Arc Dark", "Cyan", "Dark purple", "Gradianto", "Gray", "Gruvbox"
and "One Dark" themes.
- TabbedPane: Support hiding tab area if it contains only one tab. (set client
property `JTabbedPane.hideTabAreaWithOneTab` to `true`)
- MenuBar: Support different underline menu selection style UI defaults for
`MenuBar` and `MenuItem`. (PR #217; issue #216)
#### Fixed bugs
- Table: Do not paint last vertical grid line if auto-resize mode is not off.
(issue #46)
- Table: Fixed unstable grid line thickness when scaled on HiDPI screens. (issue
#152)
- TabbedPane: No longer add (internal) tab close button component as child to
`JTabbedPane`. (issue #219)
- Custom window decorations: Title bar was not hidden if window is in
full-screen mode. (issue #212)
## 0.44
#### New features and improvements
- TabbedPane: In scroll tab layout, added "Show Hidden Tabs" button to trailing
side of tab area. If pressed, it shows a popup menu that contains (partly)
hidden tabs and selecting one activates that tab. (PR #190; issue #40)
- TabbedPane: Support forward/backward scroll arrow buttons on both sides of tab
area. Backward button on left side, forward button on right side. Not
applicable scroll buttons are hidden. (PR #211; issue #40)
- TabbedPane: Support specifying default tab layout policy for all tabbed panes
in the application via UI value `TabbedPane.tabLayoutPolicy`. E.g. invoke
`UIManager.put( "TabbedPane.tabLayoutPolicy", "scroll" );` to use scroll
layout.
- TabbedPane: Support tab scrolling with mouse wheel (in scroll tab layout). (PR
#187; issue #40)
- TabbedPane: Repeat scrolling as long as scroll arrow buttons are pressed. (PR
#187; issue #40)
- TabbedPane: Support adding custom components to left and right sides of tab
area. (set client property `JTabbedPane.leadingComponent` or
`JTabbedPane.trailingComponent` to a `java.awt.Component`) (PR #192; issue
#40)
- TabbedPane: Support closable tabs. (PR #193; issues #31 and #40)
- TabbedPane: Support minimum or maximum tab widths. (set client property
`JTabbedPane.minimumTabWidth` or `JTabbedPane.maximumTabWidth` to an integer)
(PR #199)
- TabbedPane: Support alignment of tab area. (set client property
`JTabbedPane.tabAreaAlignment` to `"leading"`, `"trailing"`, `"center"` or
`"fill"`) (PR #199)
- TabbedPane: Support horizontal alignment of tab title and icon. (set client
property `JTabbedPane.tabAlignment` to `SwingConstants.LEADING`,
`SwingConstants.TRAILING` or `SwingConstants.CENTER`)
- TabbedPane: Support equal and compact tab width modes. (set client property
`JTabbedPane.tabWidthMode` to `"preferred"`, `"equal"` or `"compact"`) (PR
#199)
- TabbedPane: Support left, right, top and bottom tab icon placement. (set
client property `JTabbedPane.tabIconPlacement` to `SwingConstants.LEADING`,
`SwingConstants.TRAILING`, `SwingConstants.TOP` or `SwingConstants.BOTTOM`)
(PR #199)
- Support painting separator line between window title and content (use UI value
`TitlePane.borderColor`). (issue #184)
- Extras: `FlatSVGIcon` now allows specifying icon width and height in
constructors. (issue #196)
- SplitPane: Hide not applicable expand/collapse buttons. Added tooltips to
expand/collapse buttons. (issue #198)
- SplitPane: Added grip to divider. Can be disabled with `UIManager.put(
"SplitPaneDivider.style", "plain" )`. (issue #179)
#### Fixed bugs
- Custom window decorations: Not visible menu bar is now ignored in layout.
- Popups using `JToolTip` components did not respect their location. (issue
#188; regression in 0.42 in fix for #164)
- IntelliJ Themes: Added suffix "(Material)" to names of all Material UI Lite
themes to avoid duplicate theme names. (issue #201)
- Extras: `FlatSVGIcon` icons were not painted in disabled labels and disabled
tabs. (issue #205)
## 0.43
#### New features and improvements
- TabbedPane: Made tabs separator color lighter in dark themes so that it is
easier to recognize the tabbed pane.
- TabbedPane: Added top and bottom tab insets to avoid that large tab icons are
painted over active tab underline.
- TabbedPane: Support hiding separator between tabs and content area (set client
property `JTabbedPane.showContentSeparator` to `false`).
- CheckBoxMenuItem and RadioButtonMenuItem: Improved checkmark background colors
of selected menu items that have also an icon. This makes it is easier to
recognize selected menu items.
- Windows: Made scaling compatible with Windows OS scaling, which distinguish
between "screen scaling" and "text scaling". (issue #175)
#### Fixed bugs
- ComboBox: If using own `JTextField` as editor, default text field border is
now removed to avoid duplicate border.
- ComboBox: Limit popup width to screen width for very long items. (issue #182)
- FileChooser: Fixed localizing special Windows folders (e.g. "Documents") and
enabled hiding known file extensions (if enabled in Windows Explorer). (issue
#178)
- Spinner: Fixed `NullPointerException` in case that arrow buttons were removed
to create button-less spinner. (issue #181)
## 0.42
#### New features and improvements
- Demo: Improved "SplitPane & Tabs" and "Data Components" tabs.
- Demo: Menu items "File > Open" and "File > Save As" now show file choosers.
- InternalFrame: Support draggable border for resizing frame inside of the
visible frame border. (issue #121)
- `FlatUIDefaultsInspector` added (see [FlatLaf Extras](flatlaf-extras)). A
simple UI defaults inspector that shows a window with all UI defaults used in
current theme (look and feel).
- Made disabled text color slightly lighter in dark themes for better
readability. (issue #174)
- PasswordField: Support disabling Caps Lock warning icon. (issue #172)
#### Fixed bugs
- TextComponents: Fixed text color of disabled text components in dark themes.
- Custom window decorations: Fixed wrong window placement when moving window to
another screen with different scaling factor. (issue #166)
- Custom window decorations: Fixed wrong window bounds when resizing window to
another screen with different scaling factor. (issue #166)
- Fixed occasional wrong positioning of heavy weight popups when using multiple
screens with different scaling factors. (issue #166)
- ToolTip: Avoid that tooltip hides owner component. (issue #164)
## 0.41
#### New features and improvements
- Added API to register packages or folders where FlatLaf searches for
application specific properties files with custom UI defaults (see
`FlatLaf.registerCustomDefaultsSource(...)` methods).
- Demo: Show hint popups to guide users to some features of the FlatLaf Demo
application.
- Extras: `FlatSVGIcon` now allows specifying `ClassLoader` that is used to load
SVG file. (issue #163)
- Smoother transition from old to new theme, independent of UI complexity, when
using animated theme change (see [FlatLaf Extras](flatlaf-extras)).
#### Fixed bugs
- Button: "selected" state was not shown. (issue #161)
- TextArea: Update background color property if enabled or editable state
changes in the same way as Swing does it for all other text components. (issue
#147)
- Demo: Fixed restoring last used theme on startup. (regression in 0.39)
- Custom window decorations: Fixed iconify, maximize and close icon colors if
window is inactive.
- Custom window decorations: Fixed title pane background color in IntelliJ
themes if window is inactive.
- Fixed sub-pixel text rendering in animated theme change (see
[FlatLaf Extras](flatlaf-extras)).
#### Other Changes
- Extras: Updated dependency
[svgSalamander](https://github.com/JFormDesigner/svgSalamander) to version
1.1.2.3.
## 0.40
#### New features
- Table: Detect whether component is used in cell editor and automatically
disable round border style and reduce cell editor outer border width (used for
focus indicator) to zero. (issue #148)
- ComboBox, Spinner and TextField: Support disabling round border style per
component, if globally enabled (set client property `JComponent.roundRect` to
`false`). (issue #148)
#### Fixed bugs
- Custom window decorations: Embedded menu bar did not always respond to mouse
events after adding menus and when running in JetBrains Runtime. (issue #151)
- IntelliJ Themes: Fixed NPE in Solarized themes on scroll bar hover.
## 0.39
#### New features
- Animated theme change (see [FlatLaf Extras](flatlaf-extras)). Used in Demo.
- Demo: Added combo box above themes list to show only light or dark themes.
- IntelliJ Themes:
- Added "Arc Dark", "Arc Dark - Orange", "Carbon" and "Cobalt 2" themes.
- Replaced "Solarized" themes with much better ones from 4lex4.
- Updated "Arc", "One Dark" and "Vuesion" themes.
- ScrollPane: Enable/disable smooth scrolling per component if client property
"JScrollPane.smoothScrolling" is set to a `Boolean` on `JScrollPane`.
- ScrollBar: Increased minimum thumb size on macOS and Linux from 8 to 18
pixels. On Windows, it is now 10 pixels. (issue #131)
- Button: Support specifying button border width.
- ComboBox: Changed maximum row count of popup list to 15 (was 20). Set UI value
`ComboBox.maximumRowCount` to any integer to use a different value.
#### Fixed bugs
- Custom window decorations: Fixed maximized window bounds when programmatically
maximizing window. E.g. restoring window state at startup. (issue #129)
- InternalFrame: Title pane height was too small when iconify, maximize and
close buttons are hidden. (issue #132)
- ToolTip: Do not show empty tooltip component if tooltip text is an empty
string. (issue #134)
- ToolTip: Fixed truncated text in HTML formatted tooltip on HiDPI displays.
(issue #142)
- ComboBox: Fixed width of popup, which was too small if popup is wider than
combo box and vertical scroll bar is visible. (issue #137)
- MenuItem on macOS: Removed plus characters from accelerator text and made
modifier key order conform with macOS standard. (issue #141)
- FileChooser: Fixed too small text field when renaming a file/directory in Flat
IntelliJ/Darcula themes. (issue #143)
- IntelliJ Themes: Fixed text colors in ProgressBar. (issue #138)
## 0.38
- Hide focus indicator when window is inactive.
- Custom window decorations: Improved/fixed window border color in dark themes.
- Custom window decorations: Hide window border if window is maximized.
- Custom window decorations: Center title if menu bar is embedded.
- Custom window decorations: Cursor of components (e.g. TextField) was not
changed. (issue #125)
- CheckBox: Fixed colors in light IntelliJ themes. (issue #126; regression in
0.37)
- InternalFrame: Use default icon in internal frames. (issue #122)
## 0.37
- Custom window decorations (Windows 10 only; PR #108; issues #47 and #82)
support:
- dark window title panes
- embedding menu bar into window title pane
- native Windows 10 borders and behavior when running in
[JetBrains Runtime 11](https://confluence.jetbrains.com/display/JBR/JetBrains+Runtime)
or later (the JRE that IntelliJ IDEA uses)
- CheckBox and RadioButton: Support changing selected icon style from outline to
filled (as in FlatLaf IntelliJ theme) with `UIManager.put(
"CheckBox.icon.style", "filled" );`.
- Button and ToggleButton: Support disabled background color (use UI values
`Button.disabledBackground` and `ToggleButton.disabledBackground`). (issue
#112)
- Button and ToggleButton: Support making buttons square (set client property
`JButton.squareSize` to `true`). (issue #118)
- ScrollBar: Support pressed track, thumb and button colors (use UI values
`ScrollBar.pressedTrackColor`, `ScrollBar.pressedThumbColor` and
`ScrollBar.pressedButtonBackground`). (issue #115)
- ComboBox: Support changing arrow button style (set UI value
`ComboBox.buttonStyle` to `auto` (default), `button` or `none`). (issue #114)
- Spinner: Support changing arrows button style (set UI value
`Spinner.buttonStyle` to `button` (default) or `none`).
- TableHeader: Support top/bottom/left positioned sort arrow when using
[Glazed Lists](https://github.com/glazedlists/glazedlists). (issue #113)
- Button, CheckBox, RadioButton and ToggleButton: Do not paint focus indicator
if `AbstractButton.isFocusPainted()` returns `false`.
- ComboBox: Increase maximum row count of popup list to 20 (was 8). Set UI value
`ComboBox.maximumRowCount` to any integer to use a different value.
- Fixed/improved vertical position of text when scaled on HiDPI screens on
Windows.
- IntelliJ Themes: Updated Gradianto Themes.
- IntelliJ Themes: Fixed menu bar and menu item margins in all Material UI Lite
themes.
## 0.36
- ScrollBar: Made styling more flexible by supporting insets and arc for track
and thumb. (issue #103)
- ScrollBar: Use round thumb on macOS and Linux to make it look similar to
native platform scroll bars. (issue #103)
- ComboBox: Minimum width is now 72 pixels (was ~50 for non-editable and ~130
for editable comboboxes).
- ComboBox: Support custom borders in combobox editors. (issue #102)
- Button: Support non-square icon-only buttons. (issue #110)
- Ubuntu Linux: Fixed poorly rendered font. (issue #105)
- macOS Catalina: Use Helvetica Neue font.
- `FlatInspector` added (see [FlatLaf Extras](flatlaf-extras)).
## 0.35
- Added drop shadows to popup menus, combobox popups, tooltips and internal
frames. (issue #94)
- Support different component border colors to indicate errors, warnings or
custom state (set client property `JComponent.outline` to `error`, `warning`
or any `java.awt.Color`).
- Button and ToggleButton: Support round button style (set client property
`JButton.buttonType` to `roundRect`).
- ComboBox, Spinner and TextField: Support round border style (set client
property `JComponent.roundRect` to `true`).
- Paint nicely rounded buttons, comboboxes, spinners and text fields when
setting `Button.arc`, `Component.arc` or `TextComponent.arc` to a large value
(e.g. 1000).
- Added Java 9 module descriptor to `flatlaf-extras-<version>.jar` and
`flatlaf-swingx-<version>.jar`.
- CheckBox and RadioButton: Flag `opaque` is no longer ignored when checkbox or
radio button is used as table cell renderer. (issue #77)
- FileChooser: Use system icons. (issue #100)
- FileChooser: Fixed missing labels in file chooser when running on Java 9 or
later. (issue #98)
- PasswordField: Do not apply minimum width if `columns` property is greater
than zero.
## 0.34
- Menus: New menu item renderer brings stable left margins, right aligned
accelerators and larger gap between text and accelerator. This makes menus
look more modern and more similar to native platform menus.
- New underline menu selection style that displays selected menu items similar
to tabs (to enable use `UIManager.put( "MenuItem.selectionType", "underline"
);`).
- Menus: Fixed text color of selected menu items that use HTML. (issue #87)
- Menus: On Windows, pressing <kbd>F10</kbd> now activates the menu bar without
showing a menu popup (as usual on Windows platform). On other platforms the
first menu popup is shown.
- Menus: On Windows, releasing <kbd>Alt</kbd> key now activates the menu bar (as
usual on Windows platform). (issue #43)
- Menus: Fixed inconsistent left padding in menu items. (issue #3)
- Menus: Fixed: Setting `iconTextGap` property on a menu item did increase left
and right margins. (issue #54)
- Hide mnemonics if window is deactivated (e.g. <kbd>Alt+Tab</kbd> to another
window). (issue #43)
- macOS: Enabled drop shadows for popup menus and combobox popups. (issue #94)
- macOS: Fixed NPE if using `JMenuBar` in `JInternalFrame` and macOS screen menu
bar is enabled (with `-Dapple.laf.useScreenMenuBar=true`). (issue #90)
## 0.33
- Improved creation of disabled grayscale icons used in disabled buttons, labels

176
README.md
View File

@@ -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.
![Flat Light Demo](images/FlatLightDemo.png)
![Flat Light](images/flat_light.png)
![Flat Dark Demo](images/FlatDarkDemo.png)
![Flat Dark](images/flat_dark.png)
IntelliJ Platform Themes
@@ -22,9 +22,7 @@ IntelliJ Platform Themes
FlatLaf can use 3rd party themes created for IntelliJ Platform (see
[IntelliJ Themes Pack](flatlaf-intellij-themes)):
![Cyan Light Demo](images/CyanLightDemo.png)
![Dark Purple Demo](images/DarkPurpleDemo.png)
![IntelliJ Platform Themes](images/intellij_platform_themes.png)
Demo
@@ -39,7 +37,7 @@ Requires Java 8 or newer.
Download
--------
FlatLaf binaries are available on **JCenter** and **Maven Central**.
FlatLaf binaries are available on **Maven Central**.
If you use Maven or Gradle, add a dependency with following coordinates to your
build script:
@@ -50,16 +48,16 @@ build script:
Otherwise download `flatlaf-<version>.jar` here:
[![Download](https://api.bintray.com/packages/jformdesigner/flatlaf/flatlaf/images/download.svg)](https://bintray.com/jformdesigner/flatlaf/flatlaf/_latestVersion)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.formdev/flatlaf/badge.svg?style=flat-square&color=007ec6)](https://maven-badges.herokuapp.com/maven-central/com.formdev/flatlaf)
### Snapshots
FlatLaf snapshot binaries are available in
[JFrog Artifactory](https://oss.jfrog.org/artifactory/oss-snapshot-local/com/formdev/).
To access the latest snapshot, change the FlatLaf version(s) in the dependencies
FlatLaf snapshot binaries are available on
[Sonatype OSSRH](https://oss.sonatype.org/content/repositories/snapshots/com/formdev/flatlaf/).
To access the latest snapshot, change the FlatLaf version in your dependencies
to `<version>-SNAPSHOT` (e.g. `0.27-SNAPSHOT`) and add the repository
`https://oss.jfrog.org/artifactory/oss-snapshot-local` to your build (see
`https://oss.sonatype.org/content/repositories/snapshots/` to your build (see
[Maven](https://maven.apache.org/guides/mini/guide-multiple-repositories.html)
and
[Gradle](https://docs.gradle.org/current/userguide/declaring_repositories.html#sec:declaring_custom_repository)
@@ -69,48 +67,136 @@ docs).
Addons
------
- [SwingX](flatlaf-swingx)
- [JIDE Common Layer](flatlaf-jide-oss)
- [IntelliJ Themes Pack](flatlaf-intellij-themes)
- [IntelliJ Themes Pack](flatlaf-intellij-themes) - bundles many popular
open-source 3rd party themes
- [Extras](flatlaf-extras) - SVG icon, tri-state check box, UI inspectors, and
more
- [SwingX](flatlaf-swingx) - support for SwingX components
- [JIDE Common Layer](flatlaf-jide-oss) - support for JIDE Common Layer
components
Projects using FlatLaf
----------------------
Getting started
---------------
- [NetBeans](https://netbeans.apache.org/) 11.3
- [jclasslib bytecode viewer](https://github.com/ingokegel/jclasslib) 5.5
- [KeyStore Explorer](https://keystore-explorer.org/) 5.4.3
- [OWASP Zed Attack Proxy (ZAP)](https://www.zaproxy.org/) (in weekly releases)
- [XMLmind XML Editor](https://www.xmlmind.com/xmleditor/) 9.3 (commercial)
- [Total Validator](https://www.totalvalidator.com/) 15 (commercial)
- [j-lawyer](https://github.com/jlawyerorg/j-lawyer-org)
- [MegaMek](https://github.com/MegaMek/megamek) v0.47.4 and
[MekHQ](https://github.com/MegaMek/mekhq) v0.47.5
- [GUIslice Builder](https://github.com/ImpulseAdventure/GUIslice-Builder)
0.13.b024
- [Rest Suite](https://github.com/supanadit/restsuite)
- [ControllerBuddy](https://github.com/bwRavencl/ControllerBuddy)
- [SpringRemote](https://github.com/HaleyWang/SpringRemote)
- [mendelson AS2](https://sourceforge.net/projects/mec-as2/),
[AS4](https://sourceforge.net/projects/mendelson-as4/) and
[OFTP2](https://sourceforge.net/projects/mendelson-oftp2/) (open-source) and
[mendelson AS2](https://mendelson-e-c.com/as2/),
[AS4](https://mendelson-e-c.com/as4/) and
[OFTP2](https://mendelson-e-c.com/oftp2) (commercial)
- [MeteoInfo](https://github.com/meteoinfo/MeteoInfo) 2.1.6
- [lsfusion platform](https://github.com/lsfusion/platform)
- and more...
To use FlatLaf, add following code to your main method before you create any
Swing component:
~~~java
FlatLightLaf.setup();
Buzz
----
- [What others say about FlatLaf on Twitter](https://twitter.com/search?f=live&q=flatlaf)
- [FlatLaf announcement on Reddit](https://www.reddit.com/r/java/comments/dl0hu3/flatlaf_flat_look_and_feel/)
// create UI here...
~~~
Documentation
-------------
For more information and documentation visit
[FlatLaf Home](https://www.formdev.com/flatlaf/)
[FlatLaf Home](https://www.formdev.com/flatlaf/):
- [Themes](https://www.formdev.com/flatlaf/themes/)
- [Customizing](https://www.formdev.com/flatlaf/customizing/)
- [How to Customize](https://www.formdev.com/flatlaf/how-to-customize/)
- [Properties Files](https://www.formdev.com/flatlaf/properties-files/)
- [Client Properties](https://www.formdev.com/flatlaf/client-properties/)
- [System Properties](https://www.formdev.com/flatlaf/system-properties/)
Buzz
----
- [What others say about FlatLaf on Twitter](https://twitter.com/search?f=live&q=flatlaf)
- [FlatLaf 1.0 announcement on Reddit](https://www.reddit.com/r/java/comments/lsbcwe/flatlaf_10_swing_look_and_feel/)
- [FlatLaf announcement on Reddit](https://www.reddit.com/r/java/comments/dl0hu3/flatlaf_flat_look_and_feel/)
Applications using FlatLaf
--------------------------
- [Apache NetBeans](https://netbeans.apache.org/) 11.3 - IDE for Java, PHP, HTML
and much more
- [jclasslib bytecode viewer](https://github.com/ingokegel/jclasslib) 5.5
- [KeyStore Explorer](https://keystore-explorer.org/) 5.4.3
- ![New](images/new.svg)
[install4j](https://www.ej-technologies.com/products/install4j/overview.html)
9.0 (**commercial**) - the powerful multi-platform Java installer builder
- ![New](images/new.svg) [DbVisualizer](https://www.dbvis.com/) 12.0
(**commercial**) - the universal database tool for developers, analysts and
DBAs
- ![New](images/new.svg) [MagicPlot](https://magicplot.com/) 3.0
(**commercial**) - Software for nonlinear fitting, plotting and data analysis
- ![New](images/new.svg)
[Thermo-Calc](https://thermocalc.com/products/thermo-calc/) 2021a
(**commercial**) - Thermodynamics and Properties Software
- [OWASP ZAP](https://www.zaproxy.org/) 2.10 - the worlds most widely used web
app scanner
- ![New](images/new.svg)
[Burp Suite Professional and Community Edition](https://portswigger.net/burp/pro)
2020.11.2 (**commercial**) - the leading software for web security testing
- ![New](images/new.svg)
[BurpCustomizer](https://github.com/CoreyD97/BurpCustomizer) - adds more
FlatLaf themes to Burp Suite
- [JOSM](https://josm.openstreetmap.de/) - an extensible editor for
[OpenStreetMap](https://www.openstreetmap.org/) (requires FlatLaf JOSM plugin)
- [jAlbum](https://jalbum.net/) 21 (**commercial**) - creates photo album
websites
- [XMLmind XML Editor](https://www.xmlmind.com/xmleditor/) 9.3 (**commercial**)
- [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
- [GUIslice Builder](https://github.com/ImpulseAdventure/GUIslice-Builder)
0.13.b024 - GUI builder for
[GUIslice](https://github.com/ImpulseAdventure/GUIslice), a lightweight GUI
framework for embedded displays
- [Rest Suite](https://github.com/supanadit/restsuite) - Rest API testing
- [ControllerBuddy](https://github.com/bwRavencl/ControllerBuddy) - advanced
gamepad mapping software
- [SpringRemote](https://github.com/HaleyWang/SpringRemote) - remote Linux SSH
connections manager
- [jEnTunnel](https://github.com/ggrandes/jentunnel) - manage SSH Tunnels made
easy
- [mendelson AS2](https://sourceforge.net/projects/mec-as2/),
[AS4](https://sourceforge.net/projects/mendelson-as4/) and
[OFTP2](https://sourceforge.net/projects/mendelson-oftp2/) (open-source) and
[mendelson AS2](https://mendelson-e-c.com/as2/),
[AS4](https://mendelson-e-c.com/as4/) and
[OFTP2](https://mendelson-e-c.com/oftp2) (**commercial**)
- ![New](images/new.svg) [IGMAS+](https://www.gfz-potsdam.de/igmas) -
Interactive Gravity and Magnetic Application System
- [MeteoInfo](https://github.com/meteoinfo/MeteoInfo) 2.2 - GIS and scientific
computation environment for meteorological community
- [lsfusion platform](https://github.com/lsfusion/platform) 4 - information
systems development platform
- [JPass](https://github.com/gaborbata/jpass) - password manager with strong
encryption
- [Jes - Die Java-E<>R](https://www.jes-eur.de)
- [Mapton](https://mapton.org/) 2.0
([source code](https://github.com/trixon/mapton)) - some kind of map
application (based on NetBeans platform)
- [Pseudo Assembler IDE](https://github.com/tomasz-herman/PseudoAssemblerIDE) -
IDE for Pseudo-Assembler
- [Linotte](https://github.com/cpc6128/LangageLinotte) 3.1 - French programming
language created to learn programming
- [MEKA](https://github.com/Waikato/meka) 1.9.3 - multi-label classifiers and
evaluation procedures using the Weka machine learning framework
- [Shutter Encoder](https://www.shutterencoder.com/) 14.2
([source code](https://github.com/paulpacifico/shutter-encoder)) -
professional video converter and compression tool (screenshots show **old**
look)
- [Sound Analysis](https://github.com/tomasz-herman/SoundAnalysis) - analyze
sound files in time or frequency domain
- [RemoteLight](https://github.com/Drumber/RemoteLight) - multifunctional LED
control software
- [ThunderFocus](https://github.com/marcocipriani01/ThunderFocus) -
Arduino-based telescope focuser
- [Novel-Grabber](https://github.com/Flameish/Novel-Grabber) - download novels
from any webnovel and lightnovel site
- [lectureStudio](https://www.lecturestudio.org/) 4.3.1060 - digitize your
lectures with ease
- [Android Tool](https://github.com/fast-geek/Android-Tool) - makes popular adb
and fastboot commands easier to use
- and more...

View File

@@ -14,8 +14,8 @@
* limitations under the License.
*/
val releaseVersion = "0.33"
val developmentVersion = "0.34-SNAPSHOT"
val releaseVersion = "1.6.4"
val developmentVersion = "2.0-SNAPSHOT"
version = if( java.lang.Boolean.getBoolean( "release" ) ) releaseVersion else developmentVersion
@@ -23,7 +23,7 @@ allprojects {
version = rootProject.version
repositories {
jcenter()
mavenCentral()
}
}
@@ -40,17 +40,6 @@ println( "Java ${System.getProperty( "java.version" )}" )
println()
extra["bintray.user"] = System.getenv( "BINTRAY_USER" ) ?: System.getProperty( "bintray.user" )
extra["bintray.key"] = System.getenv( "BINTRAY_KEY" ) ?: System.getProperty( "bintray.key" )
// if true, do not upload to bintray
extra["bintray.dryRun"] = false
// if true, uploaded artifacts are visible to all
// if false, only visible to owner when logged into bintray
extra["bintray.publish"] = true
allprojects {
tasks {
withType<JavaCompile>().configureEach {
@@ -58,19 +47,35 @@ allprojects {
targetCompatibility = "1.8"
options.encoding = "ISO-8859-1"
options.isDeprecation = false
}
withType<Jar>().configureEach {
// manifest for all created JARs
manifest.attributes(mapOf(
manifest.attributes(
"Implementation-Vendor" to "FormDev Software GmbH",
"Implementation-Copyright" to "Copyright (C) ${java.time.LocalDate.now().year} FormDev Software GmbH. All rights reserved.",
"Implementation-Version" to project.version))
"Implementation-Copyright" to "Copyright (C) 2019-${java.time.LocalDate.now().year} FormDev Software GmbH. All rights reserved.",
"Implementation-Version" to project.version
)
// add META-INF/LICENSE to all created JARs
from("${rootDir}/LICENSE") {
into("META-INF")
from( "${rootDir}/LICENSE" ) {
into( "META-INF" )
}
}
withType<Javadoc>().configureEach {
options {
this as StandardJavadocDocletOptions
title = "${project.name} $version"
header = title
isUse = true
tags = listOf( "uiDefault", "clientProperty" )
addStringOption( "Xdoclint:all,-missing", "-Xdoclint:all,-missing" )
links( "https://docs.oracle.com/en/java/javase/11/docs/api/" )
}
isFailOnError = false
}
}
}

24
buildSrc/build.gradle.kts Normal file
View File

@@ -0,0 +1,24 @@
/*
* Copyright 2020 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
plugins {
`kotlin-dsl`
}
// required for kotlin-dsl or embedded-kotlin plugins
repositories {
mavenCentral()
}

View File

@@ -0,0 +1,80 @@
/*
* Copyright 2020 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.util.function.Predicate;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
/**
* Reorders entries in a JAR file so that .properties files are placed before .class files,
* which is necessary to workaround an issue in NetBeans 11.3 (and older).
* See issues #13 and #93.
*
* @author Karl Tauber
*/
public class ReorderJarEntries
{
public static void reorderJarEntries( File jarFile )
throws IOException
{
ByteArrayOutputStream outStream = new ByteArrayOutputStream( (int) jarFile.length() + 1000 );
try( ZipOutputStream zipOutStream = new ZipOutputStream( outStream ) ) {
// 1st pass: copy .properties files
copyFiles( zipOutStream, jarFile, name -> name.endsWith( ".properties" ) );
// 2st pass: copy other files
copyFiles( zipOutStream, jarFile, name -> !name.endsWith( ".properties" ) );
}
// replace JAR
Files.write( jarFile.toPath(), outStream.toByteArray(),
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING );
}
private static void copyFiles( ZipOutputStream dest, File jarFile, Predicate<String> filter )
throws IOException
{
try( ZipInputStream zipInputStream = new ZipInputStream( new FileInputStream( jarFile ) ) ) {
ZipEntry entry;
while( (entry = zipInputStream.getNextEntry()) != null ) {
if( filter.test( entry.getName() ) ) {
dest.putNextEntry( entry );
copyFile( zipInputStream, dest );
}
}
}
}
private static void copyFile( InputStream src, OutputStream dest )
throws IOException
{
byte[] buf = new byte[8*1024];
int len;
while( (len = src.read( buf )) > 0 )
dest.write( buf, 0, len );
dest.flush();
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2020 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
plugins {
java
}
if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) {
sourceSets {
create( "java9" ) {
java {
setSrcDirs( listOf( "src/main/java9" ) )
}
}
}
dependencies {
add( "java9Compile", sourceSets.main.get().output )
}
tasks {
named<JavaCompile>( "compileJava9Java" ) {
sourceCompatibility = "9"
targetCompatibility = "9"
}
jar {
manifest.attributes( "Multi-Release" to "true" )
into( "META-INF/versions/9" ) {
from( sourceSets["java9"].output )
}
}
}
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright 2020 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
open class ModuleInfoExtension {
var paths: ArrayList<String> = ArrayList()
fun dependsOn( vararg paths: String ) {
this.paths.addAll( paths )
}
}
val extension = project.extensions.create<ModuleInfoExtension>( "flatlafModuleInfo" )
plugins {
java
}
if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) {
sourceSets {
create( "module-info" ) {
java {
// include "src/main/java" and "src/main/java9" here to get compile errors if classes are
// used from other modules that are not specified in module dependencies
setSrcDirs( listOf( "src/main/module-info", "src/main/java", "src/main/java9" ) )
// exclude Java 8 source file if an equally named Java 9+ source file exists
exclude {
if( it.isDirectory )
return@exclude false
val java9file = file( "${projectDir}/src/main/java9/${it.path}" )
java9file.exists() && java9file != it.file
}
}
}
}
tasks {
named<JavaCompile>( "compileModuleInfoJava" ) {
sourceCompatibility = "9"
targetCompatibility = "9"
dependsOn( extension.paths )
options.compilerArgs.add( "--module-path" )
options.compilerArgs.add( configurations.runtimeClasspath.get().asPath
+ File.pathSeparator + configurations.compileClasspath.get().asPath )
}
jar {
manifest.attributes( "Multi-Release" to "true" )
into( "META-INF/versions/9" ) {
from( sourceSets["module-info"].output ) {
include( "module-info.class" )
}
}
}
}
}

View File

@@ -0,0 +1,112 @@
/*
* Copyright 2020 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
open class PublishExtension {
var artifactId: String? = null
var name: String? = null
var description: String? = null
}
val extension = project.extensions.create<PublishExtension>( "flatlafPublish" )
plugins {
`maven-publish`
signing
}
publishing {
publications {
create<MavenPublication>( "maven" ) {
afterEvaluate {
artifactId = extension.artifactId
}
groupId = "com.formdev"
from( components["java"] )
pom {
afterEvaluate {
this@pom.name.set( extension.name )
this@pom.description.set( extension.description )
}
url.set( "https://github.com/JFormDesigner/FlatLaf" )
licenses {
license {
name.set( "The Apache License, Version 2.0" )
url.set( "https://www.apache.org/licenses/LICENSE-2.0.txt" )
}
}
developers {
developer {
name.set( "Karl Tauber" )
organization.set( "FormDev Software GmbH" )
organizationUrl.set( "https://www.formdev.com/" )
}
}
scm {
connection.set( "scm:git:git://github.com/JFormDesigner/FlatLaf.git" )
url.set( "https://github.com/JFormDesigner/FlatLaf" )
}
issueManagement {
system.set( "GitHub" )
url.set( "https://github.com/JFormDesigner/FlatLaf/issues" )
}
}
}
}
repositories {
maven {
name = "OSSRH"
val releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
val snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots/"
url = uri( if( java.lang.Boolean.getBoolean( "release" ) ) releasesRepoUrl else snapshotsRepoUrl )
credentials {
// get from gradle.properties
val ossrhUsername: String? by project
val ossrhPassword: String? by project
username = System.getenv( "OSSRH_USERNAME" ) ?: ossrhUsername
password = System.getenv( "OSSRH_PASSWORD" ) ?: ossrhPassword
}
}
}
}
signing {
// get from gradle.properties
val signingKey: String? by project
val signingPassword: String? by project
val key = System.getenv( "SIGNING_KEY" ) ?: signingKey
val password = System.getenv( "SIGNING_PASSWORD" ) ?: signingPassword
useInMemoryPgpKeys( key, password )
sign( publishing.publications["maven"] )
}
// disable signing of snapshots
tasks.withType<Sign>().configureEach {
onlyIf { java.lang.Boolean.getBoolean( "release" ) }
}

2151
compare1.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,377 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false
org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns=false
org.eclipse.jdt.core.formatter.align_with_spaces=false
org.eclipse.jdt.core.formatter.alignment_for_additive_operator=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
org.eclipse.jdt.core.formatter.alignment_for_assignment=0
org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator=16
org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
org.eclipse.jdt.core.formatter.alignment_for_compact_loops=16
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=48
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain=0
org.eclipse.jdt.core.formatter.alignment_for_enum_constants=16
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
org.eclipse.jdt.core.formatter.alignment_for_logical_operator=16
org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_module_statements=16
org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator=16
org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_record_components=16
org.eclipse.jdt.core.formatter.alignment_for_relational_operator=0
org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
org.eclipse.jdt.core.formatter.alignment_for_shift_operator=0
org.eclipse.jdt.core.formatter.alignment_for_string_concatenation=16
org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=33
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=33
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_record_declaration=33
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=33
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=32
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=32
org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0
org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0
org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration=0
org.eclipse.jdt.core.formatter.blank_lines_after_package=1
org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method=1
org.eclipse.jdt.core.formatter.blank_lines_before_field=0
org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
org.eclipse.jdt.core.formatter.blank_lines_before_method=1
org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
org.eclipse.jdt.core.formatter.blank_lines_before_package=0
org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=0
org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch=0
org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_block=next_line_on_wrap
org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=next_line_on_wrap
org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=next_line_on_wrap
org.eclipse.jdt.core.formatter.brace_position_for_record_constructor=next_line_on_wrap
org.eclipse.jdt.core.formatter.brace_position_for_record_declaration=next_line
org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=next_line
org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped=true
org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions=false
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=true
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=true
org.eclipse.jdt.core.formatter.comment.format_block_comments=true
org.eclipse.jdt.core.formatter.comment.format_header=false
org.eclipse.jdt.core.formatter.comment.format_html=true
org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
org.eclipse.jdt.core.formatter.comment.format_line_comments=true
org.eclipse.jdt.core.formatter.comment.format_source_code=true
org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false
org.eclipse.jdt.core.formatter.comment.indent_root_tags=false
org.eclipse.jdt.core.formatter.comment.indent_tag_description=false
org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags=do not insert
org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
org.eclipse.jdt.core.formatter.comment.line_length=80
org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
org.eclipse.jdt.core.formatter.compact_else_if=true
org.eclipse.jdt.core.formatter.continuation_indentation=1
org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=1
org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=false
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_record_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
org.eclipse.jdt.core.formatter.indent_empty_lines=false
org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true
org.eclipse.jdt.core.formatter.indentation.size=4
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert
org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_additive_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case=insert
org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default=insert
org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_record_components=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
org.eclipse.jdt.core.formatter.insert_space_after_logical_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_not_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_record_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=insert
org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_relational_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
org.eclipse.jdt.core.formatter.insert_space_after_shift_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation=insert
org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_additive_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case=insert
org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default=insert
org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_record_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_record_components=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
org.eclipse.jdt.core.formatter.insert_space_before_logical_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_constructor=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_record_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_relational_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_shift_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation=insert
org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.join_lines_in_comments=true
org.eclipse.jdt.core.formatter.join_wrapped_lines=true
org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line=one_line_never
org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line=one_line_never
org.eclipse.jdt.core.formatter.keep_code_block_on_one_line=one_line_never
org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line=one_line_never
org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line=one_line_never
org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line=one_line_never
org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line=one_line_never
org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line=one_line_never
org.eclipse.jdt.core.formatter.keep_method_body_on_one_line=one_line_never
org.eclipse.jdt.core.formatter.keep_record_constructor_on_one_line=one_line_never
org.eclipse.jdt.core.formatter.keep_record_declaration_on_one_line=one_line_never
org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line=false
org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line=false
org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line=false
org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line=false
org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line=one_line_never
org.eclipse.jdt.core.formatter.lineSplit=120
org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
org.eclipse.jdt.core.formatter.number_of_blank_lines_after_code_block=0
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block=0
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block=0
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body=0
org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block=0
org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_record_declaration=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines
org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
org.eclipse.jdt.core.formatter.tabulation.char=tab
org.eclipse.jdt.core.formatter.tabulation.size=4
org.eclipse.jdt.core.formatter.text_block_indentation=0
org.eclipse.jdt.core.formatter.use_on_off_tags=false
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
org.eclipse.jdt.core.formatter.wrap_before_additive_operator=true
org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false
org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator=true
org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true
org.eclipse.jdt.core.formatter.wrap_before_logical_operator=false
org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator=true
org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
org.eclipse.jdt.core.formatter.wrap_before_relational_operator=true
org.eclipse.jdt.core.formatter.wrap_before_shift_operator=true
org.eclipse.jdt.core.formatter.wrap_before_string_concatenation=true
org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter

View File

@@ -0,0 +1,3 @@
eclipse.preferences.version=1
formatter_profile=_FlatLaf
formatter_settings_version=19

View File

@@ -16,161 +16,112 @@
plugins {
`java-library`
`maven-publish`
id( "com.jfrog.bintray" )
id( "com.jfrog.artifactory" )
`flatlaf-module-info`
`flatlaf-java9`
`flatlaf-publish`
}
if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) {
sourceSets {
create( "java9" ) {
java {
setSrcDirs( listOf( "src/main/java9" ) )
}
}
create( "module-info" ) {
java {
// include "src/main/java" here to get compile errors if classes are
// used from other modules that are not specified in module dependencies
setSrcDirs( listOf( "src/main/module-info", "src/main/java" ) )
}
}
}
val sigtest = configurations.create( "sigtest" )
dependencies {
testImplementation( "org.junit.jupiter:junit-jupiter-api:5.7.2" )
testImplementation( "org.junit.jupiter:junit-jupiter-params" )
testRuntimeOnly( "org.junit.jupiter:junit-jupiter-engine" )
// https://github.com/jtulach/netbeans-apitest
sigtest( "org.netbeans.tools:sigtest-maven-plugin:1.4" )
}
java {
withSourcesJar()
withJavadocJar()
}
tasks {
assemble {
dependsOn(
"sourcesJar",
"javadocJar"
)
compileJava {
// generate JNI headers
options.headerOutputDirectory.set( buildDir.resolve( "generated/jni-headers" ) )
}
if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) {
named<JavaCompile>( "compileModuleInfoJava" ) {
sourceCompatibility = "9"
targetCompatibility = "9"
}
processResources {
// build native libraries
dependsOn( ":flatlaf-natives-windows:assemble" )
}
jar {
archiveBaseName.set( "flatlaf" )
if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) {
manifest.attributes( "Multi-Release" to "true" )
into( "META-INF/versions/9" ) {
from( sourceSets["java9"].output )
}
from( sourceSets["module-info"].output ) {
include( "module-info.class" )
}
doLast {
ReorderJarEntries.reorderJarEntries( outputs.files.singleFile );
}
}
javadoc {
options {
this as StandardJavadocDocletOptions
tags = listOf( "uiDefault", "clientProperty" )
addStringOption( "Xdoclint:all,-missing", "-Xdoclint:all,-missing" )
}
isFailOnError = false
}
register( "sourcesJar", Jar::class ) {
named<Jar>( "sourcesJar" ) {
archiveBaseName.set( "flatlaf" )
archiveClassifier.set( "sources" )
from( sourceSets.main.get().allJava )
}
register( "javadocJar", Jar::class ) {
named<Jar>( "javadocJar" ) {
archiveBaseName.set( "flatlaf" )
archiveClassifier.set( "javadoc" )
from( javadoc )
}
}
publishing {
publications {
create<MavenPublication>( "maven" ) {
artifactId = "flatlaf"
groupId = "com.formdev"
check {
dependsOn( "sigtestCheck" )
}
from( components["java"] )
test {
useJUnitPlatform()
testLogging.exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
}
artifact( tasks["sourcesJar"] )
artifact( tasks["javadocJar"] )
register( "sigtestGenerate" ) {
group = "verification"
dependsOn( "jar" )
pom {
name.set( "FlatLaf" )
description.set( "Flat Look and Feel" )
url.set( "https://github.com/JFormDesigner/FlatLaf" )
doLast {
ant.withGroovyBuilder {
"taskdef"(
"name" to "sigtest",
"classname" to "org.netbeans.apitest.Sigtest",
"classpath" to sigtest.asPath )
licenses {
license {
name.set( "The Apache License, Version 2.0" )
url.set( "https://www.apache.org/licenses/LICENSE-2.0.txt" )
}
}
"sigtest"(
"action" to "generate",
"fileName" to "${project.name}-sigtest.txt",
"classpath" to jar.get().outputs.files.asPath,
"packages" to "com.formdev.flatlaf,com.formdev.flatlaf.util",
"version" to version,
"release" to "1.8", // Java version
"failonerror" to "true" )
}
}
}
developers {
developer {
name.set( "Karl Tauber" )
organization.set( "FormDev Software GmbH" )
organizationUrl.set( "https://www.formdev.com/" )
}
}
register( "sigtestCheck" ) {
group = "verification"
dependsOn( "jar" )
scm {
url.set( "https://github.com/JFormDesigner/FlatLaf" )
}
doLast {
ant.withGroovyBuilder {
"taskdef"(
"name" to "sigtest",
"classname" to "org.netbeans.apitest.Sigtest",
"classpath" to sigtest.asPath )
"sigtest"(
"action" to "check",
"fileName" to "${project.name}-sigtest.txt",
"classpath" to jar.get().outputs.files.asPath,
"packages" to "com.formdev.flatlaf,com.formdev.flatlaf.util",
"version" to version,
"release" to "1.8", // Java version
"failonerror" to "true" )
}
}
}
}
bintray {
user = rootProject.extra["bintray.user"] as String?
key = rootProject.extra["bintray.key"] as String?
setPublications( "maven" )
with( pkg ) {
repo = "flatlaf"
name = "flatlaf"
setLicenses( "Apache-2.0" )
vcsUrl = "https://github.com/JFormDesigner/FlatLaf"
with( version ) {
name = project.version.toString()
}
publish = rootProject.extra["bintray.publish"] as Boolean
dryRun = rootProject.extra["bintray.dryRun"] as Boolean
}
}
artifactory {
setContextUrl( "https://oss.jfrog.org" )
publish( closureOf<org.jfrog.gradle.plugin.artifactory.dsl.PublisherConfig> {
repository( delegateClosureOf<groovy.lang.GroovyObject> {
setProperty( "repoKey", "oss-snapshot-local" )
setProperty( "username", rootProject.extra["bintray.user"] as String? )
setProperty( "password", rootProject.extra["bintray.key"] as String? )
} )
defaults( delegateClosureOf<groovy.lang.GroovyObject> {
invokeMethod( "publications", "maven" )
setProperty( "publishArtifacts", true )
setProperty( "publishPom", true )
} )
} )
resolve( delegateClosureOf<org.jfrog.gradle.plugin.artifactory.dsl.ResolverConfig> {
setProperty( "repoKey", "jcenter" )
} )
flatlafPublish {
artifactId = "flatlaf"
name = "FlatLaf"
description = "Flat Look and Feel"
}

File diff suppressed because it is too large Load Diff

View File

@@ -19,18 +19,29 @@ package com.formdev.flatlaf;
import java.awt.Color;
import java.util.Objects;
import javax.swing.JComponent;
import javax.swing.SwingConstants;
/**
* Defines/documents own client properties used in FlatLaf.
*
* @author Karl Tauber
*/
public interface FlatClientProperties
{
//---- JButton ------------------------------------------------------------
/**
* Specifies type of a button.
* <p>
* <strong>Components</strong> {@link javax.swing.JButton} and {@link javax.swing.JToggleButton}<br>
* <strong>Value type</strong> {@link java.lang.String}<br>
* <strong>Allowed Values</strong> {@link #BUTTON_TYPE_SQUARE} and {@link #BUTTON_TYPE_HELP}
* <strong>Allowed Values</strong>
* {@link #BUTTON_TYPE_SQUARE},
* {@link #BUTTON_TYPE_ROUND_RECT},
* {@link #BUTTON_TYPE_TAB},
* {@link #BUTTON_TYPE_HELP},
* {@link #BUTTON_TYPE_TOOLBAR_BUTTON} or
* {@link #BUTTON_TYPE_BORDERLESS}
*/
String BUTTON_TYPE = "JButton.buttonType";
@@ -43,6 +54,15 @@ public interface FlatClientProperties
*/
String BUTTON_TYPE_SQUARE = "square";
/**
* Paint the button with round edges.
* <p>
* <strong>Components</strong> {@link javax.swing.JButton} and {@link javax.swing.JToggleButton}
*
* @see #BUTTON_TYPE
*/
String BUTTON_TYPE_ROUND_RECT = "roundRect";
/**
* Paint the toggle button in tab style.
* <p>
@@ -61,6 +81,25 @@ public interface FlatClientProperties
*/
String BUTTON_TYPE_HELP = "help";
/**
* Paint the button in toolbar style.
* <p>
* <strong>Components</strong> {@link javax.swing.JButton} and {@link javax.swing.JToggleButton}
*
* @see #BUTTON_TYPE
*/
String BUTTON_TYPE_TOOLBAR_BUTTON = "toolBarButton";
/**
* Paint the button without a border in the unfocused state.
* <p>
* <strong>Components</strong> {@link javax.swing.JButton} and {@link javax.swing.JToggleButton}
*
* @see #BUTTON_TYPE
* @since 1.2
*/
String BUTTON_TYPE_BORDERLESS = "borderless";
/**
* Specifies selected state of a checkbox.
* <p>
@@ -77,11 +116,73 @@ public interface FlatClientProperties
*/
String SELECTED_STATE_INDETERMINATE = "indeterminate";
/**
* Specifies whether the button preferred size will be made square (quadratically).
* <p>
* <strong>Components</strong> {@link javax.swing.JButton} and {@link javax.swing.JToggleButton}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
*/
String SQUARE_SIZE = "JButton.squareSize";
//---- JComponent ---------------------------------------------------------
/**
* Specifies the style of a component as String in CSS syntax ("key1: value1; key2: value2; ...")
* or as {@link java.util.Map}&lt;String, Object&gt; with binary values.
* <p>
* The keys are the same as used in UI defaults, but without component type prefix.
* E.g. for UI default {@code Slider.thumbSize} use key {@code thumbSize}.
* <p>
* The syntax of the CSS values is the same as used in FlatLaf properties files
* (<a href="https://www.formdev.com/flatlaf/properties-files/">https://www.formdev.com/flatlaf/properties-files/</a>),
* but some features are not supported (e.g. variables).
* When using a map, the values are not parsed from a string. They must be binary.
* <p>
* <strong>Components</strong> {@link javax.swing.JComponent}<br>
* <strong>Value type</strong> {@link java.lang.String} or {@link java.util.Map}&lt;String, Object&gt;<br>
*
* @since 2
*/
String STYLE = "FlatLaf.style";
/**
* Specifies the style class(es) of a component as String (single class or multiple classes separated by space characters)
* or as {@code String[]} or {@link java.util.List}&lt;String&gt; (multiple classes).
* <p>
* The style rules must be defined in UI defaults either as strings (in CSS syntax)
* or as {@link java.util.Map}&lt;String, Object&gt; (with binary values).
* The key must be in syntax: {@code [style]type.styleClass}, where the type is optional.
* E.g. in FlatLaf properties file:
* <pre>{@code
* [style]Button.primary = borderColor: #08f; background: #08f; foreground: #fff
* [style].secondary = borderColor: #0f8; background: #0f8
* }</pre>
* or in Java code:
* <pre>{@code
* UIManager.put( "[style]Button.primary", "borderColor: #08f; background: #08f; foreground: #fff" );
* UIManager.put( "[style].secondary", "borderColor: #0f8; background: #0f8" );
* }</pre>
* The rule "Button.primary" can be applied to buttons only.
* The rule ".secondary" can be applied to any component.
* <p>
* To have similar behavior as in CSS, first the rule without type is applied,
* then the rule with type.
* E.g. setting style class to "foo" on a {@code JButton} uses rules
* from UI default keys "[style].foo" and "[style]Button.foo".
* <p>
* <strong>Components</strong> {@link javax.swing.JComponent}<br>
* <strong>Value type</strong> {@link java.lang.String}, {@code String[]} or {@link java.util.List}&lt;String&gt;<br>
*
* @since 2
*/
String STYLE_CLASS = "FlatLaf.styleClass";
/**
* Specifies minimum width of a component.
* <p>
* <strong>Component</strong> {@link javax.swing.JButton}, {@link javax.swing.JToggleButton} and {@link javax.swing.text.JTextComponent}<br>
* <strong>Value type</strong> {@link java.lang.Integer}<br>
* <strong>Component</strong> {@link javax.swing.JButton}, {@link javax.swing.JToggleButton},
* {@link javax.swing.JComboBox}, {@link javax.swing.JSpinner} and {@link javax.swing.text.JTextComponent}<br>
* <strong>Value type</strong> {@link java.lang.Integer}
*/
String MINIMUM_WIDTH = "JComponent.minimumWidth";
@@ -89,10 +190,91 @@ public interface FlatClientProperties
* Specifies minimum height of a component.
* <p>
* <strong>Component</strong> {@link javax.swing.JButton} and {@link javax.swing.JToggleButton}<br>
* <strong>Value type</strong> {@link java.lang.Integer}<br>
* <strong>Value type</strong> {@link java.lang.Integer}
*/
String MINIMUM_HEIGHT = "JComponent.minimumHeight";
/**
* Paint the component with round edges.
* <p>
* <strong>Components</strong> {@link javax.swing.JComboBox}, {@link javax.swing.JSpinner},
* {@link javax.swing.JTextField}, {@link javax.swing.JFormattedTextField} and {@link javax.swing.JPasswordField}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
*/
String COMPONENT_ROUND_RECT = "JComponent.roundRect";
/**
* Specifies the outline color of the component border.
* <p>
* <strong>Components</strong> {@link javax.swing.JButton}, {@link javax.swing.JComboBox},
* {@link javax.swing.JFormattedTextField}, {@link javax.swing.JPasswordField},
* {@link javax.swing.JScrollPane}, {@link javax.swing.JSpinner},
* {@link javax.swing.JTextField} and {@link javax.swing.JToggleButton}<br>
* <strong>Value type</strong> {@link java.lang.String} or {@link java.awt.Color} or {@link java.awt.Color}[2]<br>
* <strong>Allowed Values</strong>
* {@link #OUTLINE_ERROR},
* {@link #OUTLINE_WARNING},
* any color (type {@link java.awt.Color}) or
* an array of two colors (type {@link java.awt.Color}[2]) where the first color
* is for focused state and the second for unfocused state
*/
String OUTLINE = "JComponent.outline";
/**
* Paint the component border in another color (usually reddish) to indicate an error.
*
* @see #OUTLINE
*/
String OUTLINE_ERROR = "error";
/**
* Paint the component border in another color (usually yellowish) to indicate a warning.
*
* @see #OUTLINE
*/
String OUTLINE_WARNING = "warning";
/**
* Specifies a callback that is invoked to check whether a component is permanent focus owner.
* Used to paint focus indicators.
* <p>
* May be useful in special cases for custom components.
* <p>
* Use a {@link java.util.function.Predicate} that receives the component as parameter:
* <pre>{@code
* myComponent.putClientProperty( "JComponent.focusOwner",
* (Predicate<JComponent>) c -> {
* return ...; // check here
* } );
* }</pre>
* <p>
* <strong>Component</strong> {@link javax.swing.JComponent}<br>
* <strong>Value type</strong> {@link java.util.function.Predicate}&lt;javax.swing.JComponent&gt;
*/
String COMPONENT_FOCUS_OWNER = "JComponent.focusOwner";
//---- Popup --------------------------------------------------------------
/**
* Specifies whether a drop shadow is painted if the component is shown in a popup
* or if the component is the owner of another component that is shown in a popup.
* <p>
* <strong>Component</strong> {@link javax.swing.JComponent}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
*/
String POPUP_DROP_SHADOW_PAINTED = "Popup.dropShadowPainted";
/**
* Specifies whether a heavy weight window should be used if the component is shown in a popup
* or if the component is the owner of another component that is shown in a popup.
* <p>
* <strong>Component</strong> {@link javax.swing.JComponent}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
*/
String POPUP_FORCE_HEAVY_WEIGHT = "Popup.forceHeavyWeight";
//---- JProgressBar -------------------------------------------------------
/**
* Specifies whether the progress bar has always the larger height even if no string is painted.
* <p>
@@ -109,6 +291,90 @@ public interface FlatClientProperties
*/
String PROGRESS_BAR_SQUARE = "JProgressBar.square";
//---- JRootPane ----------------------------------------------------------
/**
* Specifies whether FlatLaf native window decorations should be used
* for {@code JFrame} or {@code JDialog}.
* <p>
* Setting this enables/disables using FlatLaf native window decorations
* for the window that contains the root pane.
* <p>
* This client property has lower priority than system property
* {@link FlatSystemProperties#USE_WINDOW_DECORATIONS}, but higher priority
* than UI default {@code TitlePane.useWindowDecorations}.
* <p>
* (requires Window 10)
* <p>
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
*
* @since 1.1.1
*/
String USE_WINDOW_DECORATIONS = "JRootPane.useWindowDecorations";
/**
* Specifies whether the menu bar is embedded into the window title pane
* if window decorations are enabled.
* <p>
* Setting this enables/disables embedding
* for the window that contains the root pane.
* <p>
* This client property has lower priority than system property
* {@link FlatSystemProperties#MENUBAR_EMBEDDED}, but higher priority
* than UI default {@code TitlePane.menuBarEmbedded}.
* <p>
* (requires Window 10)
* <p>
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
*/
String MENU_BAR_EMBEDDED = "JRootPane.menuBarEmbedded";
/**
* Specifies whether the window icon should be shown in the window title bar
* (requires enabled window decorations).
* <p>
* Setting this shows/hides the windows icon
* for the {@code JFrame} or {@code JDialog} that contains the root pane.
* <p>
* This client property has higher priority than UI default {@code TitlePane.showIcon}.
* <p>
* (requires Window 10)
* <p>
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
*
* @since 2
*/
String TITLE_BAR_SHOW_ICON = "JRootPane.titleBarShowIcon";
/**
* Background color of window title bar (requires enabled window decorations).
* <p>
* (requires Window 10)
* <p>
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
* <strong>Value type</strong> {@link java.awt.Color}
*
* @since 1.1.2
*/
String TITLE_BAR_BACKGROUND = "JRootPane.titleBarBackground";
/**
* Foreground color of window title bar (requires enabled window decorations).
* <p>
* (requires Window 10)
* <p>
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
* <strong>Value type</strong> {@link java.awt.Color}
*
* @since 1.1.2
*/
String TITLE_BAR_FOREGROUND = "JRootPane.titleBarForeground";
//---- JScrollBar / JScrollPane -------------------------------------------
/**
* Specifies whether the decrease/increase arrow buttons of a scrollbar are shown.
* <p>
@@ -117,6 +383,45 @@ public interface FlatClientProperties
*/
String SCROLL_BAR_SHOW_BUTTONS = "JScrollBar.showButtons";
/**
* Specifies whether the scroll pane uses smooth scrolling.
* <p>
* <strong>Component</strong> {@link javax.swing.JScrollPane}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
*/
String SCROLL_PANE_SMOOTH_SCROLLING = "JScrollPane.smoothScrolling";
//---- JTabbedPane --------------------------------------------------------
/**
* Specifies type of the selected tab.
* <p>
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
* <strong>Value type</strong> {@link java.lang.String}<br>
* <strong>Allowed Values</strong>
* {@link #TABBED_PANE_TAB_TYPE_UNDERLINED} or
* {@link #TABBED_PANE_TAB_TYPE_CARD}
*
* @since 2
*/
String TABBED_PANE_TAB_TYPE = "JTabbedPane.tabType";
/**
* Paint the selected tab underlined.
*
* @see #TABBED_PANE_TAB_TYPE
* @since 2
*/
String TABBED_PANE_TAB_TYPE_UNDERLINED = "underlined";
/**
* Paint the selected tab as card.
*
* @see #TABBED_PANE_TAB_TYPE
* @since 2
*/
String TABBED_PANE_TAB_TYPE_CARD = "card";
/**
* Specifies whether separators are shown between tabs.
* <p>
@@ -125,6 +430,14 @@ public interface FlatClientProperties
*/
String TABBED_PANE_SHOW_TAB_SEPARATORS = "JTabbedPane.showTabSeparators";
/**
* Specifies whether the separator between tabs area and content area should be shown.
* <p>
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
*/
String TABBED_PANE_SHOW_CONTENT_SEPARATOR = "JTabbedPane.showContentSeparator";
/**
* Specifies whether a full border is painted around a tabbed pane.
* <p>
@@ -134,21 +447,356 @@ public interface FlatClientProperties
String TABBED_PANE_HAS_FULL_BORDER = "JTabbedPane.hasFullBorder";
/**
* Specifies the height of a tab.
* Specifies whether the tab area should be hidden if it contains only one tab.
* <p>
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
*/
String TABBED_PANE_HIDE_TAB_AREA_WITH_ONE_TAB = "JTabbedPane.hideTabAreaWithOneTab";
/**
* Specifies the minimum width of a tab.
* <p>
* <strong>Component</strong> {@link javax.swing.JTabbedPane}
* or tab content components (see {@link javax.swing.JTabbedPane#setComponentAt(int, java.awt.Component)})<br>
* <strong>Value type</strong> {@link java.lang.Integer}
*/
String TABBED_PANE_MINIMUM_TAB_WIDTH = "JTabbedPane.minimumTabWidth";
/**
* Specifies the maximum width of a tab.
* <p>
* Applied only if tab does not have a custom tab component
* (see {@link javax.swing.JTabbedPane#setTabComponentAt(int, java.awt.Component)}).
* <p>
* <strong>Component</strong> {@link javax.swing.JTabbedPane}
* or tab content components (see {@link javax.swing.JTabbedPane#setComponentAt(int, java.awt.Component)})<br>
* <strong>Value type</strong> {@link java.lang.Integer}
*/
String TABBED_PANE_MAXIMUM_TAB_WIDTH = "JTabbedPane.maximumTabWidth";
/**
* Specifies the minimum height of a tab.
* <p>
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
* <strong>Value type</strong> {@link java.lang.Integer}
*
* @see #TABBED_PANE_TAB_INSETS
*/
String TABBED_PANE_TAB_HEIGHT = "JTabbedPane.tabHeight";
/**
* Specifies the insets of a tab.
* <p>
* <strong>Component</strong> {@link javax.swing.JTabbedPane}
* or tab content components (see {@link javax.swing.JTabbedPane#setComponentAt(int, java.awt.Component)})<br>
* <strong>Value type</strong> {@link java.awt.Insets}
*
* @see #TABBED_PANE_TAB_HEIGHT
*/
String TABBED_PANE_TAB_INSETS = "JTabbedPane.tabInsets";
/**
* Specifies the insets of the tab area.
* <p>
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
* <strong>Value type</strong> {@link java.awt.Insets}
*/
String TABBED_PANE_TAB_AREA_INSETS = "JTabbedPane.tabAreaInsets";
/**
* Specifies whether tabs are closable.
* If set to {@code true} on a tabbed pane component, all tabs in that tabbed pane are closable.
* To make individual tabs closable, set it to {@code true} on a tab content component.
* <p>
* Note that you have to specify a callback (see {@link #TABBED_PANE_TAB_CLOSABLE})
* that is invoked when the user clicks a tab close button.
* The callback is responsible for closing the tab.
* <p>
* <strong>Component</strong> {@link javax.swing.JTabbedPane}
* or tab content components (see {@link javax.swing.JTabbedPane#setComponentAt(int, java.awt.Component)})<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
*
* @see #TABBED_PANE_TAB_CLOSE_CALLBACK
*/
String TABBED_PANE_TAB_CLOSABLE = "JTabbedPane.tabClosable";
/**
* Specifies the tooltip text used for tab close buttons.
* <p>
* <strong>Component</strong> {@link javax.swing.JTabbedPane}
* or tab content components (see {@link javax.swing.JTabbedPane#setComponentAt(int, java.awt.Component)})<br>
* <strong>Value type</strong> {@link java.lang.String}
*
* @see #TABBED_PANE_TAB_CLOSABLE
*/
String TABBED_PANE_TAB_CLOSE_TOOLTIPTEXT = "JTabbedPane.tabCloseToolTipText";
/**
* Specifies the callback that is invoked when a tab close button is clicked.
* The callback is responsible for closing the tab.
* <p>
* Either use a {@link java.util.function.IntConsumer} that receives the tab index as parameter:
* <pre>{@code
* myTabbedPane.putClientProperty( "JTabbedPane.tabCloseCallback",
* (IntConsumer) tabIndex -> {
* // close tab here
* } );
* }</pre>
* Or use a {@link java.util.function.BiConsumer}&lt;javax.swing.JTabbedPane, Integer&gt;
* that receives the tabbed pane and the tab index as parameters:
* <pre>{@code
* myTabbedPane.putClientProperty( "JTabbedPane.tabCloseCallback",
* (BiConsumer<JTabbedPane, Integer>) (tabbedPane, tabIndex) -> {
* // close tab here
* } );
* }</pre>
* If you need to check whether a modifier key (e.g. Alt or Shift) was pressed
* while the user clicked the tab close button, use {@link java.awt.EventQueue#getCurrentEvent}
* to get current event, check whether it is a {@link java.awt.event.MouseEvent}
* and invoke its methods. E.g.
* <pre>{@code
* AWTEvent e = EventQueue.getCurrentEvent();
* boolean shift = (e instanceof MouseEvent) ? ((MouseEvent)e).isShiftDown() : false;
* }</pre>
* <p>
* <strong>Component</strong> {@link javax.swing.JTabbedPane}
* or tab content components (see {@link javax.swing.JTabbedPane#setComponentAt(int, java.awt.Component)})<br>
* <strong>Value type</strong> {@link java.util.function.IntConsumer}
* or {@link java.util.function.BiConsumer}&lt;javax.swing.JTabbedPane, Integer&gt;
*
* @see #TABBED_PANE_TAB_CLOSABLE
*/
String TABBED_PANE_TAB_CLOSE_CALLBACK = "JTabbedPane.tabCloseCallback";
/**
* Specifies the display policy for the "more tabs" button,
* which shows a popup menu with the (partly) hidden tabs.
* <p>
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
* <strong>Value type</strong> {@link java.lang.String}<br>
* <strong>Allowed Values</strong>
* {@link #TABBED_PANE_POLICY_NEVER} or
* {@link #TABBED_PANE_POLICY_AS_NEEDED}
*/
String TABBED_PANE_TABS_POPUP_POLICY = "JTabbedPane.tabsPopupPolicy";
/**
* Specifies the display policy for the forward/backward scroll arrow buttons.
* <p>
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
* <strong>Value type</strong> {@link java.lang.String}<br>
* <strong>Allowed Values</strong>
* {@link #TABBED_PANE_POLICY_NEVER},
* {@link #TABBED_PANE_POLICY_AS_NEEDED} or
* {@link #TABBED_PANE_POLICY_AS_NEEDED_SINGLE}
*/
String TABBED_PANE_SCROLL_BUTTONS_POLICY = "JTabbedPane.scrollButtonsPolicy";
/**
* Display never.
*
* @see #TABBED_PANE_TABS_POPUP_POLICY
* @see #TABBED_PANE_SCROLL_BUTTONS_POLICY
*/
String TABBED_PANE_POLICY_NEVER = "never";
/**
* Display only when needed.
* <p>
* If used for {@link #TABBED_PANE_SCROLL_BUTTONS_POLICY}, both scroll arrow buttons
* are either shown or hidden. Buttons are disabled if scrolling in that
* direction is not applicable.
*
* @see #TABBED_PANE_TABS_POPUP_POLICY
* @see #TABBED_PANE_SCROLL_BUTTONS_POLICY
*/
String TABBED_PANE_POLICY_AS_NEEDED = "asNeeded";
/**
* Display single button only when needed.
* <p>
* If scroll button placement is trailing, then this option is ignored
* and both buttons are shown or hidden as needed.
*
* @see #TABBED_PANE_SCROLL_BUTTONS_POLICY
*/
String TABBED_PANE_POLICY_AS_NEEDED_SINGLE = "asNeededSingle";
/**
* Specifies the placement of the forward/backward scroll arrow buttons.
* <p>
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
* <strong>Value type</strong> {@link java.lang.String}<br>
* <strong>Allowed Values</strong>
* {@link #TABBED_PANE_PLACEMENT_BOTH} or
* {@link #TABBED_PANE_PLACEMENT_TRAILING}
*/
String TABBED_PANE_SCROLL_BUTTONS_PLACEMENT = "JTabbedPane.scrollButtonsPlacement";
/**
* The forward/backward scroll arrow buttons are placed on both sides of the tab area.
* The backward scroll button at the left/top side.
* The forward scroll button at the right/bottom side.
*
* @see #TABBED_PANE_SCROLL_BUTTONS_PLACEMENT
*/
String TABBED_PANE_PLACEMENT_BOTH = "both";
/**
* The forward/backward scroll arrow buttons are placed on the trailing side of the tab area.
*
* @see #TABBED_PANE_SCROLL_BUTTONS_PLACEMENT
*/
String TABBED_PANE_PLACEMENT_TRAILING = "trailing";
/**
* Specifies the alignment of the tab area.
* <p>
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
* <strong>Value type</strong> {@link java.lang.Integer} or {@link java.lang.String}<br>
* <strong>Allowed Values</strong>
* {@link SwingConstants#LEADING} (default)
* {@link SwingConstants#TRAILING},
* {@link SwingConstants#CENTER},
* {@link #TABBED_PANE_ALIGN_LEADING} (default),
* {@link #TABBED_PANE_ALIGN_TRAILING},
* {@link #TABBED_PANE_ALIGN_CENTER} or
* {@link #TABBED_PANE_ALIGN_FILL}
*/
String TABBED_PANE_TAB_AREA_ALIGNMENT = "JTabbedPane.tabAreaAlignment";
/**
* Specifies the horizontal alignment of the tab title and icon.
* <p>
* <strong>Component</strong> {@link javax.swing.JTabbedPane}
* or tab content components (see {@link javax.swing.JTabbedPane#setComponentAt(int, java.awt.Component)})<br>
* <strong>Value type</strong> {@link java.lang.Integer} or {@link java.lang.String}<br>
* <strong>Allowed Values</strong>
* {@link SwingConstants#LEADING},
* {@link SwingConstants#TRAILING},
* {@link SwingConstants#CENTER} (default),
* {@link #TABBED_PANE_ALIGN_LEADING},
* {@link #TABBED_PANE_ALIGN_TRAILING} or
* {@link #TABBED_PANE_ALIGN_CENTER} (default)
*/
String TABBED_PANE_TAB_ALIGNMENT = "JTabbedPane.tabAlignment";
/**
* Align to the leading edge.
*
* @see #TABBED_PANE_TAB_AREA_ALIGNMENT
* @see #TABBED_PANE_TAB_ALIGNMENT
*/
String TABBED_PANE_ALIGN_LEADING = "leading";
/**
* Align to the trailing edge.
*
* @see #TABBED_PANE_TAB_AREA_ALIGNMENT
* @see #TABBED_PANE_TAB_ALIGNMENT
*/
String TABBED_PANE_ALIGN_TRAILING = "trailing";
/**
* Align to center.
*
* @see #TABBED_PANE_TAB_AREA_ALIGNMENT
* @see #TABBED_PANE_TAB_ALIGNMENT
*/
String TABBED_PANE_ALIGN_CENTER = "center";
/**
* Stretch to fill all available space.
*
* @see #TABBED_PANE_TAB_AREA_ALIGNMENT
*/
String TABBED_PANE_ALIGN_FILL = "fill";
/**
* Specifies how the tabs should be sized.
* <p>
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
* <strong>Value type</strong> {@link java.lang.String}<br>
* <strong>Allowed Values</strong>
* {@link #TABBED_PANE_TAB_WIDTH_MODE_PREFERRED} (default),
* {@link #TABBED_PANE_TAB_WIDTH_MODE_EQUAL} or
* {@link #TABBED_PANE_TAB_WIDTH_MODE_COMPACT}
*/
String TABBED_PANE_TAB_WIDTH_MODE = "JTabbedPane.tabWidthMode";
/**
* Tab width is adjusted to tab icon and title.
*
* @see #TABBED_PANE_TAB_WIDTH_MODE
*/
String TABBED_PANE_TAB_WIDTH_MODE_PREFERRED = "preferred";
/**
* All tabs in a tabbed pane has same width.
*
* @see #TABBED_PANE_TAB_WIDTH_MODE
*/
String TABBED_PANE_TAB_WIDTH_MODE_EQUAL = "equal";
/**
* Unselected tabs are smaller because they show only the tab icon, but no tab title.
* Selected tabs show both.
*
* @see #TABBED_PANE_TAB_WIDTH_MODE
*/
String TABBED_PANE_TAB_WIDTH_MODE_COMPACT = "compact";
/**
* Specifies the tab icon placement (relative to tab title).
* <p>
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
* <strong>Value type</strong> {@link java.lang.Integer}<br>
* <strong>Allowed Values</strong>
* {@link SwingConstants#LEADING} (default),
* {@link SwingConstants#TRAILING},
* {@link SwingConstants#TOP} or
* {@link SwingConstants#BOTTOM}
*/
String TABBED_PANE_TAB_ICON_PLACEMENT = "JTabbedPane.tabIconPlacement";
/**
* Specifies a component that will be placed at the leading edge of the tabs area.
* <p>
* For top and bottom tab placement, the layed out component size will be
* the preferred component width and the tab area height.<br>
* For left and right tab placement, the layed out component size will be
* the tab area width and the preferred component height.
* <p>
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
* <strong>Value type</strong> {@link java.awt.Component}
*/
String TABBED_PANE_LEADING_COMPONENT = "JTabbedPane.leadingComponent";
/**
* Specifies a component that will be placed at the trailing edge of the tabs area.
* <p>
* For top and bottom tab placement, the layed out component size will be
* the available horizontal space (minimum is preferred component width) and the tab area height.<br>
* For left and right tab placement, the layed out component size will be
* the tab area width and the available vertical space (minimum is preferred component height).
* <p>
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
* <strong>Value type</strong> {@link java.awt.Component}
*/
String TABBED_PANE_TRAILING_COMPONENT = "JTabbedPane.trailingComponent";
//---- JTextField ---------------------------------------------------------
/**
* Specifies whether all text is selected when the text component gains focus.
* <p>
* <strong>Component</strong> {@link javax.swing.JTextField} (and subclasses)<br>
* <strong>Value type</strong> {@link java.lang.String}<br>
* <strong>Allowed Values</strong> {@link #SELECT_ALL_ON_FOCUS_POLICY_NEVER},
* {@link #SELECT_ALL_ON_FOCUS_POLICY_ONCE} (default) or
* {@link #SELECT_ALL_ON_FOCUS_POLICY_ALWAYS}
* <strong>Allowed Values</strong>
* {@link #SELECT_ALL_ON_FOCUS_POLICY_NEVER},
* {@link #SELECT_ALL_ON_FOCUS_POLICY_ONCE} (default) or
* {@link #SELECT_ALL_ON_FOCUS_POLICY_ALWAYS}
*/
String SELECT_ALL_ON_FOCUS_POLICY = "JTextField.selectAllOnFocusPolicy";
@@ -183,6 +831,40 @@ public interface FlatClientProperties
*/
String PLACEHOLDER_TEXT = "JTextField.placeholderText";
/**
* Specifies the padding of the text.
* This changes the location and size of the text view within the component bounds,
* but does not affect the size of the component.
* <p>
* <strong>Component</strong> {@link javax.swing.JTextField} (and subclasses)<br>
* <strong>Value type</strong> {@link java.awt.Insets}
*
* @since 1.4
*/
String TEXT_FIELD_PADDING = "JTextField.padding";
/**
* Specifies an icon that will be placed at the leading edge of the text field.
* <p>
* <strong>Component</strong> {@link javax.swing.JTextField} (and subclasses)<br>
* <strong>Value type</strong> {@link javax.swing.Icon}
*
* @since 2
*/
String TEXT_FIELD_LEADING_ICON = "JTextField.leadingIcon";
/**
* Specifies an icon that will be placed at the trailing edge of the text field.
* <p>
* <strong>Component</strong> {@link javax.swing.JTextField} (and subclasses)<br>
* <strong>Value type</strong> {@link javax.swing.Icon}
*
* @since 2
*/
String TEXT_FIELD_TRAILING_ICON = "JTextField.trailingIcon";
//---- JToggleButton ------------------------------------------------------
/**
* Height of underline if toggle button type is {@link #BUTTON_TYPE_TAB}.
* <p>
@@ -207,6 +889,27 @@ public interface FlatClientProperties
*/
String TAB_BUTTON_SELECTED_BACKGROUND = "JToggleButton.tab.selectedBackground";
//---- JTree --------------------------------------------------------------
/**
* Override if a tree shows a wide selection. Default is {@code true}.
* <p>
* <strong>Component</strong> {@link javax.swing.JTree}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
*/
String TREE_WIDE_SELECTION = "JTree.wideSelection";
/**
* Specifies whether tree item selection is painted. Default is {@code true}.
* If set to {@code false}, then the tree cell renderer is responsible for painting selection.
* <p>
* <strong>Component</strong> {@link javax.swing.JTree}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
*/
String TREE_PAINT_SELECTION = "JTree.paintSelection";
//---- helper methods -----------------------------------------------------
/**
* Checks whether a client property of a component has the given value.
*/
@@ -223,6 +926,14 @@ public interface FlatClientProperties
return (value instanceof Boolean) ? (boolean) value : defaultValue;
}
/**
* Checks whether a client property of a component is a {@link Boolean} and returns its value.
* If the client property is not set, or not a {@link Boolean}, defaultValue is returned.
*/
static Boolean clientPropertyBooleanStrict( JComponent c, String key, Boolean defaultValue ) {
return clientProperty( c, key, defaultValue, Boolean.class );
}
/**
* Checks whether a client property of a component is an integer and returns its value.
* If the client property is not set, or not an integer, defaultValue is returned.
@@ -237,7 +948,18 @@ public interface FlatClientProperties
* If the client property is not set, or not a color, defaultValue is returned.
*/
static Color clientPropertyColor( JComponent c, String key, Color defaultValue ) {
return clientProperty( c, key, defaultValue, Color.class );
}
/**
* Returns the value of the specified client property if it is an instance of
* the specified type. Otherwise, defaultValue is returned.
*
* @since 2
*/
@SuppressWarnings( "unchecked" )
static <T> T clientProperty( JComponent c, String key, T defaultValue, Class<T> type ) {
Object value = c.getClientProperty( key );
return (value instanceof Color) ? (Color) value : defaultValue;
return type.isInstance( value ) ? (T) value : defaultValue;
}
}

View File

@@ -16,27 +16,54 @@
package com.formdev.flatlaf;
import javax.swing.UIManager;
/**
* A Flat LaF that has a dark color scheme and looks like Darcula LaF.
*
* The UI defaults are loaded from FlatDarculaLaf.properties, FlatDarkLaf.properties and FlatLaf.properties
* <p>
* The UI defaults are loaded from {@code FlatDarculaLaf.properties},
* {@code FlatDarkLaf.properties} and {@code FlatLaf.properties}.
*
* @author Karl Tauber
*/
public class FlatDarculaLaf
extends FlatDarkLaf
{
public static boolean install( ) {
return install( new FlatDarculaLaf() );
public static final String NAME = "FlatLaf Darcula";
/**
* Sets the application look and feel to this LaF
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
*/
public static boolean setup() {
return setup( new FlatDarculaLaf() );
}
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
/**
* Adds this look and feel to the set of available look and feels.
* <p>
* Useful if your application uses {@link UIManager#getInstalledLookAndFeels()}
* to query available LaFs and display them to the user in a combobox.
*/
public static void installLafInfo() {
installLafInfo( NAME, FlatDarculaLaf.class );
}
@Override
public String getName() {
return "Flat Darcula";
return NAME;
}
@Override
public String getDescription() {
return "Flat Darcula Look and Feel";
return "FlatLaf Darcula Look and Feel";
}
}

View File

@@ -16,28 +16,54 @@
package com.formdev.flatlaf;
import javax.swing.UIManager;
/**
* A Flat LaF that has a dark color scheme.
*
* The UI defaults are loaded from FlatDarkLaf.properties and FlatLaf.properties
* <p>
* The UI defaults are loaded from {@code FlatDarkLaf.properties} and {@code FlatLaf.properties}.
*
* @author Karl Tauber
*/
public class FlatDarkLaf
extends FlatLaf
{
public static boolean install( ) {
return install( new FlatDarkLaf() );
public static final String NAME = "FlatLaf Dark";
/**
* Sets the application look and feel to this LaF
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
*/
public static boolean setup() {
return setup( new FlatDarkLaf() );
}
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
/**
* Adds this look and feel to the set of available look and feels.
* <p>
* Useful if your application uses {@link UIManager#getInstalledLookAndFeels()}
* to query available LaFs and display them to the user in a combobox.
*/
public static void installLafInfo() {
installLafInfo( NAME, FlatDarkLaf.class );
}
@Override
public String getName() {
return "Flat Dark";
return NAME;
}
@Override
public String getDescription() {
return "Flat Dark Look and Feel";
return "FlatLaf Dark Look and Feel";
}
@Override

View File

@@ -0,0 +1,89 @@
/*
* Copyright 2020 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf;
/**
* Default color palette for action icons and object icons.
* <p>
* The idea is to use only this well defined set of colors in SVG icons and
* then they are replaced at runtime to dark variants or to other theme colors.
* Then a single SVG icon (light variant) can be used for dark themes too.
* IntelliJ Platform uses this mechanism to allow themes to change IntelliJ Platform icons.
* <p>
* Use the {@code *_DARK} colors only in {@code *_dark.svg} files.
* <p>
* The colors are based on IntelliJ Platform
* <a href="https://jetbrains.design/intellij/principles/icons/#action-icons">Action icons</a>
* and
* <a href="https://jetbrains.design/intellij/principles/icons/#noun-icons">Noun icons</a>
* <p>
* These colors may be changed by IntelliJ Platform themes.
* <p>
* You may use these colors also in your application (outside of SVG icons), but do
* not use the RGB values defined in this enum.<br>
* Instead use {@code UIManager.getColor( FlatIconColors.ACTIONS_GREY.key )}.
*
* @author Karl Tauber
*/
public enum FlatIconColors
{
// colors for action icons
// see https://jetbrains.design/intellij/principles/icons/#action-icons
ACTIONS_RED ( 0xDB5860, "Actions.Red", true, false ),
ACTIONS_RED_DARK ( 0xC75450, "Actions.Red", false, true ),
ACTIONS_YELLOW ( 0xEDA200, "Actions.Yellow", true, false ),
ACTIONS_YELLOW_DARK ( 0xF0A732, "Actions.Yellow", false, true ),
ACTIONS_GREEN ( 0x59A869, "Actions.Green", true, false ),
ACTIONS_GREEN_DARK ( 0x499C54, "Actions.Green", false, true ),
ACTIONS_BLUE ( 0x389FD6, "Actions.Blue", true, false ),
ACTIONS_BLUE_DARK ( 0x3592C4, "Actions.Blue", false, true ),
ACTIONS_GREY ( 0x6E6E6E, "Actions.Grey", true, false ),
ACTIONS_GREY_DARK ( 0xAFB1B3, "Actions.Grey", false, true ),
ACTIONS_GREYINLINE ( 0x7F8B91, "Actions.GreyInline", true, false ),
ACTIONS_GREYINLINE_DARK ( 0x7F8B91, "Actions.GreyInline", false, true ),
// colors for object icons
// see https://jetbrains.design/intellij/principles/icons/#noun-icons
OBJECTS_GREY ( 0x9AA7B0, "Objects.Grey" ),
OBJECTS_BLUE ( 0x40B6E0, "Objects.Blue" ),
OBJECTS_GREEN ( 0x62B543, "Objects.Green" ),
OBJECTS_YELLOW ( 0xF4AF3D, "Objects.Yellow" ),
OBJECTS_YELLOW_DARK ( 0xD9A343, "Objects.YellowDark" ),
OBJECTS_PURPLE ( 0xB99BF8, "Objects.Purple" ),
OBJECTS_PINK ( 0xF98B9E, "Objects.Pink" ),
OBJECTS_RED ( 0xF26522, "Objects.Red" ),
OBJECTS_RED_STATUS ( 0xE05555, "Objects.RedStatus" ),
OBJECTS_GREEN_ANDROID ( 0xA4C639, "Objects.GreenAndroid" ),
OBJECTS_BLACK_TEXT ( 0x231F20, "Objects.BlackText" );
public final int rgb;
public final String key;
public final boolean light;
public final boolean dark;
FlatIconColors( int rgb, String key ) {
this( rgb, key, true, true );
}
FlatIconColors( int rgb, String key, boolean light, boolean dark ) {
this.rgb = rgb;
this.key = key;
this.light = light;
this.dark = dark;
}
}

View File

@@ -22,9 +22,11 @@ import javax.swing.KeyStroke;
import javax.swing.LookAndFeel;
import javax.swing.UIDefaults;
import javax.swing.UIDefaults.LazyValue;
import javax.swing.UIManager;
import javax.swing.plaf.InputMapUIResource;
import com.formdev.flatlaf.util.SystemInfo;
import static javax.swing.text.DefaultEditorKit.*;
import java.util.function.BooleanSupplier;
/**
* @author Karl Tauber
@@ -35,15 +37,17 @@ class FlatInputMaps
initBasicInputMaps( defaults );
initTextComponentInputMaps( defaults );
if( SystemInfo.IS_MAC )
if( SystemInfo.isMacOS )
initMacInputMaps( defaults );
}
private static void initBasicInputMaps( UIDefaults defaults ) {
defaults.put( "Button.focusInputMap", new UIDefaults.LazyInputMap( new Object[] {
"SPACE", "pressed",
"released SPACE", "released"
} ) );
if( SystemInfo.isMacOS ) {
defaults.put( "Button.focusInputMap", new UIDefaults.LazyInputMap( new Object[] {
"SPACE", "pressed",
"released SPACE", "released"
} ) );
}
modifyInputMap( defaults, "ComboBox.ancestorInputMap",
"SPACE", "spacePopup",
@@ -59,7 +63,7 @@ class FlatInputMaps
mac( "alt KP_DOWN", null ), "togglePopup"
);
if( !SystemInfo.IS_MAC ) {
if( !SystemInfo.isMacOS ) {
modifyInputMap( defaults, "FileChooser.ancestorInputMap",
"F2", "editFileName",
"BACK_SPACE", "Go Up"
@@ -81,15 +85,22 @@ class FlatInputMaps
"shift ctrl TAB", "navigatePrevious"
);
modifyInputMap( defaults, "Table.ancestorInputMap",
// swap to make it consistent with List and Tree
// swap Home/End with Ctrl+Home/End to make it consistent with List and Tree
modifyInputMap( () -> {
return UIManager.getBoolean( "Table.consistentHomeEndKeyBehavior" );
},
defaults, "Table.ancestorInputMap",
"HOME", "selectFirstRow",
"END", "selectLastRow",
"shift HOME", "selectFirstRowExtendSelection",
"shift END", "selectLastRowExtendSelection",
mac( "ctrl HOME", null ), "selectFirstColumn",
mac( "ctrl END", null ), "selectLastColumn"
mac( "ctrl END", null ), "selectLastColumn",
mac( "shift ctrl HOME", null ), "selectFirstColumnExtendSelection",
mac( "shift ctrl END", null ), "selectLastColumnExtendSelection"
);
if( !SystemInfo.IS_MAC ) {
if( !SystemInfo.isMacOS ) {
modifyInputMap( defaults, "Tree.focusInputMap",
"ADD", "expand",
"SUBTRACT", "collapse"
@@ -160,7 +171,7 @@ class FlatInputMaps
"control shift O", "toggle-componentOrientation", // DefaultEditorKit.toggleComponentOrientation
};
Object[] macCommonTextComponentBindings = SystemInfo.IS_MAC ? new Object[] {
Object[] macCommonTextComponentBindings = SystemInfo.isMacOS ? new Object[] {
// move caret one character (without selecting text)
"ctrl B", backwardAction,
"ctrl F", forwardAction,
@@ -207,7 +218,7 @@ class FlatInputMaps
"ENTER", JTextField.notifyAction,
};
Object[] macSingleLineTextComponentBindings = SystemInfo.IS_MAC ? new Object[] {
Object[] macSingleLineTextComponentBindings = SystemInfo.isMacOS ? new Object[] {
// move caret to line begin/end (without selecting text)
"UP", beginLineAction,
"DOWN", endLineAction,
@@ -285,7 +296,7 @@ class FlatInputMaps
mac( "ctrl SPACE", "meta SPACE" ), "activate-link-action",
};
Object[] macMultiLineTextComponentBindings = SystemInfo.IS_MAC ? new Object[] {
Object[] macMultiLineTextComponentBindings = SystemInfo.isMacOS ? new Object[] {
// move caret one line (without selecting text)
"ctrl N", downAction,
"ctrl P", upAction,
@@ -501,6 +512,9 @@ class FlatInputMaps
"alt KP_LEFT", "selectParent",
"alt KP_RIGHT", "selectChild",
"shift HOME", "selectFirstExtendSelection",
"shift END", "selectLastExtendSelection",
"meta A", "selectAll",
"meta C", "copy",
"meta V", "paste",
@@ -545,8 +559,6 @@ class FlatInputMaps
"shift ctrl SPACE", null,
"shift ctrl UP", null,
"shift DELETE", null,
"shift END", null,
"shift HOME", null,
"shift INSERT", null,
"shift PAGE_DOWN", null,
"shift PAGE_UP", null,
@@ -569,12 +581,16 @@ class FlatInputMaps
}
private static void modifyInputMap( UIDefaults defaults, String key, Object... bindings ) {
// Note: not using `defaults.get(key)` here because this would resolve the lazy value
defaults.put( key, new LazyModifyInputMap( defaults.remove( key ), bindings ) );
modifyInputMap( null, defaults, key, bindings );
}
private static void modifyInputMap( BooleanSupplier condition, UIDefaults defaults, String key, Object... bindings ) {
// Note: not using `defaults.get(key)` here because this would resolve a lazy value
defaults.put( key, new LazyModifyInputMap( condition, defaults.remove( key ), bindings ) );
}
private static <T> T mac( T value, T macValue ) {
return SystemInfo.IS_MAC ? macValue : value;
return SystemInfo.isMacOS ? macValue : value;
}
//---- class LazyInputMapEx -----------------------------------------------
@@ -609,10 +625,12 @@ class FlatInputMaps
private static class LazyModifyInputMap
implements LazyValue
{
private final BooleanSupplier condition;
private final Object baseInputMap;
private final Object[] bindings;
LazyModifyInputMap( Object baseInputMap, Object[] bindings ) {
LazyModifyInputMap( BooleanSupplier condition, Object baseInputMap, Object[] bindings ) {
this.condition = condition;
this.baseInputMap = baseInputMap;
this.bindings = bindings;
}
@@ -624,6 +642,9 @@ class FlatInputMaps
? (InputMap) ((LazyValue)baseInputMap).createValue( table )
: (InputMap) baseInputMap;
if( condition != null && !condition.getAsBoolean() )
return inputMap;
// modify input map (replace or remove)
for( int i = 0; i < bindings.length; i += 2 ) {
KeyStroke keyStroke = KeyStroke.getKeyStroke( (String) bindings[i] );

View File

@@ -16,27 +16,54 @@
package com.formdev.flatlaf;
import javax.swing.UIManager;
/**
* A Flat LaF that has a light color scheme and looks like IntelliJ LaF.
*
* The UI defaults are loaded from FlatIntelliJLaf.properties, FlatLightLaf.properties and FlatLaf.properties
* <p>
* The UI defaults are loaded from {@code FlatIntelliJLaf.properties},
* {@code FlatLightLaf.properties} and {@code FlatLaf.properties}.
*
* @author Karl Tauber
*/
public class FlatIntelliJLaf
extends FlatLightLaf
{
public static boolean install( ) {
return install( new FlatIntelliJLaf() );
public static final String NAME = "FlatLaf IntelliJ";
/**
* Sets the application look and feel to this LaF
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
*/
public static boolean setup() {
return setup( new FlatIntelliJLaf() );
}
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
/**
* Adds this look and feel to the set of available look and feels.
* <p>
* Useful if your application uses {@link UIManager#getInstalledLookAndFeels()}
* to query available LaFs and display them to the user in a combobox.
*/
public static void installLafInfo() {
installLafInfo( NAME, FlatIntelliJLaf.class );
}
@Override
public String getName() {
return "Flat IntelliJ";
return NAME;
}
@Override
public String getDescription() {
return "Flat IntelliJ Look and Feel";
return "FlatLaf IntelliJ Look and Feel";
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -16,28 +16,54 @@
package com.formdev.flatlaf;
import javax.swing.UIManager;
/**
* A Flat LaF that has a light color scheme.
*
* The UI defaults are loaded from FlatLightLaf.properties and FlatLaf.properties
* <p>
* The UI defaults are loaded from {@code FlatLightLaf.properties} and {@code FlatLaf.properties}.
*
* @author Karl Tauber
*/
public class FlatLightLaf
extends FlatLaf
{
public static boolean install( ) {
return install( new FlatLightLaf() );
public static final String NAME = "FlatLaf Light";
/**
* Sets the application look and feel to this LaF
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
*/
public static boolean setup() {
return setup( new FlatLightLaf() );
}
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
/**
* Adds this look and feel to the set of available look and feels.
* <p>
* Useful if your application uses {@link UIManager#getInstalledLookAndFeels()}
* to query available LaFs and display them to the user in a combobox.
*/
public static void installLafInfo() {
installLafInfo( NAME, FlatLightLaf.class );
}
@Override
public String getName() {
return "Flat Light";
return NAME;
}
@Override
public String getDescription() {
return "Flat Light Look and Feel";
return "FlatLaf Light Look and Feel";
}
@Override

View File

@@ -0,0 +1,126 @@
/*
* Copyright 2020 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Properties;
/**
* A Flat LaF that is able to load UI defaults from properties passed to the constructor.
* <p>
* Specify the base theme in the properties with {@code @baseTheme=<baseTheme>}.
* Allowed values for {@code <baseTheme>} are {@code light} (the default), {@code dark},
* {@code intellij} or {@code darcula}.
* <p>
* The properties are applied after loading the base theme and may overwrite base properties.
* All features of FlatLaf properties files are available.
*
* @author Karl Tauber
*/
public class FlatPropertiesLaf
extends FlatLaf
{
private final String name;
private final String baseTheme;
private final boolean dark;
private final Properties properties;
public FlatPropertiesLaf( String name, File propertiesFile )
throws IOException
{
this( name, new FileInputStream( propertiesFile ) );
}
public FlatPropertiesLaf( String name, InputStream in )
throws IOException
{
this( name, loadProperties( in ) );
}
private static Properties loadProperties( InputStream in )
throws IOException
{
Properties properties = new Properties();
try( InputStream in2 = in ) {
properties.load( in2 );
}
return properties;
}
public FlatPropertiesLaf( String name, Properties properties ) {
this.name = name;
this.properties = properties;
baseTheme = properties.getProperty( "@baseTheme", "light" );
dark = "dark".equalsIgnoreCase( baseTheme ) || "darcula".equalsIgnoreCase( baseTheme );
}
@Override
public String getName() {
return name;
}
@Override
public String getDescription() {
return name;
}
@Override
public boolean isDark() {
return dark;
}
public Properties getProperties() {
return properties;
}
@Override
protected ArrayList<Class<?>> getLafClassesForDefaultsLoading() {
ArrayList<Class<?>> lafClasses = new ArrayList<>();
lafClasses.add( FlatLaf.class );
switch( baseTheme.toLowerCase() ) {
default:
case "light":
lafClasses.add( FlatLightLaf.class );
break;
case "dark":
lafClasses.add( FlatDarkLaf.class );
break;
case "intellij":
lafClasses.add( FlatLightLaf.class );
lafClasses.add( FlatIntelliJLaf.class );
break;
case "darcula":
lafClasses.add( FlatDarkLaf.class );
lafClasses.add( FlatDarculaLaf.class );
break;
}
return lafClasses;
}
@Override
protected Properties getAdditionalDefaults() {
return properties;
}
}

View File

@@ -0,0 +1,165 @@
/*
* Copyright 2020 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf;
import com.formdev.flatlaf.util.UIScale;
/**
* Defines/documents own system properties used in FlatLaf.
*
* @author Karl Tauber
*/
public interface FlatSystemProperties
{
/**
* Specifies a custom scale factor used to scale the UI.
* <p>
* If Java runtime scales (Java 9 or later), this scale factor is applied on top
* of the Java system scale factor. Java 8 does not scale and this scale factor
* replaces the user scale factor that FlatLaf computes based on the font.
* To replace the Java 9+ system scale factor, use system property "sun.java2d.uiScale",
* which has the same syntax as this one.
* <p>
* Since FlatLaf 1.1.2: Scale factors less then 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>
*/
String UI_SCALE = "flatlaf.uiScale";
/**
* Specifies whether user scaling mode is enabled.
* <p>
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
* <strong>Default</strong> {@code true}
*/
String UI_SCALE_ENABLED = "flatlaf.uiScale.enabled";
/**
* Specifies whether values smaller than 100% are allowed for the user scale factor
* (see {@link UIScale#getUserScaleFactor()}).
* <p>
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
* <strong>Default</strong> {@code false}
*
* @since 1.1.2
*/
String UI_SCALE_ALLOW_SCALE_DOWN = "flatlaf.uiScale.allowScaleDown";
/**
* Specifies whether Ubuntu font should be used on Ubuntu Linux.
* By default, if not running in a JetBrains Runtime, the Liberation Sans font
* is used because there are rendering issues (in Java) with Ubuntu fonts.
* <p>
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
* <strong>Default</strong> {@code false}
*/
String USE_UBUNTU_FONT = "flatlaf.useUbuntuFont";
/**
* Specifies whether native window decorations should be used
* when creating {@code JFrame} or {@code JDialog}.
* <p>
* Setting this to {@code true} forces using native window decorations
* even if they are not enabled by the application.<br>
* Setting this to {@code false} disables using native window decorations.
* <p>
* This system property has higher priority than client property
* {@link FlatClientProperties#USE_WINDOW_DECORATIONS} and
* UI default {@code TitlePane.useWindowDecorations}.
* <p>
* (requires Window 10)
* <p>
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
* <strong>Default</strong> none
*/
String USE_WINDOW_DECORATIONS = "flatlaf.useWindowDecorations";
/**
* Specifies whether JetBrains Runtime custom window decorations should be used
* when creating {@code JFrame} or {@code JDialog}.
* Requires that the application runs in a
* <a href="https://confluence.jetbrains.com/display/JBR/JetBrains+Runtime">JetBrains Runtime</a>
* (based on OpenJDK).
* <p>
* Setting this to {@code false} disables using JetBrains Runtime custom window decorations.
* Then FlatLaf native window decorations are used.
* <p>
* (requires Window 10)
* <p>
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
* <strong>Default</strong> {@code true}
*/
String USE_JETBRAINS_CUSTOM_DECORATIONS = "flatlaf.useJetBrainsCustomDecorations";
/**
* Specifies whether the menu bar is embedded into the window title pane
* if window decorations are enabled.
* <p>
* Setting this to {@code true} forces embedding.<br>
* Setting this to {@code false} disables embedding.
* <p>
* This system property has higher priority than client property
* {@link FlatClientProperties#MENU_BAR_EMBEDDED} and
* UI default {@code TitlePane.menuBarEmbedded}.
* <p>
* (requires Window 10)
* <p>
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
* <strong>Default</strong> none
*/
String MENUBAR_EMBEDDED = "flatlaf.menuBarEmbedded";
/**
* Specifies whether animations are enabled.
* <p>
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
* <strong>Default</strong> {@code true}
*/
String ANIMATION = "flatlaf.animation";
/**
* Specifies whether vertical text position is corrected when UI is scaled on HiDPI screens.
* <p>
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
* <strong>Default</strong> {@code true}
*/
String USE_TEXT_Y_CORRECTION = "flatlaf.useTextYCorrection";
/**
* Checks whether a system property is set and returns {@code true} if its value
* is {@code "true"} (case-insensitive), otherwise it returns {@code false}.
* If the system property is not set, {@code defaultValue} is returned.
*/
static boolean getBoolean( String key, boolean defaultValue ) {
String value = System.getProperty( key );
return (value != null) ? Boolean.parseBoolean( value ) : defaultValue;
}
/**
* Checks whether a system property is set and returns {@code Boolean.TRUE} if its value
* is {@code "true"} (case-insensitive) or returns {@code Boolean.FALSE} if its value
* is {@code "false"} (case-insensitive). Otherwise {@code defaultValue} is returned.
*/
static Boolean getBooleanStrict( String key, Boolean defaultValue ) {
String value = System.getProperty( key );
if( "true".equalsIgnoreCase( value ) )
return Boolean.TRUE;
if( "false".equalsIgnoreCase( value ) )
return Boolean.FALSE;
return defaultValue;
}
}

View File

@@ -16,6 +16,7 @@
package com.formdev.flatlaf;
import java.awt.Color;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -29,11 +30,12 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import javax.swing.UIDefaults;
import javax.swing.plaf.ColorUIResource;
import com.formdev.flatlaf.json.Json;
import com.formdev.flatlaf.json.ParseException;
import com.formdev.flatlaf.util.ColorFunctions;
import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.StringUtils;
/**
@@ -56,6 +58,8 @@ public class IntelliJTheme
public final boolean dark;
public final String author;
private final boolean isMaterialUILite;
private final Map<String, String> colors;
private final Map<String, Object> ui;
private final Map<String, Object> icons;
@@ -64,20 +68,28 @@ public class IntelliJTheme
/**
* Loads a IntelliJ .theme.json file from the given input stream,
* creates a Laf instance for it and installs it.
* creates a Laf instance for it and sets it up.
*
* The input stream is automatically closed.
* Using a buffered input stream is not necessary.
*/
public static boolean install( InputStream in ) {
public static boolean setup( InputStream in ) {
try {
return FlatLaf.install( createLaf( in ) );
return FlatLaf.setup( createLaf( in ) );
} catch( Exception ex ) {
FlatLaf.LOG.log( Level.SEVERE, "FlatLaf: Failed to load IntelliJ theme", ex );
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to load IntelliJ theme", ex );
return false;
}
}
/**
* @deprecated use {@link #setup(InputStream)} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install( InputStream in ) {
return setup( in );
}
/**
* Loads a IntelliJ .theme.json file from the given input stream and
* creates a Laf instance for it.
@@ -119,6 +131,8 @@ public class IntelliJTheme
dark = Boolean.parseBoolean( (String) json.get( "dark" ) );
author = (String) json.get( "author" );
isMaterialUILite = author.equals( "Mallowigi" );
colors = (Map<String, String>) json.get( "colors" );
ui = (Map<String, Object>) json.get( "ui" );
icons = (Map<String, Object>) json.get( "icons" );
@@ -147,6 +161,20 @@ public class IntelliJTheme
applyColorPalette( defaults );
applyCheckBoxColors( defaults );
// copy values
for( Map.Entry<String, String> e : uiKeyCopying.entrySet() )
defaults.put( e.getKey(), defaults.get( e.getValue() ) );
// IDEA does not paint button background if disabled, but FlatLaf does
Object panelBackground = defaults.get( "Panel.background" );
defaults.put( "Button.disabledBackground", panelBackground );
defaults.put( "ToggleButton.disabledBackground", panelBackground );
// fix Button borders
copyIfNotSet( defaults, "Button.focusedBorderColor", "Component.focusedBorderColor", uiKeys );
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
Object helpButtonBackground = defaults.get( "Button.startBackground" );
Object helpButtonBorderColor = defaults.get( "Button.startBorderColor" );
@@ -156,7 +184,7 @@ public class IntelliJTheme
helpButtonBorderColor = defaults.get( "Button.borderColor" );
defaults.put( "HelpButton.background", helpButtonBackground );
defaults.put( "HelpButton.borderColor", helpButtonBorderColor );
defaults.put( "HelpButton.disabledBackground", defaults.get( "Panel.background" ) );
defaults.put( "HelpButton.disabledBackground", panelBackground );
defaults.put( "HelpButton.disabledBorderColor", defaults.get( "Button.disabledBorderColor" ) );
defaults.put( "HelpButton.focusedBorderColor", defaults.get( "Button.focusedBorderColor" ) );
defaults.put( "HelpButton.focusedBackground", defaults.get( "Button.focusedBackground" ) );
@@ -196,6 +224,18 @@ public class IntelliJTheme
if( !uiKeys.contains( "ToggleButton.foreground" ) && uiKeys.contains( "Button.foreground" ) )
defaults.put( "ToggleButton.foreground", defaults.get( "Button.foreground" ) );
// fix DesktopPane background (use Panel.background and make it 5% darker/lighter)
Color desktopBackgroundBase = defaults.getColor( "Panel.background" );
Color desktopBackground = ColorFunctions.applyFunctions( desktopBackgroundBase,
new ColorFunctions.HSLIncreaseDecrease( 2, dark, 5, false, true ) );
defaults.put( "Desktop.background", new ColorUIResource( desktopBackground ) );
// fix List and Table background colors in Material UI Lite themes
if( isMaterialUILite ) {
defaults.put( "List.background", defaults.get( "Tree.background" ) );
defaults.put( "Table.background", defaults.get( "Tree.background" ) );
}
// limit tree row height
int rowHeight = defaults.getInt( "Tree.rowHeight" );
if( rowHeight > 22 )
@@ -209,17 +249,25 @@ public class IntelliJTheme
// search for theme specific UI defaults keys
ArrayList<String> themeSpecificKeys = new ArrayList<>();
for( Object key : defaults.keySet() ) {
if( key instanceof String && ((String)key).startsWith( "[" ) )
if( key instanceof String && ((String)key).startsWith( "[" ) && !((String)key).startsWith( "[style]" ) )
themeSpecificKeys.add( (String) key );
}
// remove theme specific UI defaults and remember only those for current theme
Map<Object, Object> themeSpecificDefaults = new HashMap<>();
String currentThemePrefix = '[' + name.replace( ' ', '_' ) + ']';
String currentThemeAndAuthorPrefix = '[' + name.replace( ' ', '_' ) + "---" + author.replace( ' ', '_' ) + ']';
String currentAuthorPrefix = "[author-" + author.replace( ' ', '_' ) + ']';
String allThemesPrefix = "[*]";
String[] prefixes = { currentThemePrefix, currentThemeAndAuthorPrefix, currentAuthorPrefix, allThemesPrefix };
for( String key : themeSpecificKeys ) {
Object value = defaults.remove( key );
if( key.startsWith( currentThemePrefix ) )
themeSpecificDefaults.put( key.substring( currentThemePrefix.length() ), value );
for( String prefix : prefixes ) {
if( key.startsWith( prefix ) ) {
themeSpecificDefaults.put( key.substring( prefix.length() ), value );
break;
}
}
}
return themeSpecificDefaults;
@@ -240,7 +288,7 @@ public class IntelliJTheme
if( color != null ) {
String key = e.getKey();
namedColors.put( key, color );
defaults.put( "ColorPalette." + e.getKey(), color );
defaults.put( "ColorPalette." + key, color );
}
}
}
@@ -254,10 +302,12 @@ public class IntelliJTheme
for( Map.Entry<String, Object> e : ((Map<String, Object>)value).entrySet() )
apply( key + '.' + e.getKey(), e.getValue(), defaults, defaultsKeysCache, uiKeys );
} else {
if( "".equals( value ) )
return; // ignore empty value
uiKeys.add( key );
// fix ComboBox size and Spinner border in all Material UI Lite themes
boolean isMaterialUILite = author.equals( "Mallowigi" );
if( isMaterialUILite && (key.equals( "ComboBox.padding" ) || key.equals( "Spinner.border" )) )
return; // ignore
@@ -288,9 +338,9 @@ public class IntelliJTheme
// parse value
try {
uiValue = UIDefaultsLoader.parseValue( key, valueStr );
uiValue = UIDefaultsLoader.parseValue( key, valueStr, null );
} catch( RuntimeException ex ) {
UIDefaultsLoader.logParseError( Level.CONFIG, key, valueStr, ex );
UIDefaultsLoader.logParseError( key, valueStr, ex, false );
return; // ignore invalid value
}
}
@@ -310,6 +360,10 @@ public class IntelliJTheme
// replace all values in UI defaults that match the wildcard key
for( Object k : defaultsKeysCache ) {
if( k.equals( "Desktop.background" ) ||
k.equals( "DesktopIcon.background" ) )
continue;
if( k instanceof String ) {
// support replacing of mapped keys
// (e.g. set ComboBox.buttonEditableBackground to *.background
@@ -369,7 +423,7 @@ public class IntelliJTheme
}
/**
* Because IDEA uses SVGs for check boxes and radio buttons the colors for
* Because IDEA uses SVGs for check boxes and radio buttons, the colors for
* this two components are specified in "icons > ColorPalette".
* FlatLaf uses vector icons and expects colors for the two components in UI defaults.
*/
@@ -407,6 +461,10 @@ public class IntelliJTheme
String newKey = checkboxKeyMapping.get( key );
if( newKey != null ) {
String checkBoxIconPrefix = "CheckBox.icon.";
if( !dark && newKey.startsWith( checkBoxIconPrefix ) )
newKey = "CheckBox.icon[filled].".concat( newKey.substring( checkBoxIconPrefix.length() ) );
ColorUIResource color = toColor( (String) value );
if( color != null ) {
defaults.put( newKey, color );
@@ -437,22 +495,47 @@ public class IntelliJTheme
}
}
// remove hover and pressed colors
// update hover, pressed and focused colors
if( checkboxModified ) {
defaults.remove( "CheckBox.icon.hoverBorderColor" );
defaults.remove( "CheckBox.icon.focusedBackground" );
defaults.remove( "CheckBox.icon.hoverBackground" );
defaults.remove( "CheckBox.icon.pressedBackground" );
defaults.remove( "CheckBox.icon.selectedHoverBackground" );
defaults.remove( "CheckBox.icon.selectedPressedBackground" );
}
// for non-filled checkbox/radiobutton used in dark themes
defaults.remove( "CheckBox.icon.focusWidth" );
defaults.put( "CheckBox.icon.hoverBorderColor", defaults.get( "CheckBox.icon.focusedBorderColor" ) );
// copy values
for( Map.Entry<String, String> e : uiKeyCopying.entrySet() )
defaults.put( e.getKey(), defaults.get( e.getValue() ) );
// for filled checkbox/radiobutton used in light themes
defaults.remove( "CheckBox.icon[filled].focusWidth" );
defaults.put( "CheckBox.icon[filled].hoverBorderColor", defaults.get( "CheckBox.icon[filled].focusedBorderColor" ) );
defaults.put( "CheckBox.icon[filled].focusedSelectedBackground", defaults.get( "CheckBox.icon[filled].selectedBackground" ) );
if( dark ) {
// IDEA Darcula checkBoxFocused.svg, checkBoxSelectedFocused.svg,
// radioFocused.svg and radioSelectedFocused.svg
// use opacity=".65" for the border
// --> add alpha to focused border colors
String[] focusedBorderColorKeys = new String[] {
"CheckBox.icon.focusedBorderColor",
"CheckBox.icon.focusedSelectedBorderColor",
"CheckBox.icon[filled].focusedBorderColor",
"CheckBox.icon[filled].focusedSelectedBorderColor",
};
for( String key : focusedBorderColorKeys ) {
Color color = defaults.getColor( key );
if( color != null ) {
defaults.put( key, new ColorUIResource( new Color(
(color.getRGB() & 0xffffff) | 0xa6000000, true ) ) );
}
}
}
}
}
private void copyIfNotSet( UIDefaults defaults, String destKey, String srcKey, Set<String> uiKeys ) {
if( !uiKeys.contains( destKey ) )
defaults.put( destKey, defaults.get( srcKey ) );
}
/** Rename UI default keys (key --> value). */
private static 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<>();
@@ -466,15 +549,39 @@ public class IntelliJTheme
uiKeyMapping.put( "ComboBox.ArrowButton.disabledIconColor", "ComboBox.buttonDisabledArrowColor" );
uiKeyMapping.put( "ComboBox.ArrowButton.iconColor", "ComboBox.buttonArrowColor" );
uiKeyMapping.put( "ComboBox.ArrowButton.nonEditableBackground", "ComboBox.buttonBackground" );
uiKeyCopying.put( "ComboBox.buttonSeparatorColor", "Component.borderColor" );
uiKeyCopying.put( "ComboBox.buttonDisabledSeparatorColor", "Component.disabledBorderColor" );
// Component
uiKeyMapping.put( "Component.inactiveErrorFocusColor", "Component.error.borderColor" );
uiKeyMapping.put( "Component.errorFocusColor", "Component.error.focusedBorderColor" );
uiKeyMapping.put( "Component.inactiveWarningFocusColor", "Component.warning.borderColor" );
uiKeyMapping.put( "Component.warningFocusColor", "Component.warning.focusedBorderColor" );
// Link
uiKeyMapping.put( "Link.activeForeground", "Component.linkColor" );
// Menu
uiKeyMapping.put( "Menu.border", "Menu.margin" );
uiKeyMapping.put( "MenuItem.border", "MenuItem.margin" );
uiKeyCopying.put( "CheckBoxMenuItem.margin", "MenuItem.margin" );
uiKeyCopying.put( "RadioButtonMenuItem.margin", "MenuItem.margin" );
uiKeyMapping.put( "PopupMenu.border", "PopupMenu.borderInsets" );
uiKeyCopying.put( "MenuItem.underlineSelectionColor", "TabbedPane.underlineColor" );
// IDEA uses List.selectionBackground also for menu selection
uiKeyCopying.put( "Menu.selectionBackground", "List.selectionBackground" );
uiKeyCopying.put( "MenuItem.selectionBackground", "List.selectionBackground" );
uiKeyCopying.put( "CheckBoxMenuItem.selectionBackground", "List.selectionBackground" );
uiKeyCopying.put( "RadioButtonMenuItem.selectionBackground", "List.selectionBackground" );
// ProgressBar
uiKeyMapping.put( "ProgressBar.background", "" ); // ignore
uiKeyMapping.put( "ProgressBar.foreground", "" ); // ignore
uiKeyMapping.put( "ProgressBar.trackColor", "ProgressBar.background" );
uiKeyMapping.put( "ProgressBar.progressColor", "ProgressBar.foreground" );
uiKeyCopying.put( "ProgressBar.selectionForeground", "ProgressBar.background" );
uiKeyCopying.put( "ProgressBar.selectionBackground", "ProgressBar.foreground" );
// ScrollBar
uiKeyMapping.put( "ScrollBar.trackColor", "ScrollBar.track" );
@@ -485,6 +592,18 @@ public class IntelliJTheme
// Slider
uiKeyMapping.put( "Slider.trackWidth", "" ); // ignore (used in Material Theme UI Lite)
uiKeyCopying.put( "Slider.trackValueColor", "ProgressBar.foreground" );
uiKeyCopying.put( "Slider.thumbColor", "ProgressBar.foreground" );
uiKeyCopying.put( "Slider.trackColor", "ProgressBar.background" );
// Spinner
uiKeyCopying.put( "Spinner.buttonSeparatorColor", "Component.borderColor" );
uiKeyCopying.put( "Spinner.buttonDisabledSeparatorColor", "Component.disabledBorderColor" );
// TitlePane
uiKeyCopying.put( "TitlePane.inactiveBackground", "TitlePane.background" );
uiKeyMapping.put( "TitlePane.infoForeground", "TitlePane.foreground" );
uiKeyMapping.put( "TitlePane.inactiveInfoForeground", "TitlePane.inactiveForeground" );
for( Map.Entry<String, String> e : uiKeyMapping.entrySet() )
uiKeyInverseMapping.put( e.getValue(), e.getKey() );
@@ -500,12 +619,12 @@ public class IntelliJTheme
checkboxKeyMapping.put( "Checkbox.Border.Default", "CheckBox.icon.borderColor" );
checkboxKeyMapping.put( "Checkbox.Border.Disabled", "CheckBox.icon.disabledBorderColor" );
checkboxKeyMapping.put( "Checkbox.Focus.Thin.Default", "CheckBox.icon.focusedBorderColor" );
checkboxKeyMapping.put( "Checkbox.Focus.Wide", "CheckBox.icon.focusedColor" );
checkboxKeyMapping.put( "Checkbox.Focus.Wide", "CheckBox.icon.focusColor" );
checkboxKeyMapping.put( "Checkbox.Foreground.Disabled", "CheckBox.icon.disabledCheckmarkColor" );
checkboxKeyMapping.put( "Checkbox.Background.Selected", "CheckBox.icon.selectedBackground" );
checkboxKeyMapping.put( "Checkbox.Border.Selected", "CheckBox.icon.selectedBorderColor" );
checkboxKeyMapping.put( "Checkbox.Foreground.Selected", "CheckBox.icon.checkmarkColor" );
checkboxKeyMapping.put( "Checkbox.Focus.Thin.Selected", "CheckBox.icon.selectedFocusedBorderColor" );
checkboxKeyMapping.put( "Checkbox.Focus.Thin.Selected", "CheckBox.icon.focusedSelectedBorderColor" );
checkboxDuplicateColors.put( "Checkbox.Background.Default.Dark", "Checkbox.Background.Selected.Dark" );
checkboxDuplicateColors.put( "Checkbox.Border.Default.Dark", "Checkbox.Border.Selected.Dark" );
@@ -534,7 +653,7 @@ public class IntelliJTheme
@Override
public String getDescription() {
return theme.name;
return getName();
}
@Override

View File

@@ -28,7 +28,8 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.StringTokenizer;
import java.util.logging.Level;
import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.StringUtils;
import com.formdev.flatlaf.util.SystemInfo;
import com.formdev.flatlaf.util.UIScale;
@@ -39,7 +40,7 @@ import com.formdev.flatlaf.util.UIScale;
class LinuxFontPolicy
{
static Font getFont() {
return SystemInfo.IS_KDE ? getKDEFont() : getGnomeFont();
return SystemInfo.isKDE ? getKDEFont() : getGnomeFont();
}
/**
@@ -54,29 +55,50 @@ class LinuxFontPolicy
String family = "";
int style = Font.PLAIN;
int size = 10;
double dsize = 10;
// parse pango font description
// see https://developer.gnome.org/pango/1.46/pango-Fonts.html#pango-font-description-from-string
StringTokenizer st = new StringTokenizer( (String) fontName );
while( st.hasMoreTokens() ) {
String word = st.nextToken();
if( word.equalsIgnoreCase( "italic" ) )
// remove trailing ',' (e.g. in "Ubuntu Condensed, 11" or "Ubuntu Condensed, Bold 11")
if( word.endsWith( "," ) )
word = word.substring( 0, word.length() - 1 ).trim();
String lword = word.toLowerCase();
if( lword.equals( "italic" ) || lword.equals( "oblique" ) )
style |= Font.ITALIC;
else if( word.equalsIgnoreCase( "bold" ) )
else if( lword.equals( "bold" ) )
style |= Font.BOLD;
else if( Character.isDigit( word.charAt( 0 ) ) ) {
try {
size = Integer.parseInt( word );
dsize = Double.parseDouble( word );
} catch( NumberFormatException ex ) {
// ignore
}
} else
} else {
// remove '-' from "Semi-Bold", "Extra-Light", etc
if( lword.startsWith( "semi-" ) || lword.startsWith( "demi-" ) )
word = word.substring( 0, 4 ) + word.substring( 5 );
else if( lword.startsWith( "extra-" ) || lword.startsWith( "ultra-" ) )
word = word.substring( 0, 5 ) + word.substring( 6 );
family = family.isEmpty() ? word : (family + ' ' + word);
}
}
// Ubuntu font is rendered poorly (except if running in JetBrains VM)
// --> use Liberation Sans font
if( family.startsWith( "Ubuntu" ) &&
!SystemInfo.isJetBrainsJVM &&
!FlatSystemProperties.getBoolean( FlatSystemProperties.USE_UBUNTU_FONT, false ) )
family = "Liberation Sans";
// scale font size
double dsize = size * getGnomeFontScale();
size = (int) (dsize + 0.5);
dsize *= getGnomeFontScale();
int size = (int) (dsize + 0.5);
if( size < 1 )
size = 1;
@@ -85,7 +107,37 @@ class LinuxFontPolicy
if( logicalFamily != null )
family = logicalFamily;
return createFont( family, style, size, dsize );
return createFontEx( family, style, size, dsize );
}
/**
* Create a font for the given family, style and size.
* If the font family does not match any font on the system,
* then the last word (usually a font weight) from the family name is removed and tried again.
* E.g. family 'URW Bookman Light' is not found, but 'URW Bookman' is found.
* If still not found, then font of family 'Dialog' is returned.
*/
private static Font createFontEx( String family, int style, int size, double dsize ) {
for(;;) {
Font font = createFont( family, style, size, dsize );
// if the font family does not match any font on the system, "Dialog" family is returned
if( !"Dialog".equals( font.getFamily() ) || "Dialog".equals( family ) )
return font;
// find last word in family
int index = family.lastIndexOf( ' ' );
if( index < 0 )
return createFont( "Dialog", style, size, dsize );
// check whether last work contains some font weight (e.g. Ultra-Bold or Heavy)
String lastWord = family.substring( index + 1 ).toLowerCase();
if( lastWord.contains( "bold" ) || lastWord.contains( "heavy" ) || lastWord.contains( "black" ) )
style |= Font.BOLD;
// remove last word from family and try again
family = family.substring( 0, index );
}
}
private static Font createFont( String family, int style, int size, double dsize ) {
@@ -165,7 +217,7 @@ class LinuxFontPolicy
if( "1".equals( strs.get( 5 ) ) )
style |= Font.ITALIC;
} catch( RuntimeException ex ) {
FlatLaf.LOG.log( Level.CONFIG, "FlatLaf: Failed to parse 'font=" + generalFont + "'.", ex );
LoggingFacade.INSTANCE.logConfig( "FlatLaf: Failed to parse 'font=" + generalFont + "'.", ex );
}
}
@@ -179,7 +231,7 @@ class LinuxFontPolicy
if( dpi < 50 )
dpi = 50;
} catch( NumberFormatException ex ) {
FlatLaf.LOG.log( Level.CONFIG, "FlatLaf: Failed to parse 'forceFontDPI=" + forceFontDPI + "'.", ex );
LoggingFacade.INSTANCE.logConfig( "FlatLaf: Failed to parse 'forceFontDPI=" + forceFontDPI + "'.", ex );
}
}
@@ -218,7 +270,7 @@ class LinuxFontPolicy
while( (line = reader.readLine()) != null )
lines.add( line );
} catch( IOException ex ) {
FlatLaf.LOG.log( Level.CONFIG, "FlatLaf: Failed to read '" + filename + "'.", ex );
LoggingFacade.INSTANCE.logConfig( "FlatLaf: Failed to read '" + filename + "'.", ex );
}
return lines;
}
@@ -257,6 +309,9 @@ class LinuxFontPolicy
* - running on JetBrains Runtime 11 or later and scaling is enabled in system Settings
*/
private static boolean isSystemScaling() {
if( GraphicsEnvironment.isHeadless() )
return true;
GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment()
.getDefaultScreenDevice().getDefaultConfiguration();
return UIScale.getSystemScaleFactor( gc ) > 1;

View File

@@ -0,0 +1,267 @@
/*
* Copyright 2020 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf;
import java.awt.Component;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.KeyEventPostProcessor;
import java.awt.KeyboardFocusManager;
import java.awt.Window;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.lang.ref.WeakReference;
import javax.swing.AbstractButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JRootPane;
import javax.swing.JTabbedPane;
import javax.swing.MenuElement;
import javax.swing.MenuSelectionManager;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import com.formdev.flatlaf.util.SystemInfo;
/**
* Show/hide mnemonics.
*
* @author Karl Tauber
*/
class MnemonicHandler
implements KeyEventPostProcessor, ChangeListener
{
private static boolean showMnemonics;
private static WeakReference<Window> lastShowMnemonicWindow;
private static WindowListener windowListener;
static boolean isShowMnemonics() {
return showMnemonics || !UIManager.getBoolean( "Component.hideMnemonics" );
}
void install() {
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventPostProcessor( this );
MenuSelectionManager.defaultManager().addChangeListener( this );
}
void uninstall() {
KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventPostProcessor( this );
MenuSelectionManager.defaultManager().removeChangeListener( this );
}
@Override
public boolean postProcessKeyEvent( KeyEvent e ) {
int keyCode = e.getKeyCode();
if( SystemInfo.isMacOS ) {
// Ctrl+Alt keys must be pressed on Mac
if( keyCode == KeyEvent.VK_CONTROL || keyCode == KeyEvent.VK_ALT )
showMnemonics( shouldShowMnemonics( e ) && e.isControlDown() && e.isAltDown(), e.getComponent() );
} else {
// Alt key must be pressed on Windows and Linux
if( SystemInfo.isWindows )
return processKeyEventOnWindows( e );
if( keyCode == KeyEvent.VK_ALT )
showMnemonics( shouldShowMnemonics( e ), e.getComponent() );
}
return false;
}
private boolean shouldShowMnemonics( KeyEvent e ) {
return e.getID() == KeyEvent.KEY_PRESSED ||
MenuSelectionManager.defaultManager().getSelectedPath().length > 0;
}
private static int altPressedEventCount;
private static boolean selectMenuOnAltReleased;
/**
* Special Alt key behavior on Windows.
*
* Press-and-release Alt key selects first menu (if available) and moves focus
* temporary to menu bar. If menu bar has focus (some menu is selected),
* pressing Alt key unselects menu and moves focus back to permanent focus owner.
*/
private boolean processKeyEventOnWindows( KeyEvent e ) {
if( e.getKeyCode() != KeyEvent.VK_ALT ) {
selectMenuOnAltReleased = false;
return false;
}
if( e.getID() == KeyEvent.KEY_PRESSED ) {
altPressedEventCount++;
if( altPressedEventCount == 1 && !e.isConsumed() ) {
MenuSelectionManager menuSelectionManager = MenuSelectionManager.defaultManager();
selectMenuOnAltReleased = (menuSelectionManager.getSelectedPath().length == 0);
// if menu is selected when Alt key is pressed then clear menu selection
if( !selectMenuOnAltReleased )
menuSelectionManager.clearSelectedPath();
}
// show mnemonics
showMnemonics( shouldShowMnemonics( e ), e.getComponent() );
// avoid that the system menu of the window gets focus
e.consume();
return true;
} else if( e.getID() == KeyEvent.KEY_RELEASED ) {
altPressedEventCount = 0;
boolean mnemonicsShown = false;
if( selectMenuOnAltReleased && !e.isConsumed() ) {
MenuSelectionManager menuSelectionManager = MenuSelectionManager.defaultManager();
if( menuSelectionManager.getSelectedPath().length == 0 ) {
// get menu bar and first menu
Component c = e.getComponent();
JRootPane rootPane = SwingUtilities.getRootPane( c );
JMenuBar menuBar = (rootPane != null) ? rootPane.getJMenuBar() : null;
if( menuBar == null ) {
// get menu bar from frame/dialog because there
// may be multiple nested root panes in a frame/dialog
// (e.g. each internal frame has its own root pane)
Window window = SwingUtilities.getWindowAncestor( c );
if( window instanceof JFrame )
menuBar = ((JFrame)window).getJMenuBar();
else if( window instanceof JDialog )
menuBar = ((JDialog)window).getJMenuBar();
}
JMenu firstMenu = (menuBar != null) ? menuBar.getMenu( 0 ) : null;
// select first menu and show mnemonics
if( firstMenu != null ) {
menuSelectionManager.setSelectedPath( new MenuElement[] { menuBar, firstMenu } );
showMnemonics( true, c );
mnemonicsShown = true;
}
}
}
selectMenuOnAltReleased = false;
// hide mnemonics
if( !mnemonicsShown )
showMnemonics( shouldShowMnemonics( e ), e.getComponent() );
}
return false;
}
@Override
public void stateChanged( ChangeEvent e ) {
MenuElement[] selectedPath = MenuSelectionManager.defaultManager().getSelectedPath();
if( selectedPath.length == 0 && altPressedEventCount == 0 ) {
// hide mnemonics when menu selection was canceled
showMnemonics( false, null );
}
}
static void showMnemonics( boolean show, Component c ) {
if( show == showMnemonics )
return;
showMnemonics = show;
// check whether it is necessary to repaint
if( !UIManager.getBoolean( "Component.hideMnemonics" ) )
return;
if( show ) {
// get root pane
JRootPane rootPane = SwingUtilities.getRootPane( c );
if( rootPane == null )
return;
// get window
Window window = SwingUtilities.getWindowAncestor( rootPane );
if( window == null )
return;
// repaint components with mnemonics in focused window
repaintMnemonics( window );
// hide mnemonics if window is deactivated (e.g. Alt+Tab to another window)
windowListener = new WindowAdapter() {
@Override
public void windowDeactivated( WindowEvent e ) {
altPressedEventCount = 0;
selectMenuOnAltReleased = false;
// use invokeLater() to avoid that the listener is removed
// while the listener queue is iterated to fire this event
EventQueue.invokeLater( () -> {
showMnemonics( false, null );
} );
}
};
window.addWindowListener( windowListener );
lastShowMnemonicWindow = new WeakReference<>( window );
} else if( lastShowMnemonicWindow != null ) {
Window window = lastShowMnemonicWindow.get();
if( window != null ) {
repaintMnemonics( window );
if( windowListener != null ) {
window.removeWindowListener( windowListener );
windowListener = null;
}
}
lastShowMnemonicWindow = null;
}
}
private static void repaintMnemonics( Container container ) {
for( Component c : container.getComponents() ) {
if( !c.isVisible() )
continue;
if( hasMnemonic( c ) )
c.repaint();
if( c instanceof Container )
repaintMnemonics( (Container) c );
}
}
private static boolean hasMnemonic( Component c ) {
if( c instanceof JLabel && ((JLabel)c).getDisplayedMnemonicIndex() >= 0 )
return true;
if( c instanceof AbstractButton && ((AbstractButton)c).getDisplayedMnemonicIndex() >= 0 )
return true;
if( c instanceof JTabbedPane ) {
JTabbedPane tabPane = (JTabbedPane) c;
int tabCount = tabPane.getTabCount();
for( int i = 0; i < tabCount; i++ ) {
if( tabPane.getDisplayedMnemonicIndexAt( i ) >= 0 )
return true;
}
}
return false;
}
}

View File

@@ -39,7 +39,7 @@ public abstract class FlatAbstractIcon
{
protected final int width;
protected final int height;
protected final Color color;
protected Color color;
public FlatAbstractIcon( int width, int height, Color color ) {
this.width = width;
@@ -69,7 +69,13 @@ public abstract class FlatAbstractIcon
}
}
protected abstract void paintIcon( Component c, Graphics2D g2 );
/**
* Paint the icon at {@code [0,0]} location.
* <p>
* The given graphics context is scaled.
* Use unscaled coordinates, width and height for painting.
*/
protected abstract void paintIcon( Component c, Graphics2D g );
@Override
public int getIconWidth() {

View File

@@ -0,0 +1,79 @@
/*
* Copyright 2020 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.icons;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import com.formdev.flatlaf.util.AnimatedIcon;
import com.formdev.flatlaf.util.AnimatedPainter;
/**
* Base class for animated icons that scales 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.
* This makes it possible to use a shared icon instance for multiple components.
*
* @author Karl Tauber
*/
public abstract class FlatAnimatedIcon
extends FlatAbstractIcon
implements AnimatedIcon
{
public FlatAnimatedIcon( int width, int height, Color color ) {
super( width, height, color );
}
@Override
public void paintIcon( Component c, Graphics g, int x, int y ) {
super.paintIcon( c, g, x, y );
AnimatedPainter.saveRepaintLocation( this, c, x, y );
}
@Override
protected void paintIcon( Component c, Graphics2D g ) {
paintWithAnimation( c, g, 0, 0, getIconWidth(), getIconHeight() );
}
/**
* Delegates painting to {@link #paintIconAnimated(Component, Graphics2D, float[])}.
* Ignores the given bounds because {@code [x,y]} are always {@code [0,0]} and
* {@code [width,height]} are scaled, but painting code should use unscaled width
* and height because given graphics context is scaled.
*
* @since 2
*/
@Override
public void paintAnimated( Component c, Graphics2D g, int x, int y, int width, int height, float[] animatedValues ) {
paintIconAnimated( c, g, animatedValues );
}
/**
* Paint the icon at {@code 0,0} location.
* <p>
* The given graphics context is scaled.
* Use unscaled coordinates, width and height for painting.
*
* @since 2
*/
protected abstract void paintIconAnimated( Component c, Graphics2D g, float[] animatedValues );
}

View File

@@ -21,13 +21,17 @@ import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.geom.Path2D;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.plaf.TableHeaderUI;
import javax.swing.table.JTableHeader;
import com.formdev.flatlaf.ui.FlatTableHeaderUI;
import com.formdev.flatlaf.ui.FlatUIUtils;
/**
* "ascendingSort" icon for {@link javax.swing.table.JTableHeader}.
*
* @uiDefault Component.arrowType String triangle (default) or chevron
* @uiDefault Component.arrowType String chevron (default) or triangle
* @uiDefault Table.sortIconColor Color
*
* @author Karl Tauber
@@ -35,8 +39,8 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
public class FlatAscendingSortIcon
extends FlatAbstractIcon
{
protected final boolean chevron = "chevron".equals( UIManager.getString( "Component.arrowType" ) );
protected final Color sortIconColor = UIManager.getColor( "Table.sortIconColor" );
protected boolean chevron = FlatUIUtils.isChevron( UIManager.getString( "Component.arrowType" ) );
protected Color sortIconColor = UIManager.getColor( "Table.sortIconColor" );
public FlatAscendingSortIcon() {
super( 10, 5, null );
@@ -44,7 +48,28 @@ public class FlatAscendingSortIcon
@Override
protected void paintIcon( Component c, Graphics2D g ) {
boolean chevron = this.chevron;
Color sortIconColor = this.sortIconColor;
// Because this icons are always shared for all table headers,
// get icon specific style from FlatTableHeaderUI.
JTableHeader tableHeader = (JTableHeader) SwingUtilities.getAncestorOfClass( JTableHeader.class, c );
if( tableHeader != null ) {
TableHeaderUI ui = tableHeader.getUI();
if( ui instanceof FlatTableHeaderUI ) {
FlatTableHeaderUI fui = (FlatTableHeaderUI) ui;
if( fui.arrowType != null )
chevron = FlatUIUtils.isChevron( fui.arrowType );
if( fui.sortIconColor != null )
sortIconColor = fui.sortIconColor;
}
}
g.setColor( sortIconColor );
paintArrow( c, g, chevron );
}
protected void paintArrow( Component c, Graphics2D g, boolean chevron ) {
if( chevron ) {
// chevron arrow
Path2D path = FlatUIUtils.createPath( false, 1,4, 5,0, 9,4 );

View File

@@ -16,12 +16,14 @@
package com.formdev.flatlaf.icons;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
import com.formdev.flatlaf.ui.FlatUIUtils;
/**
@@ -38,13 +40,22 @@ public class FlatCapsLockIcon
super( 16, 16, UIManager.getColor( "PasswordField.capsLockIconColor" ) );
}
/** @since 2 */
public Object applyStyleProperty( String key, Object value ) {
Object oldValue;
switch( key ) {
case "capsLockIconColor": oldValue = color; color = (Color) value; return oldValue;
default: throw new UnknownStyleException( key );
}
}
@Override
protected void paintIcon( Component c, Graphics2D g ) {
/*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd">
<rect width="16" height="16" fill="#6E6E6E" rx="3"/>
<rect width="6" height="2" x="5" y="12" fill="#FFF"/>
<rect width="6" height="2" x="5" y="11.5" fill="#FFF"/>
<path fill="#FFF" d="M2,8 L8,2 L14,8 L11,8 L11,10 L5,10 L5,8 L2,8 Z"/>
</g>
</svg>
@@ -52,7 +63,7 @@ public class FlatCapsLockIcon
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
path.append( new RoundRectangle2D.Float( 0, 0, 16, 16, 6, 6 ), false );
path.append( new Rectangle2D.Float( 5, 12, 6, 2 ), false );
path.append( new Rectangle2D.Float( 5, 11.5f, 6, 2 ), false );
path.append( FlatUIUtils.createPath( 2,8, 8,2, 14,8, 11,8, 11,10, 5,10, 5,8 ), false );
g.fill( path );
}

View File

@@ -23,66 +23,138 @@ import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.geom.Path2D;
import java.awt.geom.RoundRectangle2D;
import java.util.Map;
import javax.swing.AbstractButton;
import javax.swing.JComponent;
import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatButtonUI;
import com.formdev.flatlaf.ui.FlatStylingSupport;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatUIUtils;
/**
* Icon for {@link javax.swing.JCheckBox}.
*
* Note: If Component.focusWidth is greater than zero, then the outline focus border
* <p>
* <strong>Note</strong>:
* If Component.focusWidth is greater than zero, then the outer focus border
* is painted outside of the icon bounds. Make sure that the checkbox
* has margins, which are equal or greater than focusWidth.
*
* @uiDefault CheckBox.icon.style String optional; "outlined"/null (default) or "filled"
* @uiDefault Component.focusWidth int
* @uiDefault Component.borderWidth int
* @uiDefault Component.focusColor Color
* @uiDefault CheckBox.icon.focusedColor Color optional; defaults to Component.focusColor
* @uiDefault CheckBox.icon.borderColor Color
* @uiDefault CheckBox.icon.disabledBorderColor Color
* @uiDefault CheckBox.icon.selectedBorderColor Color
* @uiDefault CheckBox.icon.focusedBorderColor Color
* @uiDefault CheckBox.icon.hoverBorderColor Color optional
* @uiDefault CheckBox.icon.selectedFocusedBorderColor Color optional
* @uiDefault CheckBox.icon.background Color
* @uiDefault CheckBox.icon.disabledBackground Color
* @uiDefault CheckBox.icon.focusedBackground Color optional
* @uiDefault CheckBox.icon.hoverBackground Color optional
* @uiDefault CheckBox.icon.pressedBackground Color optional
* @uiDefault CheckBox.icon.selectedBackground Color
* @uiDefault CheckBox.icon.selectedHoverBackground Color optional
* @uiDefault CheckBox.icon.selectedPressedBackground Color optional
* @uiDefault CheckBox.icon.checkmarkColor Color
* @uiDefault CheckBox.icon.disabledCheckmarkColor Color
* @uiDefault CheckBox.icon.focusWidth int or float optional; defaults to Component.focusWidth
* @uiDefault CheckBox.icon.borderWidth int or float optional; defaults to Component.borderWidth
* @uiDefault CheckBox.icon.selectedBorderWidth int or float optional; defaults to CheckBox.icon.borderWidth
* @uiDefault CheckBox.icon.disabledSelectedBorderWidth int or float optional; defaults to CheckBox.icon.selectedBorderWidth
* @uiDefault CheckBox.arc int
*
* @uiDefault CheckBox.icon.focusColor Color optional; defaults to Component.focusColor
* @uiDefault CheckBox.icon.borderColor Color
* @uiDefault CheckBox.icon.background Color
* @uiDefault CheckBox.icon.selectedBorderColor Color
* @uiDefault CheckBox.icon.selectedBackground Color
* @uiDefault CheckBox.icon.checkmarkColor Color
*
* @uiDefault CheckBox.icon.disabledBorderColor Color
* @uiDefault CheckBox.icon.disabledBackground Color
* @uiDefault CheckBox.icon.disabledSelectedBorderColor Color optional; CheckBox.icon.disabledBorderColor is used if not specified
* @uiDefault CheckBox.icon.disabledSelectedBackground Color optional; CheckBox.icon.disabledBackground is used if not specified
* @uiDefault CheckBox.icon.disabledCheckmarkColor Color
*
* @uiDefault CheckBox.icon.focusedBorderColor Color optional
* @uiDefault CheckBox.icon.focusedBackground Color optional
* @uiDefault CheckBox.icon.focusedSelectedBorderColor Color optional; CheckBox.icon.focusedBorderColor is used if not specified
* @uiDefault CheckBox.icon.focusedSelectedBackground Color optional; CheckBox.icon.focusedBackground is used if not specified
* @uiDefault CheckBox.icon.focusedCheckmarkColor Color optional; CheckBox.icon.checkmarkColor is used if not specified
*
* @uiDefault CheckBox.icon.hoverBorderColor Color optional
* @uiDefault CheckBox.icon.hoverBackground Color optional
* @uiDefault CheckBox.icon.hoverSelectedBorderColor Color optional; CheckBox.icon.hoverBorderColor is used if not specified
* @uiDefault CheckBox.icon.hoverSelectedBackground Color optional; CheckBox.icon.hoverBackground is used if not specified
* @uiDefault CheckBox.icon.hoverCheckmarkColor Color optional; CheckBox.icon.checkmarkColor is used if not specified
*
* @uiDefault CheckBox.icon.pressedBorderColor Color optional
* @uiDefault CheckBox.icon.pressedBackground Color optional
* @uiDefault CheckBox.icon.pressedSelectedBorderColor Color optional; CheckBox.icon.pressedBorderColor is used if not specified
* @uiDefault CheckBox.icon.pressedSelectedBackground Color optional; CheckBox.icon.pressedBackground is used if not specified
* @uiDefault CheckBox.icon.pressedCheckmarkColor Color optional; CheckBox.icon.checkmarkColor is used if not specified
*
* @author Karl Tauber
*/
public class FlatCheckBoxIcon
extends FlatAbstractIcon
{
public final int focusWidth = UIManager.getInt( "Component.focusWidth" );
protected final Color focusColor = FlatUIUtils.getUIColor( "CheckBox.icon.focusedColor",
UIManager.getColor( "Component.focusColor" ) );
protected final int arc = FlatUIUtils.getUIInt( "CheckBox.arc", 2 );
protected final String style = UIManager.getString( getPropertyPrefix() + "icon.style" );
@Styleable protected float focusWidth = getUIFloat( "CheckBox.icon.focusWidth", UIManager.getInt( "Component.focusWidth" ), style );
@Styleable protected Color focusColor = FlatUIUtils.getUIColor( "CheckBox.icon.focusColor", UIManager.getColor( "Component.focusColor" ) );
/** @since 2 */ @Styleable protected float borderWidth = getUIFloat( "CheckBox.icon.borderWidth", FlatUIUtils.getUIFloat( "Component.borderWidth", 1 ), style );
/** @since 2 */ @Styleable protected float selectedBorderWidth = getUIFloat( "CheckBox.icon.selectedBorderWidth", Float.MIN_VALUE, style );
/** @since 2 */ @Styleable protected float disabledSelectedBorderWidth = getUIFloat( "CheckBox.icon.disabledSelectedBorderWidth", Float.MIN_VALUE, style );
@Styleable protected int arc = FlatUIUtils.getUIInt( "CheckBox.arc", 2 );
protected final Color borderColor = UIManager.getColor( "CheckBox.icon.borderColor" );
protected final Color disabledBorderColor = UIManager.getColor( "CheckBox.icon.disabledBorderColor" );
protected final Color selectedBorderColor = UIManager.getColor( "CheckBox.icon.selectedBorderColor" );
protected final Color focusedBorderColor = UIManager.getColor( "CheckBox.icon.focusedBorderColor" );
protected final Color hoverBorderColor = UIManager.getColor( "CheckBox.icon.hoverBorderColor" );
protected final Color selectedFocusedBorderColor = UIManager.getColor( "CheckBox.icon.selectedFocusedBorderColor" );
protected final Color background = UIManager.getColor( "CheckBox.icon.background" );
protected final Color disabledBackground = UIManager.getColor( "CheckBox.icon.disabledBackground" );
protected final Color focusedBackground = UIManager.getColor( "CheckBox.icon.focusedBackground" );
protected final Color hoverBackground = UIManager.getColor( "CheckBox.icon.hoverBackground" );
protected final Color pressedBackground = UIManager.getColor( "CheckBox.icon.pressedBackground" );
protected final Color selectedBackground = UIManager.getColor( "CheckBox.icon.selectedBackground" );
protected final Color selectedHoverBackground = UIManager.getColor( "CheckBox.icon.selectedHoverBackground" );
protected final Color selectedPressedBackground = UIManager.getColor( "CheckBox.icon.selectedPressedBackground" );
protected final Color checkmarkColor = UIManager.getColor( "CheckBox.icon.checkmarkColor" );
protected final Color disabledCheckmarkColor = UIManager.getColor( "CheckBox.icon.disabledCheckmarkColor" );
// enabled
@Styleable protected Color borderColor = getUIColor( "CheckBox.icon.borderColor", style );
@Styleable protected Color background = getUIColor( "CheckBox.icon.background", style );
@Styleable protected Color selectedBorderColor = getUIColor( "CheckBox.icon.selectedBorderColor", style );
@Styleable protected Color selectedBackground = getUIColor( "CheckBox.icon.selectedBackground", style );
@Styleable protected Color checkmarkColor = getUIColor( "CheckBox.icon.checkmarkColor", style );
// disabled
@Styleable protected Color disabledBorderColor = getUIColor( "CheckBox.icon.disabledBorderColor", style );
@Styleable protected Color disabledBackground = getUIColor( "CheckBox.icon.disabledBackground", style );
/** @since 2 */ @Styleable protected Color disabledSelectedBorderColor = getUIColor( "CheckBox.icon.disabledSelectedBorderColor", style );
/** @since 2 */ @Styleable protected Color disabledSelectedBackground = getUIColor( "CheckBox.icon.disabledSelectedBackground", style );
@Styleable protected Color disabledCheckmarkColor = getUIColor( "CheckBox.icon.disabledCheckmarkColor", style );
// focused
@Styleable protected Color focusedBorderColor = getUIColor( "CheckBox.icon.focusedBorderColor", style );
@Styleable protected Color focusedBackground = getUIColor( "CheckBox.icon.focusedBackground", style );
/** @since 2 */ @Styleable protected Color focusedSelectedBorderColor = getUIColor( "CheckBox.icon.focusedSelectedBorderColor", style );
/** @since 2 */ @Styleable protected Color focusedSelectedBackground = getUIColor( "CheckBox.icon.focusedSelectedBackground", style );
/** @since 2 */ @Styleable protected Color focusedCheckmarkColor = getUIColor( "CheckBox.icon.focusedCheckmarkColor", style );
// hover
@Styleable protected Color hoverBorderColor = getUIColor( "CheckBox.icon.hoverBorderColor", style );
@Styleable protected Color hoverBackground = getUIColor( "CheckBox.icon.hoverBackground", style );
/** @since 2 */ @Styleable protected Color hoverSelectedBorderColor = getUIColor( "CheckBox.icon.hoverSelectedBorderColor", style );
/** @since 2 */ @Styleable protected Color hoverSelectedBackground = getUIColor( "CheckBox.icon.hoverSelectedBackground", style );
/** @since 2 */ @Styleable protected Color hoverCheckmarkColor = getUIColor( "CheckBox.icon.hoverCheckmarkColor", style );
// pressed
/** @since 2 */ @Styleable protected Color pressedBorderColor = getUIColor( "CheckBox.icon.pressedBorderColor", style );
@Styleable protected Color pressedBackground = getUIColor( "CheckBox.icon.pressedBackground", style );
/** @since 2 */ @Styleable protected Color pressedSelectedBorderColor = getUIColor( "CheckBox.icon.pressedSelectedBorderColor", style );
/** @since 2 */ @Styleable protected Color pressedSelectedBackground = getUIColor( "CheckBox.icon.pressedSelectedBackground", style );
/** @since 2 */ @Styleable protected Color pressedCheckmarkColor = getUIColor( "CheckBox.icon.pressedCheckmarkColor", style );
protected String getPropertyPrefix() {
return "CheckBox.";
}
protected static Color getUIColor( String key, String style ) {
if( style != null ) {
Color color = UIManager.getColor( styleKey( key, style ) );
if( color != null )
return color;
}
return UIManager.getColor( key );
}
/** @since 2 */
protected static float getUIFloat( String key, float defaultValue, String style ) {
if( style != null ) {
float value = FlatUIUtils.getUIFloat( styleKey( key, style ), Float.MIN_VALUE );
if( value != Float.MIN_VALUE )
return value;
}
return FlatUIUtils.getUIFloat( key, defaultValue );
}
private static String styleKey( String key, String style ) {
return key.replace( ".icon.", ".icon[" + style + "]." );
}
static final int ICON_SIZE = 15;
@@ -90,74 +162,135 @@ public class FlatCheckBoxIcon
super( ICON_SIZE, ICON_SIZE, null );
}
/** @since 2 */
public Object applyStyleProperty( String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
}
/** @since 2 */
public Map<String, Class<?>> getStyleableInfos() {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
}
@Override
protected void paintIcon( Component c, Graphics2D g2 ) {
boolean indeterminate = c instanceof JComponent && clientPropertyEquals( (JComponent) c, SELECTED_STATE, SELECTED_STATE_INDETERMINATE );
boolean selected = indeterminate || (c instanceof AbstractButton && ((AbstractButton)c).isSelected());
protected void paintIcon( Component c, Graphics2D g ) {
boolean indeterminate = isIndeterminate( c );
boolean selected = indeterminate || isSelected( c );
boolean isFocused = FlatUIUtils.isPermanentFocusOwner( c );
float bw = selected
? (disabledSelectedBorderWidth != Float.MIN_VALUE && !c.isEnabled()
? disabledSelectedBorderWidth
: (selectedBorderWidth != Float.MIN_VALUE ? selectedBorderWidth : borderWidth))
: borderWidth;
// paint focused border
if( FlatUIUtils.isPermanentFocusOwner( c ) && focusWidth > 0 ) {
g2.setColor( focusColor );
paintFocusBorder( g2 );
if( isFocused && focusWidth > 0 && FlatButtonUI.isFocusPainted( c ) ) {
g.setColor( getFocusColor( c ) );
paintFocusBorder( c, g );
}
// paint border
g2.setColor( FlatButtonUI.buttonStateColor( c,
selected ? selectedBorderColor : borderColor,
disabledBorderColor,
selected && selectedFocusedBorderColor != null ? selectedFocusedBorderColor : focusedBorderColor,
hoverBorderColor,
null ) );
paintBorder( g2 );
g.setColor( getBorderColor( c, selected ) );
paintBorder( c, g, bw );
// paint background
FlatUIUtils.setColor( g2, FlatButtonUI.buttonStateColor( c,
selected ? selectedBackground : background,
disabledBackground,
focusedBackground,
selected && selectedHoverBackground != null ? selectedHoverBackground : hoverBackground,
selected && selectedPressedBackground != null ? selectedPressedBackground : pressedBackground ),
background );
paintBackground( g2 );
Color bg = FlatUIUtils.deriveColor( getBackground( c, selected ),
selected ? selectedBackground : background );
if( bg.getAlpha() < 255 ) {
// fill background with default color before filling with non-opaque background
g.setColor( selected ? selectedBackground : background );
paintBackground( c, g, bw );
}
g.setColor( bg );
paintBackground( c, g, bw );
// paint checkmark
if( selected || indeterminate ) {
g2.setColor( c.isEnabled() ? checkmarkColor : disabledCheckmarkColor );
if( selected ) {
g.setColor( getCheckmarkColor( c ) );
if( indeterminate )
paintIndeterminate( g2 );
paintIndeterminate( c, g );
else
paintCheckmark( g2 );
paintCheckmark( c, g );
}
}
protected void paintFocusBorder( Graphics2D g2 ) {
// the outline focus border is painted outside of the icon
int wh = ICON_SIZE - 1 + (focusWidth * 2);
int arcwh = arc + (focusWidth * 2);
g2.fillRoundRect( -focusWidth + 1, -focusWidth, wh, wh, arcwh, arcwh );
protected void paintFocusBorder( Component c, Graphics2D g ) {
// the outer focus border is painted outside of the icon
float wh = ICON_SIZE - 1 + (focusWidth * 2);
float arcwh = arc + (focusWidth * 2);
g.fill( new RoundRectangle2D.Float( -focusWidth + 1, -focusWidth, wh, wh, arcwh, arcwh ) );
}
protected void paintBorder( Graphics2D g2 ) {
protected void paintBorder( Component c, Graphics2D g, float borderWidth ) {
if( borderWidth == 0 )
return;
int arcwh = arc;
g2.fillRoundRect( 1, 0, 14, 14, arcwh, arcwh );
g.fillRoundRect( 1, 0, 14, 14, arcwh, arcwh );
}
protected void paintBackground( Graphics2D g2 ) {
int arcwh = arc - 1;
g2.fillRoundRect( 2, 1, 12, 12, arcwh, arcwh );
protected void paintBackground( Component c, Graphics2D g, float borderWidth ) {
float xy = borderWidth;
float wh = 14 - (borderWidth * 2);
float arcwh = arc - borderWidth;
g.fill( new RoundRectangle2D.Float( 1 + xy, xy, wh, wh, arcwh, arcwh ) );
}
protected void paintCheckmark( Graphics2D g2 ) {
protected void paintCheckmark( Component c, Graphics2D g ) {
Path2D.Float path = new Path2D.Float();
path.moveTo( 4.5f, 7.5f );
path.lineTo( 6.6f, 10f );
path.lineTo( 11.25f, 3.5f );
g2.setStroke( new BasicStroke( 1.9f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) );
g2.draw( path );
g.setStroke( new BasicStroke( 1.9f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) );
g.draw( path );
}
protected void paintIndeterminate( Graphics2D g2 ) {
g2.fill( new RoundRectangle2D.Float( 3.75f, 5.75f, 8.5f, 2.5f, 2f, 2f ) );
protected void paintIndeterminate( Component c, Graphics2D g ) {
g.fill( new RoundRectangle2D.Float( 3.75f, 5.75f, 8.5f, 2.5f, 2f, 2f ) );
}
protected boolean isIndeterminate( Component c ) {
return c instanceof JComponent && clientPropertyEquals( (JComponent) c, SELECTED_STATE, SELECTED_STATE_INDETERMINATE );
}
protected boolean isSelected( Component c ) {
return c instanceof AbstractButton && ((AbstractButton)c).isSelected();
}
/** @since 2 */
public float getFocusWidth() {
return focusWidth;
}
protected Color getFocusColor( Component c ) {
return focusColor;
}
protected Color getBorderColor( Component c, boolean selected ) {
return FlatButtonUI.buttonStateColor( c,
selected ? selectedBorderColor : borderColor,
(selected && disabledSelectedBorderColor != null) ? disabledSelectedBorderColor : disabledBorderColor,
(selected && focusedSelectedBorderColor != null) ? focusedSelectedBorderColor : focusedBorderColor,
(selected && hoverSelectedBorderColor != null) ? hoverSelectedBorderColor : hoverBorderColor,
(selected && pressedSelectedBorderColor != null) ? pressedSelectedBorderColor : pressedBorderColor );
}
protected Color getBackground( Component c, boolean selected ) {
return FlatButtonUI.buttonStateColor( c,
selected ? selectedBackground : background,
(selected && disabledSelectedBackground != null) ? disabledSelectedBackground : disabledBackground,
(selected && focusedSelectedBackground != null) ? focusedSelectedBackground : focusedBackground,
(selected && hoverSelectedBackground != null) ? hoverSelectedBackground : hoverBackground,
(selected && pressedSelectedBackground != null) ? pressedSelectedBackground : pressedBackground );
}
protected Color getCheckmarkColor( Component c ) {
return FlatButtonUI.buttonStateColor( c,
checkmarkColor,
disabledCheckmarkColor,
focusedCheckmarkColor,
hoverCheckmarkColor,
pressedCheckmarkColor );
}
}

View File

@@ -21,30 +21,44 @@ import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.geom.Path2D;
import java.util.Map;
import javax.swing.AbstractButton;
import javax.swing.JMenuItem;
import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatStylingSupport;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
/**
* Icon for {@link javax.swing.JCheckBoxMenuItem}.
*
* @uiDefault MenuItemCheckBox.icon.checkmarkColor Color
* @uiDefault MenuItemCheckBox.icon.disabledCheckmarkColor Color
* @uiDefault Menu.selectionForeground Color
* @uiDefault CheckBoxMenuItem.icon.checkmarkColor Color
* @uiDefault CheckBoxMenuItem.icon.disabledCheckmarkColor Color
* @uiDefault MenuItem.selectionForeground Color
* @uiDefault MenuItem.selectionType String
*
* @author Karl Tauber
*/
public class FlatCheckBoxMenuItemIcon
extends FlatAbstractIcon
{
protected final Color checkmarkColor = UIManager.getColor( "MenuItemCheckBox.icon.checkmarkColor" );
protected final Color disabledCheckmarkColor = UIManager.getColor( "MenuItemCheckBox.icon.disabledCheckmarkColor" );
protected final Color selectionForeground = UIManager.getColor( "Menu.selectionForeground" );
@Styleable protected Color checkmarkColor = UIManager.getColor( "CheckBoxMenuItem.icon.checkmarkColor" );
@Styleable protected Color disabledCheckmarkColor = UIManager.getColor( "CheckBoxMenuItem.icon.disabledCheckmarkColor" );
@Styleable protected Color selectionForeground = UIManager.getColor( "MenuItem.selectionForeground" );
public FlatCheckBoxMenuItemIcon() {
super( 15, 15, null );
}
/** @since 2 */
public Object applyStyleProperty( String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
}
/** @since 2 */
public Map<String, Class<?>> getStyleableInfos() {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
}
@Override
protected void paintIcon( Component c, Graphics2D g2 ) {
boolean selected = (c instanceof AbstractButton) && ((AbstractButton)c).isSelected();
@@ -66,10 +80,15 @@ public class FlatCheckBoxMenuItemIcon
g2.draw( path );
}
private Color getCheckmarkColor( Component c ) {
if( c instanceof JMenuItem && ((JMenuItem)c).isArmed() )
protected Color getCheckmarkColor( Component c ) {
if( c instanceof JMenuItem && ((JMenuItem)c).isArmed() && !isUnderlineSelection() )
return selectionForeground;
return c.isEnabled() ? checkmarkColor : disabledCheckmarkColor;
}
protected boolean isUnderlineSelection() {
// not storing value of "MenuItem.selectionType" in class to allow changing at runtime
return "underline".equals( UIManager.getString( "MenuItem.selectionType" ) );
}
}

View File

@@ -0,0 +1,98 @@
/*
* Copyright 2021 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.icons;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
import java.util.Map;
import javax.swing.AbstractButton;
import javax.swing.ButtonModel;
import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatStylingSupport;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatUIUtils;
/**
* "clear" icon for search fields.
*
* @uiDefault SearchField.clearIconColor Color
* @uiDefault SearchField.clearIconHoverColor Color
* @uiDefault SearchField.clearIconPressedColor Color
*
* @author Karl Tauber
* @since 1.5
*/
public class FlatClearIcon
extends FlatAbstractIcon
{
@Styleable protected Color clearIconColor = UIManager.getColor( "SearchField.clearIconColor" );
@Styleable protected Color clearIconHoverColor = UIManager.getColor( "SearchField.clearIconHoverColor" );
@Styleable protected Color clearIconPressedColor = UIManager.getColor( "SearchField.clearIconPressedColor" );
public FlatClearIcon() {
super( 16, 16, null );
}
/** @since 2 */
public Object applyStyleProperty( String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
}
/** @since 2 */
public Map<String, Class<?>> getStyleableInfos() {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
}
@Override
protected void paintIcon( Component c, Graphics2D g ) {
if( c instanceof AbstractButton ) {
ButtonModel model = ((AbstractButton)c).getModel();
if( model.isPressed() || model.isRollover() ) {
/*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="#7F8B91" fill-opacity=".5" fill-rule="evenodd" d="M8,1.75 C11.4517797,1.75 14.25,4.54822031 14.25,8 C14.25,11.4517797 11.4517797,14.25 8,14.25 C4.54822031,14.25 1.75,11.4517797 1.75,8 C1.75,4.54822031 4.54822031,1.75 8,1.75 Z M10.5,4.5 L8,7 L5.5,4.5 L4.5,5.5 L7,8 L4.5,10.5 L5.5,11.5 L8,9 L10.5,11.5 L11.5,10.5 L9,8 L11.5,5.5 L10.5,4.5 Z"/>
</svg>
*/
// paint filled circle with cross
g.setColor( model.isPressed() ? clearIconPressedColor : clearIconHoverColor );
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
path.append( new Ellipse2D.Float( 1.75f, 1.75f, 12.5f, 12.5f ), false );
path.append( FlatUIUtils.createPath( 4.5,5.5, 5.5,4.5, 8,7, 10.5,4.5, 11.5,5.5, 9,8, 11.5,10.5, 10.5,11.5, 8,9, 5.5,11.5, 4.5,10.5, 7,8 ), false );
g.fill( path );
return;
}
}
/*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="none" stroke="#7F8B91" stroke-linecap="square" stroke-opacity=".5" d="M5,5 L11,11 M5,11 L11,5"/>
</svg>
*/
// paint cross
g.setColor( clearIconColor );
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
path.append( new Line2D.Float( 5,5, 11,11 ), false );
path.append( new Line2D.Float( 5,11, 11,5 ), false );
g.draw( path );
}
}

View File

@@ -17,34 +17,28 @@
package com.formdev.flatlaf.icons;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.geom.Path2D;
import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatUIUtils;
/**
* "descendingSort" icon for {@link javax.swing.table.JTableHeader}.
*
* @uiDefault Component.arrowType String triangle (default) or chevron
* @uiDefault Component.arrowType String chevron (default) or triangle
* @uiDefault Table.sortIconColor Color
*
* @author Karl Tauber
*/
public class FlatDescendingSortIcon
extends FlatAbstractIcon
extends FlatAscendingSortIcon
{
protected final boolean chevron = "chevron".equals( UIManager.getString( "Component.arrowType" ) );
protected final Color sortIconColor = UIManager.getColor( "Table.sortIconColor" );
public FlatDescendingSortIcon() {
super( 10, 5, null );
super();
}
@Override
protected void paintIcon( Component c, Graphics2D g ) {
g.setColor( sortIconColor );
protected void paintArrow( Component c, Graphics2D g, boolean chevron ) {
if( chevron ) {
// chevron arrow
Path2D path = FlatUIUtils.createPath( false, 1,0, 5,4, 9,0 );

View File

@@ -22,8 +22,11 @@ import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D;
import java.util.Map;
import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatButtonUI;
import com.formdev.flatlaf.ui.FlatStylingSupport;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatUIUtils;
/**
@@ -31,6 +34,8 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
*
* @uiDefault Component.focusWidth int
* @uiDefault Component.focusColor Color
* @uiDefault HelpButton.innerFocusWidth int or float optional; defaults to Component.innerFocusWidth
* @uiDefault HelpButton.borderWidth int optional; default is 1
* @uiDefault HelpButton.borderColor Color
* @uiDefault HelpButton.disabledBorderColor Color
* @uiDefault HelpButton.focusedBorderColor Color
@@ -48,27 +53,37 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
public class FlatHelpButtonIcon
extends FlatAbstractIcon
{
protected final int focusWidth = UIManager.getInt( "Component.focusWidth" );
protected final Color focusColor = UIManager.getColor( "Component.focusColor" );
@Styleable protected int focusWidth = UIManager.getInt( "Component.focusWidth" );
@Styleable protected Color focusColor = UIManager.getColor( "Component.focusColor" );
@Styleable protected float innerFocusWidth = FlatUIUtils.getUIFloat( "HelpButton.innerFocusWidth", FlatUIUtils.getUIFloat( "Component.innerFocusWidth", 0 ) );
@Styleable protected int borderWidth = FlatUIUtils.getUIInt( "HelpButton.borderWidth", 1 );
protected final Color borderColor = UIManager.getColor( "HelpButton.borderColor" );
protected final Color disabledBorderColor = UIManager.getColor( "HelpButton.disabledBorderColor" );
protected final Color focusedBorderColor = UIManager.getColor( "HelpButton.focusedBorderColor" );
protected final Color hoverBorderColor = UIManager.getColor( "HelpButton.hoverBorderColor" );
protected final Color background = UIManager.getColor( "HelpButton.background" );
protected final Color disabledBackground = UIManager.getColor( "HelpButton.disabledBackground" );
protected final Color focusedBackground = UIManager.getColor( "HelpButton.focusedBackground" );
protected final Color hoverBackground = UIManager.getColor( "HelpButton.hoverBackground" );
protected final Color pressedBackground = UIManager.getColor( "HelpButton.pressedBackground" );
protected final Color questionMarkColor = UIManager.getColor( "HelpButton.questionMarkColor" );
protected final Color disabledQuestionMarkColor = UIManager.getColor( "HelpButton.disabledQuestionMarkColor" );
protected final int iconSize = 22 + (focusWidth * 2);
@Styleable protected Color borderColor = UIManager.getColor( "HelpButton.borderColor" );
@Styleable protected Color disabledBorderColor = UIManager.getColor( "HelpButton.disabledBorderColor" );
@Styleable protected Color focusedBorderColor = UIManager.getColor( "HelpButton.focusedBorderColor" );
@Styleable protected Color hoverBorderColor = UIManager.getColor( "HelpButton.hoverBorderColor" );
@Styleable protected Color background = UIManager.getColor( "HelpButton.background" );
@Styleable protected Color disabledBackground = UIManager.getColor( "HelpButton.disabledBackground" );
@Styleable protected Color focusedBackground = UIManager.getColor( "HelpButton.focusedBackground" );
@Styleable protected Color hoverBackground = UIManager.getColor( "HelpButton.hoverBackground" );
@Styleable protected Color pressedBackground = UIManager.getColor( "HelpButton.pressedBackground" );
@Styleable protected Color questionMarkColor = UIManager.getColor( "HelpButton.questionMarkColor" );
@Styleable protected Color disabledQuestionMarkColor = UIManager.getColor( "HelpButton.disabledQuestionMarkColor" );
public FlatHelpButtonIcon() {
super( 0, 0, null );
}
/** @since 2 */
public Object applyStyleProperty( String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
}
/** @since 2 */
public Map<String, Class<?>> getStyleableInfos() {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
}
@Override
protected void paintIcon( Component c, Graphics2D g2 ) {
/*
@@ -84,12 +99,18 @@ public class FlatHelpButtonIcon
boolean enabled = c.isEnabled();
boolean focused = FlatUIUtils.isPermanentFocusOwner( c );
// paint focused border
if( focused ) {
float xy = 0.5f;
float wh = iconSize() - 1;
// paint outer focus border
if( focused && FlatButtonUI.isFocusPainted( c ) ) {
g2.setColor( focusColor );
g2.fill( new Ellipse2D.Float( 0.5f, 0.5f, iconSize - 1, iconSize - 1 ) );
g2.fill( new Ellipse2D.Float( xy, xy, wh, wh ) );
}
xy += focusWidth;
wh -= (focusWidth * 2);
// paint border
g2.setColor( FlatButtonUI.buttonStateColor( c,
borderColor,
@@ -97,16 +118,28 @@ public class FlatHelpButtonIcon
focusedBorderColor,
hoverBorderColor,
null ) );
g2.fill( new Ellipse2D.Float( focusWidth + 0.5f, focusWidth + 0.5f, 21, 21 ) );
g2.fill( new Ellipse2D.Float( xy, xy, wh, wh ) );
xy += borderWidth;
wh -= (borderWidth * 2);
// paint inner focus border
if( innerFocusWidth > 0 && focused && FlatButtonUI.isFocusPainted( c ) ) {
g2.setColor( focusColor );
g2.fill( new Ellipse2D.Float( xy, xy, wh, wh ) );
xy += innerFocusWidth;
wh -= (innerFocusWidth * 2);
}
// paint background
FlatUIUtils.setColor( g2, FlatButtonUI.buttonStateColor( c,
g2.setColor( FlatUIUtils.deriveColor( FlatButtonUI.buttonStateColor( c,
background,
disabledBackground,
focusedBackground,
hoverBackground,
pressedBackground ), background );
g2.fill( new Ellipse2D.Float( focusWidth + 1.5f, focusWidth + 1.5f, 19, 19 ) );
pressedBackground ), background ) );
g2.fill( new Ellipse2D.Float( xy, xy, wh, wh ) );
// paint question mark
Path2D q = new Path2D.Float();
@@ -129,11 +162,15 @@ public class FlatHelpButtonIcon
@Override
public int getIconWidth() {
return scale( iconSize );
return scale( iconSize() );
}
@Override
public int getIconHeight() {
return scale( iconSize );
return scale( iconSize() );
}
private int iconSize() {
return 22 + (focusWidth * 2);
}
}

View File

@@ -27,6 +27,7 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
/**
* Base class for internal frame icons.
*
* @uiDefault InternalFrame.buttonSize Dimension
* @uiDefault InternalFrame.buttonHoverBackground Color
* @uiDefault InternalFrame.buttonPressedBackground Color
*
@@ -53,7 +54,7 @@ public abstract class FlatInternalFrameAbstractIcon
protected void paintBackground( Component c, Graphics2D g ) {
Color background = FlatButtonUI.buttonStateColor( c, null, null, null, hoverBackground, pressedBackground );
if( background != null ) {
FlatUIUtils.setColor( g, background, c.getBackground() );
g.setColor( FlatUIUtils.deriveColor( background, c.getBackground() ) );
g.fillRect( 0, 0, width, height );
}
}

View File

@@ -28,8 +28,11 @@ import com.formdev.flatlaf.ui.FlatButtonUI;
/**
* "close" icon for {@link javax.swing.JInternalFrame}.
*
* @uiDefault InternalFrame.buttonHoverBackground Color
* @uiDefault InternalFrame.buttonPressedBackground Color
* @uiDefault InternalFrame.buttonSize Dimension
* @uiDefault InternalFrame.closeHoverBackground Color
* @uiDefault InternalFrame.closePressedBackground Color
* @uiDefault InternalFrame.closeHoverForeground Color
* @uiDefault InternalFrame.closePressedForeground Color
*
* @author Karl Tauber
*/

View File

@@ -24,14 +24,14 @@ import java.awt.geom.Rectangle2D;
import com.formdev.flatlaf.ui.FlatUIUtils;
/**
* "minimize" (actually "restore") icon for {@link javax.swing.JInternalFrame}.
* "restore" (or "minimize") icon for {@link javax.swing.JInternalFrame}.
*
* @author Karl Tauber
*/
public class FlatInternalFrameMinimizeIcon
public class FlatInternalFrameRestoreIcon
extends FlatInternalFrameAbstractIcon
{
public FlatInternalFrameMinimizeIcon() {
public FlatInternalFrameRestoreIcon() {
}
@Override

View File

@@ -21,39 +21,53 @@ import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.geom.Path2D;
import java.util.Map;
import javax.swing.JMenu;
import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatStylingSupport;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
/**
* "arrow" icon for {@link javax.swing.JMenu}.
*
* @uiDefault Component.arrowType String triangle (default) or chevron
* @uiDefault Component.arrowType String chevron (default) or triangle
* @uiDefault Menu.icon.arrowColor Color
* @uiDefault Menu.icon.disabledArrowColor Color
* @uiDefault Menu.selectionForeground Color
* @uiDefault MenuItem.selectionType String
*
* @author Karl Tauber
*/
public class FlatMenuArrowIcon
extends FlatAbstractIcon
{
protected final boolean chevron = "chevron".equals( UIManager.getString( "Component.arrowType" ) );
protected final Color arrowColor = UIManager.getColor( "Menu.icon.arrowColor" );
protected final Color disabledArrowColor = UIManager.getColor( "Menu.icon.disabledArrowColor" );
protected final Color selectionForeground = UIManager.getColor( "Menu.selectionForeground" );
@Styleable protected String arrowType = UIManager.getString( "Component.arrowType" );
@Styleable protected Color arrowColor = UIManager.getColor( "Menu.icon.arrowColor" );
@Styleable protected Color disabledArrowColor = UIManager.getColor( "Menu.icon.disabledArrowColor" );
@Styleable protected Color selectionForeground = UIManager.getColor( "Menu.selectionForeground" );
public FlatMenuArrowIcon() {
super( 6, 10, null );
}
/** @since 2 */
public Object applyStyleProperty( String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
}
/** @since 2 */
public Map<String, Class<?>> getStyleableInfos() {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
}
@Override
protected void paintIcon( Component c, Graphics2D g ) {
if( !c.getComponentOrientation().isLeftToRight() )
g.rotate( Math.toRadians( 180 ), width / 2., height / 2. );
g.setColor( getArrowColor( c ) );
if( chevron ) {
if( FlatUIUtils.isChevron( arrowType ) ) {
// chevron arrow
Path2D path = FlatUIUtils.createPath( false, 1,1, 5,5, 1,9 );
g.setStroke( new BasicStroke( 1f ) );
@@ -64,10 +78,15 @@ public class FlatMenuArrowIcon
}
}
private Color getArrowColor( Component c ) {
if( c instanceof JMenu && ((JMenu)c).isSelected() )
protected Color getArrowColor( Component c ) {
if( c instanceof JMenu && ((JMenu)c).isSelected() && !isUnderlineSelection() )
return selectionForeground;
return c.isEnabled() ? arrowColor : disabledArrowColor;
}
protected boolean isUnderlineSelection() {
// not storing value of "MenuItem.selectionType" in class to allow changing at runtime
return "underline".equals( UIManager.getString( "MenuItem.selectionType" ) );
}
}

View File

@@ -16,46 +16,59 @@
package com.formdev.flatlaf.icons;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
/**
* Icon for {@link javax.swing.JRadioButton}.
*
* Note: If Component.focusWidth is greater than zero, then the outline focus border
* <p>
* <strong>Note</strong>:
* If Component.focusWidth is greater than zero, then the outer focus border
* is painted outside of the icon bounds. Make sure that the radiobutton
* has margins, which are equal or greater than focusWidth.
*
* @uiDefault RadioButton.icon.centerDiameter int
* @uiDefault RadioButton.icon.style String optional; "outlined"/null (default) or "filled"
* @uiDefault RadioButton.icon.centerDiameter int or float
*
* @author Karl Tauber
*/
public class FlatRadioButtonIcon
extends FlatCheckBoxIcon
{
protected final int centerDiameter = FlatUIUtils.getUIInt( "RadioButton.icon.centerDiameter", 8 );
@Styleable protected float centerDiameter = getUIFloat( "RadioButton.icon.centerDiameter", 8, style );
@Override
protected void paintFocusBorder( Graphics2D g2 ) {
// the outline focus border is painted outside of the icon
int wh = ICON_SIZE + (focusWidth * 2);
g2.fillOval( -focusWidth, -focusWidth, wh, wh );
protected String getPropertyPrefix() {
return "RadioButton.";
}
@Override
protected void paintBorder( Graphics2D g2 ) {
g2.fillOval( 0, 0, 15, 15 );
protected void paintFocusBorder( Component c, Graphics2D g ) {
// the outer focus border is painted outside of the icon
float wh = ICON_SIZE + (focusWidth * 2);
g.fill( new Ellipse2D.Float( -focusWidth, -focusWidth, wh, wh ) );
}
@Override
protected void paintBackground( Graphics2D g2 ) {
g2.fillOval( 1, 1, 13, 13 );
protected void paintBorder( Component c, Graphics2D g, float borderWidth ) {
if( borderWidth == 0 )
return;
g.fillOval( 0, 0, 15, 15 );
}
@Override
protected void paintCheckmark( Graphics2D g2 ) {
protected void paintBackground( Component c, Graphics2D g, float borderWidth ) {
float xy = borderWidth;
float wh = 15 - (borderWidth * 2);
g.fill( new Ellipse2D.Float( xy, xy, wh, wh ) );
}
@Override
protected void paintCheckmark( Component c, Graphics2D g ) {
float xy = (ICON_SIZE - centerDiameter) / 2f;
g2.fill( new Ellipse2D.Float( xy, xy, centerDiameter, centerDiameter ) );
g.fill( new Ellipse2D.Float( xy, xy, centerDiameter, centerDiameter ) );
}
}

View File

@@ -0,0 +1,82 @@
/*
* Copyright 2021 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.icons;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.util.Map;
import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatButtonUI;
import com.formdev.flatlaf.ui.FlatStylingSupport;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatUIUtils;
/**
* "search" icon for search fields.
*
* @uiDefault SearchField.searchIconColor Color
* @uiDefault SearchField.searchIconHoverColor Color
* @uiDefault SearchField.searchIconPressedColor Color
*
* @author Karl Tauber
* @since 1.5
*/
public class FlatSearchIcon
extends FlatAbstractIcon
{
@Styleable protected Color searchIconColor = UIManager.getColor( "SearchField.searchIconColor" );
@Styleable protected Color searchIconHoverColor = UIManager.getColor( "SearchField.searchIconHoverColor" );
@Styleable protected Color searchIconPressedColor = UIManager.getColor( "SearchField.searchIconPressedColor" );
public FlatSearchIcon() {
super( 16, 16, null );
}
/** @since 2 */
public Object applyStyleProperty( String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
}
/** @since 2 */
public Map<String, Class<?>> getStyleableInfos() {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
}
@Override
protected void paintIcon( Component c, Graphics2D g ) {
/*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-opacity=".9" fill-rule="evenodd">
<polygon fill="#7F8B91" points="10.813 9.75 14 12.938 12.938 14 9.75 10.813"/>
<path fill="#7F8B91" d="M7,2 C9.76142375,2 12,4.23857625 12,7 C12,9.76142375 9.76142375,12 7,12 C4.23857625,12 2,9.76142375 2,7 C2,4.23857625 4.23857625,2 7,2 Z M7,3 C4.790861,3 3,4.790861 3,7 C3,9.209139 4.790861,11 7,11 C9.209139,11 11,9.209139 11,7 C11,4.790861 9.209139,3 7,3 Z"/>
</g>
</svg>
*/
g.setColor( FlatButtonUI.buttonStateColor( c, searchIconColor, searchIconColor,
null, searchIconHoverColor, searchIconPressedColor ) );
// paint magnifier
Area area = new Area( new Ellipse2D.Float( 2, 2, 10, 10 ) );
area.subtract( new Area( new Ellipse2D.Float( 3, 3, 8, 8 ) ) );
area.add( new Area( FlatUIUtils.createPath( 10.813,9.75, 14,12.938, 12.938,14, 9.75,10.813 ) ) );
g.fill( area );
}
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright 2021 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.icons;
import java.awt.Component;
import java.awt.Graphics2D;
import com.formdev.flatlaf.ui.FlatUIUtils;
/**
* "search with history" icon for search fields.
*
* @author Karl Tauber
* @since 1.5
*/
public class FlatSearchWithHistoryIcon
extends FlatSearchIcon
{
public FlatSearchWithHistoryIcon() {
}
@Override
protected void paintIcon( Component c, Graphics2D g ) {
/*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-opacity=".9" fill-rule="evenodd">
<polygon fill="#7F8B91" points="8.813 9.75 12 12.938 10.938 14 7.75 10.813"/>
<path fill="#7F8B91" d="M5,2 C7.76142375,2 10,4.23857625 10,7 C10,9.76142375 7.76142375,12 5,12 C2.23857625,12 0,9.76142375 0,7 C0,4.23857625 2.23857625,2 5,2 Z M5,3 C2.790861,3 1,4.790861 1,7 C1,9.209139 2.790861,11 5,11 C7.209139,11 9,9.209139 9,7 C9,4.790861 7.209139,3 5,3 Z"/>
<polygon fill="#7F8B91" points="11 7 16 7 13.5 10"/>
</g>
</svg>
*/
// paint magnifier
g.translate( -2, 0 );
super.paintIcon( c, g );
g.translate( 2, 0 );
// paint history arrow
g.fill( FlatUIUtils.createPath( 11,7, 16,7, 13.5,10 ) );
}
}

View File

@@ -0,0 +1,104 @@
/*
* Copyright 2020 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.icons;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
import java.util.Map;
import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatButtonUI;
import com.formdev.flatlaf.ui.FlatStylingSupport;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatUIUtils;
/**
* "close" icon for closable tabs in {@link javax.swing.JTabbedPane}.
*
* @uiDefault TabbedPane.closeSize Dimension
* @uiDefault TabbedPane.closeArc int
* @uiDefault TabbedPane.closeCrossPlainSize float
* @uiDefault TabbedPane.closeCrossFilledSize float
* @uiDefault TabbedPane.closeCrossLineWidth float
* @uiDefault TabbedPane.closeBackground Color
* @uiDefault TabbedPane.closeForeground Color
* @uiDefault TabbedPane.closeHoverBackground Color
* @uiDefault TabbedPane.closeHoverForeground Color
* @uiDefault TabbedPane.closePressedBackground Color
* @uiDefault TabbedPane.closePressedForeground Color
*
* @author Karl Tauber
*/
public class FlatTabbedPaneCloseIcon
extends FlatAbstractIcon
{
@Styleable protected Dimension closeSize = UIManager.getDimension( "TabbedPane.closeSize" );
@Styleable protected int closeArc = UIManager.getInt( "TabbedPane.closeArc" );
@Styleable protected float closeCrossPlainSize = FlatUIUtils.getUIFloat( "TabbedPane.closeCrossPlainSize", 7.5f );
@Styleable protected float closeCrossFilledSize = FlatUIUtils.getUIFloat( "TabbedPane.closeCrossFilledSize", closeCrossPlainSize );
@Styleable protected float closeCrossLineWidth = FlatUIUtils.getUIFloat( "TabbedPane.closeCrossLineWidth", 1f );
@Styleable protected Color closeBackground = UIManager.getColor( "TabbedPane.closeBackground" );
@Styleable protected Color closeForeground = UIManager.getColor( "TabbedPane.closeForeground" );
@Styleable protected Color closeHoverBackground = UIManager.getColor( "TabbedPane.closeHoverBackground" );
@Styleable protected Color closeHoverForeground = UIManager.getColor( "TabbedPane.closeHoverForeground" );
@Styleable protected Color closePressedBackground = UIManager.getColor( "TabbedPane.closePressedBackground" );
@Styleable protected Color closePressedForeground = UIManager.getColor( "TabbedPane.closePressedForeground" );
public FlatTabbedPaneCloseIcon() {
super( 16, 16, null );
}
/** @since 2 */
public Object applyStyleProperty( String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
}
/** @since 2 */
public Map<String, Class<?>> getStyleableInfos() {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
}
@Override
protected void paintIcon( Component c, Graphics2D g ) {
// paint background
Color bg = FlatButtonUI.buttonStateColor( c, closeBackground, null, null, closeHoverBackground, closePressedBackground );
if( bg != null ) {
g.setColor( FlatUIUtils.deriveColor( bg, c.getBackground() ) );
g.fillRoundRect( (width - closeSize.width) / 2, (height - closeSize.height) / 2,
closeSize.width, closeSize.height, closeArc, closeArc );
}
// set cross color
Color fg = FlatButtonUI.buttonStateColor( c, closeForeground, null, null, closeHoverForeground, closePressedForeground );
g.setColor( FlatUIUtils.deriveColor( fg, c.getForeground() ) );
float mx = width / 2;
float my = height / 2;
float r = ((bg != null) ? closeCrossFilledSize : closeCrossPlainSize) / 2;
// paint cross
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
path.append( new Line2D.Float( mx - r, my - r, mx + r, my + r ), false );
path.append( new Line2D.Float( mx - r, my + r, mx + r, my - r ), false );
g.setStroke( new BasicStroke( closeCrossLineWidth ) );
g.draw( path );
}
}

View File

@@ -37,6 +37,8 @@ public class FlatTreeClosedIcon
@Override
protected void paintIcon( Component c, Graphics2D g ) {
FlatTreeCollapsedIcon.setStyleColorFromTreeUI( c, g, ui -> ui.iconClosedColor );
/*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<polygon fill="#6E6E6E" fill-rule="evenodd" points="1 2 6 2 8 4 15 4 15 13 1 13"/>

View File

@@ -19,13 +19,18 @@ package com.formdev.flatlaf.icons;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics2D;
import java.util.function.Function;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.plaf.TreeUI;
import com.formdev.flatlaf.ui.FlatTreeUI;
import com.formdev.flatlaf.ui.FlatUIUtils;
/**
* "collapsed" icon for {@link javax.swing.JTree}.
*
* @uiDefault Component.arrowType String triangle (default) or chevron
* @uiDefault Component.arrowType String chevron (default) or triangle
* @uiDefault Tree.icon.collapsedColor Color
*
* @author Karl Tauber
@@ -41,13 +46,17 @@ public class FlatTreeCollapsedIcon
FlatTreeCollapsedIcon( Color color ) {
super( 11, 11, color );
chevron = "chevron".equals( UIManager.getString( "Component.arrowType" ) );
chevron = FlatUIUtils.isChevron( UIManager.getString( "Component.arrowType" ) );
}
@Override
protected void paintIcon( Component c, Graphics2D g ) {
setStyleColorFromTreeUI( c, g );
rotate( c, g );
String arrowType = getStyleFromTreeUI( c, ui -> ui.iconArrowType );
boolean chevron = (arrowType != null) ? FlatUIUtils.isChevron( arrowType ) : this.chevron;
if( chevron ) {
// chevron arrow
g.fill( FlatUIUtils.createPath( 3,1, 3,2.5, 6,5.5, 3,8.5, 3,10, 4.5,10, 9,5.5, 4.5,1 ) );
@@ -57,8 +66,34 @@ public class FlatTreeCollapsedIcon
}
}
void setStyleColorFromTreeUI( Component c, Graphics2D g ) {
setStyleColorFromTreeUI( c, g, ui -> ui.iconCollapsedColor );
}
void rotate( Component c, Graphics2D g ) {
if( !c.getComponentOrientation().isLeftToRight() )
g.rotate( Math.toRadians( 180 ), width / 2., height / 2. );
}
/**
* Because this icons are always shared for all trees,
* get icon specific style from FlatTreeUI.
*/
static <T> T getStyleFromTreeUI( Component c, Function<FlatTreeUI, T> f ) {
JTree tree = (c instanceof JTree)
? (JTree) c
: (JTree) SwingUtilities.getAncestorOfClass( JTree.class, c );
if( tree != null ) {
TreeUI ui = tree.getUI();
if( ui instanceof FlatTreeUI )
return f.apply( (FlatTreeUI) ui );
}
return null;
}
static void setStyleColorFromTreeUI( Component c, Graphics2D g, Function<FlatTreeUI, Color> f ) {
Color color = getStyleFromTreeUI( c, f );
if( color != null )
g.setColor( color );
}
}

View File

@@ -34,6 +34,11 @@ public class FlatTreeExpandedIcon
super( UIManager.getColor( "Tree.icon.expandedColor" ) );
}
@Override
void setStyleColorFromTreeUI( Component c, Graphics2D g ) {
setStyleColorFromTreeUI( c, g, ui -> ui.iconExpandedColor );
}
@Override
void rotate( Component c, Graphics2D g ) {
g.rotate( Math.toRadians( 90 ), width / 2., height / 2. );

View File

@@ -37,6 +37,8 @@ public class FlatTreeLeafIcon
@Override
protected void paintIcon( Component c, Graphics2D g ) {
FlatTreeCollapsedIcon.setStyleColorFromTreeUI( c, g, ui -> ui.iconLeafColor );
/*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd">

View File

@@ -37,6 +37,8 @@ public class FlatTreeOpenIcon
@Override
protected void paintIcon( Component c, Graphics2D g ) {
FlatTreeCollapsedIcon.setStyleColorFromTreeUI( c, g, ui -> ui.iconOpenColor );
/*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd">

View File

@@ -0,0 +1,76 @@
/*
* Copyright 2020 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.icons;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics2D;
import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatButtonUI;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.util.HiDPIUtils;
/**
* Base class for window icons.
*
* @uiDefault TitlePane.buttonSize Dimension
* @uiDefault TitlePane.buttonHoverBackground Color
* @uiDefault TitlePane.buttonPressedBackground Color
*
* @author Karl Tauber
*/
public abstract class FlatWindowAbstractIcon
extends FlatAbstractIcon
{
private final Color hoverBackground;
private final Color pressedBackground;
public FlatWindowAbstractIcon() {
this( UIManager.getDimension( "TitlePane.buttonSize" ),
UIManager.getColor( "TitlePane.buttonHoverBackground" ),
UIManager.getColor( "TitlePane.buttonPressedBackground" ) );
}
public FlatWindowAbstractIcon( Dimension size, Color hoverBackground, Color pressedBackground ) {
super( size.width, size.height, null );
this.hoverBackground = hoverBackground;
this.pressedBackground = pressedBackground;
}
@Override
protected void paintIcon( Component c, Graphics2D g ) {
paintBackground( c, g );
g.setColor( getForeground( c ) );
HiDPIUtils.paintAtScale1x( g, 0, 0, width, height, this::paintIconAt1x );
}
protected abstract void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor );
protected void paintBackground( Component c, Graphics2D g ) {
Color background = FlatButtonUI.buttonStateColor( c, null, null, null, hoverBackground, pressedBackground );
if( background != null ) {
g.setColor( FlatUIUtils.deriveColor( background, c.getBackground() ) );
g.fillRect( 0, 0, width, height );
}
}
protected Color getForeground( Component c ) {
return c.getForeground();
}
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright 2020 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.icons;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatButtonUI;
/**
* "close" icon for windows (frames and dialogs).
*
* @uiDefault TitlePane.closeHoverBackground Color
* @uiDefault TitlePane.closePressedBackground Color
* @uiDefault TitlePane.closeHoverForeground Color
* @uiDefault TitlePane.closePressedForeground Color
*
* @author Karl Tauber
*/
public class FlatWindowCloseIcon
extends FlatWindowAbstractIcon
{
private final Color hoverForeground = UIManager.getColor( "TitlePane.closeHoverForeground" );
private final Color pressedForeground = UIManager.getColor( "TitlePane.closePressedForeground" );
public FlatWindowCloseIcon() {
super( UIManager.getDimension( "TitlePane.buttonSize" ),
UIManager.getColor( "TitlePane.closeHoverBackground" ),
UIManager.getColor( "TitlePane.closePressedBackground" ) );
}
@Override
protected void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
int iwh = (int) (10 * scaleFactor);
int ix = x + ((width - iwh) / 2);
int iy = y + ((height - iwh) / 2);
int ix2 = ix + iwh - 1;
int iy2 = iy + iwh - 1;
int thickness = (int) scaleFactor;
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
path.append( new Line2D.Float( ix, iy, ix2, iy2 ), false );
path.append( new Line2D.Float( ix, iy2, ix2, iy ), false );
g.setStroke( new BasicStroke( thickness ) );
g.draw( path );
}
@Override
protected Color getForeground( Component c ) {
return FlatButtonUI.buttonStateColor( c, c.getForeground(), null, null, hoverForeground, pressedForeground );
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2020 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.icons;
import java.awt.Graphics2D;
/**
* "iconify" icon for windows (frames and dialogs).
*
* @author Karl Tauber
*/
public class FlatWindowIconifyIcon
extends FlatWindowAbstractIcon
{
public FlatWindowIconifyIcon() {
}
@Override
protected void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
int iw = (int) (10 * scaleFactor);
int ih = (int) scaleFactor;
int ix = x + ((width - iw) / 2);
int iy = y + ((height - ih) / 2);
g.fillRect( ix, iy, iw, ih );
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright 2020 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.icons;
import java.awt.Graphics2D;
import com.formdev.flatlaf.ui.FlatUIUtils;
/**
* "maximize" icon for windows (frames and dialogs).
*
* @author Karl Tauber
*/
public class FlatWindowMaximizeIcon
extends FlatWindowAbstractIcon
{
public FlatWindowMaximizeIcon() {
}
@Override
protected void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
int iwh = (int) (10 * scaleFactor);
int ix = x + ((width - iwh) / 2);
int iy = y + ((height - iwh) / 2);
int thickness = (int) scaleFactor;
g.fill( FlatUIUtils.createRectangle( ix, iy, iwh, iwh, thickness ) );
}
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright 2020 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.icons;
import java.awt.Graphics2D;
import java.awt.geom.Area;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import com.formdev.flatlaf.ui.FlatUIUtils;
/**
* "restore" icon for windows (frames and dialogs).
*
* @author Karl Tauber
*/
public class FlatWindowRestoreIcon
extends FlatWindowAbstractIcon
{
public FlatWindowRestoreIcon() {
}
@Override
protected void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
int iwh = (int) (10 * scaleFactor);
int ix = x + ((width - iwh) / 2);
int iy = y + ((height - iwh) / 2);
int thickness = (int) scaleFactor;
int rwh = (int) (8 * scaleFactor);
int ro2 = iwh - rwh;
Path2D r1 = FlatUIUtils.createRectangle( ix + ro2, iy, rwh, rwh, thickness );
Path2D r2 = FlatUIUtils.createRectangle( ix, iy + ro2, rwh, rwh, thickness );
Area area = new Area( r1 );
area.subtract( new Area( new Rectangle2D.Float( ix, iy + ro2, rwh, rwh ) ) );
g.fill( area );
g.fill( r2 );
}
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright 2021 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.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.
*
* @author Karl Tauber
*/
interface EmptyPackage
{
}

View File

@@ -17,15 +17,14 @@
package com.formdev.flatlaf.ui;
import static com.formdev.flatlaf.util.UIScale.scale;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Path2D;
import javax.swing.JComponent;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicArrowButton;
@@ -40,33 +39,34 @@ public class FlatArrowButton
{
public static final int DEFAULT_ARROW_WIDTH = 8;
private final boolean chevron;
private final Color foreground;
private final Color disabledForeground;
private final Color hoverForeground;
private final Color hoverBackground;
protected boolean chevron;
protected Color foreground;
protected Color disabledForeground;
protected Color hoverForeground;
protected Color hoverBackground;
protected Color pressedForeground;
protected Color pressedBackground;
private int arrowWidth = DEFAULT_ARROW_WIDTH;
private int xOffset = 0;
private int yOffset = 0;
private float xOffset = 0;
private float yOffset = 0;
private boolean hover;
private boolean pressed;
public FlatArrowButton( int direction, String type, Color foreground, Color disabledForeground,
Color hoverForeground, Color hoverBackground )
Color hoverForeground, Color hoverBackground, Color pressedForeground, Color pressedBackground )
{
super( direction, Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE );
this.chevron = "chevron".equals( type );
this.foreground = foreground;
this.disabledForeground = disabledForeground;
this.hoverForeground = hoverForeground;
this.hoverBackground = hoverBackground;
updateStyle( type, foreground, disabledForeground, hoverForeground, hoverBackground,
pressedForeground, pressedBackground );
setOpaque( false );
setBorder( null );
if( hoverForeground != null || hoverBackground != null ) {
if( hoverForeground != null || hoverBackground != null ||
pressedForeground != null || pressedBackground != null )
{
addMouseListener( new MouseAdapter() {
@Override
public void mouseEntered( MouseEvent e ) {
@@ -79,10 +79,35 @@ public class FlatArrowButton
hover = false;
repaint();
}
@Override
public void mousePressed( MouseEvent e ) {
pressed = true;
repaint();
}
@Override
public void mouseReleased( MouseEvent e ) {
pressed = false;
repaint();
}
} );
}
}
/** @since 2 */
public void updateStyle( String type, Color foreground, Color disabledForeground,
Color hoverForeground, Color hoverBackground, Color pressedForeground, Color pressedBackground )
{
this.chevron = FlatUIUtils.isChevron( type );
this.foreground = foreground;
this.disabledForeground = disabledForeground;
this.hoverForeground = hoverForeground;
this.hoverBackground = hoverBackground;
this.pressedForeground = pressedForeground;
this.pressedBackground = pressedBackground;
}
public int getArrowWidth() {
return arrowWidth;
}
@@ -95,22 +120,49 @@ public class FlatArrowButton
return hover;
}
public int getXOffset() {
protected boolean isPressed() {
return pressed;
}
public float getXOffset() {
return xOffset;
}
public void setXOffset( int xOffset ) {
public void setXOffset( float xOffset ) {
this.xOffset = xOffset;
}
public int getYOffset() {
public float getYOffset() {
return yOffset;
}
public void setYOffset( int yOffset ) {
public void setYOffset( float yOffset ) {
this.yOffset = yOffset;
}
protected Color deriveBackground( Color background ) {
return background;
}
protected Color deriveForeground( Color foreground ) {
return FlatUIUtils.deriveColor( foreground, this.foreground );
}
/**
* Returns the color used to paint the arrow.
*
* @since 1.2
*/
protected Color getArrowColor() {
return isEnabled()
? (pressedForeground != null && isPressed()
? pressedForeground
: (hoverForeground != null && isHover()
? hoverForeground
: foreground))
: disabledForeground;
}
@Override
public Dimension getPreferredSize() {
return scale( super.getPreferredSize() );
@@ -123,58 +175,42 @@ public class FlatArrowButton
@Override
public void paint( Graphics g ) {
Graphics2D g2 = (Graphics2D)g;
FlatUIUtils.setRenderingHints( g2 );
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g );
int width = getWidth();
int height = getHeight();
boolean enabled = isEnabled();
// paint hover or pressed background
if( isEnabled() ) {
Color background = (pressedBackground != null && isPressed())
? pressedBackground
: (hoverBackground != null && isHover()
? hoverBackground
: null);
// paint hover background
if( enabled && isHover() && hoverBackground != null ) {
g.setColor( hoverBackground );
g.fillRect( 0, 0, width, height );
if( background != null ) {
g.setColor( deriveBackground( background ) );
paintBackground( (Graphics2D) g );
}
}
int direction = getDirection();
boolean vert = (direction == NORTH || direction == SOUTH);
int w = scale( arrowWidth + (chevron ? 0 : 1) );
int h = scale( (arrowWidth / 2) + (chevron ? 0 : 1) );
int rw = vert ? w : h;
int rh = vert ? h : w;
int x = Math.round( (width - rw) / 2f + scale( (float) xOffset ) );
int y = Math.round( (height - rh) / 2f + scale( (float) yOffset ) );
// optimization for small chevron arrows (e.g. OneTouchButtons in SplitPane)
if( x + rw >= width && x > 0 )
x--;
if( y + rh >= height && y > 0 )
y--;
// paint arrow
g.setColor( enabled
? (isHover() && hoverForeground != null ? hoverForeground : foreground)
: disabledForeground );
g.translate( x, y );
Shape arrowShape = createArrowShape( direction, chevron, w, h );
if( chevron ) {
g2.setStroke( new BasicStroke( scale( 1f ) ) );
g2.draw( arrowShape );
} else {
// triangle
g2.fill( arrowShape );
}
g.translate( -x, -y );
g.setColor( deriveForeground( getArrowColor() ) );
paintArrow( (Graphics2D) g );
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
}
public static Shape createArrowShape( int direction, boolean chevron, float w, float h ) {
switch( direction ) {
case NORTH: return FlatUIUtils.createPath( !chevron, 0,h, (w / 2f),0, w,h );
case SOUTH: return FlatUIUtils.createPath( !chevron, 0,0, (w / 2f),h, w,0 );
case WEST: return FlatUIUtils.createPath( !chevron, h,0, 0,(w / 2f), h,w );
case EAST: return FlatUIUtils.createPath( !chevron, 0,0, h,(w / 2f), 0,w );
default: return new Path2D.Float();
}
protected void paintBackground( Graphics2D g ) {
g.fillRect( 0, 0, getWidth(), getHeight() );
}
protected void paintArrow( Graphics2D g ) {
boolean vert = (direction == NORTH || direction == SOUTH);
int x = 0;
// move arrow for round borders
Container parent = getParent();
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 );
}
}

View File

@@ -22,49 +22,84 @@ import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.KeyboardFocusManager;
import java.awt.Paint;
import java.util.Map;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.JViewport;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.plaf.basic.BasicBorders;
import javax.swing.text.JTextComponent;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableBorder;
import com.formdev.flatlaf.util.DerivedColor;
/**
* Border for various components (e.g. {@link javax.swing.JTextField}).
*
* <p>
* There is empty space around the component border, if Component.focusWidth is greater than zero,
* which is used to paint focus border.
*
* Because there is empty space (if focus border is not painted),
* which is used to paint outer focus border.
* <p>
* Because there is empty space (if outer focus border is not painted),
* UI delegates that use this border (or subclasses) must invoke
* {@link FlatUIUtils#paintParentBackground} to paint the empty space correctly.
* {@link FlatUIUtils#paintParentBackground} to fill the empty space correctly.
*
* @uiDefault Component.focusWidth int
* @uiDefault Component.innerFocusWidth int or float
* @uiDefault Component.focusColor Color
* @uiDefault Component.borderColor Color
* @uiDefault Component.disabledBorderColor Color
* @uiDefault Component.focusedBorderColor Color
* @uiDefault Component.focusWidth int
* @uiDefault Component.innerFocusWidth int or float
* @uiDefault Component.innerOutlineWidth int or float
* @uiDefault Component.borderWidth int or float
*
* @uiDefault Component.focusColor Color
* @uiDefault Component.borderColor Color
* @uiDefault Component.disabledBorderColor Color
* @uiDefault Component.focusedBorderColor Color
*
* @uiDefault Component.error.borderColor Color
* @uiDefault Component.error.focusedBorderColor Color
* @uiDefault Component.warning.borderColor Color
* @uiDefault Component.warning.focusedBorderColor Color
* @uiDefault Component.custom.borderColor Color
*
* @author Karl Tauber
*/
public class FlatBorder
extends BasicBorders.MarginBorder
implements StyleableBorder
{
protected final int focusWidth = UIManager.getInt( "Component.focusWidth" );
protected final float innerFocusWidth = FlatUIUtils.getUIFloat( "Component.innerFocusWidth", 0 );
protected final Color focusColor = UIManager.getColor( "Component.focusColor" );
protected final Color borderColor = UIManager.getColor( "Component.borderColor" );
protected final Color disabledBorderColor = UIManager.getColor( "Component.disabledBorderColor" );
protected final Color focusedBorderColor = UIManager.getColor( "Component.focusedBorderColor" );
@Styleable protected int focusWidth = UIManager.getInt( "Component.focusWidth" );
@Styleable protected float innerFocusWidth = FlatUIUtils.getUIFloat( "Component.innerFocusWidth", 0 );
@Styleable protected float innerOutlineWidth = FlatUIUtils.getUIFloat( "Component.innerOutlineWidth", 0 );
/** @since 2 */ @Styleable protected float borderWidth = FlatUIUtils.getUIFloat( "Component.borderWidth", 1 );
@Styleable protected Color focusColor = UIManager.getColor( "Component.focusColor" );
@Styleable protected Color borderColor = UIManager.getColor( "Component.borderColor" );
@Styleable protected Color disabledBorderColor = UIManager.getColor( "Component.disabledBorderColor" );
@Styleable protected Color focusedBorderColor = UIManager.getColor( "Component.focusedBorderColor" );
@Styleable(dot=true) protected Color errorBorderColor = UIManager.getColor( "Component.error.borderColor" );
@Styleable(dot=true) protected Color errorFocusedBorderColor = UIManager.getColor( "Component.error.focusedBorderColor" );
@Styleable(dot=true) protected Color warningBorderColor = UIManager.getColor( "Component.warning.borderColor" );
@Styleable(dot=true) protected Color warningFocusedBorderColor = UIManager.getColor( "Component.warning.focusedBorderColor" );
@Styleable(dot=true) protected Color customBorderColor = UIManager.getColor( "Component.custom.borderColor" );
// only used via styling (not in UI defaults, but has likewise client properties)
/** @since 2 */ @Styleable protected String outline;
/** @since 2 */ @Styleable protected Color outlineColor;
/** @since 2 */ @Styleable protected Color outlineFocusedColor;
/** @since 2 */
@Override
public Object applyStyleProperty( String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
}
/** @since 2 */
@Override
public Map<String, Class<?>> getStyleableInfos() {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
}
@Override
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
@@ -72,26 +107,75 @@ public class FlatBorder
try {
FlatUIUtils.setRenderingHints( g2 );
boolean isCellEditor = isTableCellEditor( c );
float focusWidth = isCellEditor ? 0 : getFocusWidth( c );
float borderWidth = getBorderWidth( c );
float arc = isCellEditor ? 0 : getArc( c );
float focusWidth = scale( (float) getFocusWidth( c ) );
float focusInnerWidth = 0;
float borderWidth = scale( getBorderWidth( c ) );
float arc = scale( (float) getArc( c ) );
Color outlineColor = getOutlineColor( c );
Color focusColor = null;
if( isFocused( c ) ) {
float innerFocusWidth = !(c instanceof JScrollPane) ? this.innerFocusWidth : 0;
// paint outer border
if( outlineColor != null || isFocused( c ) ) {
float innerWidth = !isCellEditor( c ) && !(c instanceof JScrollPane)
? (outlineColor != null ? innerOutlineWidth : getInnerFocusWidth( c ))
: 0;
g2.setColor( getFocusColor( c ) );
FlatUIUtils.paintComponentOuterBorder( g2, x, y, width, height, focusWidth,
getLineWidth( c ) + scale( innerFocusWidth ), arc );
if( focusWidth > 0 || innerWidth > 0 ) {
focusColor = (outlineColor != null) ? outlineColor : getFocusColor( c );
focusInnerWidth = borderWidth + scale( innerWidth );
}
}
g2.setPaint( getBorderColor( c ) );
FlatUIUtils.paintComponentBorder( g2, x, y, width, height, focusWidth, borderWidth, arc );
// paint border
Paint borderColor = (outlineColor != null) ? outlineColor : getBorderColor( c );
FlatUIUtils.paintOutlinedComponent( g2, x, y, width, height,
focusWidth, 1, focusInnerWidth, borderWidth, arc,
focusColor, borderColor, null );
} finally {
g2.dispose();
}
}
/**
* Returns the outline color of the component border specified in client property
* {@link FlatClientProperties#OUTLINE}.
*/
protected Color getOutlineColor( Component c ) {
if( !(c instanceof JComponent) )
return null;
Object outline = ((JComponent)c).getClientProperty( FlatClientProperties.OUTLINE );
if( outline == null )
outline = this.outline;
if( outline == null ) {
if( outlineColor != null && outlineFocusedColor != null )
outline = new Color[] { outlineFocusedColor, outlineColor };
else if( outlineColor != null )
outline = outlineColor;
else if( outlineFocusedColor != null )
outline = outlineFocusedColor;
}
if( outline instanceof String ) {
switch( (String) outline ) {
case FlatClientProperties.OUTLINE_ERROR:
return isFocused( c ) ? errorFocusedBorderColor : errorBorderColor;
case FlatClientProperties.OUTLINE_WARNING:
return isFocused( c ) ? warningFocusedBorderColor : warningBorderColor;
}
} else if( outline instanceof Color ) {
Color color = (Color) outline;
// use color functions to compute color for unfocused state
if( !isFocused( c ) && customBorderColor instanceof DerivedColor )
color = ((DerivedColor)customBorderColor).derive( color );
return color;
} else if( outline instanceof Color[] && ((Color[])outline).length >= 2 )
return ((Color[])outline)[isFocused( c ) ? 0 : 1];
return null;
}
protected Color getFocusColor( Component c ) {
return focusColor;
}
@@ -111,71 +195,87 @@ public class FlatBorder
return false;
}
return c.isEnabled() && (!(c instanceof JTextComponent) || ((JTextComponent)c).isEditable());
return c.isEnabled();
}
protected boolean isFocused( Component c ) {
if( c instanceof JScrollPane ) {
JViewport viewport = ((JScrollPane)c).getViewport();
Component view = (viewport != null) ? viewport.getView() : null;
if( view != null ) {
if( FlatUIUtils.isPermanentFocusOwner( view ) )
return true;
if( (view instanceof JTable && ((JTable)view).isEditing()) ||
(view instanceof JTree && ((JTree)view).isEditing()) )
{
Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
if( focusOwner != null )
return SwingUtilities.isDescendingFrom( focusOwner, view );
}
}
return false;
} else if( c instanceof JComboBox && ((JComboBox<?>)c).isEditable() ) {
Component editorComponent = ((JComboBox<?>)c).getEditor().getEditorComponent();
return (editorComponent != null) ? FlatUIUtils.isPermanentFocusOwner( editorComponent ) : false;
} else if( c instanceof JSpinner ) {
JComponent editor = ((JSpinner)c).getEditor();
if( editor instanceof JSpinner.DefaultEditor ) {
JTextField textField = ((JSpinner.DefaultEditor)editor).getTextField();
if( textField != null )
return FlatUIUtils.isPermanentFocusOwner( textField );
}
return false;
} else
if( c instanceof JScrollPane )
return FlatScrollPaneUI.isPermanentFocusOwner( (JScrollPane) c );
else if( c instanceof JComboBox )
return FlatComboBoxUI.isPermanentFocusOwner( (JComboBox<?>) c );
else if( c instanceof JSpinner )
return FlatSpinnerUI.isPermanentFocusOwner( (JSpinner) c );
else
return FlatUIUtils.isPermanentFocusOwner( c );
}
protected boolean isTableCellEditor( Component c ) {
return FlatUIUtils.isTableCellEditor( c );
protected boolean isCellEditor( Component c ) {
return FlatUIUtils.isCellEditor( c );
}
@Override
public Insets getBorderInsets( Component c, Insets insets ) {
boolean isCellEditor = isTableCellEditor( c );
float ow = (isCellEditor ? 0 : getFocusWidth( c )) + getLineWidth( c );
float focusWidth = scale( (float) getFocusWidth( c ) );
int ow = Math.round( focusWidth + scale( (float) getLineWidth( c ) ) );
insets = super.getBorderInsets( c, insets );
insets.top = Math.round( scale( (float) insets.top ) + ow );
insets.left = Math.round( scale( (float) insets.left ) + ow );
insets.bottom = Math.round( scale( (float) insets.bottom ) + ow );
insets.right = Math.round( scale( (float) insets.right ) + ow );
insets.top = scale( insets.top ) + ow;
insets.left = scale( insets.left ) + ow;
insets.bottom = scale( insets.bottom ) + ow;
insets.right = scale( insets.right ) + ow;
if( isCellEditor( c ) ) {
// remove top and bottom insets if used as cell editor
insets.top = insets.bottom = 0;
// remove right/left insets to avoid that text is truncated (e.g. in file chooser)
if( c.getComponentOrientation().isLeftToRight() )
insets.right = 0;
else
insets.left = 0;
}
return insets;
}
protected float getFocusWidth( Component c ) {
return scale( (float) focusWidth );
/**
* Returns the (unscaled) thickness of the outer focus border.
*/
protected int getFocusWidth( Component c ) {
if( isCellEditor( c ) )
return 0;
return focusWidth;
}
protected float getLineWidth( Component c ) {
return scale( 1f );
/**
* Returns the (unscaled) thickness of the inner focus border.
*/
protected float getInnerFocusWidth( Component c ) {
return innerFocusWidth;
}
/**
* Returns the (unscaled) line thickness used to compute the border insets.
* This may be different to {@link #getBorderWidth}.
*/
protected int getLineWidth( Component c ) {
return 1;
}
/**
* Returns the (unscaled) line thickness used to paint the border.
* This may be different to {@link #getLineWidth}.
*/
protected float getBorderWidth( Component c ) {
return getLineWidth( c );
return borderWidth;
}
protected float getArc( Component c ) {
/**
* Returns the (unscaled) arc diameter of the border.
*/
protected int getArc( Component c ) {
return 0;
}
}

View File

@@ -16,70 +16,124 @@
package com.formdev.flatlaf.ui;
import static com.formdev.flatlaf.util.UIScale.scale;
import java.awt.Color;
import java.awt.Component;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Paint;
import javax.swing.AbstractButton;
import javax.swing.UIManager;
import javax.swing.plaf.UIResource;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.util.UIScale;
/**
* Border for {@link javax.swing.JButton}.
*
* @uiDefault Button.arc int
* @uiDefault Button.innerFocusWidth int or float optional; defaults to Component.innerFocusWidth
* @uiDefault Button.borderWidth int or float optional; defaults to Component.borderWidth
*
* @uiDefault Button.borderColor Color
* @uiDefault Button.startBorderColor Color optional; if set, a gradient paint is used and Button.borderColor is ignored
* @uiDefault Button.endBorderColor Color optional; if set, a gradient paint is used
* @uiDefault Button.disabledBorderColor Color
* @uiDefault Button.focusedBorderColor Color
* @uiDefault Button.hoverBorderColor Color optional
*
* @uiDefault Button.default.borderWidth int or float
* @uiDefault Button.default.borderColor Color
* @uiDefault Button.default.startBorderColor Color optional; if set, a gradient paint is used and Button.default.borderColor is ignored
* @uiDefault Button.default.endBorderColor Color optional; if set, a gradient paint is used
* @uiDefault Button.default.hoverBorderColor Color optional
* @uiDefault Button.default.focusedBorderColor Color
* @uiDefault Button.default.focusColor Color
* @uiDefault Button.default.borderWidth int
* @uiDefault Button.default.hoverBorderColor Color optional
*
* @uiDefault Button.toolbar.focusWidth int or float optional; default is 1.5
* @uiDefault Button.toolbar.focusColor Color optional; defaults to Component.focusColor
* @uiDefault Button.toolbar.margin Insets
* @uiDefault Button.toolbar.spacingInsets Insets
* @uiDefault Button.arc int
*
* @author Karl Tauber
*/
public class FlatButtonBorder
extends FlatBorder
{
protected final Color borderColor = FlatUIUtils.getUIColor( "Button.startBorderColor", "Button.borderColor" );
protected final Color endBorderColor = UIManager.getColor( "Button.endBorderColor" );
protected final Color disabledBorderColor = UIManager.getColor( "Button.disabledBorderColor" );
protected final Color focusedBorderColor = UIManager.getColor( "Button.focusedBorderColor" );
protected final Color hoverBorderColor = UIManager.getColor( "Button.hoverBorderColor" );
protected final Color defaultBorderColor = FlatUIUtils.getUIColor( "Button.default.startBorderColor", "Button.default.borderColor" );
protected final Color defaultEndBorderColor = UIManager.getColor( "Button.default.endBorderColor" );
protected final Color defaultHoverBorderColor = UIManager.getColor( "Button.default.hoverBorderColor" );
protected final Color defaultFocusedBorderColor = UIManager.getColor( "Button.default.focusedBorderColor" );
protected final Color defaultFocusColor = UIManager.getColor( "Button.default.focusColor" );
protected final int defaultBorderWidth = UIManager.getInt( "Button.default.borderWidth" );
protected final Insets toolbarMargin = UIManager.getInsets( "Button.toolbar.margin" );
protected final Insets toolbarSpacingInsets = UIManager.getInsets( "Button.toolbar.spacingInsets" );
protected final int arc = UIManager.getInt( "Button.arc" );
@Styleable protected int arc = UIManager.getInt( "Button.arc" );
protected Color endBorderColor = UIManager.getColor( "Button.endBorderColor" );
@Styleable protected Color hoverBorderColor = UIManager.getColor( "Button.hoverBorderColor" );
@Styleable(dot=true) protected float defaultBorderWidth = FlatUIUtils.getUIFloat( "Button.default.borderWidth", 1 );
@Styleable(dot=true) protected Color defaultBorderColor = FlatUIUtils.getUIColor( "Button.default.startBorderColor", "Button.default.borderColor" );
protected Color defaultEndBorderColor = UIManager.getColor( "Button.default.endBorderColor" );
@Styleable(dot=true) protected Color defaultFocusedBorderColor = UIManager.getColor( "Button.default.focusedBorderColor" );
@Styleable(dot=true) protected Color defaultFocusColor = UIManager.getColor( "Button.default.focusColor" );
@Styleable(dot=true) protected Color defaultHoverBorderColor = UIManager.getColor( "Button.default.hoverBorderColor" );
/** @since 1.4 */ @Styleable(dot=true) protected float toolbarFocusWidth = FlatUIUtils.getUIFloat( "Button.toolbar.focusWidth", 1.5f );
/** @since 1.4 */ @Styleable(dot=true) protected Color toolbarFocusColor = UIManager.getColor( "Button.toolbar.focusColor" );
@Styleable(dot=true) protected Insets toolbarMargin = UIManager.getInsets( "Button.toolbar.margin" );
@Styleable(dot=true) protected Insets toolbarSpacingInsets = UIManager.getInsets( "Button.toolbar.spacingInsets" );
public FlatButtonBorder() {
innerFocusWidth = FlatUIUtils.getUIFloat( "Button.innerFocusWidth", innerFocusWidth );
borderWidth = FlatUIUtils.getUIFloat( "Button.borderWidth", borderWidth );
borderColor = FlatUIUtils.getUIColor( "Button.startBorderColor", "Button.borderColor" );
disabledBorderColor = UIManager.getColor( "Button.disabledBorderColor" );
focusedBorderColor = UIManager.getColor( "Button.focusedBorderColor" );
}
@Override
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
if( FlatButtonUI.isContentAreaFilled( c ) &&
!FlatButtonUI.isToolBarButton( c ) &&
(!FlatButtonUI.isBorderlessButton( c ) || FlatUIUtils.isPermanentFocusOwner( c )) &&
!FlatButtonUI.isHelpButton( c ) &&
!FlatToggleButtonUI.isTabButton( c ) )
super.paintBorder( c, g, x, y, width, height );
else if( FlatButtonUI.isToolBarButton( c ) && isFocused( c ) )
paintToolBarFocus( c, g, x, y, width, height );
}
/** @since 1.4 */
protected void paintToolBarFocus( Component c, Graphics g, int x, int y, int width, int height ) {
Graphics2D g2 = (Graphics2D) g.create();
try {
FlatUIUtils.setRenderingHints( g2 );
float focusWidth = UIScale.scale( toolbarFocusWidth );
float arc = UIScale.scale( (float) getArc( c ) );
Color outlineColor = getOutlineColor( c );
Insets spacing = UIScale.scale( toolbarSpacingInsets );
x += spacing.left;
y += spacing.top;
width -= spacing.left + spacing.right;
height -= spacing.top + spacing.bottom;
Color color = (outlineColor != null) ? outlineColor : getFocusColor( c );
// not using focus border painting of paintOutlinedComponent() here
// because its round edges look too "thick"
FlatUIUtils.paintOutlinedComponent( g2, x, y, width, height, 0, 0, 0, focusWidth, arc, null, color, null );
} finally {
g2.dispose();
}
}
@Override
protected Color getFocusColor( Component c ) {
return FlatButtonUI.isDefaultButton( c ) ? defaultFocusColor : super.getFocusColor( c );
return (toolbarFocusColor != null && FlatButtonUI.isToolBarButton( c ))
? toolbarFocusColor
: (FlatButtonUI.isDefaultButton( c ) ? defaultFocusColor : super.getFocusColor( c ));
}
@Override
protected boolean isFocused( Component c ) {
return FlatButtonUI.isFocusPainted( c ) && super.isFocused( c );
}
@Override
@@ -115,8 +169,8 @@ public class FlatButtonBorder
} else {
insets = super.getBorderInsets( c, insets );
// use smaller left and right insets for icon-only buttons (so that they are square)
if( FlatButtonUI.isIconOnlyButton( c ) && ((AbstractButton)c).getMargin() instanceof UIResource )
// use smaller left and right insets for icon-only or single-character buttons (so that they are square)
if( FlatButtonUI.isIconOnlyOrSingleCharacterButton( c ) && ((AbstractButton)c).getMargin() instanceof UIResource )
insets.left = insets.right = Math.min( insets.top, insets.bottom );
}
@@ -124,17 +178,24 @@ public class FlatButtonBorder
}
@Override
protected float getFocusWidth( Component c ) {
return FlatToggleButtonUI.isTabButton( c ) ? 0 : super.getFocusWidth(c );
protected int getFocusWidth( Component c ) {
return FlatToggleButtonUI.isTabButton( c ) ? 0 : super.getFocusWidth( c );
}
@Override
protected float getBorderWidth( Component c ) {
return FlatButtonUI.isDefaultButton( c ) ? scale( (float) defaultBorderWidth ) : super.getBorderWidth( c );
return FlatButtonUI.isDefaultButton( c ) ? defaultBorderWidth : borderWidth;
}
@Override
protected float getArc( Component c ) {
return FlatButtonUI.isSquareButton( c ) ? 0 : scale( (float) arc );
protected int getArc( Component c ) {
if( isCellEditor( c ) )
return 0;
switch( FlatButtonUI.getButtonType( c ) ) {
case FlatButtonUI.TYPE_SQUARE: return 0;
case FlatButtonUI.TYPE_ROUND_RECT: return Short.MAX_VALUE;
default: return arc;
}
}
}

View File

@@ -30,6 +30,9 @@ import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.geom.RoundRectangle2D;
import java.beans.PropertyChangeEvent;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.AbstractButton;
import javax.swing.ButtonModel;
import javax.swing.Icon;
@@ -39,12 +42,17 @@ import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import javax.swing.LookAndFeel;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.plaf.ButtonUI;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicButtonListener;
import javax.swing.plaf.basic.BasicButtonUI;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.icons.FlatHelpButtonIcon;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.UIScale;
/**
@@ -61,8 +69,6 @@ import com.formdev.flatlaf.util.UIScale;
*
* <!-- FlatButtonUI -->
*
* @uiDefault Component.focusWidth int
* @uiDefault Button.arc int
* @uiDefault Button.minimumWidth int
* @uiDefault Button.iconTextGap int
* @uiDefault Button.startBackground Color optional; if set, a gradient paint is used and Button.background is ignored
@@ -70,7 +76,11 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault Button.focusedBackground Color optional
* @uiDefault Button.hoverBackground Color optional
* @uiDefault Button.pressedBackground 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.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
@@ -86,50 +96,78 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault Button.toolbar.spacingInsets Insets
* @uiDefault Button.toolbar.hoverBackground Color
* @uiDefault Button.toolbar.pressedBackground Color
* @uiDefault Button.toolbar.selectedBackground Color
*
* @author Karl Tauber
*/
public class FlatButtonUI
extends BasicButtonUI
implements StyleableUI
{
protected int focusWidth;
protected int arc;
protected int minimumWidth;
@Styleable protected int minimumWidth;
protected int iconTextGap;
protected Color background;
protected Color foreground;
protected Color startBackground;
protected Color endBackground;
protected Color focusedBackground;
protected Color hoverBackground;
protected Color pressedBackground;
protected Color disabledText;
@Styleable protected Color focusedBackground;
@Styleable protected Color hoverBackground;
@Styleable protected Color pressedBackground;
@Styleable protected Color selectedBackground;
@Styleable protected Color selectedForeground;
@Styleable protected Color disabledBackground;
@Styleable protected Color disabledText;
@Styleable protected Color disabledSelectedBackground;
protected Color defaultBackground;
@Styleable(dot=true) protected Color defaultBackground;
protected Color defaultEndBackground;
protected Color defaultForeground;
protected Color defaultFocusedBackground;
protected Color defaultHoverBackground;
protected Color defaultPressedBackground;
protected boolean defaultBoldText;
@Styleable(dot=true) protected Color defaultForeground;
@Styleable(dot=true) protected Color defaultFocusedBackground;
@Styleable(dot=true) protected Color defaultHoverBackground;
@Styleable(dot=true) protected Color defaultPressedBackground;
@Styleable(dot=true) protected boolean defaultBoldText;
protected int shadowWidth;
protected Color shadowColor;
protected Color defaultShadowColor;
@Styleable protected boolean paintShadow;
@Styleable protected int shadowWidth;
@Styleable protected Color shadowColor;
@Styleable(dot=true) protected Color defaultShadowColor;
protected Insets toolbarSpacingInsets;
protected Color toolbarHoverBackground;
protected Color toolbarPressedBackground;
@Styleable(dot=true) protected Color toolbarHoverBackground;
@Styleable(dot=true) protected Color toolbarPressedBackground;
@Styleable(dot=true) protected Color toolbarSelectedBackground;
// only used via styling (not in UI defaults, but has likewise client properties)
/** @since 2 */ @Styleable protected String buttonType;
/** @since 2 */ @Styleable protected boolean squareSize;
/** @since 2 */ @Styleable protected int minimumHeight;
private Icon helpButtonIcon;
private Insets defaultMargin;
private final boolean shared;
private boolean helpButtonIconShared = true;
private boolean defaults_initialized = false;
private static ComponentUI instance;
private Map<String, Object> oldStyleValues;
private AtomicBoolean borderShared;
public static ComponentUI createUI( JComponent c ) {
if( instance == null )
instance = new FlatButtonUI();
return instance;
return FlatUIUtils.canUseSharedUI( c )
? FlatUIUtils.createSharedUI( FlatButtonUI.class, () -> new FlatButtonUI( true ) )
: new FlatButtonUI( false );
}
/** @since 2 */
protected FlatButtonUI( boolean shared ) {
this.shared = shared;
}
@Override
public void installUI( JComponent c ) {
super.installUI( c );
installStyle( (AbstractButton) c );
}
@Override
@@ -139,27 +177,22 @@ public class FlatButtonUI
if( !defaults_initialized ) {
String prefix = getPropertyPrefix();
focusWidth = UIManager.getInt( "Component.focusWidth" );
arc = UIManager.getInt( "Button.arc" );
minimumWidth = UIManager.getInt( prefix + "minimumWidth" );
iconTextGap = FlatUIUtils.getUIInt( prefix + "iconTextGap", 4 );
background = UIManager.getColor( prefix + "background" );
foreground = UIManager.getColor( prefix + "foreground" );
startBackground = UIManager.getColor( prefix + "startBackground" );
endBackground = UIManager.getColor( prefix + "endBackground" );
focusedBackground = UIManager.getColor( prefix + "focusedBackground" );
hoverBackground = UIManager.getColor( prefix + "hoverBackground" );
pressedBackground = UIManager.getColor( prefix + "pressedBackground" );
selectedBackground = UIManager.getColor( prefix + "selectedBackground" );
selectedForeground = UIManager.getColor( prefix + "selectedForeground" );
disabledBackground = UIManager.getColor( prefix + "disabledBackground" );
disabledText = UIManager.getColor( prefix + "disabledText" );
if( UIManager.getBoolean( "Button.paintShadow" ) ) {
shadowWidth = FlatUIUtils.getUIInt( "Button.shadowWidth", 2 );
shadowColor = UIManager.getColor( "Button.shadowColor" );
defaultShadowColor = UIManager.getColor( "Button.default.shadowColor" );
} else {
shadowWidth = 0;
shadowColor = null;
defaultShadowColor = null;
}
disabledSelectedBackground = UIManager.getColor( prefix + "disabledSelectedBackground" );
defaultBackground = FlatUIUtils.getUIColor( "Button.default.startBackground", "Button.default.background" );
defaultEndBackground = UIManager.getColor( "Button.default.endBackground" );
@@ -169,12 +202,19 @@ public class FlatButtonUI
defaultPressedBackground = UIManager.getColor( "Button.default.pressedBackground" );
defaultBoldText = UIManager.getBoolean( "Button.default.boldText" );
toolbarSpacingInsets = UIManager.getInsets( "Button.toolbar.spacingInsets" );
paintShadow = UIManager.getBoolean( "Button.paintShadow" );
shadowWidth = FlatUIUtils.getUIInt( "Button.shadowWidth", 2 );
shadowColor = UIManager.getColor( "Button.shadowColor" );
defaultShadowColor = UIManager.getColor( "Button.default.shadowColor" );
toolbarHoverBackground = UIManager.getColor( prefix + "toolbar.hoverBackground" );
toolbarPressedBackground = UIManager.getColor( prefix + "toolbar.pressedBackground" );
toolbarSelectedBackground = UIManager.getColor( prefix + "toolbar.selectedBackground" );
helpButtonIcon = UIManager.getIcon( "HelpButton.icon" );
defaultMargin = UIManager.getInsets( prefix + "margin" );
helpButtonIconShared = true;
defaults_initialized = true;
}
@@ -187,65 +227,171 @@ public class FlatButtonUI
LookAndFeel.installProperty( b, "opaque", false );
LookAndFeel.installProperty( b, "iconTextGap", scale( iconTextGap ) );
MigLayoutVisualPadding.install( b, getFocusWidth( b ) );
MigLayoutVisualPadding.install( b );
}
@Override
protected void uninstallDefaults( AbstractButton b ) {
super.uninstallDefaults( b );
oldStyleValues = null;
borderShared = null;
MigLayoutVisualPadding.uninstall( b );
defaults_initialized = false;
}
@Override
protected BasicButtonListener createButtonListener( AbstractButton b ) {
return new BasicButtonListener( b ) {
@Override
public void propertyChange( PropertyChangeEvent e ) {
super.propertyChange( e );
FlatButtonUI.this.propertyChange( b, e );
}
};
return new FlatButtonListener( b );
}
protected void propertyChange( AbstractButton b, PropertyChangeEvent e ) {
switch( e.getPropertyName() ) {
case SQUARE_SIZE:
case MINIMUM_WIDTH:
case MINIMUM_HEIGHT:
b.revalidate();
break;
case BUTTON_TYPE:
b.revalidate();
b.repaint();
break;
case STYLE:
case STYLE_CLASS:
if( shared && FlatStylingSupport.hasStyleProperty( b ) ) {
// unshare component UI if necessary
// updateUI() invokes applyStyle() from installUI()
b.updateUI();
} else
installStyle( b );
b.revalidate();
b.repaint();
break;
}
}
/** @since 2 */
protected void installStyle( AbstractButton b ) {
try {
applyStyle( b, FlatStylingSupport.getResolvedStyle( b, getStyleType() ) );
} catch( RuntimeException ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex );
}
}
/** @since 2 */
String getStyleType() {
return "Button";
}
/** @since 2 */
protected void applyStyle( AbstractButton b, Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style,
(key, value) -> applyStyleProperty( b, key, value ) );
}
/** @since 2 */
protected Object applyStyleProperty( AbstractButton b, String key, Object value ) {
if( key.startsWith( "help." ) ) {
if( !(helpButtonIcon instanceof FlatHelpButtonIcon) )
return new UnknownStyleException( key );
if( helpButtonIconShared ) {
helpButtonIcon = FlatStylingSupport.cloneIcon( helpButtonIcon );
helpButtonIconShared = false;
}
key = key.substring( "help.".length() );
return ((FlatHelpButtonIcon)helpButtonIcon).applyStyleProperty( key, value );
}
if( borderShared == null )
borderShared = new AtomicBoolean( true );
return FlatStylingSupport.applyToAnnotatedObjectOrBorder( this, key, value, b, borderShared );
}
/** @since 2 */
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
Map<String, Class<?>> infos = FlatStylingSupport.getAnnotatedStyleableInfos( this, c.getBorder() );
if( helpButtonIcon instanceof FlatHelpButtonIcon )
FlatStylingSupport.putAllPrefixKey( infos, "help.", ((FlatHelpButtonIcon)helpButtonIcon).getStyleableInfos() );
return infos;
}
static boolean isContentAreaFilled( Component c ) {
return !(c instanceof AbstractButton) || ((AbstractButton)c).isContentAreaFilled();
}
public static boolean isFocusPainted( Component c ) {
return !(c instanceof AbstractButton) || ((AbstractButton)c).isFocusPainted();
}
static boolean isDefaultButton( Component c ) {
return c instanceof JButton && ((JButton)c).isDefaultButton();
}
static boolean isIconOnlyButton( Component c ) {
/**
* Returns true if the button has an icon but no text,
* or it it does not have an icon and the text is either "..." or one character.
*/
static boolean isIconOnlyOrSingleCharacterButton( Component c ) {
if( !(c instanceof JButton) && !(c instanceof JToggleButton) )
return false;
Icon icon = ((AbstractButton)c).getIcon();
String text = ((AbstractButton)c).getText();
return (icon != null && (text == null || text.isEmpty())) ||
(icon == null && text != null && ("...".equals( text ) || text.length() == 1));
(icon == null && text != null &&
("...".equals( text ) ||
text.length() == 1 ||
(text.length() == 2 && Character.isSurrogatePair( text.charAt( 0 ), text.charAt( 1 ) ))));
}
static boolean isSquareButton( Component c ) {
return c instanceof AbstractButton && clientPropertyEquals( (AbstractButton) c, BUTTON_TYPE, BUTTON_TYPE_SQUARE );
static final int TYPE_OTHER = -1;
static final int TYPE_SQUARE = 0;
static final int TYPE_ROUND_RECT = 1;
static int getButtonType( Component c ) {
if( !(c instanceof AbstractButton) )
return TYPE_OTHER;
String value = getButtonTypeStr( (AbstractButton) c );
if( value == null )
return TYPE_OTHER;
switch( value ) {
case BUTTON_TYPE_SQUARE: return TYPE_SQUARE;
case BUTTON_TYPE_ROUND_RECT: return TYPE_ROUND_RECT;
default: return TYPE_OTHER;
}
}
static boolean isHelpButton( Component c ) {
return c instanceof JButton && clientPropertyEquals( (JButton) c, BUTTON_TYPE, BUTTON_TYPE_HELP );
return c instanceof JButton && BUTTON_TYPE_HELP.equals( getButtonTypeStr( (JButton) c ) );
}
static boolean isToolBarButton( Component c ) {
return c.getParent() instanceof JToolBar;
return c.getParent() instanceof JToolBar ||
(c instanceof AbstractButton && BUTTON_TYPE_TOOLBAR_BUTTON.equals( getButtonTypeStr( (AbstractButton) c ) ));
}
static boolean isBorderlessButton( Component c ) {
return c instanceof AbstractButton && BUTTON_TYPE_BORDERLESS.equals( getButtonTypeStr( (AbstractButton) c ) );
}
static String getButtonTypeStr( AbstractButton c ) {
// get from client property
Object value = c.getClientProperty( BUTTON_TYPE );
if( value instanceof String )
return (String) value;
// get from styling property
ButtonUI ui = c.getUI();
return (ui instanceof FlatButtonUI) ? ((FlatButtonUI)ui).buttonType : null;
}
@Override
@@ -267,56 +413,63 @@ public class FlatButtonUI
protected void paintBackground( Graphics g, JComponent c ) {
Color background = getBackground( c );
if( background != null ) {
Graphics2D g2 = (Graphics2D) g.create();
try {
FlatUIUtils.setRenderingHints( g2 );
if( background == null )
return;
Border border = c.getBorder();
boolean isToolBarButton = isToolBarButton( c );
float focusWidth = (border instanceof FlatBorder && !isToolBarButton) ? scale( (float) getFocusWidth( c ) ) : 0;
float arc = ((border instanceof FlatButtonBorder && !isSquareButton( c )) || isToolBarButton)
? scale( (float) this.arc ) : 0;
boolean def = isDefaultButton( c );
Graphics2D g2 = (Graphics2D) g.create();
try {
FlatUIUtils.setRenderingHints( g2 );
int x = 0;
int y = 0;
int width = c.getWidth();
int height = c.getHeight();
boolean isToolBarButton = isToolBarButton( c );
float focusWidth = isToolBarButton ? 0 : FlatUIUtils.getBorderFocusWidth( c );
float arc = FlatUIUtils.getBorderArc( c );
if( isToolBarButton ) {
Insets spacing = UIScale.scale( toolbarSpacingInsets );
x += spacing.left;
y += spacing.top;
width -= spacing.left + spacing.right;
height -= spacing.top + spacing.bottom;
}
boolean def = isDefaultButton( c );
// paint shadow
Color shadowColor = def ? defaultShadowColor : this.shadowColor;
if( !isToolBarButton && shadowColor != null && shadowWidth > 0 && focusWidth > 0 &&
!FlatUIUtils.isPermanentFocusOwner( c ) && c.isEnabled() )
{
g2.setColor( shadowColor );
g2.fill( new RoundRectangle2D.Float( focusWidth, focusWidth + UIScale.scale( (float) shadowWidth ),
width - focusWidth * 2, height - focusWidth * 2, arc, arc ) );
}
int x = 0;
int y = 0;
int width = c.getWidth();
int height = c.getHeight();
// paint background
Color startBg = def ? defaultBackground : startBackground;
Color endBg = def ? defaultEndBackground : endBackground;
if( background == startBg && endBg != null && !startBg.equals( endBg ) )
g2.setPaint( new GradientPaint( 0, 0, startBg, 0, height, endBg ) );
else
FlatUIUtils.setColor( g2, background, def ? defaultBackground : c.getBackground() );
FlatUIUtils.paintComponentBackground( g2, x, y, width, height, focusWidth, arc );
} finally {
g2.dispose();
if( isToolBarButton && c.getBorder() instanceof FlatButtonBorder ) {
Insets spacing = UIScale.scale( ((FlatButtonBorder)c.getBorder()).toolbarSpacingInsets );
x += spacing.left;
y += spacing.top;
width -= spacing.left + spacing.right;
height -= spacing.top + spacing.bottom;
}
// paint shadow
Color shadowColor = def ? defaultShadowColor : this.shadowColor;
if( paintShadow &&
shadowColor != null && shadowWidth > 0 && focusWidth > 0 && c.isEnabled() &&
!isToolBarButton && !isBorderlessButton( c ) &&
!(isFocusPainted( c ) && FlatUIUtils.isPermanentFocusOwner( c )) )
{
g2.setColor( shadowColor );
g2.fill( new RoundRectangle2D.Float( focusWidth, focusWidth + UIScale.scale( (float) shadowWidth ),
width - focusWidth * 2, height - focusWidth * 2, arc, arc ) );
}
// paint background
Color startBg = def ? defaultBackground : startBackground;
Color endBg = def ? defaultEndBackground : endBackground;
if( background == startBg && endBg != null && !startBg.equals( endBg ) )
g2.setPaint( new GradientPaint( 0, 0, startBg, 0, height, endBg ) );
else
g2.setColor( FlatUIUtils.deriveColor( background, getBackgroundBase( c, def ) ) );
FlatUIUtils.paintComponentBackground( g2, x, y, width, height, focusWidth, arc );
} finally {
g2.dispose();
}
}
@Override
public void paint( Graphics g, JComponent c ) {
super.paint( FlatLabelUI.createGraphicsHTMLTextYCorrection( g, c ), c );
}
@Override
protected void paintText( Graphics g, AbstractButton b, Rectangle textRect, String text ) {
if( isHelpButton( b ) )
@@ -333,7 +486,7 @@ public class FlatButtonUI
}
}
paintText( g, b, textRect, text, b.isEnabled() ? getForeground( b ) : disabledText );
paintText( g, b, textRect, text, getForeground( b ) );
}
public static void paintText( Graphics g, AbstractButton b, Rectangle textRect, String text, Color foreground ) {
@@ -346,53 +499,93 @@ public class FlatButtonUI
}
protected Color getBackground( JComponent c ) {
if( !c.isEnabled() )
return null;
boolean toolBarButton = isToolBarButton( c ) || isBorderlessButton( c );
// selected state
if( ((AbstractButton)c).isSelected() ) {
// in toolbar 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,
null,
null,
toolBarButton ? toolbarPressedBackground : pressedBackground );
}
// toolbar button
if( isToolBarButton( c ) ) {
ButtonModel model = ((AbstractButton)c).getModel();
if( model.isPressed() )
return toolbarPressedBackground;
if( model.isRollover() )
return toolbarHoverBackground;
// use background of toolbar
return c.getParent().getBackground();
if( toolBarButton ) {
Color bg = c.getBackground();
return buttonStateColor( c,
isCustomBackground( bg ) ? bg : null,
null,
null,
toolbarHoverBackground,
toolbarPressedBackground );
}
boolean def = isDefaultButton( c );
return buttonStateColor( c,
def ? defaultBackground : c.getBackground(),
null,
def ? defaultFocusedBackground : focusedBackground,
getBackgroundBase( c, def ),
disabledBackground,
isCustomBackground( c.getBackground() ) ? null : (def ? defaultFocusedBackground : focusedBackground),
def ? defaultHoverBackground : hoverBackground,
def ? defaultPressedBackground : pressedBackground );
}
protected Color getBackgroundBase( JComponent c, boolean def ) {
// use component background if explicitly set
Color bg = c.getBackground();
if( isCustomBackground( bg ) )
return bg;
return def ? defaultBackground : bg;
}
protected boolean isCustomBackground( Color bg ) {
return bg != background && (startBackground == null || bg != startBackground);
}
public static Color buttonStateColor( Component c, Color enabledColor, Color disabledColor,
Color focusedColor, Color hoverColor, Color pressedColor )
{
AbstractButton b = (c instanceof AbstractButton) ? (AbstractButton) c : null;
if( !c.isEnabled() )
return disabledColor;
if( pressedColor != null && b != null && b.getModel().isPressed() )
return pressedColor;
if( c instanceof AbstractButton ) {
ButtonModel model = ((AbstractButton)c).getModel();
if( hoverColor != null && b != null && b.getModel().isRollover() )
return hoverColor;
if( pressedColor != null && model.isPressed() )
return pressedColor;
if( focusedColor != null && FlatUIUtils.isPermanentFocusOwner( c ) )
if( hoverColor != null && model.isRollover() )
return hoverColor;
}
if( focusedColor != null && isFocusPainted( c ) && FlatUIUtils.isPermanentFocusOwner( c ) )
return focusedColor;
return enabledColor;
}
protected Color getForeground( JComponent c ) {
if( !c.isEnabled() )
return disabledText;
if( ((AbstractButton)c).isSelected() && !(isToolBarButton( c ) || isBorderlessButton( c )) )
return selectedForeground;
// use component foreground if explicitly set
Color fg = c.getForeground();
if( isCustomForeground( fg ) )
return fg;
boolean def = isDefaultButton( c );
return def ? defaultForeground : c.getForeground();
return def ? defaultForeground : fg;
}
protected boolean isCustomForeground( Color fg ) {
return fg != foreground;
}
@Override
@@ -401,23 +594,50 @@ public class FlatButtonUI
return new Dimension( helpButtonIcon.getIconWidth(), helpButtonIcon.getIconHeight() );
Dimension prefSize = super.getPreferredSize( c );
if ( prefSize == null )
if( prefSize == null )
return null;
// make button square if it is a icon-only button
// or apply minimum width, if not in toolbar and not a icon-only button
if( isIconOnlyButton( c ) )
// make square or apply minimum width/height
boolean isIconOnlyOrSingleCharacter = isIconOnlyOrSingleCharacterButton( c );
if( clientPropertyBoolean( c, SQUARE_SIZE, squareSize ) ) {
// make button square (increase width or height so that they are equal)
prefSize.width = prefSize.height = Math.max( prefSize.width, prefSize.height );
} else if( isIconOnlyOrSingleCharacter && ((AbstractButton)c).getIcon() == null ) {
// make single-character-no-icon button square (increase width)
prefSize.width = Math.max( prefSize.width, prefSize.height );
else if( !isToolBarButton( c ) && c.getBorder() instanceof FlatButtonBorder ) {
int focusWidth = getFocusWidth( c );
prefSize.width = Math.max( prefSize.width, scale( FlatUIUtils.minimumWidth( c, minimumWidth ) + (focusWidth * 2) ) );
prefSize.height = Math.max( prefSize.height, scale( FlatUIUtils.minimumHeight( c, 0 ) + (focusWidth * 2) ) );
} else if( !isIconOnlyOrSingleCharacter && !isToolBarButton( c ) &&
c.getBorder() instanceof FlatButtonBorder && hasDefaultMargins( c ) )
{
// apply minimum width/height
int fw = Math.round( FlatUIUtils.getBorderFocusWidth( c ) * 2 );
prefSize.width = Math.max( prefSize.width, scale( FlatUIUtils.minimumWidth( c, minimumWidth ) ) + fw );
prefSize.height = Math.max( prefSize.height, scale( FlatUIUtils.minimumHeight( c, minimumHeight ) ) + fw );
}
return prefSize;
}
protected int getFocusWidth( JComponent c ) {
return focusWidth;
private boolean hasDefaultMargins( JComponent c ) {
Insets margin = ((AbstractButton)c).getMargin();
return margin instanceof UIResource && Objects.equals( margin, defaultMargin );
}
//---- class FlatButtonListener -------------------------------------------
protected class FlatButtonListener
extends BasicButtonListener
{
private final AbstractButton b;
protected FlatButtonListener( AbstractButton b ) {
super( b );
this.b = b;
}
@Override
public void propertyChange( PropertyChangeEvent e ) {
super.propertyChange( e );
FlatButtonUI.this.propertyChange( b, e );
}
}
}

View File

@@ -18,50 +18,128 @@ package com.formdev.flatlaf.ui;
import static com.formdev.flatlaf.FlatClientProperties.*;
import java.awt.EventQueue;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.MouseEvent;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.JFormattedTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.plaf.UIResource;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultCaret;
import javax.swing.text.DefaultEditorKit;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
import javax.swing.text.Utilities;
/**
* Caret that can select all text on focus gained.
* Also fixes Swing's double-click-and-drag behavior so that dragging after
* a double-click extends selection by whole words.
*
* @author Karl Tauber
*/
class FlatCaret
public class FlatCaret
extends DefaultCaret
implements UIResource
{
private final String selectAllOnFocusPolicy;
private static final String KEY_CARET_INFO = "FlatLaf.internal.caretInfo";
private final String selectAllOnFocusPolicy;
private final boolean selectAllOnMouseClick;
private boolean inInstall;
private boolean wasFocused;
private boolean wasTemporaryLost;
private boolean isMousePressed;
private boolean isWordSelection;
private boolean isLineSelection;
private int dragSelectionStart;
private int dragSelectionEnd;
FlatCaret( String selectAllOnFocusPolicy ) {
public FlatCaret( String selectAllOnFocusPolicy, boolean selectAllOnMouseClick ) {
this.selectAllOnFocusPolicy = selectAllOnFocusPolicy;
this.selectAllOnMouseClick = selectAllOnMouseClick;
}
@Override
public void install( JTextComponent c ) {
super.install( c );
// get caret info if switched theme
long[] ci = (long[]) c.getClientProperty( KEY_CARET_INFO );
if( ci != null ) {
c.putClientProperty( KEY_CARET_INFO, null );
// the dot and mark are lost when switching LaF
// --> move dot to end of text so that all text may be selected when it gains focus
Document doc = c.getDocument();
if( doc != null && getDot() == 0 && getMark() == 0 ) {
int length = doc.getLength();
if( length > 0 )
setDot( length );
// if caret info is too old assume that switched from FlatLaf
// to another Laf and back to FlatLaf
if( System.currentTimeMillis() - 500 > ci[3] )
ci = null;
}
if( ci != null ) {
// when switching theme, it is necessary to set blink rate before
// invoking super.install() otherwise the caret does not blink
setBlinkRate( (int) ci[2] );
}
inInstall = true;
try {
super.install( c );
} finally {
inInstall = false;
}
if( ci != null ) {
// restore selection
select( (int) ci[1], (int) ci[0] );
// if text component is focused, then caret and selection are visible,
// but when switching theme, the component does not yet have
// an highlighter and the selection is not painted
// --> make selection temporary invisible later, then the caret
// adds selection highlights to the text component highlighter
if( isSelectionVisible() ) {
EventQueue.invokeLater( () -> {
if( isSelectionVisible() ) {
setSelectionVisible( false );
setSelectionVisible( true );
}
} );
}
}
}
@Override
public void deinstall( JTextComponent c ) {
// remember dot and mark (the selection) when switching theme
c.putClientProperty( KEY_CARET_INFO, new long[] {
getDot(),
getMark(),
getBlinkRate(),
System.currentTimeMillis(),
} );
super.deinstall( c );
}
@Override
protected void adjustVisibility( Rectangle nloc ) {
JTextComponent c = getComponent();
if( c != null && c.getUI() instanceof FlatTextFieldUI ) {
// need to fix x location because JTextField.scrollRectToVisible() uses insets.left
// (as BasicTextUI.getVisibleEditorRect() does),
// but FlatTextFieldUI.getVisibleEditorRect() may add some padding
Rectangle r = ((FlatTextFieldUI)c.getUI()).getVisibleEditorRect();
if( r != null )
nloc.x -= r.x - c.getInsets().left;
}
super.adjustVisibility( nloc );
}
@Override
public void focusGained( FocusEvent e ) {
if( !wasTemporaryLost && !isMousePressed )
if( !inInstall && !wasTemporaryLost && (!isMousePressed || selectAllOnMouseClick) )
selectAllOnFocusGained();
wasTemporaryLost = false;
wasFocused = true;
@@ -79,18 +157,76 @@ class FlatCaret
public void mousePressed( MouseEvent e ) {
isMousePressed = true;
super.mousePressed( e );
JTextComponent c = getComponent();
// left double-click starts word selection
isWordSelection = e.getClickCount() == 2 && SwingUtilities.isLeftMouseButton( e ) && !e.isConsumed();
// left triple-click starts line selection
isLineSelection = e.getClickCount() == 3 && SwingUtilities.isLeftMouseButton( e ) && (!e.isConsumed() || c.getDragEnabled());
// select line
// (this is also done in DefaultCaret.mouseClicked(), but this event is
// sent when the mouse is released, which is too late for triple-click-and-drag)
if( isLineSelection ) {
ActionMap actionMap = c.getActionMap();
Action selectLineAction = (actionMap != null)
? actionMap.get( DefaultEditorKit.selectLineAction )
: null;
if( selectLineAction != null ) {
selectLineAction.actionPerformed( new ActionEvent( c,
ActionEvent.ACTION_PERFORMED, null, e.getWhen(), e.getModifiers() ) );
}
}
// remember selection where word/line selection starts to keep it always selected while dragging
if( isWordSelection || isLineSelection ) {
int mark = getMark();
int dot = getDot();
dragSelectionStart = Math.min( dot, mark );
dragSelectionEnd = Math.max( dot, mark );
}
}
@Override
public void mouseReleased( MouseEvent e ) {
isMousePressed = false;
isWordSelection = false;
isLineSelection = false;
super.mouseReleased( e );
}
private void selectAllOnFocusGained() {
@Override
public void mouseDragged( MouseEvent e ) {
if( (isWordSelection || isLineSelection) &&
!e.isConsumed() && SwingUtilities.isLeftMouseButton( e ) )
{
// fix Swing's double/triple-click-and-drag behavior so that dragging after
// a double/triple-click extends selection by whole words/lines
JTextComponent c = getComponent();
int pos = c.viewToModel( e.getPoint() );
if( pos < 0 )
return;
try {
if( pos > dragSelectionEnd )
select( dragSelectionStart, isWordSelection ? Utilities.getWordEnd( c, pos ) : Utilities.getRowEnd( c, pos ) );
else if( pos < dragSelectionStart )
select( dragSelectionEnd, isWordSelection ? Utilities.getWordStart( c, pos ) : Utilities.getRowStart( c, pos ) );
else
select( dragSelectionStart, dragSelectionEnd );
} catch( BadLocationException ex ) {
UIManager.getLookAndFeel().provideErrorFeedback( c );
}
} else
super.mouseDragged( e );
}
protected void selectAllOnFocusGained() {
JTextComponent c = getComponent();
Document doc = c.getDocument();
if( doc == null || !c.isEnabled() || !c.isEditable() )
if( doc == null || !c.isEnabled() || !c.isEditable() || FlatUIUtils.isCellEditor( c ) )
return;
Object selectAllOnFocusPolicy = c.getClientProperty( SELECT_ALL_ON_FOCUS_POLICY );
@@ -117,12 +253,34 @@ class FlatCaret
// select all
if( c instanceof JFormattedTextField ) {
EventQueue.invokeLater( () -> {
setDot( 0 );
moveDot( doc.getLength() );
select( 0, doc.getLength() );
} );
} else {
setDot( 0 );
moveDot( doc.getLength() );
select( 0, doc.getLength() );
}
}
private void select( int mark, int dot ) {
if( mark != getMark() )
setDot( mark );
if( dot != getDot() )
moveDot( dot );
}
/** @since 1.4 */
public void scrollCaretToVisible() {
JTextComponent c = getComponent();
if( c == null || c.getUI() == null )
return;
try {
Rectangle loc = c.getUI().modelToView( c, getDot(), getDotBias() );
if( loc != null ) {
adjustVisibility( loc );
damage( loc );
}
} catch( BadLocationException ex ) {
// ignore
}
}
}

View File

@@ -16,70 +16,141 @@
package com.formdev.flatlaf.ui;
import static com.formdev.flatlaf.util.UIScale.scale;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.beans.PropertyChangeListener;
import java.util.Map;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JMenuItem;
import javax.swing.LookAndFeel;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicCheckBoxMenuItemUI;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
import com.formdev.flatlaf.util.LoggingFacade;
/**
* Provides the Flat LaF UI delegate for {@link javax.swing.JCheckBoxMenuItem}.
*
* <!-- BasicCheckBoxMenuItemUI -->
*
* @uiDefault CheckBoxMenuItem.font Font
* @uiDefault CheckBoxMenuItem.background Color
* @uiDefault CheckBoxMenuItem.foreground Color
* @uiDefault CheckBoxMenuItem.disabledForeground Color
* @uiDefault CheckBoxMenuItem.selectionBackground Color
* @uiDefault CheckBoxMenuItem.selectionForeground Color
* @uiDefault CheckBoxMenuItem.acceleratorForeground Color
* @uiDefault CheckBoxMenuItem.acceleratorSelectionForeground Color
* @uiDefault MenuItem.acceleratorFont Font defaults to MenuItem.font
* @uiDefault MenuItem.acceleratorDelimiter String
* @uiDefault CheckBoxMenuItem.border Border
* @uiDefault CheckBoxMenuItem.borderPainted boolean
* @uiDefault CheckBoxMenuItem.margin Insets
* @uiDefault CheckBoxMenuItem.arrowIcon Icon
* @uiDefault CheckBoxMenuItem.checkIcon Icon
* @uiDefault CheckBoxMenuItem.opaque boolean
* @uiDefault CheckBoxMenuItem.evenHeight boolean
* @uiDefault CheckBoxMenuItem.font Font
* @uiDefault CheckBoxMenuItem.background Color
* @uiDefault CheckBoxMenuItem.foreground Color
* @uiDefault CheckBoxMenuItem.disabledForeground Color
* @uiDefault CheckBoxMenuItem.selectionBackground Color
* @uiDefault CheckBoxMenuItem.selectionForeground Color
* @uiDefault CheckBoxMenuItem.acceleratorForeground Color
* @uiDefault CheckBoxMenuItem.acceleratorSelectionForeground Color
* @uiDefault MenuItem.acceleratorFont Font defaults to MenuItem.font
* @uiDefault MenuItem.acceleratorDelimiter String
* @uiDefault CheckBoxMenuItem.border Border
* @uiDefault CheckBoxMenuItem.borderPainted boolean
* @uiDefault CheckBoxMenuItem.margin Insets
* @uiDefault CheckBoxMenuItem.arrowIcon Icon
* @uiDefault CheckBoxMenuItem.checkIcon Icon
* @uiDefault CheckBoxMenuItem.opaque boolean
*
* <!-- FlatCheckBoxMenuItemUI -->
*
* @uiDefault MenuItem.iconTextGap int
*
* @author Karl Tauber
*/
public class FlatCheckBoxMenuItemUI
extends BasicCheckBoxMenuItemUI
implements StyleableUI
{
private FlatMenuItemRenderer renderer;
private Map<String, Object> oldStyleValues;
public static ComponentUI createUI( JComponent c ) {
return new FlatCheckBoxMenuItemUI();
}
@Override
public void installUI( JComponent c ) {
super.installUI( c );
installStyle();
}
@Override
protected void installDefaults() {
super.installDefaults();
// scale
defaultTextIconGap = scale( defaultTextIconGap );
LookAndFeel.installProperty( menuItem, "iconTextGap", FlatUIUtils.getUIInt( "MenuItem.iconTextGap", 4 ) );
renderer = createRenderer();
}
@Override
protected void uninstallDefaults() {
super.uninstallDefaults();
renderer = null;
oldStyleValues = null;
}
protected FlatMenuItemRenderer createRenderer() {
return new FlatMenuItemRenderer( menuItem, checkIcon, arrowIcon, acceleratorFont, acceleratorDelimiter );
}
/**
* Scale defaultTextIconGap again if iconTextGap property has changed.
*/
@Override
protected PropertyChangeListener createPropertyChangeListener( JComponent c ) {
PropertyChangeListener superListener = super.createPropertyChangeListener( c );
return e -> {
superListener.propertyChange( e );
if( e.getPropertyName() == "iconTextGap" )
defaultTextIconGap = scale( defaultTextIconGap );
};
return FlatStylingSupport.createPropertyChangeListener( c, this::installStyle, super.createPropertyChangeListener( c ) );
}
/** @since 2 */
protected void installStyle() {
try {
applyStyle( FlatStylingSupport.getResolvedStyle( menuItem, "CheckBoxMenuItem" ) );
} catch( RuntimeException ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex );
}
}
/** @since 2 */
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
}
/** @since 2 */
protected Object applyStyleProperty( String key, Object value ) {
try {
return renderer.applyStyleProperty( key, value );
} catch ( UnknownStyleException ex ) {
// ignore
}
Object oldValue;
switch( key ) {
// BasicMenuItemUI
case "selectionBackground": oldValue = selectionBackground; selectionBackground = (Color) value; return oldValue;
case "selectionForeground": oldValue = selectionForeground; selectionForeground = (Color) value; return oldValue;
case "disabledForeground": oldValue = disabledForeground; disabledForeground = (Color) value; return oldValue;
case "acceleratorForeground": oldValue = acceleratorForeground; acceleratorForeground = (Color) value; return oldValue;
case "acceleratorSelectionForeground": oldValue = acceleratorSelectionForeground; acceleratorSelectionForeground = (Color) value; return oldValue;
}
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, menuItem, key, value );
}
/** @since 2 */
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return FlatMenuItemUI.getStyleableInfos( renderer );
}
@Override
protected void paintText( Graphics g, JMenuItem menuItem, Rectangle textRect, String text ) {
FlatMenuItemUI.paintText( g, menuItem, textRect, text, disabledForeground, selectionForeground );
protected Dimension getPreferredMenuItemSize( JComponent c, Icon checkIcon, Icon arrowIcon, int defaultTextIconGap ) {
return renderer.getPreferredMenuItemSize();
}
@Override
public void paint( Graphics g, JComponent c ) {
renderer.paintMenuItem( g, selectionBackground, selectionForeground, disabledForeground,
acceleratorForeground, acceleratorSelectionForeground );
}
}

View File

@@ -42,16 +42,25 @@ import javax.swing.plaf.ComponentUI;
public class FlatCheckBoxUI
extends FlatRadioButtonUI
{
private static ComponentUI instance;
public static ComponentUI createUI( JComponent c ) {
if( instance == null )
instance = new FlatCheckBoxUI();
return instance;
return FlatUIUtils.canUseSharedUI( c )
? FlatUIUtils.createSharedUI( FlatCheckBoxUI.class, () -> new FlatCheckBoxUI( true ) )
: new FlatCheckBoxUI( false );
}
/** @since 2 */
protected FlatCheckBoxUI( boolean shared ) {
super( shared );
}
@Override
public String getPropertyPrefix() {
return "CheckBox.";
}
/** @since 2 */
@Override
String getStyleType() {
return "CheckBox";
}
}

View File

@@ -16,10 +16,12 @@
package com.formdev.flatlaf.ui;
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.Image;
import java.awt.Insets;
@@ -28,11 +30,13 @@ import java.awt.Point;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeListener;
import java.beans.PropertyVetoException;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDesktopPane;
import javax.swing.event.MouseInputAdapter;
import javax.swing.event.MouseInputListener;
import javax.swing.JLabel;
@@ -45,6 +49,7 @@ import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicDesktopIconUI;
import com.formdev.flatlaf.util.MultiResolutionImageSupport;
import com.formdev.flatlaf.util.UIScale;
/**
@@ -75,11 +80,21 @@ public class FlatDesktopIconUI
private JToolTip titleTip;
private ActionListener closeListener;
private MouseInputListener mouseInputListener;
private PropertyChangeListener ancestorListener;
public static ComponentUI createUI( JComponent c ) {
return new FlatDesktopIconUI();
}
@Override
public void installUI( JComponent c ) {
super.installUI( c );
// update dock icon preview if already iconified
if( c.isDisplayable() )
updateDockIconPreviewLater();
}
@Override
public void uninstallUI( JComponent c ) {
super.uninstallUI( c );
@@ -136,6 +151,17 @@ public class FlatDesktopIconUI
};
closeButton.addActionListener( closeListener );
closeButton.addMouseListener( mouseInputListener );
ancestorListener = e -> {
if( e.getNewValue() != null ) {
// update dock icon preview if desktopIcon is added to desktop (internal frame was iconified)
updateDockIconPreviewLater();
} else {
// remove preview icon to release memory
dockIcon.setIcon( null );
}
};
desktopIcon.addPropertyChangeListener( "ancestor", ancestorListener );
}
@Override
@@ -146,6 +172,9 @@ public class FlatDesktopIconUI
closeButton.removeMouseListener( mouseInputListener );
closeListener = null;
mouseInputListener = null;
desktopIcon.removePropertyChangeListener( "ancestor", ancestorListener );
ancestorListener = null;
}
@Override
@@ -228,15 +257,30 @@ public class FlatDesktopIconUI
return getPreferredSize( c );
}
void updateDockIcon() {
@Override
public void update( Graphics g, JComponent c ) {
if( c.isOpaque() ) {
// fill background with color derived from desktop pane
Color background = c.getBackground();
JDesktopPane desktopPane = desktopIcon.getDesktopPane();
g.setColor( (desktopPane != null)
? FlatUIUtils.deriveColor( background, desktopPane.getBackground() )
: background );
g.fillRect( 0, 0, c.getWidth(), c.getHeight() );
}
paint( g, c );
}
private void updateDockIconPreviewLater() {
// use invoke later to make sure that components are updated when switching LaF
EventQueue.invokeLater( () -> {
if( dockIcon != null )
updateDockIconLater();
updateDockIconPreview();
} );
}
private void updateDockIconLater() {
protected void updateDockIconPreview() {
// make sure that frame is not selected
if( frame.isSelected() ) {
try {
@@ -246,13 +290,22 @@ public class FlatDesktopIconUI
}
}
// layout internal frame title pane, which was recreated when switching Laf
// (directly invoke doLayout() because frame.validate() does not work here
// because frame is not displayable)
if( !frame.isValid() )
frame.doLayout();
for( Component c : frame.getComponents() ) {
if( !c.isValid() )
c.doLayout();
}
// paint internal frame to buffered image
int frameWidth = Math.max( frame.getWidth(), 1 );
int frameHeight = Math.max( frame.getHeight(), 1 );
BufferedImage frameImage = new BufferedImage( frameWidth, frameHeight, BufferedImage.TYPE_INT_ARGB );
Graphics2D g = frameImage.createGraphics();
try {
//TODO fix missing internal frame header when switching LaF
frame.paint( g );
} finally {
g.dispose();
@@ -270,6 +323,27 @@ public class FlatDesktopIconUI
// scale preview
Image previewImage = frameImage.getScaledInstance( previewWidth, previewHeight, Image.SCALE_SMOOTH );
if( MultiResolutionImageSupport.isAvailable() ) {
// On HiDPI screens, create preview images for 1x, 2x and current scale factor.
// The icon then chooses the best resolution for painting, which is usually
// the one for the current scale factor. But if changing scale factor or
// moving window to another screen with different scale factor, then another
// resolution may be used because the preview icon is not updated.
Image previewImage2x = frameImage.getScaledInstance( previewWidth * 2, previewHeight * 2, Image.SCALE_SMOOTH );
double scaleFactor = UIScale.getSystemScaleFactor( desktopIcon.getGraphicsConfiguration() );
if( scaleFactor != 1 && scaleFactor != 2 ) {
Image previewImageCurrent = frameImage.getScaledInstance(
(int) Math.round( previewWidth * scaleFactor ),
(int) Math.round( previewHeight * scaleFactor ),
Image.SCALE_SMOOTH );
// the images must be ordered by resolution
previewImage = (scaleFactor < 2)
? MultiResolutionImageSupport.create( 0, previewImage, previewImageCurrent, previewImage2x )
: MultiResolutionImageSupport.create( 0, previewImage, previewImage2x, previewImageCurrent );
} else
previewImage = MultiResolutionImageSupport.create( 0, previewImage, previewImage2x );
}
dockIcon.setIcon( new ImageIcon( previewImage ) );
}

View File

@@ -16,11 +16,16 @@
package com.formdev.flatlaf.ui;
import javax.swing.DefaultDesktopManager;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ContainerEvent;
import java.awt.event.ContainerListener;
import javax.swing.JComponent;
import javax.swing.JInternalFrame;
import javax.swing.JInternalFrame.JDesktopIcon;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicDesktopPaneUI;
/**
@@ -36,30 +41,96 @@ import javax.swing.plaf.basic.BasicDesktopPaneUI;
public class FlatDesktopPaneUI
extends BasicDesktopPaneUI
{
private LayoutDockListener layoutDockListener;
private boolean layoutDockPending;
public static ComponentUI createUI( JComponent c ) {
return new FlatDesktopPaneUI();
}
@Override
protected void installDesktopManager() {
desktopManager = desktop.getDesktopManager();
if( desktopManager == null ) {
desktopManager = new FlatDesktopManager();
desktop.setDesktopManager( desktopManager );
public void installUI( JComponent c ) {
super.installUI( c );
layoutDockLaterOnce();
}
@Override
protected void installListeners() {
super.installListeners();
layoutDockListener = new LayoutDockListener();
desktop.addContainerListener( layoutDockListener );
desktop.addComponentListener( layoutDockListener );
}
@Override
protected void uninstallListeners() {
super.uninstallListeners();
desktop.removeContainerListener( layoutDockListener );
desktop.removeComponentListener( layoutDockListener );
layoutDockListener = null;
}
private void layoutDockLaterOnce() {
if( layoutDockPending )
return;
layoutDockPending = true;
EventQueue.invokeLater( () -> {
layoutDockPending = false;
if( desktop != null )
layoutDock();
} );
}
protected void layoutDock() {
Dimension desktopSize = desktop.getSize();
int x = 0;
int y = desktopSize.height;
int rowHeight = 0;
for( Component c : desktop.getComponents() ) {
if( !(c instanceof JDesktopIcon) )
continue;
JDesktopIcon icon = (JDesktopIcon) c;
Dimension iconSize = icon.getPreferredSize();
if( x + iconSize.width > desktopSize.width ) {
// new row
x = 0;
y -= rowHeight;
rowHeight = 0;
}
icon.setLocation( x, y - iconSize.height );
x += iconSize.width;
rowHeight = Math.max( iconSize.height, rowHeight );
}
}
//---- class FlatDesktopManager -------------------------------------------
//---- class LayoutDockListener -------------------------------------------
private class FlatDesktopManager
extends DefaultDesktopManager
implements UIResource
private class LayoutDockListener
extends ComponentAdapter
implements ContainerListener
{
@Override
public void iconifyFrame( JInternalFrame f ) {
super.iconifyFrame( f );
public void componentAdded( ContainerEvent e ) {
layoutDockLaterOnce();
}
((FlatDesktopIconUI)f.getDesktopIcon().getUI()).updateDockIcon();
@Override
public void componentRemoved( ContainerEvent e ) {
layoutDockLaterOnce();
}
@Override
public void componentResized( ComponentEvent e ) {
layoutDockLaterOnce();
}
}
}

View File

@@ -0,0 +1,259 @@
/*
* Copyright 2020 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.ui;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Insets;
import java.awt.RadialGradientPaint;
import java.awt.image.BufferedImage;
import java.util.Map;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableBorder;
import com.formdev.flatlaf.util.HiDPIUtils;
import com.formdev.flatlaf.util.UIScale;
/**
* Paints a drop shadow border around the component.
* Supports 1-sided, 2-side, 3-sided or 4-sided drop shadows.
* <p>
* The shadow insets allow specifying drop shadow thickness for each side.
* A zero or negative value hides the drop shadow on that side.
* A negative value can be used to indent the drop shadow on corners.
* E.g. -4 on left indents drop shadow at top-left and bottom-left corners by 4 pixels.
*
* @author Karl Tauber
*/
public class FlatDropShadowBorder
extends FlatEmptyBorder
implements StyleableBorder
{
@Styleable protected Color shadowColor;
@Styleable protected Insets shadowInsets;
@Styleable protected float shadowOpacity;
private int shadowSize;
private Image shadowImage;
private Color lastShadowColor;
private float lastShadowOpacity;
private int lastShadowSize;
private double lastSystemScaleFactor;
private float lastUserScaleFactor;
public FlatDropShadowBorder() {
this( null );
}
public FlatDropShadowBorder( Color shadowColor ) {
this( shadowColor, 4, 0.5f );
}
public FlatDropShadowBorder( Color shadowColor, int shadowSize, float shadowOpacity ) {
this( shadowColor, new Insets( -shadowSize, -shadowSize, shadowSize, shadowSize ), shadowOpacity );
}
public FlatDropShadowBorder( Color shadowColor, Insets shadowInsets, float shadowOpacity ) {
super( nonNegativeInsets( shadowInsets ) );
this.shadowColor = shadowColor;
this.shadowInsets = shadowInsets;
this.shadowOpacity = shadowOpacity;
shadowSize = maxInset( shadowInsets );
}
private static Insets nonNegativeInsets( Insets shadowInsets ) {
return new Insets( Math.max( shadowInsets.top, 0 ), Math.max( shadowInsets.left, 0 ),
Math.max( shadowInsets.bottom, 0 ), Math.max( shadowInsets.right, 0 ) );
}
private int maxInset( Insets shadowInsets ) {
return Math.max(
Math.max( shadowInsets.left, shadowInsets.right ),
Math.max( shadowInsets.top, shadowInsets.bottom ) );
}
/** @since 2 */
@Override
public Object applyStyleProperty( String key, Object value ) {
Object oldValue = FlatStylingSupport.applyToAnnotatedObject( this, key, value );
if( key.equals( "shadowInsets" ) ) {
applyStyleProperty( nonNegativeInsets( shadowInsets ) );
shadowSize = maxInset( shadowInsets );
}
return oldValue;
}
/** @since 2 */
@Override
public Map<String, Class<?>> getStyleableInfos() {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
}
@Override
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
if( shadowSize <= 0 )
return;
HiDPIUtils.paintAtScale1x( (Graphics2D) g, x, y, width, height, this::paintImpl );
}
private void paintImpl( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
Color shadowColor = (this.shadowColor != null) ? this.shadowColor : g.getColor();
int shadowSize = scale( this.shadowSize, scaleFactor );
// create and cache shadow image
float userScaleFactor = UIScale.getUserScaleFactor();
if( shadowImage == null ||
!shadowColor.equals( lastShadowColor ) ||
lastShadowOpacity != shadowOpacity ||
lastShadowSize != shadowSize ||
lastSystemScaleFactor != scaleFactor ||
lastUserScaleFactor != userScaleFactor )
{
shadowImage = createShadowImage( shadowColor, shadowSize, shadowOpacity,
(float) (scaleFactor * userScaleFactor) );
lastShadowColor = shadowColor;
lastShadowOpacity = shadowOpacity;
lastShadowSize = shadowSize;
lastSystemScaleFactor = scaleFactor;
lastUserScaleFactor = userScaleFactor;
}
/*debug
int m = shadowImage.getWidth( null );
Color oldColor = g.getColor();
g.setColor( Color.lightGray );
g.drawRect( x - m - 1, y - m - 1, m + 1, m + 1 );
g.setColor( Color.white );
g.fillRect( x - m, y - m, m, m );
g.drawImage( shadowImage, x - m, y - m, null );
g.setColor( oldColor );
debug*/
int left = scale( shadowInsets.left, scaleFactor );
int right = scale( shadowInsets.right, scaleFactor );
int top = scale( shadowInsets.top, scaleFactor );
int bottom = scale( shadowInsets.bottom, scaleFactor );
// shadow outer coordinates
int x1o = x - Math.min( left, 0 );
int y1o = y - Math.min( top, 0 );
int x2o = x + width + Math.min( right, 0 );
int y2o = y + height + Math.min( bottom, 0 );
// shadow inner coordinates
int x1i = x1o + shadowSize;
int y1i = y1o + shadowSize;
int x2i = x2o - shadowSize;
int y2i = y2o - shadowSize;
int wh = (shadowSize * 2) - 1;
int center = shadowSize - 1;
// left-top edge
if( left > 0 || top > 0 ) {
g.drawImage( shadowImage, x1o, y1o, x1i, y1i,
0, 0, center, center, null );
}
// top shadow
if( top > 0 ) {
g.drawImage( shadowImage, x1i, y1o, x2i, y1i,
center, 0, center + 1, center, null );
}
// right-top edge
if( right > 0 || top > 0 ) {
g.drawImage( shadowImage, x2i, y1o, x2o, y1i,
center, 0, wh, center, null );
}
// left shadow
if( left > 0 ) {
g.drawImage( shadowImage, x1o, y1i, x1i, y2i,
0, center, center, center + 1, null );
}
// right shadow
if( right > 0 ) {
g.drawImage( shadowImage, x2i, y1i, x2o, y2i,
center, center, wh, center + 1, null );
}
// left-bottom edge
if( left > 0 || bottom > 0 ) {
g.drawImage( shadowImage, x1o, y2i, x1i, y2o,
0, center, center, wh, null );
}
// bottom shadow
if( bottom > 0 ) {
g.drawImage( shadowImage, x1i, y2i, x2i, y2o,
center, center, center + 1, wh, null );
}
// right-bottom edge
if( right > 0 || bottom > 0 ) {
g.drawImage( shadowImage, x2i, y2i, x2o, y2o,
center, center, wh, wh, null );
}
}
private int scale( int value, double scaleFactor ) {
return (int) Math.ceil( UIScale.scale( value ) * scaleFactor );
}
private static BufferedImage createShadowImage( Color shadowColor, int shadowSize,
float shadowOpacity, float scaleFactor )
{
int shadowRGB = shadowColor.getRGB() & 0xffffff;
int shadowAlpha = (int) (255 * shadowOpacity);
Color startColor = new Color( shadowRGB | ((shadowAlpha & 0xff) << 24), true );
Color midColor = new Color( shadowRGB | (((shadowAlpha / 2) & 0xff) << 24), true );
Color endColor = new Color( shadowRGB, true );
/*debug
startColor = Color.red;
midColor = Color.green;
endColor = Color.blue;
debug*/
int wh = (shadowSize * 2) - 1;
int center = shadowSize - 1;
RadialGradientPaint p = new RadialGradientPaint( center, center,
shadowSize - (0.75f * scaleFactor),
new float[] { 0, 0.35f, 1 },
new Color[] { startColor, midColor, endColor } );
BufferedImage image = new BufferedImage( wh, wh, BufferedImage.TYPE_INT_ARGB );
Graphics2D g = image.createGraphics();
try {
g.setPaint( p );
g.fillRect( 0, 0, wh, wh );
} finally {
g.dispose();
}
return image;
}
}

View File

@@ -17,15 +17,26 @@
package com.formdev.flatlaf.ui;
import static com.formdev.flatlaf.util.UIScale.scale;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.event.FocusListener;
import java.beans.PropertyChangeEvent;
import java.util.Map;
import javax.swing.JComponent;
import javax.swing.JEditorPane;
import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicEditorPaneUI;
import javax.swing.text.Caret;
import javax.swing.text.JTextComponent;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.util.HiDPIUtils;
import com.formdev.flatlaf.util.LoggingFacade;
/**
* Provides the Flat LaF UI delegate for {@link javax.swing.JEditorPane}.
@@ -49,27 +60,54 @@ import javax.swing.text.JTextComponent;
*
* @uiDefault Component.minimumWidth int
* @uiDefault Component.isIntelliJTheme boolean
* @uiDefault EditorPane.focusedBackground Color optional
*
* @author Karl Tauber
*/
public class FlatEditorPaneUI
extends BasicEditorPaneUI
implements StyleableUI
{
protected int minimumWidth;
@Styleable protected int minimumWidth;
protected boolean isIntelliJTheme;
private Color background;
@Styleable protected Color disabledBackground;
@Styleable protected Color inactiveBackground;
@Styleable protected Color focusedBackground;
private Color oldDisabledBackground;
private Color oldInactiveBackground;
private Insets defaultMargin;
private Object oldHonorDisplayProperties;
private FocusListener focusListener;
private Map<String, Object> oldStyleValues;
public static ComponentUI createUI( JComponent c ) {
return new FlatEditorPaneUI();
}
@Override
public void installUI( JComponent c ) {
super.installUI( c );
installStyle();
}
@Override
protected void installDefaults() {
super.installDefaults();
String prefix = getPropertyPrefix();
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
background = UIManager.getColor( prefix + ".background" );
disabledBackground = UIManager.getColor( prefix + ".disabledBackground" );
inactiveBackground = UIManager.getColor( prefix + ".inactiveBackground" );
focusedBackground = UIManager.getColor( prefix + ".focusedBackground" );
defaultMargin = UIManager.getInsets( prefix + ".margin" );
// use component font and foreground for HTML text
oldHonorDisplayProperties = getComponent().getClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES );
@@ -80,39 +118,139 @@ public class FlatEditorPaneUI
protected void uninstallDefaults() {
super.uninstallDefaults();
background = null;
disabledBackground = null;
inactiveBackground = null;
focusedBackground = null;
oldDisabledBackground = null;
oldInactiveBackground = null;
oldStyleValues = null;
getComponent().putClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES, oldHonorDisplayProperties );
}
@Override
protected void installListeners() {
super.installListeners();
// necessary to update focus background
focusListener = new FlatUIUtils.RepaintFocusListener( getComponent(), c -> focusedBackground != null );
getComponent().addFocusListener( focusListener );
}
@Override
protected void uninstallListeners() {
super.uninstallListeners();
getComponent().removeFocusListener( focusListener );
focusListener = null;
}
@Override
protected Caret createCaret() {
return new FlatCaret( null, false );
}
@Override
protected void propertyChange( PropertyChangeEvent e ) {
// invoke updateBackground() before super.propertyChange()
String propertyName = e.getPropertyName();
if( "editable".equals( propertyName ) || "enabled".equals( propertyName ) )
updateBackground();
super.propertyChange( e );
propertyChange( getComponent(), e, this::installStyle );
}
static void propertyChange( JTextComponent c, PropertyChangeEvent e, Runnable installStyle ) {
switch( e.getPropertyName() ) {
case FlatClientProperties.MINIMUM_WIDTH:
c.revalidate();
break;
case FlatClientProperties.STYLE:
case FlatClientProperties.STYLE_CLASS:
installStyle.run();
c.revalidate();
c.repaint();
break;
}
}
/** @since 2 */
protected void installStyle() {
try {
applyStyle( FlatStylingSupport.getResolvedStyle( getComponent(), "EditorPane" ) );
} catch( RuntimeException ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex );
}
}
/** @since 2 */
protected void applyStyle( Object style ) {
oldDisabledBackground = disabledBackground;
oldInactiveBackground = inactiveBackground;
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
updateBackground();
}
/** @since 2 */
protected Object applyStyleProperty( String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, getComponent(), key, value );
}
/** @since 2 */
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
}
private void updateBackground() {
FlatTextFieldUI.updateBackground( getComponent(), background,
disabledBackground, inactiveBackground,
oldDisabledBackground, oldInactiveBackground );
}
@Override
public Dimension getPreferredSize( JComponent c ) {
return applyMinimumWidth( super.getPreferredSize( c ) );
return applyMinimumWidth( c, super.getPreferredSize( c ), minimumWidth, defaultMargin );
}
@Override
public Dimension getMinimumSize( JComponent c ) {
return applyMinimumWidth( super.getMinimumSize( c ) );
return applyMinimumWidth( c, super.getMinimumSize( c ), minimumWidth, defaultMargin );
}
private Dimension applyMinimumWidth( Dimension size ) {
static Dimension applyMinimumWidth( JComponent c, Dimension size, int minimumWidth, Insets defaultMargin ) {
// do not apply minimum width if JTextComponent.margin is set
if( !FlatTextFieldUI.hasDefaultMargins( c, defaultMargin ) )
return size;
// Assume that text area is in a scroll pane (that displays the border)
// and subtract 1px border line width.
// Using "(scale( 1 ) * 2)" instead of "scale( 2 )" to deal with rounding
// issues. E.g. at scale factor 1.5 the first returns 4, but the second 3.
int minimumWidth = FlatUIUtils.minimumWidth( getComponent(), this.minimumWidth );
minimumWidth = FlatUIUtils.minimumWidth( c, minimumWidth );
size.width = Math.max( size.width, scale( minimumWidth ) - (scale( 1 ) * 2) );
return size;
}
@Override
protected void paintSafely( Graphics g ) {
super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) );
}
@Override
protected void paintBackground( Graphics g ) {
JTextComponent c = getComponent();
paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground );
}
// for compatibility with IntelliJ themes
if( isIntelliJTheme && (!c.isEnabled() || !c.isEditable()) && (c.getBackground() instanceof UIResource) ) {
FlatUIUtils.paintParentBackground( g, c );
return;
}
super.paintBackground( g );
static void paintBackground( Graphics g, JTextComponent c, boolean isIntelliJTheme, Color focusedBackground ) {
g.setColor( FlatTextFieldUI.getBackground( c, isIntelliJTheme, focusedBackground ) );
g.fillRect( 0, 0, c.getWidth(), c.getHeight() );
}
}

View File

@@ -50,6 +50,12 @@ public class FlatEmptyBorder
@Override
public Insets getBorderInsets( Component c, Insets insets ) {
return scaleInsets( c, insets, top, left, bottom, right );
}
protected static Insets scaleInsets( Component c, Insets insets,
int top, int left, int bottom, int right )
{
boolean leftToRight = left == right || c.getComponentOrientation().isLeftToRight();
insets.left = scale( leftToRight ? left : right );
insets.top = scale( top );
@@ -57,4 +63,17 @@ public class FlatEmptyBorder
insets.bottom = scale( bottom );
return insets;
}
public Insets getUnscaledBorderInsets() {
return super.getBorderInsets();
}
public Object applyStyleProperty( Insets insets ) {
Insets oldInsets = getUnscaledBorderInsets();
top = insets.top;
left = insets.left;
bottom = insets.bottom;
right = insets.right;
return oldInsets;
}
}

View File

@@ -16,11 +16,32 @@
package com.formdev.flatlaf.ui;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Insets;
import java.io.File;
import javax.swing.AbstractButton;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JToggleButton;
import javax.swing.UIManager;
import javax.swing.filechooser.FileView;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.metal.MetalFileChooserUI;
import javax.swing.table.TableCellRenderer;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.util.ScaledImageIcon;
import com.formdev.flatlaf.util.SystemInfo;
import com.formdev.flatlaf.util.UIScale;
/**
@@ -86,6 +107,7 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault FileChooser.folderNameLabelText String
* @uiDefault FileChooser.filesOfTypeLabelMnemonic String
* @uiDefault FileChooser.filesOfTypeLabelText String
*
* @uiDefault FileChooser.upFolderToolTipText String
* @uiDefault FileChooser.upFolderAccessibleName String
* @uiDefault FileChooser.homeFolderToolTipText String
@@ -97,11 +119,27 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault FileChooser.detailsViewButtonToolTipText String
* @uiDefault FileChooser.detailsViewButtonAccessibleName String
*
* <!-- FilePane -->
*
* @uiDefault FileChooser.fileNameHeaderText String
* @uiDefault FileChooser.fileSizeHeaderText String
* @uiDefault FileChooser.fileTypeHeaderText String
* @uiDefault FileChooser.fileDateHeaderText String
* @uiDefault FileChooser.fileAttrHeaderText String
*
* @uiDefault FileChooser.viewMenuLabelText String
* @uiDefault FileChooser.refreshActionLabelText String
* @uiDefault FileChooser.newFolderActionLabelText String
* @uiDefault FileChooser.listViewActionLabelText String
* @uiDefault FileChooser.detailsViewActionLabelText String
*
* @author Karl Tauber
*/
public class FlatFileChooserUI
extends MetalFileChooserUI
{
private final FlatFileView fileView = new FlatFileView();
public static ComponentUI createUI( JComponent c ) {
return new FlatFileChooserUI( (JFileChooser) c );
}
@@ -110,6 +148,108 @@ public class FlatFileChooserUI
super( filechooser );
}
@Override
public void installComponents( JFileChooser fc ) {
super.installComponents( fc );
patchUI( fc );
}
private void patchUI( JFileChooser fc ) {
// turn top-right buttons into toolbar buttons
Component topPanel = fc.getComponent( 0 );
if( (topPanel instanceof JPanel) &&
(((JPanel)topPanel).getLayout() instanceof BorderLayout) )
{
Component topButtonPanel = ((JPanel)topPanel).getComponent( 0 );
if( (topButtonPanel instanceof JPanel) &&
(((JPanel)topButtonPanel).getLayout() instanceof BoxLayout) )
{
Insets margin = UIManager.getInsets( "Button.margin" );
Component[] comps = ((JPanel)topButtonPanel).getComponents();
for( int i = comps.length - 1; i >= 0; i-- ) {
Component c = comps[i];
if( c instanceof JButton || c instanceof JToggleButton ) {
AbstractButton b = (AbstractButton)c;
b.putClientProperty( FlatClientProperties.BUTTON_TYPE,
FlatClientProperties.BUTTON_TYPE_TOOLBAR_BUTTON );
b.setMargin( margin );
b.setFocusable( false );
} else if( c instanceof Box.Filler )
((JPanel)topButtonPanel).remove( i );
}
}
}
// increase maximum row count of directory combo box popup list
try {
Component directoryComboBox = ((JPanel)topPanel).getComponent( 2 );
if( directoryComboBox instanceof JComboBox ) {
int maximumRowCount = UIManager.getInt( "ComboBox.maximumRowCount" );
if( maximumRowCount > 0 )
((JComboBox<?>)directoryComboBox).setMaximumRowCount( maximumRowCount );
}
} catch( ArrayIndexOutOfBoundsException ex ) {
// ignore
}
}
@Override
protected JPanel createDetailsView( JFileChooser fc ) {
JPanel p = super.createDetailsView( fc );
if( !SystemInfo.isWindows )
return p;
// find scroll pane
JScrollPane scrollPane = null;
for( Component c : p.getComponents() ) {
if( c instanceof JScrollPane ) {
scrollPane = (JScrollPane) c;
break;
}
}
if( scrollPane == null )
return p;
// get scroll view, which should be a table
Component view = scrollPane.getViewport().getView();
if( !(view instanceof JTable) )
return p;
JTable table = (JTable) view;
// on Windows 10, the date may contain left-to-right (0x200e) and right-to-left (0x200f)
// mark characters (see https://en.wikipedia.org/wiki/Left-to-right_mark)
// when the "current user" item is selected in the "look in" combobox
// --> remove them
TableCellRenderer defaultRenderer = table.getDefaultRenderer( Object.class );
table.setDefaultRenderer( Object.class, new TableCellRenderer() {
@Override
public Component getTableCellRendererComponent( JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int column )
{
// remove left-to-right and right-to-left mark characters
if( value instanceof String && ((String)value).startsWith( "\u200e" ) ) {
String str = (String) value;
char[] buf = new char[str.length()];
int j = 0;
for( int i = 0; i < buf.length; i++ ) {
char ch = str.charAt( i );
if( ch != '\u200e' && ch != '\u200f' )
buf[j++] = ch;
}
value = new String( buf, 0, j );
}
return defaultRenderer.getTableCellRendererComponent( table, value, isSelected, hasFocus, row, column );
}
} );
return p;
}
@Override
public Dimension getPreferredSize( JComponent c ) {
return UIScale.scale( super.getPreferredSize( c ) );
@@ -119,4 +259,58 @@ public class FlatFileChooserUI
public Dimension getMinimumSize( JComponent c ) {
return UIScale.scale( super.getMinimumSize( c ) );
}
@Override
public FileView getFileView( JFileChooser fc ) {
return doNotUseSystemIcons() ? super.getFileView( fc ) : fileView;
}
@Override
public void clearIconCache() {
if( doNotUseSystemIcons() )
super.clearIconCache();
else
fileView.clearIconCache();
}
private boolean doNotUseSystemIcons() {
// Java 17 32bit craches on Windows when using system icons
return SystemInfo.isWindows && SystemInfo.isJava_17_orLater && !SystemInfo.isX86_64;
}
//---- class FlatFileView -------------------------------------------------
private class FlatFileView
extends BasicFileView
{
@Override
public Icon getIcon( File f ) {
// get cached icon
Icon icon = getCachedIcon( f );
if( icon != null )
return icon;
// get system icon
if( f != null ) {
icon = getFileChooser().getFileSystemView().getSystemIcon( f );
if( icon != null ) {
if( icon instanceof ImageIcon )
icon = new ScaledImageIcon( (ImageIcon) icon );
cacheIcon( f, icon );
return icon;
}
}
// get default icon
icon = super.getIcon( f );
if( icon instanceof ImageIcon ) {
icon = new ScaledImageIcon( (ImageIcon) icon );
cacheIcon( f, icon );
}
return icon;
}
}
}

View File

@@ -39,12 +39,13 @@ import javax.swing.plaf.ComponentUI;
*
* <!-- FlatTextFieldUI -->
*
* @uiDefault TextComponent.arc int
* @uiDefault Component.focusWidth int
* @uiDefault Component.minimumWidth int
* @uiDefault Component.isIntelliJTheme boolean
* @uiDefault FormattedTextField.placeholderForeground Color
* @uiDefault FormattedTextField.focusedBackground Color optional
* @uiDefault FormattedTextField.iconTextGap int optional, default is 4
* @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always
* @uiDefault TextComponent.selectAllOnMouseClick boolean
*
* @author Karl Tauber
*/
@@ -59,4 +60,10 @@ public class FlatFormattedTextFieldUI
protected String getPropertyPrefix() {
return "FormattedTextField";
}
/** @since 2 */
@Override
String getStyleType() {
return "FormattedTextField";
}
}

View File

@@ -21,18 +21,20 @@ import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.LayoutManager;
import java.awt.Rectangle;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.LookAndFeel;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.plaf.basic.BasicInternalFrameTitlePane;
import com.formdev.flatlaf.util.ScaledImageIcon;
import com.formdev.flatlaf.util.UIScale;
/**
@@ -91,7 +93,21 @@ public class FlatInternalFrameTitlePane
updateFrameIcon();
updateColors();
buttonPanel = new JPanel();
buttonPanel = new JPanel() {
@Override
public Dimension getPreferredSize() {
Dimension size = super.getPreferredSize();
int height = size.height;
// use height of invisible buttons to always have same title pane height
if( !iconButton.isVisible() )
height = Math.max( height, iconButton.getPreferredSize().height );
if( !maxButton.isVisible() )
height = Math.max( height, maxButton.getPreferredSize().height );
if( !closeButton.isVisible() )
height = Math.max( height, closeButton.getPreferredSize().height );
return new Dimension( size.width, height );
}
};
buttonPanel.setLayout( new BoxLayout( buttonPanel, BoxLayout.LINE_AXIS ) );
buttonPanel.setOpaque( false );
@@ -103,14 +119,16 @@ public class FlatInternalFrameTitlePane
add( buttonPanel, BorderLayout.LINE_END );
}
private void updateFrameIcon() {
protected void updateFrameIcon() {
Icon frameIcon = frame.getFrameIcon();
if( frameIcon == UIManager.getIcon( "InternalFrame.icon" ) )
if( frameIcon != null && (frameIcon.getIconWidth() == 0 || frameIcon.getIconHeight() == 0) )
frameIcon = null;
else if( frameIcon instanceof ImageIcon )
frameIcon = new ScaledImageIcon( (ImageIcon) frameIcon );
titleLabel.setIcon( frameIcon );
}
private void updateColors() {
protected void updateColors() {
Color background = FlatUIUtils.nonUIResource( frame.isSelected() ? selectedTitleColor : notSelectedTitleColor );
Color foreground = FlatUIUtils.nonUIResource( frame.isSelected() ? selectedTextColor : notSelectedTextColor );
@@ -123,12 +141,25 @@ public class FlatInternalFrameTitlePane
closeButton.setForeground( foreground );
}
private void updateButtonsVisibility() {
protected void updateButtonsVisibility() {
iconButton.setVisible( frame.isIconifiable() );
maxButton.setVisible( frame.isMaximizable() );
closeButton.setVisible( frame.isClosable() );
}
Rectangle getFrameIconBounds() {
Icon icon = titleLabel.getIcon();
if( icon == null )
return null;
int iconWidth = icon.getIconWidth();
int iconHeight = icon.getIconHeight();
boolean leftToRight = titleLabel.getComponentOrientation().isLeftToRight();
int x = titleLabel.getX() + (leftToRight ? 0 : (titleLabel.getWidth() - iconWidth));
int y = titleLabel.getY() + ((titleLabel.getHeight() - iconHeight) / 2);
return new Rectangle( x, y, iconWidth, iconHeight );
}
/**
* Does nothing because FlatLaf internal frames do not have system menus.
*/
@@ -150,7 +181,7 @@ public class FlatInternalFrameTitlePane
//---- class FlatPropertyChangeHandler ------------------------------------
private class FlatPropertyChangeHandler
protected class FlatPropertyChangeHandler
extends PropertyChangeHandler
{
@Override

View File

@@ -22,12 +22,22 @@ import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeListener;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.JComponent;
import javax.swing.JInternalFrame;
import javax.swing.LookAndFeel;
import javax.swing.UIManager;
import javax.swing.event.MouseInputAdapter;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicInternalFrameUI;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableBorder;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.util.LoggingFacade;
/**
* Provides the Flat LaF UI delegate for {@link javax.swing.JInternalFrame}.
@@ -83,7 +93,13 @@ import javax.swing.plaf.basic.BasicInternalFrameUI;
*/
public class FlatInternalFrameUI
extends BasicInternalFrameUI
implements StyleableUI
{
protected FlatWindowResizer windowResizer;
private Map<String, Object> oldStyleValues;
private AtomicBoolean borderShared;
public static ComponentUI createUI( JComponent c ) {
return new FlatInternalFrameUI( (JInternalFrame) c );
}
@@ -97,6 +113,23 @@ public class FlatInternalFrameUI
super.installUI( c );
LookAndFeel.installProperty( frame, "opaque", false );
windowResizer = createWindowResizer();
installStyle();
}
@Override
public void uninstallUI( JComponent c ) {
super.uninstallUI( c );
if( windowResizer != null ) {
windowResizer.uninstall();
windowResizer = null;
}
oldStyleValues = null;
borderShared = null;
}
@Override
@@ -104,19 +137,102 @@ public class FlatInternalFrameUI
return new FlatInternalFrameTitlePane( w );
}
protected FlatWindowResizer createWindowResizer() {
return new FlatWindowResizer.InternalFrameResizer( frame, this::getDesktopManager );
}
@Override
protected MouseInputAdapter createBorderListener( JInternalFrame w ) {
return new FlatBorderListener();
}
@Override
protected PropertyChangeListener createPropertyChangeListener() {
return FlatStylingSupport.createPropertyChangeListener( frame, this::installStyle,
super.createPropertyChangeListener() );
}
/** @since 2 */
protected void installStyle() {
try {
applyStyle( FlatStylingSupport.getResolvedStyle( frame, "InternalFrame" ) );
} catch( RuntimeException ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex );
}
}
/** @since 2 */
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
}
/** @since 2 */
protected Object applyStyleProperty( String key, Object value ) {
if( borderShared == null )
borderShared = new AtomicBoolean( true );
return FlatStylingSupport.applyToAnnotatedObjectOrBorder( this, key, value, frame, borderShared );
}
/** @since 2 */
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return FlatStylingSupport.getAnnotatedStyleableInfos( this, frame.getBorder() );
}
//---- class FlatInternalFrameBorder --------------------------------------
public static class FlatInternalFrameBorder
extends FlatEmptyBorder
implements StyleableBorder
{
private final Color activeBorderColor = UIManager.getColor( "InternalFrame.activeBorderColor" );
private final Color inactiveBorderColor = UIManager.getColor( "InternalFrame.inactiveBorderColor" );
private final int borderLineWidth = FlatUIUtils.getUIInt( "InternalFrame.borderLineWidth", 1 );
@Styleable protected Color activeBorderColor = UIManager.getColor( "InternalFrame.activeBorderColor" );
@Styleable protected Color inactiveBorderColor = UIManager.getColor( "InternalFrame.inactiveBorderColor" );
@Styleable protected int borderLineWidth = FlatUIUtils.getUIInt( "InternalFrame.borderLineWidth", 1 );
@Styleable protected boolean dropShadowPainted = UIManager.getBoolean( "InternalFrame.dropShadowPainted" );
private final FlatDropShadowBorder activeDropShadowBorder = new FlatDropShadowBorder(
UIManager.getColor( "InternalFrame.activeDropShadowColor" ),
UIManager.getInsets( "InternalFrame.activeDropShadowInsets" ),
FlatUIUtils.getUIFloat( "InternalFrame.activeDropShadowOpacity", 0.5f ) );
private final FlatDropShadowBorder inactiveDropShadowBorder = new FlatDropShadowBorder(
UIManager.getColor( "InternalFrame.inactiveDropShadowColor" ),
UIManager.getInsets( "InternalFrame.inactiveDropShadowInsets" ),
FlatUIUtils.getUIFloat( "InternalFrame.inactiveDropShadowOpacity", 0.5f ) );
public FlatInternalFrameBorder() {
super( UIManager.getInsets( "InternalFrame.borderMargins" ) );
}
@Override
public Object applyStyleProperty( String key, Object value ) {
switch( key ) {
case "borderMargins": return applyStyleProperty( (Insets) value );
case "activeDropShadowColor": return activeDropShadowBorder.applyStyleProperty( "shadowColor", value );
case "activeDropShadowInsets": return activeDropShadowBorder.applyStyleProperty( "shadowInsets", value );
case "activeDropShadowOpacity": return activeDropShadowBorder.applyStyleProperty( "shadowOpacity", value );
case "inactiveDropShadowColor": return inactiveDropShadowBorder.applyStyleProperty( "shadowColor", value );
case "inactiveDropShadowInsets": return inactiveDropShadowBorder.applyStyleProperty( "shadowInsets", value );
case "inactiveDropShadowOpacity": return inactiveDropShadowBorder.applyStyleProperty( "shadowOpacity", value );
}
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
}
@Override
public Map<String, Class<?>> getStyleableInfos() {
Map<String, Class<?>> infos = new FlatStylingSupport.StyleableInfosMap<>();
FlatStylingSupport.collectAnnotatedStyleableInfos( this, infos );
infos.put( "borderMargins", Insets.class );
infos.put( "activeDropShadowColor", Color.class );
infos.put( "activeDropShadowInsets", Insets.class );
infos.put( "activeDropShadowOpacity", float.class );
infos.put( "inactiveDropShadowColor", Color.class );
infos.put( "inactiveDropShadowInsets", Insets.class );
infos.put( "inactiveDropShadowOpacity", float.class );
return infos;
}
@Override
public Insets getBorderInsets( Component c, Insets insets ) {
if( c instanceof JInternalFrame && ((JInternalFrame)c).isMaximum() ) {
@@ -137,19 +253,57 @@ public class FlatInternalFrameUI
Insets insets = getBorderInsets( c );
float lineWidth = scale( (float) borderLineWidth );
float rx = x + insets.left - lineWidth;
float ry = y + insets.top - lineWidth;
float rwidth = width - insets.left - insets.right + (lineWidth * 2);
float rheight = height - insets.top - insets.bottom + (lineWidth * 2);
Graphics2D g2 = (Graphics2D) g.create();
try {
FlatUIUtils.setRenderingHints( g2 );
g2.setColor( f.isSelected() ? activeBorderColor : inactiveBorderColor );
g2.fill( FlatUIUtils.createRectangle(
x + insets.left - lineWidth,
y + insets.top - lineWidth,
width - insets.left - insets.right + (lineWidth * 2),
height - insets.top - insets.bottom + (lineWidth * 2),
lineWidth ) );
// paint drop shadow
if( dropShadowPainted ) {
FlatDropShadowBorder dropShadowBorder = f.isSelected()
? activeDropShadowBorder : inactiveDropShadowBorder;
Insets dropShadowInsets = dropShadowBorder.getBorderInsets();
dropShadowBorder.paintBorder( c, g2,
(int) rx - dropShadowInsets.left,
(int) ry - dropShadowInsets.top,
(int) rwidth + dropShadowInsets.left + dropShadowInsets.right,
(int) rheight + dropShadowInsets.top + dropShadowInsets.bottom );
}
// paint border
g2.fill( FlatUIUtils.createRectangle( rx, ry, rwidth, rheight, lineWidth ) );
} finally {
g2.dispose();
}
}
}
//---- class FlatBorderListener -------------------------------------------
/** @since 1.6 */
protected class FlatBorderListener
extends BorderListener
{
@Override
public void mouseClicked( MouseEvent e ) {
if( e.getClickCount() == 2 && !frame.isIcon() &&
e.getSource() instanceof FlatInternalFrameTitlePane )
{
Rectangle iconBounds = ((FlatInternalFrameTitlePane)e.getSource()).getFrameIconBounds();
if( iconBounds != null && iconBounds.contains( e.getX(), e.getY() ) ) {
if( frame.isClosable() )
frame.doDefaultCloseAction();
return;
}
}
super.mouseClicked( e );
}
}
}

View File

@@ -19,8 +19,13 @@ package com.formdev.flatlaf.ui;
import java.awt.Color;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.beans.PropertyChangeEvent;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JLabel;
@@ -29,7 +34,12 @@ import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicHTML;
import javax.swing.plaf.basic.BasicLabelUI;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.util.HiDPIUtils;
import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.UIScale;
/**
@@ -49,17 +59,30 @@ import com.formdev.flatlaf.util.UIScale;
*/
public class FlatLabelUI
extends BasicLabelUI
implements StyleableUI
{
private Color disabledForeground;
@Styleable protected Color disabledForeground;
private final boolean shared;
private boolean defaults_initialized = false;
private static ComponentUI instance;
private Map<String, Object> oldStyleValues;
public static ComponentUI createUI( JComponent c ) {
if( instance == null )
instance = new FlatLabelUI();
return instance;
return FlatUIUtils.canUseSharedUI( c )
? FlatUIUtils.createSharedUI( FlatLabelUI.class, () -> new FlatLabelUI( true ) )
: new FlatLabelUI( false );
}
/** @since 2 */
protected FlatLabelUI( boolean shared ) {
this.shared = shared;
}
@Override
public void installUI( JComponent c ) {
super.installUI( c );
installStyle( (JLabel) c );
}
@Override
@@ -76,7 +99,9 @@ public class FlatLabelUI
@Override
protected void uninstallDefaults( JLabel c ) {
super.uninstallDefaults( c );
defaults_initialized = false;
oldStyleValues = null;
}
@Override
@@ -93,28 +118,78 @@ public class FlatLabelUI
if( name == "text" || name == "font" || name == "foreground" ) {
JLabel label = (JLabel) e.getSource();
updateHTMLRenderer( label, label.getText(), true );
} else if( name.equals( FlatClientProperties.STYLE ) || name.equals( FlatClientProperties.STYLE_CLASS ) ) {
JLabel label = (JLabel) e.getSource();
if( shared && FlatStylingSupport.hasStyleProperty( label ) ) {
// unshare component UI if necessary
// updateUI() invokes applyStyle() from installUI()
label.updateUI();
} else
installStyle( label );
label.revalidate();
label.repaint();
} else
super.propertyChange( e );
}
/** @since 2 */
protected void installStyle( JLabel c ) {
try {
applyStyle( c, FlatStylingSupport.getResolvedStyle( c, "Label" ) );
} catch( RuntimeException ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex );
}
}
/** @since 2 */
protected void applyStyle( JLabel c, Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style,
(key, value) -> applyStyleProperty( c, key, value ) );
}
/** @since 2 */
protected Object applyStyleProperty( JLabel c, String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, c, key, value );
}
/** @since 2 */
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
}
/**
* Checks whether text contains HTML headings and adds a special CSS rule to
* re-calculate heading font sizes based on current component font size.
* Checks whether text contains HTML tags that use "absolute-size" keywords
* (e.g. "x-large") for font-size in default style sheet
* (see javax/swing/text/html/default.css).
* If yes, adds a special CSS rule (BASE_SIZE) to the HTML text, which
* re-calculates font sizes based on current component font size.
*/
static void updateHTMLRenderer( JComponent c, String text, boolean always ) {
if( BasicHTML.isHTMLString( text ) &&
c.getClientProperty( "html.disable" ) != Boolean.TRUE &&
text.contains( "<h" ) &&
(text.contains( "<h1" ) || text.contains( "<h2" ) || text.contains( "<h3" ) ||
text.contains( "<h4" ) || text.contains( "<h5" ) || text.contains( "<h6" )) )
needsFontBaseSize( text ) )
{
int headIndex = text.indexOf( "<head>" );
// BASE_SIZE rule is parsed in javax.swing.text.html.StyleSheet.addRule()
String style = "<style>BASE_SIZE " + c.getFont().getSize() + "</style>";
if( headIndex < 0 )
style = "<head>" + style + "</head>";
int insertIndex = headIndex >= 0 ? (headIndex + "<head>".length()) : "<html>".length();
String lowerText = text.toLowerCase();
int headIndex;
int styleIndex;
int insertIndex;
if( (headIndex = lowerText.indexOf( "<head>" )) >= 0 ) {
// there is a <head> tag --> insert after <head> tag
insertIndex = headIndex + "<head>".length();
} else if( (styleIndex = lowerText.indexOf( "<style>" )) >= 0 ) {
// there is a <style> tag --> insert before <style> tag
insertIndex = styleIndex;
} else {
// no <head> or <style> tag --> insert <head> tag after <html> tag
style = "<head>" + style + "</head>";
insertIndex = "<html>".length();
}
text = text.substring( 0, insertIndex )
+ style
+ text.substring( insertIndex );
@@ -124,6 +199,55 @@ public class FlatLabelUI
BasicHTML.updateRenderer( c, text );
}
private static Set<String> tagsUseFontSizeSet;
private static boolean needsFontBaseSize( String text ) {
if( tagsUseFontSizeSet == null ) {
// tags that use font-size in javax/swing/text/html/default.css
tagsUseFontSizeSet = new HashSet<>( Arrays.asList(
"h1", "h2", "h3", "h4", "h5", "h6", "code", "kbd", "big", "small", "samp" ) );
}
// search for tags in HTML text
int textLength = text.length();
for( int i = 6; i < textLength - 1; i++ ) {
if( text.charAt( i ) == '<' ) {
switch( text.charAt( i + 1 ) ) {
// first letters of tags in tagsUseFontSizeSet
case 'b': case 'B':
case 'c': case 'C':
case 'h': case 'H':
case 'k': case 'K':
case 's': case 'S':
int tagBegin = i + 1;
for( i += 2; i < textLength; i++ ) {
if( !Character.isLetterOrDigit( text.charAt( i ) ) ) {
String tag = text.substring( tagBegin, i ).toLowerCase();
if( tagsUseFontSizeSet.contains( tag ) )
return true;
break;
}
}
break;
}
}
}
return false;
}
static Graphics createGraphicsHTMLTextYCorrection( Graphics g, JComponent c ) {
return (c.getClientProperty( BasicHTML.propertyKey ) != null)
? HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g )
: g;
}
@Override
public void paint( Graphics g, JComponent c ) {
super.paint( createGraphicsHTMLTextYCorrection( g, c ), c );
}
@Override
protected void paintEnabledText( JLabel l, Graphics g, String s, int textX, int textY ) {
int mnemIndex = FlatLaf.isShowMnemonics() ? l.getDisplayedMnemonicIndex() : -1;

View File

@@ -48,13 +48,21 @@ public class FlatLineBorder
this.lineThickness = lineThickness;
}
public Color getLineColor() {
return lineColor;
}
public float getLineThickness() {
return lineThickness;
}
@Override
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
Graphics2D g2 = (Graphics2D) g.create();
try {
FlatUIUtils.setRenderingHints( g2 );
g2.setColor( lineColor );
FlatUIUtils.paintComponentBorder( g2, x, y, width, height, 0f, scale( lineThickness ), 0f );
FlatUIUtils.paintOutlinedComponent( g2, x, y, width, height,
0, 0, 0, scale( getLineThickness() ), 0, null, getLineColor(), null );
} finally {
g2.dispose();
}

View File

@@ -16,11 +16,15 @@
package com.formdev.flatlaf.ui;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Insets;
import java.util.function.Function;
import javax.swing.JList;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.plaf.ListUI;
/**
* Cell border for {@link javax.swing.DefaultListCellRenderer}
@@ -33,12 +37,54 @@ import javax.swing.UIManager;
public class FlatListCellBorder
extends FlatLineBorder
{
final boolean showCellFocusIndicator = UIManager.getBoolean( "List.showCellFocusIndicator" );
protected boolean showCellFocusIndicator = UIManager.getBoolean( "List.showCellFocusIndicator" );
private Component c;
protected FlatListCellBorder() {
super( UIManager.getInsets( "List.cellMargins" ), UIManager.getColor( "List.cellFocusColor" ) );
}
@Override
public Insets getBorderInsets( Component c, Insets insets ) {
Insets m = getStyleFromListUI( c, ui -> ui.cellMargins );
if( m != null )
return scaleInsets( c, insets, m.top, m.left, m.bottom, m.right );
return super.getBorderInsets( c, insets );
}
@Override
public Color getLineColor() {
if( c != null ) {
Color color = getStyleFromListUI( c, ui -> ui.cellFocusColor );
if( color != null )
return color;
}
return super.getLineColor();
}
@Override
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
this.c = c;
super.paintBorder( c, g, x, y, width, height );
this.c = null;
}
/**
* Because this borders are always shared for all lists,
* get border specific style from FlatListUI.
*/
static <T> T getStyleFromListUI( Component c, Function<FlatListUI, T> f ) {
JList<?> list = (JList<?>) SwingUtilities.getAncestorOfClass( JList.class, c );
if( list != null ) {
ListUI ui = list.getUI();
if( ui instanceof FlatListUI )
return f.apply( (FlatListUI) ui );
}
return null;
}
//---- class Default ------------------------------------------------------
/**
@@ -74,6 +120,8 @@ public class FlatListCellBorder
{
@Override
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
Boolean b = getStyleFromListUI( c, ui -> ui.showCellFocusIndicator );
boolean showCellFocusIndicator = (b != null) ? b : this.showCellFocusIndicator;
if( !showCellFocusIndicator )
return;

View File

@@ -17,12 +17,20 @@
package com.formdev.flatlaf.ui;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Insets;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.beans.PropertyChangeListener;
import java.util.Map;
import javax.swing.JComponent;
import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicListUI;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.util.LoggingFacade;
/**
* Provides the Flat LaF UI delegate for {@link javax.swing.JList}.
@@ -62,16 +70,31 @@ import javax.swing.plaf.basic.BasicListUI;
*/
public class FlatListUI
extends BasicListUI
implements StyleableUI
{
protected Color selectionBackground;
protected Color selectionForeground;
protected Color selectionInactiveBackground;
protected Color selectionInactiveForeground;
@Styleable protected Color selectionBackground;
@Styleable protected Color selectionForeground;
@Styleable protected Color selectionInactiveBackground;
@Styleable protected Color selectionInactiveForeground;
// for FlatListCellBorder
@Styleable protected Insets cellMargins;
@Styleable protected Color cellFocusColor;
@Styleable protected boolean showCellFocusIndicator;
private Map<String, Object> oldStyleValues;
public static ComponentUI createUI( JComponent c ) {
return new FlatListUI();
}
@Override
public void installUI( JComponent c ) {
super.installUI( c );
installStyle();
}
@Override
protected void installDefaults() {
super.installDefaults();
@@ -92,6 +115,8 @@ public class FlatListUI
selectionForeground = null;
selectionInactiveBackground = null;
selectionInactiveForeground = null;
oldStyleValues = null;
}
@Override
@@ -106,11 +131,84 @@ public class FlatListUI
@Override
public void focusLost( FocusEvent e ) {
super.focusLost( e );
toggleSelectionColors();
// use invokeLater for the case that the window is deactivated
EventQueue.invokeLater( () -> {
toggleSelectionColors();
} );
}
};
}
@Override
protected PropertyChangeListener createPropertyChangeListener() {
PropertyChangeListener superListener = super.createPropertyChangeListener();
return e -> {
superListener.propertyChange( e );
switch( e.getPropertyName() ) {
case FlatClientProperties.COMPONENT_FOCUS_OWNER:
toggleSelectionColors();
break;
case FlatClientProperties.STYLE:
case FlatClientProperties.STYLE_CLASS:
installStyle();
list.revalidate();
list.repaint();
break;
}
};
}
/** @since 2 */
protected void installStyle() {
try {
applyStyle( FlatStylingSupport.getResolvedStyle( list, "List" ) );
} catch( RuntimeException ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex );
}
}
/** @since 2 */
protected void applyStyle( Object style ) {
Color oldSelectionBackground = selectionBackground;
Color oldSelectionForeground = selectionForeground;
Color oldSelectionInactiveBackground = selectionInactiveBackground;
Color oldSelectionInactiveForeground = selectionInactiveForeground;
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
// update selection background
if( selectionBackground != oldSelectionBackground ) {
Color selBg = list.getSelectionBackground();
if( selBg == oldSelectionBackground )
list.setSelectionBackground( selectionBackground );
else if( selBg == oldSelectionInactiveBackground )
list.setSelectionBackground( selectionInactiveBackground );
}
// update selection foreground
if( selectionForeground != oldSelectionForeground ) {
Color selFg = list.getSelectionForeground();
if( selFg == oldSelectionForeground )
list.setSelectionForeground( selectionForeground );
else if( selFg == oldSelectionInactiveForeground )
list.setSelectionForeground( selectionInactiveForeground );
}
}
/** @since 2 */
protected Object applyStyleProperty( String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, list, key, value );
}
/** @since 2 */
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
}
/**
* Toggle selection colors from focused to inactive and vice versa.
*
@@ -121,6 +219,9 @@ public class FlatListUI
* or the application has to be changed to extend a FlatLaf renderer.
*/
private void toggleSelectionColors() {
if( list == null )
return;
if( FlatUIUtils.isPermanentFocusOwner( list ) ) {
if( list.getSelectionBackground() == selectionInactiveBackground )
list.setSelectionBackground( selectionBackground );

View File

@@ -29,7 +29,7 @@ import javax.swing.plaf.basic.BasicBorders;
public class FlatMarginBorder
extends BasicBorders.MarginBorder
{
private final int left, right, top, bottom;
protected int left, right, top, bottom;
public FlatMarginBorder() {
left = right = top = bottom = 0;

View File

@@ -20,11 +20,12 @@ import static com.formdev.flatlaf.util.UIScale.scale;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.geom.Rectangle2D;
import java.util.Map;
import javax.swing.JMenuBar;
import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableBorder;
/**
* Border for {@link javax.swing.JMenuBar}.
@@ -35,21 +36,28 @@ import javax.swing.UIManager;
*/
public class FlatMenuBarBorder
extends FlatMarginBorder
implements StyleableBorder
{
private final Color borderColor = UIManager.getColor( "MenuBar.borderColor" );
@Styleable protected Color borderColor = UIManager.getColor( "MenuBar.borderColor" );
/** @since 2 */
@Override
public Object applyStyleProperty( String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
}
@Override
public Map<String, Class<?>> getStyleableInfos() {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
}
@Override
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
Graphics2D g2 = (Graphics2D) g.create();
try {
float lineHeight = scale( (float) 1 );
if( !showBottomSeparator( c ) )
return;
FlatUIUtils.setRenderingHints( g2 );
g2.setColor( borderColor );
g2.fill( new Rectangle2D.Float( x, y + height - lineHeight, width, lineHeight ) );
} finally {
g2.dispose();
}
float lineHeight = scale( (float) 1 );
FlatUIUtils.paintFilledRectangle( g, borderColor, x, y + height - lineHeight, width, lineHeight );
}
@Override
@@ -63,4 +71,9 @@ public class FlatMenuBarBorder
insets.right = scale( margin.right );
return insets;
}
/** @since 2 */
protected boolean showBottomSeparator( Component c ) {
return !FlatMenuBarUI.useUnifiedBackground( c );
}
}

View File

@@ -16,9 +16,35 @@
package com.formdev.flatlaf.ui;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeListener;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.JComponent;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JRootPane;
import javax.swing.LookAndFeel;
import javax.swing.MenuElement;
import javax.swing.MenuSelectionManager;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.plaf.ActionMapUIResource;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicMenuBarUI;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.SystemInfo;
/**
* Provides the Flat LaF UI delegate for {@link javax.swing.JMenuBar}.
@@ -30,12 +56,188 @@ import javax.swing.plaf.basic.BasicMenuBarUI;
* @uiDefault MenuBar.foreground Color
* @uiDefault MenuBar.border Border
*
* <!-- FlatMenuBarUI -->
*
* @uiDefault TitlePane.unifiedBackground boolean
*
* @author Karl Tauber
*/
public class FlatMenuBarUI
extends BasicMenuBarUI
implements StyleableUI
{
// used in FlatMenuItemBorder
/** @since 2 */ @Styleable protected Insets itemMargins;
// used in FlatMenuUI
/** @since 2 */ @Styleable protected Color hoverBackground;
/** @since 2 */ @Styleable protected Color underlineSelectionBackground;
/** @since 2 */ @Styleable protected Color underlineSelectionColor;
/** @since 2 */ @Styleable protected int underlineSelectionHeight = -1;
private PropertyChangeListener propertyChangeListener;
private Map<String, Object> oldStyleValues;
private AtomicBoolean borderShared;
public static ComponentUI createUI( JComponent c ) {
return new FlatMenuBarUI();
}
/*
* WARNING: This class is not used on macOS if screen menu bar is enabled.
* Do not add any functionality here.
*/
@Override
public void installUI( JComponent c ) {
super.installUI( c );
installStyle();
}
@Override
protected void installDefaults() {
super.installDefaults();
LookAndFeel.installProperty( menuBar, "opaque", false );
}
@Override
protected void uninstallDefaults() {
super.uninstallDefaults();
oldStyleValues = null;
borderShared = null;
}
@Override
protected void installListeners() {
super.installListeners();
propertyChangeListener = FlatStylingSupport.createPropertyChangeListener( menuBar, this::installStyle, null );
menuBar.addPropertyChangeListener( propertyChangeListener );
}
@Override
protected void uninstallListeners() {
super.uninstallListeners();
menuBar.removePropertyChangeListener( propertyChangeListener );
propertyChangeListener = null;
}
@Override
protected void installKeyboardActions() {
super.installKeyboardActions();
ActionMap map = SwingUtilities.getUIActionMap( menuBar );
if( map == null ) {
map = new ActionMapUIResource();
SwingUtilities.replaceUIActionMap( menuBar, map );
}
map.put( "takeFocus", new TakeFocus() );
}
/** @since 2 */
protected void installStyle() {
try {
applyStyle( FlatStylingSupport.getResolvedStyle( menuBar, "MenuBar" ) );
} catch( RuntimeException ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex );
}
}
/** @since 2 */
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
}
/** @since 2 */
protected Object applyStyleProperty( String key, Object value ) {
if( borderShared == null )
borderShared = new AtomicBoolean( true );
return FlatStylingSupport.applyToAnnotatedObjectOrBorder( this, key, value, menuBar, borderShared );
}
/** @since 2 */
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return FlatStylingSupport.getAnnotatedStyleableInfos( this, menuBar.getBorder() );
}
@Override
public void update( Graphics g, JComponent c ) {
// paint background
Color background = getBackground( c );
if( background != null ) {
g.setColor( background );
g.fillRect( 0, 0, c.getWidth(), c.getHeight() );
}
paint( g, c );
}
protected Color getBackground( JComponent c ) {
Color background = c.getBackground();
// paint background if opaque or if having custom background color
if( c.isOpaque() || !(background instanceof UIResource) )
return background;
// paint background if menu bar is not the "main" menu bar
JRootPane rootPane = SwingUtilities.getRootPane( c );
if( rootPane == null || !(rootPane.getParent() instanceof Window) || rootPane.getJMenuBar() != c )
return background;
// use parent background for unified title pane
if( useUnifiedBackground( c ) )
background = FlatUIUtils.getParentBackground( c );
// paint background in full screen mode
if( FlatUIUtils.isFullScreen( rootPane ) )
return background;
// do not paint background if menu bar is embedded into title pane
return FlatRootPaneUI.isMenuBarEmbedded( rootPane ) ? null : background;
}
/**@since 2 */
static boolean useUnifiedBackground( Component c ) {
// check whether:
// - TitlePane.unifiedBackground is true and
// - menu bar is the "main" menu bar and
// - window has custom decorations enabled
JRootPane rootPane;
// (not storing value of "TitlePane.unifiedBackground" in class to allow changing at runtime)
return UIManager.getBoolean( "TitlePane.unifiedBackground" ) &&
(rootPane = SwingUtilities.getRootPane( c )) != null &&
rootPane.getParent() instanceof Window &&
rootPane.getJMenuBar() == c &&
FlatNativeWindowBorder.hasCustomDecoration( (Window) rootPane.getParent() );
}
//---- class TakeFocus ----------------------------------------------------
/**
* Activates the menu bar and shows mnemonics.
* On Windows, the popup of the first menu is not shown.
* On other platforms, the popup of the first menu is shown.
*/
private static class TakeFocus
extends AbstractAction
{
@Override
public void actionPerformed( ActionEvent e ) {
JMenuBar menuBar = (JMenuBar) e.getSource();
JMenu menu = menuBar.getMenu( 0 );
if( menu != null ) {
MenuSelectionManager.defaultManager().setSelectedPath( SystemInfo.isWindows
? new MenuElement[] { menuBar, menu }
: new MenuElement[] { menuBar, menu, menu.getPopupMenu() } );
FlatLaf.showMnemonics( menuBar );
}
}
}
}

View File

@@ -18,9 +18,11 @@ package com.formdev.flatlaf.ui;
import static com.formdev.flatlaf.util.UIScale.scale;
import java.awt.Component;
import java.awt.Container;
import java.awt.Insets;
import javax.swing.JMenuBar;
import javax.swing.UIManager;
import javax.swing.plaf.MenuBarUI;
/**
* Border for {@link javax.swing.JMenu}, {@link javax.swing.JMenuItem},
@@ -33,15 +35,22 @@ import javax.swing.UIManager;
public class FlatMenuItemBorder
extends FlatMarginBorder
{
// only used if parent menubar is not a instance of FlatMenuBarUI
private final Insets menuBarItemMargins = UIManager.getInsets( "MenuBar.itemMargins" );
@Override
public Insets getBorderInsets( Component c, Insets insets ) {
if( c.getParent() instanceof JMenuBar ) {
insets.top = scale( menuBarItemMargins.top );
insets.left = scale( menuBarItemMargins.left );
insets.bottom = scale( menuBarItemMargins.bottom + 1 );
insets.right = scale( menuBarItemMargins.right );
Container parent = c.getParent();
if( parent instanceof JMenuBar ) {
// get margins from FlatMenuBarUI to allow styling
MenuBarUI ui = ((JMenuBar)parent).getUI();
Insets margins = (ui instanceof FlatMenuBarUI && ((FlatMenuBarUI)ui).itemMargins != null)
? ((FlatMenuBarUI)ui).itemMargins
: this.menuBarItemMargins;
insets.top = scale( margins.top );
insets.left = scale( margins.left );
insets.bottom = scale( margins.bottom );
insets.right = scale( margins.right );
return insets;
} else
return super.getBorderInsets( c, insets );

View File

@@ -0,0 +1,643 @@
/*
* Copyright 2020 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.ui;
import static com.formdev.flatlaf.util.UIScale.scale;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Paint;
import java.awt.Rectangle;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.text.AttributedCharacterIterator;
import java.util.Map;
import javax.swing.Icon;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.plaf.basic.BasicHTML;
import javax.swing.text.View;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.icons.FlatCheckBoxMenuItemIcon;
import com.formdev.flatlaf.icons.FlatMenuArrowIcon;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
import com.formdev.flatlaf.util.DerivedColor;
import com.formdev.flatlaf.util.Graphics2DProxy;
import com.formdev.flatlaf.util.HiDPIUtils;
import com.formdev.flatlaf.util.SystemInfo;
/**
* Renderer for menu items.
*
* @uiDefault MenuItem.minimumWidth int
* @uiDefault MenuItem.minimumIconSize Dimension
* @uiDefault MenuItem.textAcceleratorGap int
* @uiDefault MenuItem.textNoAcceleratorGap int
* @uiDefault MenuItem.acceleratorArrowGap int
* @uiDefault MenuItem.checkBackground Color
* @uiDefault MenuItem.underlineSelectionBackground Color
* @uiDefault MenuItem.underlineSelectionCheckBackground Color
* @uiDefault MenuItem.underlineSelectionColor Color
* @uiDefault MenuItem.underlineSelectionHeight int
*
* @author Karl Tauber
*/
public class FlatMenuItemRenderer
{
protected final JMenuItem menuItem;
protected Icon checkIcon;
protected Icon arrowIcon;
protected final Font acceleratorFont;
protected final String acceleratorDelimiter;
@Styleable protected int minimumWidth = UIManager.getInt( "MenuItem.minimumWidth" );
@Styleable protected Dimension minimumIconSize;
@Styleable protected int textAcceleratorGap = FlatUIUtils.getUIInt( "MenuItem.textAcceleratorGap", 28 );
@Styleable protected int textNoAcceleratorGap = FlatUIUtils.getUIInt( "MenuItem.textNoAcceleratorGap", 6 );
@Styleable protected int acceleratorArrowGap = FlatUIUtils.getUIInt( "MenuItem.acceleratorArrowGap", 2 );
@Styleable protected Color checkBackground = UIManager.getColor( "MenuItem.checkBackground" );
@Styleable protected Insets checkMargins = UIManager.getInsets( "MenuItem.checkMargins" );
@Styleable protected Color underlineSelectionBackground = UIManager.getColor( "MenuItem.underlineSelectionBackground" );
@Styleable protected Color underlineSelectionCheckBackground = UIManager.getColor( "MenuItem.underlineSelectionCheckBackground" );
@Styleable protected Color underlineSelectionColor = UIManager.getColor( "MenuItem.underlineSelectionColor" );
@Styleable protected int underlineSelectionHeight = UIManager.getInt( "MenuItem.underlineSelectionHeight" );
private boolean iconsShared = true;
protected FlatMenuItemRenderer( JMenuItem menuItem, Icon checkIcon, Icon arrowIcon,
Font acceleratorFont, String acceleratorDelimiter )
{
this.menuItem = menuItem;
this.checkIcon = checkIcon;
this.arrowIcon = arrowIcon;
this.acceleratorFont = acceleratorFont;
this.acceleratorDelimiter = acceleratorDelimiter;
Dimension minimumIconSize = UIManager.getDimension( "MenuItem.minimumIconSize" );
this.minimumIconSize = (minimumIconSize != null) ? minimumIconSize : new Dimension( 16, 16 );
}
/** @since 2 */
protected Object applyStyleProperty( String key, Object value ) {
// style icon
if( key.startsWith( "icon." ) || key.equals( "selectionForeground" ) ) {
if( iconsShared ) {
if( checkIcon instanceof FlatCheckBoxMenuItemIcon )
checkIcon = FlatStylingSupport.cloneIcon( checkIcon );
if( arrowIcon instanceof FlatMenuArrowIcon )
arrowIcon = FlatStylingSupport.cloneIcon( arrowIcon );
iconsShared = false;
}
if( key.startsWith( "icon." ) ) {
String key2 = key.substring( "icon.".length() );
try {
if( checkIcon instanceof FlatCheckBoxMenuItemIcon )
return ((FlatCheckBoxMenuItemIcon)checkIcon).applyStyleProperty( key2, value );
} catch ( UnknownStyleException ex ) {
// ignore
}
try {
if( arrowIcon instanceof FlatMenuArrowIcon )
return ((FlatMenuArrowIcon)arrowIcon).applyStyleProperty( key2, value );
} catch ( UnknownStyleException ex ) {
// ignore
}
// keys with prefix "icon." are only for icons
throw new UnknownStyleException( key );
} else if( key.equals( "selectionForeground" ) ) {
// special case: same key is used in icons and in menuitem
if( checkIcon instanceof FlatCheckBoxMenuItemIcon )
((FlatCheckBoxMenuItemIcon)checkIcon).applyStyleProperty( key, value );
if( arrowIcon instanceof FlatMenuArrowIcon )
((FlatMenuArrowIcon)arrowIcon).applyStyleProperty( key, value );
// throw exception because the caller should also apply this key
throw new UnknownStyleException( key );
}
}
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
}
/** @since 2 */
public Map<String, Class<?>> getStyleableInfos() {
Map<String, Class<?>> infos = FlatStylingSupport.getAnnotatedStyleableInfos( this );
if( checkIcon instanceof FlatCheckBoxMenuItemIcon )
FlatStylingSupport.putAllPrefixKey( infos, "icon.", ((FlatCheckBoxMenuItemIcon)checkIcon).getStyleableInfos() );
infos.remove( "icon.selectionForeground" );
if( arrowIcon instanceof FlatMenuArrowIcon )
FlatStylingSupport.putAllPrefixKey( infos, "icon.", ((FlatMenuArrowIcon)arrowIcon).getStyleableInfos() );
infos.remove( "icon.selectionForeground" );
return infos;
}
protected Dimension getPreferredMenuItemSize() {
int width = 0;
int height = 0;
boolean isTopLevelMenu = isTopLevelMenu( menuItem );
Rectangle viewRect = new Rectangle( 0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE );
Rectangle iconRect = new Rectangle();
Rectangle textRect = new Rectangle();
// layout icon and text
SwingUtilities.layoutCompoundLabel( menuItem,
menuItem.getFontMetrics( menuItem.getFont() ), menuItem.getText(), getIconForLayout(),
menuItem.getVerticalAlignment(), menuItem.getHorizontalAlignment(),
menuItem.getVerticalTextPosition(), menuItem.getHorizontalTextPosition(),
viewRect, iconRect, textRect, scale( menuItem.getIconTextGap() ) );
// union icon and text rectangles
Rectangle labelRect = iconRect.union( textRect );
width += labelRect.width;
height = Math.max( labelRect.height, height );
// accelerator size
String accelText = getAcceleratorText();
if( accelText != null ) {
// gap between text and accelerator
width += scale( !isTopLevelMenu ? textAcceleratorGap : menuItem.getIconTextGap() );
FontMetrics accelFm = menuItem.getFontMetrics( acceleratorFont );
width += SwingUtilities.computeStringWidth( accelFm, accelText );
height = Math.max( accelFm.getHeight(), height );
}
// arrow size
if( !isTopLevelMenu && arrowIcon != null ) {
// gap between text and arrow
if( accelText == null )
width += scale( textNoAcceleratorGap );
// gap between accelerator and arrow
width += scale( acceleratorArrowGap );
width += arrowIcon.getIconWidth();
height = Math.max( arrowIcon.getIconHeight(), height );
}
// add insets
Insets insets = menuItem.getInsets();
width += insets.left + insets.right;
height += insets.top + insets.bottom;
// minimum width
if( !isTopLevelMenu ) {
int minimumWidth = FlatUIUtils.minimumWidth( menuItem, this.minimumWidth );
width = Math.max( width, scale( minimumWidth ) );
}
return new Dimension( width, height );
}
private void layout( Rectangle viewRect, Rectangle iconRect, Rectangle textRect,
Rectangle accelRect, Rectangle arrowRect, Rectangle labelRect )
{
boolean isTopLevelMenu = isTopLevelMenu( menuItem );
// layout arrow
if( !isTopLevelMenu && arrowIcon != null ) {
arrowRect.width = arrowIcon.getIconWidth();
arrowRect.height = arrowIcon.getIconHeight();
} else
arrowRect.setSize( 0, 0 );
arrowRect.y = viewRect.y + centerOffset( viewRect.height, arrowRect.height );
// layout accelerator
String accelText = getAcceleratorText();
if( accelText != null ) {
FontMetrics accelFm = menuItem.getFontMetrics( acceleratorFont );
accelRect.width = SwingUtilities.computeStringWidth( accelFm, accelText );
accelRect.height = accelFm.getHeight();
accelRect.y = viewRect.y + centerOffset( viewRect.height, accelRect.height );
} else
accelRect.setBounds( 0, 0, 0, 0 );
// compute horizontal positions of accelerator and arrow
int accelArrowGap = !isTopLevelMenu ? scale( acceleratorArrowGap ) : 0;
if( menuItem.getComponentOrientation().isLeftToRight() ) {
// left-to-right
arrowRect.x = viewRect.x + viewRect.width - arrowRect.width;
accelRect.x = arrowRect.x - accelArrowGap - accelRect.width;
} else {
// right-to-left
arrowRect.x = viewRect.x;
accelRect.x = arrowRect.x + accelArrowGap + arrowRect.width;
}
// width of accelerator, arrow and gap
int accelArrowWidth = accelRect.width + arrowRect.width;
if( accelText != null )
accelArrowWidth += scale( !isTopLevelMenu ? textAcceleratorGap : menuItem.getIconTextGap() );
if( !isTopLevelMenu && arrowIcon != null ) {
if( accelText == null )
accelArrowWidth += scale( textNoAcceleratorGap );
accelArrowWidth += scale( acceleratorArrowGap );
}
// label rectangle is view rectangle subtracted by accelerator, arrow and gap
labelRect.setBounds( viewRect );
labelRect.width -= accelArrowWidth;
if( !menuItem.getComponentOrientation().isLeftToRight() )
labelRect.x += accelArrowWidth;
// layout icon and text
SwingUtilities.layoutCompoundLabel( menuItem,
menuItem.getFontMetrics( menuItem.getFont() ), menuItem.getText(), getIconForLayout(),
menuItem.getVerticalAlignment(), menuItem.getHorizontalAlignment(),
menuItem.getVerticalTextPosition(), menuItem.getHorizontalTextPosition(),
labelRect, iconRect, textRect, scale( menuItem.getIconTextGap() ) );
}
private static int centerOffset( int wh1, int wh2 ) {
return (wh1 / 2) - (wh2 / 2);
}
protected void paintMenuItem( Graphics g, Color selectionBackground, Color selectionForeground,
Color disabledForeground, Color acceleratorForeground, Color acceleratorSelectionForeground )
{
Rectangle viewRect = new Rectangle( menuItem.getWidth(), menuItem.getHeight() );
// subtract insets
Insets insets = menuItem.getInsets();
viewRect.x += insets.left;
viewRect.y += insets.top;
viewRect.width -= (insets.left + insets.right);
viewRect.height -= (insets.top + insets.bottom);
Rectangle iconRect = new Rectangle();
Rectangle textRect = new Rectangle();
Rectangle accelRect = new Rectangle();
Rectangle arrowRect = new Rectangle();
Rectangle labelRect = new Rectangle();
layout( viewRect, iconRect, textRect, accelRect, arrowRect, labelRect );
/*debug
g.setColor( Color.green ); g.drawRect( viewRect.x, viewRect.y, viewRect.width - 1, viewRect.height - 1 );
g.setColor( Color.red ); g.drawRect( labelRect.x, labelRect.y, labelRect.width - 1, labelRect.height - 1 );
g.setColor( Color.blue ); g.drawRect( iconRect.x, iconRect.y, iconRect.width - 1, iconRect.height - 1 );
g.setColor( Color.cyan ); g.drawRect( textRect.x, textRect.y, textRect.width - 1, textRect.height - 1 );
g.setColor( Color.magenta ); g.drawRect( accelRect.x, accelRect.y, accelRect.width - 1, accelRect.height - 1 );
g.setColor( Color.orange ); g.drawRect( arrowRect.x, arrowRect.y, arrowRect.width - 1, arrowRect.height - 1 );
debug*/
boolean underlineSelection = isUnderlineSelection();
paintBackground( g, underlineSelection ? underlineSelectionBackground : selectionBackground );
if( underlineSelection && isArmedOrSelected( menuItem ) )
paintUnderlineSelection( g, underlineSelectionColor, underlineSelectionHeight );
paintIcon( g, iconRect, getIconForPainting(), underlineSelection ? underlineSelectionCheckBackground : checkBackground, selectionBackground );
paintText( g, textRect, menuItem.getText(), selectionForeground, disabledForeground );
paintAccelerator( g, accelRect, getAcceleratorText(), acceleratorForeground, acceleratorSelectionForeground, disabledForeground );
if( !isTopLevelMenu( menuItem ) )
paintArrowIcon( g, arrowRect, arrowIcon );
}
protected void paintBackground( Graphics g, Color selectionBackground ) {
boolean armedOrSelected = isArmedOrSelected( menuItem );
if( menuItem.isOpaque() || armedOrSelected ) {
// paint background
g.setColor( armedOrSelected
? deriveBackground( selectionBackground )
: menuItem.getBackground() );
g.fillRect( 0, 0, menuItem.getWidth(), menuItem.getHeight() );
}
}
protected void paintUnderlineSelection( Graphics g, Color underlineSelectionColor, int underlineSelectionHeight ) {
int width = menuItem.getWidth();
int height = menuItem.getHeight();
int underlineHeight = scale( underlineSelectionHeight );
g.setColor( underlineSelectionColor );
if( isTopLevelMenu( menuItem ) ) {
// paint underline at bottom
g.fillRect( 0, height - underlineHeight, width, underlineHeight );
} else if( menuItem.getComponentOrientation().isLeftToRight() ) {
// paint underline at left side
g.fillRect( 0, 0, underlineHeight, height );
} else {
// paint underline at right side
g.fillRect( width - underlineHeight, 0, underlineHeight, height );
}
}
protected Color deriveBackground( Color background ) {
if( !(background instanceof DerivedColor) )
return background;
Color baseColor = menuItem.isOpaque()
? menuItem.getBackground()
: FlatUIUtils.getParentBackground( menuItem );
return FlatUIUtils.deriveColor( background, baseColor );
}
protected void paintIcon( Graphics g, Rectangle iconRect, Icon icon, Color checkBackground, Color selectionBackground ) {
// if checkbox/radiobutton menu item is selected and also has a custom icon,
// then use filled icon background to indicate selection (instead of using checkIcon)
if( menuItem.isSelected() && checkIcon != null && icon != checkIcon ) {
Rectangle r = FlatUIUtils.addInsets( iconRect, scale( checkMargins ) );
g.setColor( FlatUIUtils.deriveColor( checkBackground, selectionBackground ) );
g.fillRect( r.x, r.y, r.width, r.height );
}
paintIcon( g, menuItem, icon, iconRect );
}
protected void paintText( Graphics g, Rectangle textRect, String text, Color selectionForeground, Color disabledForeground ) {
View htmlView = (View) menuItem.getClientProperty( BasicHTML.propertyKey );
if( htmlView != null ) {
paintHTMLText( g, menuItem, textRect, htmlView, isUnderlineSelection() ? null : selectionForeground );
return;
}
int mnemonicIndex = FlatLaf.isShowMnemonics() ? menuItem.getDisplayedMnemonicIndex() : -1;
Color foreground = (isTopLevelMenu( menuItem ) ? menuItem.getParent() : menuItem).getForeground();
paintText( g, menuItem, textRect, text, mnemonicIndex, menuItem.getFont(),
foreground, isUnderlineSelection() ? foreground : selectionForeground, disabledForeground );
}
protected void paintAccelerator( Graphics g, Rectangle accelRect, String accelText,
Color foreground, Color selectionForeground, Color disabledForeground )
{
paintText( g, menuItem, accelRect, accelText, -1, acceleratorFont,
foreground, isUnderlineSelection() ? foreground : selectionForeground, disabledForeground );
}
protected void paintArrowIcon( Graphics g, Rectangle arrowRect, Icon arrowIcon ) {
paintIcon( g, menuItem, arrowIcon, arrowRect );
}
protected static void paintIcon( Graphics g, JMenuItem menuItem, Icon icon, Rectangle iconRect ) {
if( icon == null )
return;
// center because the real icon may be smaller than dimension in iconRect
int x = iconRect.x + centerOffset( iconRect.width, icon.getIconWidth() );
int y = iconRect.y + centerOffset( iconRect.height, icon.getIconHeight() );
// paint
icon.paintIcon( menuItem, g, x, y );
}
protected static void paintText( Graphics g, JMenuItem menuItem,
Rectangle textRect, String text, int mnemonicIndex, Font font,
Color foreground, Color selectionForeground, Color disabledForeground )
{
if( text == null || text.isEmpty() )
return;
FontMetrics fm = menuItem.getFontMetrics( font );
Font oldFont = g.getFont();
g.setFont( font );
g.setColor( !menuItem.isEnabled()
? disabledForeground
: (isArmedOrSelected( menuItem )
? selectionForeground
: foreground) );
FlatUIUtils.drawStringUnderlineCharAt( menuItem, g, text, mnemonicIndex,
textRect.x, textRect.y + fm.getAscent() );
g.setFont( oldFont );
}
protected static void paintHTMLText( Graphics g, JMenuItem menuItem,
Rectangle textRect, View htmlView, Color selectionForeground )
{
if( isArmedOrSelected( menuItem ) && selectionForeground != null )
g = new GraphicsProxyWithTextColor( (Graphics2D) g, selectionForeground );
htmlView.paint( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ), textRect );
}
protected static boolean isArmedOrSelected( JMenuItem menuItem ) {
return menuItem.isArmed() || (menuItem instanceof JMenu && menuItem.isSelected());
}
protected static boolean isTopLevelMenu( JMenuItem menuItem ) {
return menuItem instanceof JMenu && ((JMenu)menuItem).isTopLevelMenu();
}
protected boolean isUnderlineSelection() {
return "underline".equals( UIManager.getString( "MenuItem.selectionType" ) );
}
private Icon getIconForPainting() {
Icon icon = menuItem.getIcon();
if( icon == null && checkIcon != null && !isTopLevelMenu( menuItem ) )
return checkIcon;
if( icon == null )
return null;
if( !menuItem.isEnabled() )
return menuItem.getDisabledIcon();
if( menuItem.getModel().isPressed() && menuItem.isArmed() ) {
Icon pressedIcon = menuItem.getPressedIcon();
if( pressedIcon != null )
return pressedIcon;
}
return icon;
}
private Icon getIconForLayout() {
Icon icon = menuItem.getIcon();
if( isTopLevelMenu( menuItem ) )
return (icon != null) ? new MinSizeIcon( icon ) : null;
return new MinSizeIcon( (icon != null) ? icon : checkIcon );
}
private KeyStroke cachedAccelerator;
private String cachedAcceleratorText;
private boolean cachedAcceleratorLeftToRight;
private String getAcceleratorText() {
KeyStroke accelerator = menuItem.getAccelerator();
if( accelerator == null )
return null;
boolean leftToRight = menuItem.getComponentOrientation().isLeftToRight();
if( accelerator == cachedAccelerator && leftToRight == cachedAcceleratorLeftToRight )
return cachedAcceleratorText;
cachedAccelerator = accelerator;
cachedAcceleratorText = getTextForAccelerator( accelerator );
cachedAcceleratorLeftToRight = leftToRight;
return cachedAcceleratorText;
}
protected String getTextForAccelerator( KeyStroke accelerator ) {
StringBuilder buf = new StringBuilder();
boolean leftToRight = menuItem.getComponentOrientation().isLeftToRight();
// modifiers
int modifiers = accelerator.getModifiers();
if( modifiers != 0 ) {
if( SystemInfo.isMacOS ) {
if( leftToRight )
buf.append( getMacOSModifiersExText( modifiers, leftToRight ) );
} else
buf.append( InputEvent.getModifiersExText( modifiers ) ).append( acceleratorDelimiter );
}
// key
int keyCode = accelerator.getKeyCode();
if( keyCode != 0 )
buf.append( KeyEvent.getKeyText( keyCode ) );
else
buf.append( accelerator.getKeyChar() );
// modifiers if right-to-left on macOS
if( modifiers != 0 && !leftToRight && SystemInfo.isMacOS )
buf.append( getMacOSModifiersExText( modifiers, leftToRight ) );
return buf.toString();
}
protected String getMacOSModifiersExText( int modifiers, boolean leftToRight ) {
StringBuilder buf = new StringBuilder();
if( (modifiers & InputEvent.CTRL_DOWN_MASK) != 0 )
buf.append( controlGlyph );
if( (modifiers & (InputEvent.ALT_DOWN_MASK | InputEvent.ALT_GRAPH_DOWN_MASK)) != 0 )
buf.append( optionGlyph );
if( (modifiers & InputEvent.SHIFT_DOWN_MASK) != 0 )
buf.append( shiftGlyph );
if( (modifiers & InputEvent.META_DOWN_MASK) != 0 )
buf.append( commandGlyph );
// reverse order for right-to-left
if( !leftToRight )
buf.reverse();
return buf.toString();
}
private static final char
controlGlyph = 0x2303,
optionGlyph = 0x2325,
shiftGlyph = 0x21E7,
commandGlyph = 0x2318;
//---- class MinSizeIcon --------------------------------------------------
private class MinSizeIcon
implements Icon
{
private final Icon delegate;
MinSizeIcon( Icon delegate ) {
this.delegate = delegate;
}
@Override
public int getIconWidth() {
int iconWidth = (delegate != null) ? delegate.getIconWidth() : 0;
return Math.max( iconWidth, scale( minimumIconSize.width ) );
}
@Override
public int getIconHeight() {
int iconHeight = (delegate != null) ? delegate.getIconHeight() : 0;
return Math.max( iconHeight, scale( minimumIconSize.height ) );
}
@Override
public void paintIcon( Component c, Graphics g, int x, int y ) {
}
}
//---- class GraphicsProxyWithTextColor -----------------------------------
private static class GraphicsProxyWithTextColor
extends Graphics2DProxy
{
private final Color textColor;
GraphicsProxyWithTextColor( Graphics2D delegate, Color textColor ) {
super( delegate );
this.textColor = textColor;
}
@Override
public void drawString( String str, int x, int y ) {
Paint oldPaint = getPaint();
setPaint( textColor );
super.drawString( str, x, y );
setPaint( oldPaint );
}
@Override
public void drawString( String str, float x, float y ) {
Paint oldPaint = getPaint();
setPaint( textColor );
super.drawString( str, x, y );
setPaint( oldPaint );
}
@Override
public void drawString( AttributedCharacterIterator iterator, int x, int y ) {
Paint oldPaint = getPaint();
setPaint( textColor );
super.drawString( iterator, x, y );
setPaint( oldPaint );
}
@Override
public void drawString( AttributedCharacterIterator iterator, float x, float y ) {
Paint oldPaint = getPaint();
setPaint( textColor );
super.drawString( iterator, x, y );
setPaint( oldPaint );
}
@Override
public void drawChars( char[] data, int offset, int length, int x, int y ) {
Paint oldPaint = getPaint();
setPaint( textColor );
super.drawChars( data, offset, length, x, y );
setPaint( oldPaint );
}
}
}

View File

@@ -16,92 +16,152 @@
package com.formdev.flatlaf.ui;
import static com.formdev.flatlaf.util.UIScale.scale;
import java.awt.Color;
import java.awt.FontMetrics;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.beans.PropertyChangeListener;
import javax.swing.ButtonModel;
import java.util.Map;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.LookAndFeel;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicMenuItemUI;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
import com.formdev.flatlaf.util.LoggingFacade;
/**
* Provides the Flat LaF UI delegate for {@link javax.swing.JMenuItem}.
*
* <!-- BasicMenuItemUI -->
*
* @uiDefault MenuItem.font Font
* @uiDefault MenuItem.background Color
* @uiDefault MenuItem.foreground Color
* @uiDefault MenuItem.disabledForeground Color
* @uiDefault MenuItem.selectionBackground Color
* @uiDefault MenuItem.selectionForeground Color
* @uiDefault MenuItem.acceleratorForeground Color
* @uiDefault MenuItem.acceleratorSelectionForeground Color
* @uiDefault MenuItem.acceleratorFont Font defaults to MenuItem.font
* @uiDefault MenuItem.acceleratorDelimiter String
* @uiDefault MenuItem.border Border
* @uiDefault MenuItem.borderPainted boolean
* @uiDefault MenuItem.margin Insets
* @uiDefault MenuItem.arrowIcon Icon
* @uiDefault MenuItem.checkIcon Icon
* @uiDefault MenuItem.opaque boolean
* @uiDefault MenuItem.evenHeight boolean
* @uiDefault MenuItem.font Font
* @uiDefault MenuItem.background Color
* @uiDefault MenuItem.foreground Color
* @uiDefault MenuItem.disabledForeground Color
* @uiDefault MenuItem.selectionBackground Color
* @uiDefault MenuItem.selectionForeground Color
* @uiDefault MenuItem.acceleratorForeground Color
* @uiDefault MenuItem.acceleratorSelectionForeground Color
* @uiDefault MenuItem.acceleratorFont Font defaults to MenuItem.font
* @uiDefault MenuItem.acceleratorDelimiter String
* @uiDefault MenuItem.border Border
* @uiDefault MenuItem.borderPainted boolean
* @uiDefault MenuItem.margin Insets
* @uiDefault MenuItem.arrowIcon Icon
* @uiDefault MenuItem.checkIcon Icon
* @uiDefault MenuItem.opaque boolean
*
* <!-- FlatMenuItemUI -->
*
* @uiDefault MenuItem.iconTextGap int
*
* @author Karl Tauber
*/
public class FlatMenuItemUI
extends BasicMenuItemUI
implements StyleableUI
{
private FlatMenuItemRenderer renderer;
private Map<String, Object> oldStyleValues;
public static ComponentUI createUI( JComponent c ) {
return new FlatMenuItemUI();
}
@Override
public void installUI( JComponent c ) {
super.installUI( c );
installStyle();
}
@Override
protected void installDefaults() {
super.installDefaults();
// scale
defaultTextIconGap = scale( defaultTextIconGap );
LookAndFeel.installProperty( menuItem, "iconTextGap", FlatUIUtils.getUIInt( "MenuItem.iconTextGap", 4 ) );
renderer = createRenderer();
}
/**
* Scale defaultTextIconGap again if iconTextGap property has changed.
*/
@Override
protected PropertyChangeListener createPropertyChangeListener( JComponent c ) {
PropertyChangeListener superListener = super.createPropertyChangeListener( c );
return e -> {
superListener.propertyChange( e );
if( e.getPropertyName() == "iconTextGap" )
defaultTextIconGap = scale( defaultTextIconGap );
};
protected void uninstallDefaults() {
super.uninstallDefaults();
renderer = null;
oldStyleValues = null;
}
protected FlatMenuItemRenderer createRenderer() {
return new FlatMenuItemRenderer( menuItem, checkIcon, arrowIcon, acceleratorFont, acceleratorDelimiter );
}
@Override
protected void paintText( Graphics g, JMenuItem menuItem, Rectangle textRect, String text ) {
paintText( g, menuItem, textRect, text, disabledForeground, selectionForeground );
protected PropertyChangeListener createPropertyChangeListener( JComponent c ) {
return FlatStylingSupport.createPropertyChangeListener( c, this::installStyle, super.createPropertyChangeListener( c ) );
}
public static void paintText( Graphics g, JMenuItem menuItem, Rectangle textRect,
String text, Color disabledForeground, Color selectionForeground )
{
FontMetrics fm = menuItem.getFontMetrics( menuItem.getFont() );
int mnemonicIndex = FlatLaf.isShowMnemonics() ? menuItem.getDisplayedMnemonicIndex() : -1;
/** @since 2 */
protected void installStyle() {
try {
applyStyle( FlatStylingSupport.getResolvedStyle( menuItem, "MenuItem" ) );
} catch( RuntimeException ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex );
}
}
ButtonModel model = menuItem.getModel();
g.setColor( !model.isEnabled()
? disabledForeground
: (model.isArmed() || (menuItem instanceof JMenu && model.isSelected())
? selectionForeground
: menuItem.getForeground()) );
/** @since 2 */
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
}
FlatUIUtils.drawStringUnderlineCharAt( menuItem, g, text, mnemonicIndex,
textRect.x, textRect.y + fm.getAscent() );
/** @since 2 */
protected Object applyStyleProperty( String key, Object value ) {
try {
return renderer.applyStyleProperty( key, value );
} catch ( UnknownStyleException ex ) {
// ignore
}
Object oldValue;
switch( key ) {
// BasicMenuItemUI
case "selectionBackground": oldValue = selectionBackground; selectionBackground = (Color) value; return oldValue;
case "selectionForeground": oldValue = selectionForeground; selectionForeground = (Color) value; return oldValue;
case "disabledForeground": oldValue = disabledForeground; disabledForeground = (Color) value; return oldValue;
case "acceleratorForeground": oldValue = acceleratorForeground; acceleratorForeground = (Color) value; return oldValue;
case "acceleratorSelectionForeground": oldValue = acceleratorSelectionForeground; acceleratorSelectionForeground = (Color) value; return oldValue;
}
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, menuItem, key, value );
}
/** @since 2 */
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return getStyleableInfos( renderer );
}
static Map<String, Class<?>> getStyleableInfos( FlatMenuItemRenderer renderer ) {
Map<String, Class<?>> infos = new FlatStylingSupport.StyleableInfosMap<>();
infos.put( "selectionBackground", Color.class );
infos.put( "selectionForeground", Color.class );
infos.put( "disabledForeground", Color.class );
infos.put( "acceleratorForeground", Color.class );
infos.put( "acceleratorSelectionForeground", Color.class );
infos.putAll( renderer.getStyleableInfos() );
return infos;
}
@Override
protected Dimension getPreferredMenuItemSize( JComponent c, Icon checkIcon, Icon arrowIcon, int defaultTextIconGap ) {
return renderer.getPreferredMenuItemSize();
}
@Override
public void paint( Graphics g, JComponent c ) {
renderer.paintMenuItem( g, selectionBackground, selectionForeground, disabledForeground,
acceleratorForeground, acceleratorSelectionForeground );
}
}

View File

@@ -16,92 +16,107 @@
package com.formdev.flatlaf.ui;
import static com.formdev.flatlaf.util.UIScale.scale;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeListener;
import java.util.Map;
import java.util.function.Function;
import javax.swing.ButtonModel;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.LookAndFeel;
import javax.swing.UIManager;
import javax.swing.event.MouseInputListener;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.MenuBarUI;
import javax.swing.plaf.basic.BasicMenuUI;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
import com.formdev.flatlaf.util.LoggingFacade;
/**
* Provides the Flat LaF UI delegate for {@link javax.swing.JMenu}.
*
* <!-- BasicMenuUI -->
*
* @uiDefault Menu.font Font
* @uiDefault Menu.background Color
* @uiDefault Menu.foreground Color
* @uiDefault Menu.disabledForeground Color
* @uiDefault Menu.selectionBackground Color
* @uiDefault Menu.selectionForeground Color
* @uiDefault Menu.acceleratorForeground Color
* @uiDefault Menu.acceleratorSelectionForeground Color
* @uiDefault MenuItem.acceleratorFont Font defaults to MenuItem.font
* @uiDefault MenuItem.acceleratorDelimiter String
* @uiDefault Menu.border Border
* @uiDefault Menu.borderPainted boolean
* @uiDefault Menu.margin Insets
* @uiDefault Menu.arrowIcon Icon
* @uiDefault Menu.checkIcon Icon
* @uiDefault Menu.opaque boolean
* @uiDefault Menu.evenHeight boolean
* @uiDefault Menu.crossMenuMnemonic boolean default is false
* @uiDefault Menu.useMenuBarBackgroundForTopLevel boolean default is false
* @uiDefault MenuBar.background Color used if Menu.useMenuBarBackgroundForTopLevel is true
* @uiDefault Menu.font Font
* @uiDefault Menu.background Color
* @uiDefault Menu.foreground Color
* @uiDefault Menu.disabledForeground Color
* @uiDefault Menu.selectionBackground Color
* @uiDefault Menu.selectionForeground Color
* @uiDefault Menu.acceleratorForeground Color
* @uiDefault Menu.acceleratorSelectionForeground Color
* @uiDefault MenuItem.acceleratorFont Font defaults to MenuItem.font
* @uiDefault MenuItem.acceleratorDelimiter String
* @uiDefault Menu.border Border
* @uiDefault Menu.borderPainted boolean
* @uiDefault Menu.margin Insets
* @uiDefault Menu.arrowIcon Icon
* @uiDefault Menu.checkIcon Icon
* @uiDefault Menu.opaque boolean
* @uiDefault Menu.crossMenuMnemonic boolean default is false
* @uiDefault Menu.useMenuBarBackgroundForTopLevel boolean default is false
* @uiDefault MenuBar.background Color used if Menu.useMenuBarBackgroundForTopLevel is true
*
* <!-- FlatMenuUI -->
*
* @uiDefault MenuBar.hoverBackground Color
* @uiDefault MenuItem.iconTextGap int
*
* <!-- FlatMenuRenderer -->
*
* @uiDefault MenuBar.hoverBackground Color
* @uiDefault MenuBar.underlineSelectionBackground Color
* @uiDefault MenuBar.underlineSelectionColor Color
* @uiDefault MenuBar.underlineSelectionHeight int
*
* @author Karl Tauber
*/
public class FlatMenuUI
extends BasicMenuUI
implements StyleableUI
{
private Color hoverBackground;
private FlatMenuItemRenderer renderer;
private Map<String, Object> oldStyleValues;
public static ComponentUI createUI( JComponent c ) {
return new FlatMenuUI();
}
@Override
public void installUI( JComponent c ) {
super.installUI( c );
installStyle();
}
@Override
protected void installDefaults() {
super.installDefaults();
LookAndFeel.installProperty( menuItem, "iconTextGap", FlatUIUtils.getUIInt( "MenuItem.iconTextGap", 4 ) );
menuItem.setRolloverEnabled( true );
hoverBackground = UIManager.getColor( "MenuBar.hoverBackground" );
// scale
defaultTextIconGap = scale( defaultTextIconGap );
renderer = createRenderer();
}
@Override
protected void uninstallDefaults() {
super.uninstallDefaults();
hoverBackground = null;
renderer = null;
oldStyleValues = null;
}
/**
* Scale defaultTextIconGap again if iconTextGap property has changed.
*/
@Override
protected PropertyChangeListener createPropertyChangeListener( JComponent c ) {
PropertyChangeListener superListener = super.createPropertyChangeListener( c );
return e -> {
superListener.propertyChange( e );
if( e.getPropertyName() == "iconTextGap" )
defaultTextIconGap = scale( defaultTextIconGap );
};
protected FlatMenuItemRenderer createRenderer() {
return new FlatMenuRenderer( menuItem, checkIcon, arrowIcon, acceleratorFont, acceleratorDelimiter );
}
@Override
@@ -130,19 +145,121 @@ public class FlatMenuUI
}
@Override
protected void paintBackground( Graphics g, JMenuItem menuItem, Color bgColor ) {
ButtonModel model = menuItem.getModel();
if( model.isArmed() || model.isSelected() ) {
super.paintBackground( g, menuItem, bgColor );
} else if( model.isRollover() && model.isEnabled() && ((JMenu)menuItem).isTopLevelMenu() ) {
FlatUIUtils.setColor( g, hoverBackground, menuItem.getBackground() );
g.fillRect( 0, 0, menuItem.getWidth(), menuItem.getHeight() );
} else
super.paintBackground( g, menuItem, bgColor );
protected PropertyChangeListener createPropertyChangeListener( JComponent c ) {
return FlatStylingSupport.createPropertyChangeListener( c, this::installStyle, super.createPropertyChangeListener( c ) );
}
/** @since 2 */
protected void installStyle() {
try {
applyStyle( FlatStylingSupport.getResolvedStyle( menuItem, "Menu" ) );
} catch( RuntimeException ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex );
}
}
/** @since 2 */
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
}
/** @since 2 */
protected Object applyStyleProperty( String key, Object value ) {
try {
return renderer.applyStyleProperty( key, value );
} catch ( UnknownStyleException ex ) {
// ignore
}
Object oldValue;
switch( key ) {
// BasicMenuItemUI
case "selectionBackground": oldValue = selectionBackground; selectionBackground = (Color) value; return oldValue;
case "selectionForeground": oldValue = selectionForeground; selectionForeground = (Color) value; return oldValue;
case "disabledForeground": oldValue = disabledForeground; disabledForeground = (Color) value; return oldValue;
case "acceleratorForeground": oldValue = acceleratorForeground; acceleratorForeground = (Color) value; return oldValue;
case "acceleratorSelectionForeground": oldValue = acceleratorSelectionForeground; acceleratorSelectionForeground = (Color) value; return oldValue;
}
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, menuItem, key, value );
}
/** @since 2 */
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return FlatMenuItemUI.getStyleableInfos( renderer );
}
@Override
protected void paintText( Graphics g, JMenuItem menuItem, Rectangle textRect, String text ) {
FlatMenuItemUI.paintText( g, menuItem, textRect, text, disabledForeground, selectionForeground );
public Dimension getMinimumSize( JComponent c ) {
// avoid that top-level menus (in menu bar) are made smaller if horizontal space is rare
// same code is in BasicMenuUI since Java 10
// see https://bugs.openjdk.java.net/browse/JDK-8178430
return ((JMenu)menuItem).isTopLevelMenu() ? c.getPreferredSize() : null;
}
@Override
protected Dimension getPreferredMenuItemSize( JComponent c, Icon checkIcon, Icon arrowIcon, int defaultTextIconGap ) {
return renderer.getPreferredMenuItemSize();
}
@Override
public void paint( Graphics g, JComponent c ) {
renderer.paintMenuItem( g, selectionBackground, selectionForeground, disabledForeground,
acceleratorForeground, acceleratorSelectionForeground );
}
//---- class FlatMenuRenderer ---------------------------------------------
protected class FlatMenuRenderer
extends FlatMenuItemRenderer
{
protected Color hoverBackground = UIManager.getColor( "MenuBar.hoverBackground" );
protected Color menuBarUnderlineSelectionBackground = FlatUIUtils.getUIColor( "MenuBar.underlineSelectionBackground", underlineSelectionBackground );
protected Color menuBarUnderlineSelectionColor = FlatUIUtils.getUIColor( "MenuBar.underlineSelectionColor", underlineSelectionColor );
protected int menuBarUnderlineSelectionHeight = FlatUIUtils.getUIInt( "MenuBar.underlineSelectionHeight", underlineSelectionHeight );
protected FlatMenuRenderer( JMenuItem menuItem, Icon checkIcon, Icon arrowIcon,
Font acceleratorFont, String acceleratorDelimiter )
{
super( menuItem, checkIcon, arrowIcon, acceleratorFont, acceleratorDelimiter );
}
@Override
protected void paintBackground( Graphics g, Color selectionBackground ) {
if( ((JMenu)menuItem).isTopLevelMenu() ) {
if( isUnderlineSelection() )
selectionBackground = getStyleFromMenuBarUI( ui -> ui.underlineSelectionBackground, menuBarUnderlineSelectionBackground );
ButtonModel model = menuItem.getModel();
if( model.isRollover() && !model.isArmed() && !model.isSelected() && model.isEnabled() ) {
g.setColor( deriveBackground( getStyleFromMenuBarUI( ui -> ui.hoverBackground, hoverBackground ) ) );
g.fillRect( 0, 0, menuItem.getWidth(), menuItem.getHeight() );
return;
}
}
super.paintBackground( g, selectionBackground );
}
@Override
protected void paintUnderlineSelection( Graphics g, Color underlineSelectionColor, int underlineSelectionHeight ) {
if( ((JMenu)menuItem).isTopLevelMenu() ) {
underlineSelectionColor = getStyleFromMenuBarUI( ui -> ui.underlineSelectionColor, menuBarUnderlineSelectionColor );
underlineSelectionHeight = getStyleFromMenuBarUI( ui -> (ui.underlineSelectionHeight != -1)
? ui.underlineSelectionHeight : null, menuBarUnderlineSelectionHeight );
}
super.paintUnderlineSelection( g, underlineSelectionColor, underlineSelectionHeight );
}
private <T> T getStyleFromMenuBarUI( Function<FlatMenuBarUI, T> f, T defaultValue ) {
MenuBarUI ui = ((JMenuBar)menuItem.getParent()).getUI();
if( !(ui instanceof FlatMenuBarUI) )
return defaultValue;
T value = f.apply( (FlatMenuBarUI) ui );
return (value != null) ? value : defaultValue;
}
}
}

View File

@@ -0,0 +1,358 @@
/*
* Copyright 2021 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.ui;
import java.awt.Color;
import java.awt.Container;
import java.awt.Rectangle;
import java.awt.Window;
import java.beans.PropertyChangeListener;
import java.util.List;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JRootPane;
import javax.swing.UIManager;
import javax.swing.event.ChangeListener;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.FlatSystemProperties;
import com.formdev.flatlaf.ui.JBRCustomDecorations.JBRWindowTopBorder;
import com.formdev.flatlaf.util.SystemInfo;
/**
* Support for custom window decorations with native window border.
*
* @author Karl Tauber
* @since 1.1
*/
public class FlatNativeWindowBorder
{
// can use window decorations if:
// - 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.isProjector &&
!SystemInfo.isWebswing &&
!SystemInfo.isWinPE &&
FlatSystemProperties.getBoolean( FlatSystemProperties.USE_WINDOW_DECORATIONS, true );
// check this field before using class JBRCustomDecorations to avoid unnecessary loading of that class
private static final boolean canUseJBRCustomDecorations =
canUseWindowDecorations &&
SystemInfo.isJetBrainsJVM_11_orLater &&
FlatSystemProperties.getBoolean( FlatSystemProperties.USE_JETBRAINS_CUSTOM_DECORATIONS, true );
private static Boolean supported;
private static Provider nativeProvider;
public static boolean isSupported() {
if( canUseJBRCustomDecorations )
return JBRCustomDecorations.isSupported();
initialize();
return supported;
}
static Object install( JRootPane rootPane ) {
if( canUseJBRCustomDecorations )
return JBRCustomDecorations.install( rootPane );
if( !isSupported() )
return null;
// do nothing if root pane has a parent that is not a window (e.g. a JInternalFrame)
Container parent = rootPane.getParent();
if( parent != null && !(parent instanceof Window) )
return null;
// Check whether root pane already has a window, which is the case when
// switching from another LaF to FlatLaf.
// Also check whether the window is displayable, which is required to install
// FlatLaf native window border.
// If the window is not displayable, then it was probably closed/disposed but not yet removed
// from the list of windows that AWT maintains and returns with Window.getWindows().
// It could be also be a window that is currently hidden, but may be shown later.
if( parent instanceof Window && parent.isDisplayable() )
install( (Window) parent );
// Install FlatLaf native window border, which must be done late,
// when the native window is already created, because it needs access to the window.
// Uninstall FlatLaf native window border when window is disposed (or root pane removed).
// "ancestor" property change event is fired from JComponent.addNotify() and removeNotify().
PropertyChangeListener ancestorListener = e -> {
Object newValue = e.getNewValue();
if( newValue instanceof Window )
install( (Window) newValue );
else if( newValue == null && e.getOldValue() instanceof Window )
uninstall( (Window) e.getOldValue() );
};
rootPane.addPropertyChangeListener( "ancestor", ancestorListener );
return ancestorListener;
}
static void install( Window window ) {
if( hasCustomDecoration( window ) )
return;
// do not enable native window border if LaF provides decorations
if( UIManager.getLookAndFeel().getSupportsWindowDecorations() )
return;
if( window instanceof JFrame ) {
JFrame frame = (JFrame) window;
JRootPane rootPane = frame.getRootPane();
// check whether disabled via system property, client property or UI default
if( !useWindowDecorations( rootPane ) )
return;
// do not enable native window border if frame is undecorated
if( frame.isUndecorated() )
return;
// enable native window border for window
setHasCustomDecoration( frame, true );
// avoid double window title bar if enabling native window border failed
if( !hasCustomDecoration( frame ) )
return;
// enable Swing window decoration
rootPane.setWindowDecorationStyle( JRootPane.FRAME );
} else if( window instanceof JDialog ) {
JDialog dialog = (JDialog) window;
JRootPane rootPane = dialog.getRootPane();
// check whether disabled via system property, client property or UI default
if( !useWindowDecorations( rootPane ) )
return;
// do not enable native window border if dialog is undecorated
if( dialog.isUndecorated() )
return;
// enable native window border for window
setHasCustomDecoration( dialog, true );
// avoid double window title bar if enabling native window border failed
if( !hasCustomDecoration( dialog ) )
return;
// enable Swing window decoration
rootPane.setWindowDecorationStyle( JRootPane.PLAIN_DIALOG );
}
}
static void uninstall( JRootPane rootPane, Object data ) {
if( canUseJBRCustomDecorations ) {
JBRCustomDecorations.uninstall( rootPane, data );
return;
}
if( !isSupported() )
return;
// remove listener
if( data instanceof PropertyChangeListener )
rootPane.removePropertyChangeListener( "ancestor", (PropertyChangeListener) data );
// do not uninstall when switching to another FlatLaf theme and if still enabled
if( UIManager.getLookAndFeel() instanceof FlatLaf && useWindowDecorations( rootPane ) )
return;
// uninstall native window border
Container parent = rootPane.getParent();
if( parent instanceof Window )
uninstall( (Window) parent );
}
private static void uninstall( Window window ) {
if( !hasCustomDecoration( window ) )
return;
// disable native window border for window
setHasCustomDecoration( window, false );
if( window instanceof JFrame ) {
JFrame frame = (JFrame) window;
// disable Swing window decoration
frame.getRootPane().setWindowDecorationStyle( JRootPane.NONE );
} else if( window instanceof JDialog ) {
JDialog dialog = (JDialog) window;
// disable Swing window decoration
dialog.getRootPane().setWindowDecorationStyle( JRootPane.NONE );
}
}
private static boolean useWindowDecorations( JRootPane rootPane ) {
return FlatUIUtils.getBoolean( rootPane,
FlatSystemProperties.USE_WINDOW_DECORATIONS,
FlatClientProperties.USE_WINDOW_DECORATIONS,
"TitlePane.useWindowDecorations",
false );
}
public static boolean hasCustomDecoration( Window window ) {
if( canUseJBRCustomDecorations )
return JBRCustomDecorations.hasCustomDecoration( window );
if( !isSupported() )
return false;
return nativeProvider.hasCustomDecoration( window );
}
public static void setHasCustomDecoration( Window window, boolean hasCustomDecoration ) {
if( canUseJBRCustomDecorations ) {
JBRCustomDecorations.setHasCustomDecoration( window, hasCustomDecoration );
return;
}
if( !isSupported() )
return;
nativeProvider.setHasCustomDecoration( window, hasCustomDecoration );
}
static void setTitleBarHeightAndHitTestSpots( Window window, int titleBarHeight,
List<Rectangle> hitTestSpots, Rectangle appIconBounds, Rectangle minimizeButtonBounds,
Rectangle maximizeButtonBounds, Rectangle closeButtonBounds )
{
if( canUseJBRCustomDecorations ) {
JBRCustomDecorations.setTitleBarHeightAndHitTestSpots( window, titleBarHeight, hitTestSpots );
return;
}
if( !isSupported() )
return;
nativeProvider.updateTitleBarInfo( window, titleBarHeight, hitTestSpots,
appIconBounds, minimizeButtonBounds, maximizeButtonBounds, closeButtonBounds );
}
static boolean showWindow( Window window, int cmd ) {
if( canUseJBRCustomDecorations || !isSupported() )
return false;
return nativeProvider.showWindow( window, cmd );
}
private static void initialize() {
if( supported != null )
return;
supported = false;
if( !canUseWindowDecorations )
return;
try {
/*
Class<?> cls = Class.forName( "com.formdev.flatlaf.natives.jna.windows.FlatWindowsNativeWindowBorder" );
java.lang.reflect.Method m = cls.getMethod( "getInstance" );
setNativeProvider( (Provider) m.invoke( null ) );
*/
setNativeProvider( FlatWindowsNativeWindowBorder.getInstance() );
} catch( Exception ex ) {
// ignore
}
}
/** @since 1.1.1 */
public static void setNativeProvider( Provider provider ) {
if( nativeProvider != null )
throw new IllegalStateException();
nativeProvider = provider;
supported = (nativeProvider != null);
}
//---- interface Provider -------------------------------------------------
public interface Provider
{
boolean hasCustomDecoration( Window window );
void setHasCustomDecoration( Window window, boolean hasCustomDecoration );
void updateTitleBarInfo( Window window, int titleBarHeight, List<Rectangle> hitTestSpots,
Rectangle appIconBounds, Rectangle minimizeButtonBounds, Rectangle maximizeButtonBounds,
Rectangle closeButtonBounds );
// commands for showWindow(); values must match Win32 API
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow
int SW_MAXIMIZE = 3;
int SW_MINIMIZE = 6;
int SW_RESTORE = 9;
boolean showWindow( Window window, int cmd );
boolean isColorizationColorAffectsBorders();
Color getColorizationColor();
int getColorizationColorBalance();
void addChangeListener( ChangeListener l );
void removeChangeListener( ChangeListener l );
}
//---- class WindowTopBorder -------------------------------------------
static class WindowTopBorder
extends JBRCustomDecorations.JBRWindowTopBorder
{
private static WindowTopBorder instance;
static JBRWindowTopBorder getInstance() {
if( canUseJBRCustomDecorations )
return JBRWindowTopBorder.getInstance();
if( instance == null )
instance = new WindowTopBorder();
return instance;
}
@Override
void installListeners() {
nativeProvider.addChangeListener( e -> {
update();
// repaint top borders of all windows
for( Window window : Window.getWindows() ) {
if( window.isDisplayable() )
window.repaint( 0, 0, window.getWidth(), 1 );
}
} );
}
@Override
boolean isColorizationColorAffectsBorders() {
return nativeProvider.isColorizationColorAffectsBorders();
}
@Override
Color getColorizationColor() {
return nativeProvider.getColorizationColor();
}
@Override
int getColorizationColorBalance() {
return nativeProvider.getColorizationColorBalance();
}
}
}

View File

@@ -22,14 +22,22 @@ import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.Insets;
import java.beans.PropertyChangeListener;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicHTML;
import javax.swing.plaf.basic.BasicOptionPaneUI;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.util.UIScale;
/**
@@ -75,6 +83,7 @@ import com.formdev.flatlaf.util.UIScale;
*
* <!-- FlatOptionPaneUI -->
*
* @uiDefault OptionPane.showIcon boolean
* @uiDefault OptionPane.iconMessageGap int
* @uiDefault OptionPane.messagePadding int
* @uiDefault OptionPane.maxCharactersPerLine int
@@ -84,10 +93,12 @@ import com.formdev.flatlaf.util.UIScale;
public class FlatOptionPaneUI
extends BasicOptionPaneUI
{
/** @since 2 */ protected boolean showIcon;
protected int iconMessageGap;
protected int messagePadding;
protected int maxCharactersPerLine;
private int focusWidth;
private boolean sameSizeButtons;
public static ComponentUI createUI( JComponent c ) {
return new FlatOptionPaneUI();
@@ -97,10 +108,12 @@ public class FlatOptionPaneUI
protected void installDefaults() {
super.installDefaults();
showIcon = UIManager.getBoolean( "OptionPane.showIcon" );
iconMessageGap = UIManager.getInt( "OptionPane.iconMessageGap" );
messagePadding = UIManager.getInt( "OptionPane.messagePadding" );
maxCharactersPerLine = UIManager.getInt( "OptionPane.maxCharactersPerLine" );
focusWidth = UIManager.getInt( "Component.focusWidth" );
sameSizeButtons = FlatUIUtils.getUIBoolean( "OptionPane.sameSizeButtons", true );
}
@Override
@@ -110,6 +123,24 @@ public class FlatOptionPaneUI
updateChildPanels( optionPane );
}
@Override
protected PropertyChangeListener createPropertyChangeListener() {
PropertyChangeListener superListener = super.createPropertyChangeListener();
return e -> {
superListener.propertyChange( e );
// hide window title bar icon
// (only if showIcon is false, otherwise the default behavior is used)
if( !showIcon && "ancestor".equals( e.getPropertyName() ) && e.getNewValue() != null ) {
JRootPane rootPane = SwingUtilities.getRootPane( optionPane );
if( rootPane != null &&
rootPane.getContentPane().getComponentCount() > 0 &&
rootPane.getContentPane().getComponent( 0 ) == optionPane )
rootPane.putClientProperty( FlatClientProperties.TITLE_BAR_SHOW_ICON, false );
}
};
}
@Override
public Dimension getMinimumOptionPaneSize() {
return UIScale.scale( super.getMinimumOptionPaneSize() );
@@ -157,15 +188,40 @@ public class FlatOptionPaneUI
cons.insets.bottom = UIScale.scale( messagePadding );
// disable line wrapping for HTML
if( msg instanceof String && BasicHTML.isHTMLString( (String) msg ) )
maxll = Integer.MAX_VALUE;
if( msg != null &&
!(msg instanceof Component) &&
!(msg instanceof Object[]) &&
!(msg instanceof Icon) )
{
msg = msg.toString();
if( BasicHTML.isHTMLString( (String) msg ) )
maxll = Integer.MAX_VALUE;
}
// fix right-to-left alignment if super.addMessageComponents() breaks longer lines
// into multiple labels and puts them into a box that aligns them to the left
if( msg instanceof Box ) {
Box box = (Box) msg;
if( "OptionPane.verticalBox".equals( box.getName() ) &&
box.getLayout() instanceof BoxLayout &&
((BoxLayout)box.getLayout()).getAxis() == BoxLayout.Y_AXIS )
{
box.addPropertyChangeListener( "componentOrientation", e -> {
float alignX = box.getComponentOrientation().isLeftToRight() ? 0 : 1;
for( Component c : box.getComponents() ) {
if( c instanceof JLabel && "OptionPane.label".equals( c.getName() ) )
((JLabel)c).setAlignmentX( alignX );
}
} );
}
}
super.addMessageComponents( container, cons, msg, maxll, internallyCreated );
}
private void updateChildPanels( Container c ) {
for( Component child : c.getComponents() ) {
if( child instanceof JPanel ) {
if( child.getClass() == JPanel.class ) {
JPanel panel = (JPanel)child;
// make sub-panel non-opaque for OptionPane.background
@@ -177,9 +233,8 @@ public class FlatOptionPaneUI
panel.setBorder( new NonUIResourceBorder( border ) );
}
if( child instanceof Container ) {
if( child instanceof Container )
updateChildPanels( (Container) child );
}
}
}
@@ -197,6 +252,11 @@ public class FlatOptionPaneUI
return null;
}
@Override
protected boolean getSizeButtonsToSameWidth() {
return sameSizeButtons;
}
//---- class NonUIResourceBorder ------------------------------------------
private static class NonUIResourceBorder

View File

@@ -35,11 +35,7 @@ import javax.swing.plaf.basic.BasicPanelUI;
public class FlatPanelUI
extends BasicPanelUI
{
private static ComponentUI instance;
public static ComponentUI createUI( JComponent c ) {
if( instance == null )
instance = new FlatPanelUI();
return instance;
return FlatUIUtils.createSharedUI( FlatPanelUI.class, FlatPanelUI::new );
}
}

View File

@@ -16,30 +16,35 @@
package com.formdev.flatlaf.ui;
import static com.formdev.flatlaf.util.UIScale.scale;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.FocusListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.beans.PropertyChangeEvent;
import java.util.Map;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.LookAndFeel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicPasswordFieldUI;
import javax.swing.text.Caret;
import javax.swing.text.DefaultEditorKit;
import javax.swing.text.Element;
import javax.swing.text.JTextComponent;
import com.formdev.flatlaf.FlatClientProperties;
import javax.swing.text.PasswordView;
import javax.swing.text.View;
import com.formdev.flatlaf.icons.FlatCapsLockIcon;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.util.UIScale;
/**
* Provides the Flat LaF UI delegate for {@link javax.swing.JPasswordField}.
*
* <!-- BasicPasswordFieldUI -->
* <!-- BasicTextFieldUI -->
*
* @uiDefault PasswordField.font Font
* @uiDefault PasswordField.background Color
@@ -52,70 +57,70 @@ import com.formdev.flatlaf.FlatClientProperties;
* @uiDefault PasswordField.inactiveForeground Color used if not enabled (yes, this is confusing; this should be named disabledForeground)
* @uiDefault PasswordField.border Border
* @uiDefault PasswordField.margin Insets
* @uiDefault PasswordField.echoChar character
* @uiDefault PasswordField.caretBlinkRate int default is 500 milliseconds
*
* <!-- FlatPasswordFieldUI -->
* <!-- FlatTextFieldUI -->
*
* @uiDefault TextComponent.arc int
* @uiDefault Component.focusWidth int
* @uiDefault Component.minimumWidth int
* @uiDefault Component.isIntelliJTheme boolean
* @uiDefault PasswordField.placeholderForeground Color
* @uiDefault PasswordField.capsLockIcon Icon
* @uiDefault PasswordField.focusedBackground Color optional
* @uiDefault PasswordField.iconTextGap int optional, default is 4
* @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always
* @uiDefault TextComponent.selectAllOnMouseClick boolean
*
* <!-- FlatPasswordFieldUI -->
*
* @uiDefault PasswordField.echoChar character
* @uiDefault PasswordField.showCapsLock boolean
* @uiDefault PasswordField.capsLockIcon Icon
*
* @author Karl Tauber
*/
public class FlatPasswordFieldUI
extends BasicPasswordFieldUI
extends FlatTextFieldUI
{
protected int arc;
protected int focusWidth;
protected int minimumWidth;
protected boolean isIntelliJTheme;
protected Color placeholderForeground;
@Styleable protected boolean showCapsLock;
protected Icon capsLockIcon;
private FocusListener focusListener;
private KeyListener capsLockListener;
private boolean capsLockIconShared = true;
public static ComponentUI createUI( JComponent c ) {
return new FlatPasswordFieldUI();
}
@Override
protected String getPropertyPrefix() {
return "PasswordField";
}
@Override
protected void installDefaults() {
super.installDefaults();
String prefix = getPropertyPrefix();
arc = UIManager.getInt( "TextComponent.arc" );
focusWidth = UIManager.getInt( "Component.focusWidth" );
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
placeholderForeground = UIManager.getColor( prefix + ".placeholderForeground" );
Character echoChar = (Character) UIManager.get( prefix + ".echoChar" );
if( echoChar != null )
LookAndFeel.installProperty( getComponent(), "echoChar", echoChar );
showCapsLock = UIManager.getBoolean( "PasswordField.showCapsLock" );
capsLockIcon = UIManager.getIcon( "PasswordField.capsLockIcon" );
LookAndFeel.installProperty( getComponent(), "opaque", focusWidth == 0 );
MigLayoutVisualPadding.install( getComponent(), focusWidth );
capsLockIconShared = true;
}
@Override
protected void uninstallDefaults() {
super.uninstallDefaults();
placeholderForeground = null;
capsLockIcon = null;
MigLayoutVisualPadding.uninstall( getComponent() );
}
@Override
protected void installListeners() {
super.installListeners();
focusListener = new FlatUIUtils.RepaintFocusListener( getComponent() );
// update caps lock indicator
capsLockListener = new KeyAdapter() {
@Override
public void keyPressed( KeyEvent e ) {
@@ -126,12 +131,13 @@ public class FlatPasswordFieldUI
repaint( e );
}
private void repaint( KeyEvent e ) {
if( e.getKeyCode() == KeyEvent.VK_CAPS_LOCK )
if( e.getKeyCode() == KeyEvent.VK_CAPS_LOCK ) {
e.getComponent().repaint();
scrollCaretToVisible();
}
}
};
getComponent().addFocusListener( focusListener );
getComponent().addKeyListener( capsLockListener );
}
@@ -139,63 +145,95 @@ public class FlatPasswordFieldUI
protected void uninstallListeners() {
super.uninstallListeners();
getComponent().removeFocusListener( focusListener );
getComponent().removeKeyListener( capsLockListener );
focusListener = null;
capsLockListener = null;
}
@Override
protected Caret createCaret() {
return new FlatCaret( UIManager.getString( "TextComponent.selectAllOnFocusPolicy" ) );
protected void installKeyboardActions() {
super.installKeyboardActions();
// map "select-word" action (double-click) to "select-line" action
ActionMap map = SwingUtilities.getUIActionMap( getComponent() );
if( map != null && map.get( DefaultEditorKit.selectWordAction ) != null ) {
Action selectLineAction = map.get( DefaultEditorKit.selectLineAction );
if( selectLineAction != null )
map.put( DefaultEditorKit.selectWordAction, selectLineAction );
}
}
/** @since 2 */
@Override
String getStyleType() {
return "PasswordField";
}
/** @since 2 */
@Override
protected Object applyStyleProperty( String key, Object value ) {
if( key.equals( "capsLockIconColor" ) && capsLockIcon instanceof FlatCapsLockIcon ) {
if( capsLockIconShared ) {
capsLockIcon = FlatStylingSupport.cloneIcon( capsLockIcon );
capsLockIconShared = false;
}
return ((FlatCapsLockIcon)capsLockIcon).applyStyleProperty( key, value );
}
return super.applyStyleProperty( key, value );
}
/** @since 2 */
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
Map<String, Class<?>> infos = super.getStyleableInfos( c );
infos.put( "capsLockIconColor", Color.class );
return infos;
}
@Override
protected void propertyChange( PropertyChangeEvent e ) {
super.propertyChange( e );
if( FlatClientProperties.PLACEHOLDER_TEXT.equals( e.getPropertyName() ) )
getComponent().repaint();
public View create( Element elem ) {
return new PasswordView( elem );
}
/** @since 2 */
@Override
protected void paintSafely( Graphics g ) {
FlatTextFieldUI.paintBackground( g, getComponent(), focusWidth, arc, isIntelliJTheme );
FlatTextFieldUI.paintPlaceholder( g, getComponent(), placeholderForeground );
paintCapsLock( g );
super.paintSafely( g );
protected void paintIcons( Graphics g, Rectangle r ) {
super.paintIcons( g, r );
if( isCapsLockVisible() )
paintCapsLock( g, r );
}
protected void paintCapsLock( Graphics g ) {
/** @since 2 */
protected void paintCapsLock( Graphics g, Rectangle r ) {
JTextComponent c = getComponent();
if( !FlatUIUtils.isPermanentFocusOwner( c ) ||
!Toolkit.getDefaultToolkit().getLockingKeyState( KeyEvent.VK_CAPS_LOCK ) )
return;
int y = (c.getHeight() - capsLockIcon.getIconHeight()) / 2;
int x = c.getWidth() - capsLockIcon.getIconWidth() - y;
int x = c.getComponentOrientation().isLeftToRight()
? r.x + r.width - capsLockIcon.getIconWidth()
: r.x;
int y = r.y + Math.round( (r.height - capsLockIcon.getIconHeight()) / 2f );
capsLockIcon.paintIcon( c, g, x, y );
}
/** @since 2 */
@Override
protected void paintBackground( Graphics g ) {
// background is painted elsewhere
protected boolean hasTrailingIcon() {
return super.hasTrailingIcon() || isCapsLockVisible();
}
/** @since 2 */
@Override
public Dimension getPreferredSize( JComponent c ) {
return applyMinimumWidth( super.getPreferredSize( c ), c );
protected int getTrailingIconWidth() {
return super.getTrailingIconWidth()
+ (isCapsLockVisible() ? capsLockIcon.getIconWidth() + UIScale.scale( iconTextGap ) : 0);
}
@Override
public Dimension getMinimumSize( JComponent c ) {
return applyMinimumWidth( super.getMinimumSize( c ), c );
}
/** @since 1.4 */
protected boolean isCapsLockVisible() {
if( !showCapsLock )
return false;
private Dimension applyMinimumWidth( Dimension size, JComponent c ) {
int minimumWidth = FlatUIUtils.minimumWidth( getComponent(), this.minimumWidth );
int focusWidth = (c.getBorder() instanceof FlatBorder) ? this.focusWidth : 0;
size.width = Math.max( size.width, scale( minimumWidth + (focusWidth * 2) ) );
return size;
JTextComponent c = getComponent();
return FlatUIUtils.isPermanentFocusOwner( c ) &&
Toolkit.getDefaultToolkit().getLockingKeyState( KeyEvent.VK_CAPS_LOCK );
}
}

View File

@@ -0,0 +1,545 @@
/*
* Copyright 2020 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.ui;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Insets;
import java.awt.MouseInfo;
import java.awt.Panel;
import java.awt.Point;
import java.awt.PointerInfo;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import javax.swing.JComponent;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.JToolTip;
import javax.swing.JWindow;
import javax.swing.Popup;
import javax.swing.PopupFactory;
import javax.swing.RootPaneContainer;
import javax.swing.SwingUtilities;
import javax.swing.ToolTipManager;
import javax.swing.UIManager;
import javax.swing.border.Border;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.util.SystemInfo;
import com.formdev.flatlaf.util.UIScale;
/**
* A popup factory that adds drop shadows to popups on Windows.
* On macOS and Linux, heavy weight popups (without drop shadow) are produced and the
* operating system automatically adds drop shadows.
*
* @author Karl Tauber
*/
public class FlatPopupFactory
extends PopupFactory
{
private Method java8getPopupMethod;
private Method java9getPopupMethod;
@Override
public Popup getPopup( Component owner, Component contents, int x, int y )
throws IllegalArgumentException
{
Point pt = fixToolTipLocation( owner, contents, x, y );
if( pt != null ) {
x = pt.x;
y = pt.y;
}
boolean forceHeavyWeight = isOptionEnabled( owner, contents, FlatClientProperties.POPUP_FORCE_HEAVY_WEIGHT, "Popup.forceHeavyWeight" );
if( !isOptionEnabled( owner, contents, FlatClientProperties.POPUP_DROP_SHADOW_PAINTED, "Popup.dropShadowPainted" ) || SystemInfo.isProjector || SystemInfo.isWebswing )
return new NonFlashingPopup( getPopupForScreenOfOwner( owner, contents, x, y, forceHeavyWeight ), contents );
// macOS and Linux adds drop shadow to heavy weight popups
if( SystemInfo.isMacOS || SystemInfo.isLinux )
return new NonFlashingPopup( getPopupForScreenOfOwner( owner, contents, x, y, true ), contents );
// create drop shadow popup
return new DropShadowPopup( getPopupForScreenOfOwner( owner, contents, x, y, forceHeavyWeight ), owner, contents );
}
/**
* Creates a popup for the screen that the owner component is on.
* <p>
* PopupFactory caches heavy weight popup windows and reuses them.
* On a dual screen setup, if the popup owner has moved from one screen to the other one,
* then the cached heavy weight popup window may be connected to the wrong screen.
* If the two screens use different scaling factors, then the popup location and size
* is scaled when the popup becomes visible, which shows the popup in the wrong location
* (or on wrong screen). The re-scaling is done in WWindowPeer.setBounds() (Java 9+).
* <p>
* To fix this, dispose popup windows that are on wrong screen and get new popup.
* <p>
* This is a workaround for https://bugs.openjdk.java.net/browse/JDK-8224608
*/
private Popup getPopupForScreenOfOwner( Component owner, Component contents, int x, int y, boolean forceHeavyWeight )
throws IllegalArgumentException
{
int count = 0;
for(;;) {
// create new or get cached popup
Popup popup = forceHeavyWeight
? getHeavyWeightPopup( owner, contents, x, y )
: super.getPopup( owner, contents, x, y );
// get heavy weight popup window; is null for non-heavy weight popup
Window popupWindow = SwingUtilities.windowForComponent( contents );
// check whether heavy weight popup window is on same screen as owner component
if( popupWindow == null ||
owner == null ||
popupWindow.getGraphicsConfiguration() == owner.getGraphicsConfiguration() )
return popup;
// remove contents component from popup window
if( popupWindow instanceof JWindow )
((JWindow)popupWindow).getContentPane().removeAll();
// dispose unused popup
// (do not invoke popup.hide() because this would cache the popup window)
popupWindow.dispose();
// avoid endless loop (should newer happen; PopupFactory cache size is 5)
if( ++count > 10 )
return popup;
}
}
/**
* Shows the given popup and, if necessary, fixes the location of a heavy weight popup window.
* <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.
* <p>
* This is a workaround for https://bugs.openjdk.java.net/browse/JDK-8224608
*/
private static void showPopupAndFixLocation( Popup popup, Window popupWindow ) {
if( popupWindow != null ) {
// remember location of heavy weight popup window
int x = popupWindow.getX();
int y = popupWindow.getY();
popup.show();
// restore popup window location if it has changed
// (probably scaled when screens use different scale factors)
if( popupWindow.getX() != x || popupWindow.getY() != y )
popupWindow.setLocation( x, y );
} else
popup.show();
}
private boolean isOptionEnabled( Component owner, Component contents, String clientKey, String uiKey ) {
if( owner instanceof JComponent ) {
Boolean b = FlatClientProperties.clientPropertyBooleanStrict( (JComponent) owner, clientKey, null );
if( b != null )
return b;
}
if( contents instanceof JComponent ) {
Boolean b = FlatClientProperties.clientPropertyBooleanStrict( (JComponent) contents, clientKey, null );
if( b != null )
return b;
}
return UIManager.getBoolean( uiKey );
}
/**
* There is no API in Java 8 to force creation of heavy weight popups,
* but it is possible with reflection. Java 9 provides a new method.
*
* When changing FlatLaf system requirements to Java 9+,
* then this method can be replaced with:
* return getPopup( owner, contents, x, y, true );
*/
private Popup getHeavyWeightPopup( Component owner, Component contents, int x, int y )
throws IllegalArgumentException
{
try {
if( SystemInfo.isJava_9_orLater ) {
if( java9getPopupMethod == null ) {
java9getPopupMethod = PopupFactory.class.getDeclaredMethod(
"getPopup", Component.class, Component.class, int.class, int.class, boolean.class );
}
return (Popup) java9getPopupMethod.invoke( this, owner, contents, x, y, true );
} else {
// Java 8
if( java8getPopupMethod == null ) {
java8getPopupMethod = PopupFactory.class.getDeclaredMethod(
"getPopup", Component.class, Component.class, int.class, int.class, int.class );
java8getPopupMethod.setAccessible( true );
}
return (Popup) java8getPopupMethod.invoke( this, owner, contents, x, y, /*HEAVY_WEIGHT_POPUP*/ 2 );
}
} catch( NoSuchMethodException | SecurityException | IllegalAccessException | InvocationTargetException ex ) {
// ignore
return null;
}
}
/**
* Usually ToolTipManager places a tooltip at (mouseLocation.x, mouseLocation.y + 20).
* In case that the tooltip would be partly outside of the screen,
* the ToolTipManager changes the location so that the entire tooltip fits on screen.
* But this can place the tooltip under the mouse location and hide the owner component.
* <p>
* This method checks whether the current mouse location is within tooltip bounds
* and corrects the y-location so that the tooltip is placed above the mouse location.
*/
private Point fixToolTipLocation( Component owner, Component contents, int x, int y ) {
if( !(contents instanceof JToolTip) || !wasInvokedFromToolTipManager() )
return null;
PointerInfo pointerInfo = MouseInfo.getPointerInfo();
if( pointerInfo == null )
return null;
Point mouseLocation = pointerInfo.getLocation();
Dimension tipSize = contents.getPreferredSize();
// check whether mouse location is within tooltip bounds
Rectangle tipBounds = new Rectangle( x, y, tipSize.width, tipSize.height );
if( !tipBounds.contains( mouseLocation ) )
return null;
// find GraphicsConfiguration at mouse location (similar to ToolTipManager.getDrawingGC())
GraphicsConfiguration gc = null;
for( GraphicsDevice device : GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices() ) {
GraphicsConfiguration dgc = device.getDefaultConfiguration();
if( dgc.getBounds().contains( mouseLocation ) ) {
gc = dgc;
break;
}
}
if( gc == null )
gc = owner.getGraphicsConfiguration();
if( gc == null )
return null;
Rectangle screenBounds = gc.getBounds();
Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets( gc );
int screenTop = screenBounds.y + screenInsets.top;
// place tooltip above mouse location if there is enough space
int newY = mouseLocation.y - tipSize.height - UIScale.scale( 20 );
if( newY < screenTop )
return null;
return new Point( x, newY );
}
private boolean wasInvokedFromToolTipManager() {
return StackUtils.wasInvokedFrom( ToolTipManager.class.getName(), "showTipWindow", 8 );
}
//---- class NonFlashingPopup ---------------------------------------------
private class NonFlashingPopup
extends Popup
{
private Popup delegate;
private Component contents;
// heavy weight
protected Window popupWindow;
private Color oldPopupWindowBackground;
NonFlashingPopup( Popup delegate, Component contents ) {
this.delegate = delegate;
this.contents = contents;
popupWindow = SwingUtilities.windowForComponent( contents );
if( popupWindow != null ) {
// heavy weight popup
// fix background flashing which may occur on some platforms
// (e.g. macOS and Linux) when using dark theme
oldPopupWindowBackground = popupWindow.getBackground();
popupWindow.setBackground( contents.getBackground() );
}
}
@Override
public void show() {
if( delegate != null ) {
showPopupAndFixLocation( delegate, popupWindow );
// increase tooltip size if necessary because it may be too small on HiDPI screens
// https://bugs.openjdk.java.net/browse/JDK-8213535
if( contents instanceof JToolTip && popupWindow == null ) {
Container parent = contents.getParent();
if( parent instanceof JPanel ) {
Dimension prefSize = parent.getPreferredSize();
if( !prefSize.equals( parent.getSize() ) ) {
Container mediumWeightPanel = SwingUtilities.getAncestorOfClass( Panel.class, parent );
Container c = (mediumWeightPanel != null)
? mediumWeightPanel // medium weight popup
: parent; // light weight popup
c.setSize( prefSize );
c.validate();
}
}
}
}
}
@Override
public void hide() {
if( delegate != null ) {
delegate.hide();
delegate = null;
contents = null;
}
if( popupWindow != null ) {
// restore background so that it can not affect other LaFs (when switching)
// because popup windows are cached and reused
popupWindow.setBackground( oldPopupWindowBackground );
popupWindow = null;
}
}
}
//---- class DropShadowPopup ----------------------------------------------
private class DropShadowPopup
extends NonFlashingPopup
{
private final Component owner;
// light weight
private JComponent lightComp;
private Border oldBorder;
private boolean oldOpaque;
// medium weight
private boolean mediumWeightShown;
private Panel mediumWeightPanel;
private JPanel dropShadowPanel;
private ComponentListener mediumPanelListener;
// heavy weight
private Popup dropShadowDelegate;
private Window dropShadowWindow;
private Color oldDropShadowWindowBackground;
DropShadowPopup( Popup delegate, Component owner, Component contents ) {
super( delegate, contents );
this.owner = owner;
Dimension size = contents.getPreferredSize();
if( size.width <= 0 || size.height <= 0 )
return;
if( popupWindow != null ) {
// heavy weight popup
// Since Java has a problem with sub-pixel text rendering on translucent
// windows, we can not make the popup window translucent for the drop shadow.
// (see https://bugs.openjdk.java.net/browse/JDK-8215980)
// The solution is to create a second translucent window that paints
// the drop shadow and is positioned behind the popup window.
// create panel that paints the drop shadow
JPanel dropShadowPanel = new JPanel();
dropShadowPanel.setBorder( createDropShadowBorder() );
dropShadowPanel.setOpaque( false );
// set preferred size of drop shadow panel
Dimension prefSize = popupWindow.getPreferredSize();
Insets insets = dropShadowPanel.getInsets();
dropShadowPanel.setPreferredSize( new Dimension(
prefSize.width + insets.left + insets.right,
prefSize.height + insets.top + insets.bottom ) );
// create heavy weight popup for drop shadow
int x = popupWindow.getX() - insets.left;
int y = popupWindow.getY() - insets.top;
dropShadowDelegate = getPopupForScreenOfOwner( owner, dropShadowPanel, x, y, true );
// make drop shadow popup window translucent
dropShadowWindow = SwingUtilities.windowForComponent( dropShadowPanel );
if( dropShadowWindow != null ) {
oldDropShadowWindowBackground = dropShadowWindow.getBackground();
dropShadowWindow.setBackground( new Color( 0, true ) );
}
} else {
mediumWeightPanel = (Panel) SwingUtilities.getAncestorOfClass( Panel.class, contents );
if( mediumWeightPanel != null ) {
// medium weight popup
dropShadowPanel = new JPanel();
dropShadowPanel.setBorder( createDropShadowBorder() );
dropShadowPanel.setOpaque( false );
dropShadowPanel.setSize( FlatUIUtils.addInsets( mediumWeightPanel.getSize(), dropShadowPanel.getInsets() ) );
} else {
// light weight popup
Container p = contents.getParent();
if( !(p instanceof JComponent) )
return;
lightComp = (JComponent) p;
oldBorder = lightComp.getBorder();
oldOpaque = lightComp.isOpaque();
lightComp.setBorder( createDropShadowBorder() );
lightComp.setOpaque( false );
lightComp.setSize( lightComp.getPreferredSize() );
}
}
}
private Border createDropShadowBorder() {
return new FlatDropShadowBorder(
UIManager.getColor( "Popup.dropShadowColor" ),
UIManager.getInsets( "Popup.dropShadowInsets" ),
FlatUIUtils.getUIFloat( "Popup.dropShadowOpacity", 0.5f ) );
}
@Override
public void show() {
if( dropShadowDelegate != null )
showPopupAndFixLocation( dropShadowDelegate, dropShadowWindow );
if( mediumWeightPanel != null )
showMediumWeightDropShadow();
super.show();
// fix location of light weight popup in case it has left or top drop shadow
if( lightComp != null ) {
Insets insets = lightComp.getInsets();
if( insets.left != 0 || insets.top != 0 )
lightComp.setLocation( lightComp.getX() - insets.left, lightComp.getY() - insets.top );
}
}
@Override
public void hide() {
if( dropShadowDelegate != null ) {
dropShadowDelegate.hide();
dropShadowDelegate = null;
}
if( mediumWeightPanel != null ) {
hideMediumWeightDropShadow();
dropShadowPanel = null;
mediumWeightPanel = null;
}
super.hide();
if( dropShadowWindow != null ) {
dropShadowWindow.setBackground( oldDropShadowWindowBackground );
dropShadowWindow = null;
}
if( lightComp != null ) {
lightComp.setBorder( oldBorder );
lightComp.setOpaque( oldOpaque );
lightComp = null;
}
}
private void showMediumWeightDropShadow() {
if( mediumWeightShown )
return;
mediumWeightShown = true;
if( owner == null )
return;
Window window = SwingUtilities.windowForComponent( owner );
if( !(window instanceof RootPaneContainer) )
return;
dropShadowPanel.setVisible( false );
JLayeredPane layeredPane = ((RootPaneContainer)window).getLayeredPane();
layeredPane.add( dropShadowPanel, JLayeredPane.POPUP_LAYER, 0 );
moveMediumWeightDropShadow();
resizeMediumWeightDropShadow();
mediumPanelListener = new ComponentListener() {
@Override
public void componentShown( ComponentEvent e ) {
if( dropShadowPanel != null )
dropShadowPanel.setVisible( true );
}
@Override
public void componentHidden( ComponentEvent e ) {
if( dropShadowPanel != null )
dropShadowPanel.setVisible( false );
}
@Override
public void componentMoved( ComponentEvent e ) {
moveMediumWeightDropShadow();
}
@Override
public void componentResized( ComponentEvent e ) {
resizeMediumWeightDropShadow();
}
};
mediumWeightPanel.addComponentListener( mediumPanelListener );
}
private void hideMediumWeightDropShadow() {
mediumWeightPanel.removeComponentListener( mediumPanelListener );
Container parent = dropShadowPanel.getParent();
if( parent != null ) {
Rectangle bounds = dropShadowPanel.getBounds();
parent.remove( dropShadowPanel );
parent.repaint( bounds.x, bounds.y, bounds.width, bounds.height );
}
}
private void moveMediumWeightDropShadow() {
if( dropShadowPanel != null && mediumWeightPanel != null ) {
Point location = mediumWeightPanel.getLocation();
Insets insets = dropShadowPanel.getInsets();
dropShadowPanel.setLocation( location.x - insets.left, location.y - insets.top );
}
}
private void resizeMediumWeightDropShadow() {
if( dropShadowPanel != null && mediumWeightPanel != null )
dropShadowPanel.setSize( FlatUIUtils.addInsets( mediumWeightPanel.getSize(), dropShadowPanel.getInsets() ) );
}
}
}

View File

@@ -16,11 +16,15 @@
package com.formdev.flatlaf.ui;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Insets;
import java.util.Map;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableBorder;
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
import com.formdev.flatlaf.util.UIScale;
/**
@@ -33,12 +37,40 @@ import com.formdev.flatlaf.util.UIScale;
*/
public class FlatPopupMenuBorder
extends FlatLineBorder
implements StyleableBorder
{
private Color borderColor;
public FlatPopupMenuBorder() {
super( UIManager.getInsets( "PopupMenu.borderInsets" ),
UIManager.getColor( "PopupMenu.borderColor" ) );
}
/** @since 2 */
@Override
public Object applyStyleProperty( String key, Object value ) {
Object oldValue;
switch( key ) {
case "borderInsets": return applyStyleProperty( (Insets) value );
case "borderColor": oldValue = getLineColor(); borderColor = (Color) value; return oldValue;
}
throw new UnknownStyleException( key );
}
/** @since 2 */
@Override
public Map<String, Class<?>> getStyleableInfos() {
Map<String, Class<?>> infos = new FlatStylingSupport.StyleableInfosMap<>();
infos.put( "borderInsets", Insets.class );
infos.put( "borderColor", Color.class );
return infos;
}
@Override
public Color getLineColor() {
return (borderColor != null) ? borderColor : super.getLineColor();
}
@Override
public Insets getBorderInsets( Component c, Insets insets ) {
if( c instanceof Container &&

View File

@@ -24,8 +24,8 @@ import javax.swing.plaf.ComponentUI;
*
* <!-- BasicSeparatorUI -->
*
* @uiDefault PopupMenuSeparator.background Color unused
* @uiDefault PopupMenuSeparator.foreground Color
* @uiDefault Separator.background Color unused
* @uiDefault Separator.foreground Color
*
* <!-- FlatSeparatorUI -->
*
@@ -38,16 +38,25 @@ import javax.swing.plaf.ComponentUI;
public class FlatPopupMenuSeparatorUI
extends FlatSeparatorUI
{
private static ComponentUI instance;
public static ComponentUI createUI( JComponent c ) {
if( instance == null )
instance = new FlatPopupMenuSeparatorUI();
return instance;
return FlatUIUtils.canUseSharedUI( c )
? FlatUIUtils.createSharedUI( FlatPopupMenuSeparatorUI.class, () -> new FlatPopupMenuSeparatorUI( true ) )
: new FlatPopupMenuSeparatorUI( false );
}
/** @since 2 */
protected FlatPopupMenuSeparatorUI( boolean shared ) {
super( shared );
}
@Override
protected String getPropertyPrefix() {
return "PopupMenuSeparator";
}
/** @since 2 */
@Override
String getStyleType() {
return "PopupMenuSeparator";
}
}

View File

@@ -16,9 +16,14 @@
package com.formdev.flatlaf.ui;
import java.beans.PropertyChangeListener;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.JComponent;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicPopupMenuUI;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.util.LoggingFacade;
/**
* Provides the Flat LaF UI delegate for {@link javax.swing.JPopupMenu}.
@@ -34,8 +39,71 @@ import javax.swing.plaf.basic.BasicPopupMenuUI;
*/
public class FlatPopupMenuUI
extends BasicPopupMenuUI
implements StyleableUI
{
private PropertyChangeListener propertyChangeListener;
private Map<String, Object> oldStyleValues;
private AtomicBoolean borderShared;
public static ComponentUI createUI( JComponent c ) {
return new FlatPopupMenuUI();
}
@Override
public void installUI( JComponent c ) {
super.installUI( c );
installStyle();
}
@Override
public void uninstallUI( JComponent c ) {
super.uninstallUI( c );
oldStyleValues = null;
borderShared = null;
}
@Override
protected void installListeners() {
super.installListeners();
propertyChangeListener = FlatStylingSupport.createPropertyChangeListener( popupMenu, this::installStyle, null );
popupMenu.addPropertyChangeListener( propertyChangeListener );
}
@Override
protected void uninstallListeners() {
super.uninstallListeners();
popupMenu.removePropertyChangeListener( propertyChangeListener );
propertyChangeListener = null;
}
/** @since 2 */
protected void installStyle() {
try {
applyStyle( FlatStylingSupport.getResolvedStyle( popupMenu, "PopupMenu" ) );
} catch( RuntimeException ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex );
}
}
/** @since 2 */
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
}
/** @since 2 */
protected Object applyStyleProperty( String key, Object value ) {
if( borderShared == null )
borderShared = new AtomicBoolean( true );
return FlatStylingSupport.applyToAnnotatedObjectOrBorder( this, key, value, popupMenu, borderShared );
}
/** @since 2 */
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return FlatStylingSupport.getAnnotatedStyleableInfos( this, popupMenu.getBorder() );
}
}

View File

@@ -25,12 +25,17 @@ import java.awt.Insets;
import java.awt.geom.Area;
import java.awt.geom.RoundRectangle2D;
import java.beans.PropertyChangeListener;
import java.util.Map;
import javax.swing.JComponent;
import javax.swing.JProgressBar;
import javax.swing.LookAndFeel;
import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicProgressBarUI;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.util.HiDPIUtils;
import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.UIScale;
/**
@@ -57,17 +62,30 @@ import com.formdev.flatlaf.util.UIScale;
*/
public class FlatProgressBarUI
extends BasicProgressBarUI
implements StyleableUI
{
protected int arc;
protected Dimension horizontalSize;
protected Dimension verticalSize;
@Styleable protected int arc;
@Styleable protected Dimension horizontalSize;
@Styleable protected Dimension verticalSize;
// only used via styling (not in UI defaults, but has likewise client properties)
/** @since 2 */ @Styleable protected boolean largeHeight;
/** @since 2 */ @Styleable protected boolean square;
private PropertyChangeListener propertyChangeListener;
private Map<String, Object> oldStyleValues;
public static ComponentUI createUI( JComponent c ) {
return new FlatProgressBarUI();
}
@Override
public void installUI( JComponent c ) {
super.installUI( c );
installStyle();
}
@Override
protected void installDefaults() {
super.installDefaults();
@@ -79,6 +97,13 @@ public class FlatProgressBarUI
verticalSize = UIManager.getDimension( "ProgressBar.verticalSize" );
}
@Override
protected void uninstallDefaults() {
super.uninstallDefaults();
oldStyleValues = null;
}
@Override
protected void installListeners() {
super.installListeners();
@@ -90,6 +115,13 @@ public class FlatProgressBarUI
progressBar.revalidate();
progressBar.repaint();
break;
case STYLE:
case STYLE_CLASS:
installStyle();
progressBar.revalidate();
progressBar.repaint();
break;
}
};
progressBar.addPropertyChangeListener( propertyChangeListener );
@@ -103,11 +135,36 @@ public class FlatProgressBarUI
propertyChangeListener = null;
}
/** @since 2 */
protected void installStyle() {
try {
applyStyle( FlatStylingSupport.getResolvedStyle( progressBar, "ProgressBar" ) );
} catch( RuntimeException ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex );
}
}
/** @since 2 */
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
}
/** @since 2 */
protected Object applyStyleProperty( String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, progressBar, key, value );
}
/** @since 2 */
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
}
@Override
public Dimension getPreferredSize( JComponent c ) {
Dimension size = super.getPreferredSize( c );
if( progressBar.isStringPainted() || clientPropertyBoolean( c, PROGRESS_BAR_LARGE_HEIGHT, false ) ) {
if( progressBar.isStringPainted() || clientPropertyBoolean( c, PROGRESS_BAR_LARGE_HEIGHT, largeHeight ) ) {
// recalculate progress height/width to make it smaller
Insets insets = progressBar.getInsets();
FontMetrics fm = progressBar.getFontMetrics( progressBar.getFont() );
@@ -150,11 +207,11 @@ public class FlatProgressBarUI
return;
boolean horizontal = (progressBar.getOrientation() == JProgressBar.HORIZONTAL);
int arc = clientPropertyBoolean( c, PROGRESS_BAR_SQUARE, false )
int arc = clientPropertyBoolean( c, PROGRESS_BAR_SQUARE, square )
? 0
: Math.min( UIScale.scale( this.arc ), horizontal ? height : width );
FlatUIUtils.setRenderingHints( (Graphics2D) g );
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g );
// paint track
RoundRectangle2D.Float trackShape = new RoundRectangle2D.Float( x, y, width, height, arc, arc );
@@ -162,6 +219,7 @@ public class FlatProgressBarUI
((Graphics2D)g).fill( trackShape );
// paint progress
int amountFull = 0;
if( progressBar.isIndeterminate() ) {
boxRect = getBox( boxRect );
if( boxRect != null ) {
@@ -169,11 +227,8 @@ public class FlatProgressBarUI
((Graphics2D)g).fill( new RoundRectangle2D.Float( boxRect.x, boxRect.y,
boxRect.width, boxRect.height, arc, arc ) );
}
if( progressBar.isStringPainted() )
paintString( g, x, y, width, height, 0, insets );
} else {
int amountFull = getAmountFull( insets, width, height );
amountFull = getAmountFull( insets, width, height );
RoundRectangle2D.Float progressShape = horizontal
? new RoundRectangle2D.Float( c.getComponentOrientation().isLeftToRight() ? x : x + (width - amountFull),
@@ -188,10 +243,17 @@ public class FlatProgressBarUI
((Graphics2D)g).fill( area );
} else
((Graphics2D)g).fill( progressShape );
if( progressBar.isStringPainted() )
paintString( g, x, y, width, height, amountFull, insets );
}
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
if( progressBar.isStringPainted() )
paintString( g, x, y, width, height, amountFull, insets );
}
@Override
protected void paintString( Graphics g, int x, int y, int width, int height, int amountFull, Insets b ) {
super.paintString( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ), x, y, width, height, amountFull, b );
}
@Override

View File

@@ -16,14 +16,19 @@
package com.formdev.flatlaf.ui;
import static com.formdev.flatlaf.util.UIScale.scale;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.beans.PropertyChangeListener;
import java.util.Map;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JMenuItem;
import javax.swing.LookAndFeel;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicRadioButtonMenuItemUI;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
import com.formdev.flatlaf.util.LoggingFacade;
/**
* Provides the Flat LaF UI delegate for {@link javax.swing.JRadioButtonMenuItem}.
@@ -46,40 +51,106 @@ import javax.swing.plaf.basic.BasicRadioButtonMenuItemUI;
* @uiDefault RadioButtonMenuItem.arrowIcon Icon
* @uiDefault RadioButtonMenuItem.checkIcon Icon
* @uiDefault RadioButtonMenuItem.opaque boolean
* @uiDefault RadioButtonMenuItem.evenHeight boolean
*
* <!-- FlatRadioButtonMenuItemUI -->
*
* @uiDefault MenuItem.iconTextGap int
*
* @author Karl Tauber
*/
public class FlatRadioButtonMenuItemUI
extends BasicRadioButtonMenuItemUI
implements StyleableUI
{
private FlatMenuItemRenderer renderer;
private Map<String, Object> oldStyleValues;
public static ComponentUI createUI( JComponent c ) {
return new FlatRadioButtonMenuItemUI();
}
@Override
public void installUI( JComponent c ) {
super.installUI( c );
installStyle();
}
@Override
protected void installDefaults() {
super.installDefaults();
// scale
defaultTextIconGap = scale( defaultTextIconGap );
LookAndFeel.installProperty( menuItem, "iconTextGap", FlatUIUtils.getUIInt( "MenuItem.iconTextGap", 4 ) );
renderer = createRenderer();
}
@Override
protected void uninstallDefaults() {
super.uninstallDefaults();
renderer = null;
oldStyleValues = null;
}
protected FlatMenuItemRenderer createRenderer() {
return new FlatMenuItemRenderer( menuItem, checkIcon, arrowIcon, acceleratorFont, acceleratorDelimiter );
}
/**
* Scale defaultTextIconGap again if iconTextGap property has changed.
*/
@Override
protected PropertyChangeListener createPropertyChangeListener( JComponent c ) {
PropertyChangeListener superListener = super.createPropertyChangeListener( c );
return e -> {
superListener.propertyChange( e );
if( e.getPropertyName() == "iconTextGap" )
defaultTextIconGap = scale( defaultTextIconGap );
};
return FlatStylingSupport.createPropertyChangeListener( c, this::installStyle, super.createPropertyChangeListener( c ) );
}
/** @since 2 */
protected void installStyle() {
try {
applyStyle( FlatStylingSupport.getResolvedStyle( menuItem, "RadioButtonMenuItem" ) );
} catch( RuntimeException ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex );
}
}
/** @since 2 */
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
}
/** @since 2 */
protected Object applyStyleProperty( String key, Object value ) {
try {
return renderer.applyStyleProperty( key, value );
} catch ( UnknownStyleException ex ) {
// ignore
}
Object oldValue;
switch( key ) {
// BasicMenuItemUI
case "selectionBackground": oldValue = selectionBackground; selectionBackground = (Color) value; return oldValue;
case "selectionForeground": oldValue = selectionForeground; selectionForeground = (Color) value; return oldValue;
case "disabledForeground": oldValue = disabledForeground; disabledForeground = (Color) value; return oldValue;
case "acceleratorForeground": oldValue = acceleratorForeground; acceleratorForeground = (Color) value; return oldValue;
case "acceleratorSelectionForeground": oldValue = acceleratorSelectionForeground; acceleratorSelectionForeground = (Color) value; return oldValue;
}
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, menuItem, key, value );
}
/** @since 2 */
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return FlatMenuItemUI.getStyleableInfos( renderer );
}
@Override
protected void paintText( Graphics g, JMenuItem menuItem, Rectangle textRect, String text ) {
FlatMenuItemUI.paintText( g, menuItem, textRect, text, disabledForeground, selectionForeground );
protected Dimension getPreferredMenuItemSize( JComponent c, Icon checkIcon, Icon arrowIcon, int defaultTextIconGap ) {
return renderer.getPreferredMenuItemSize();
}
@Override
public void paint( Graphics g, JComponent c ) {
renderer.paintMenuItem( g, selectionBackground, selectionForeground, disabledForeground,
acceleratorForeground, acceleratorSelectionForeground );
}
}

View File

@@ -18,19 +18,29 @@ package com.formdev.flatlaf.ui;
import static com.formdev.flatlaf.util.UIScale.scale;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Rectangle;
import java.beans.PropertyChangeEvent;
import java.util.Map;
import java.util.Objects;
import javax.swing.AbstractButton;
import javax.swing.CellRendererPane;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.LookAndFeel;
import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicButtonListener;
import javax.swing.plaf.basic.BasicRadioButtonUI;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.icons.FlatCheckBoxIcon;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.UIScale;
/**
@@ -55,18 +65,34 @@ import com.formdev.flatlaf.util.UIScale;
*/
public class FlatRadioButtonUI
extends BasicRadioButtonUI
implements StyleableUI
{
protected int iconTextGap;
protected Color disabledText;
@Styleable protected Color disabledText;
private Color defaultBackground;
private final boolean shared;
private boolean iconShared = true;
private boolean defaults_initialized = false;
private static ComponentUI instance;
private Map<String, Object> oldStyleValues;
public static ComponentUI createUI( JComponent c ) {
if( instance == null )
instance = new FlatRadioButtonUI();
return instance;
return FlatUIUtils.canUseSharedUI( c )
? FlatUIUtils.createSharedUI( FlatRadioButtonUI.class, () -> new FlatRadioButtonUI( true ) )
: new FlatRadioButtonUI( false );
}
/** @since 2 */
protected FlatRadioButtonUI( boolean shared ) {
this.shared = shared;
}
@Override
public void installUI( JComponent c ) {
super.installUI( c );
installStyle( (AbstractButton) c );
}
@Override
@@ -79,6 +105,9 @@ public class FlatRadioButtonUI
iconTextGap = FlatUIUtils.getUIInt( prefix + "iconTextGap", 4 );
disabledText = UIManager.getColor( prefix + "disabledText" );
defaultBackground = UIManager.getColor( prefix + "background" );
iconShared = true;
defaults_initialized = true;
}
@@ -92,10 +121,84 @@ public class FlatRadioButtonUI
protected void uninstallDefaults( AbstractButton b ) {
super.uninstallDefaults( b );
oldStyleValues = null;
MigLayoutVisualPadding.uninstall( b );
defaults_initialized = false;
}
@Override
protected BasicButtonListener createButtonListener( AbstractButton b ) {
return new FlatRadioButtonListener( b );
}
/** @since 2 */
protected void propertyChange( AbstractButton b, PropertyChangeEvent e ) {
switch( e.getPropertyName() ) {
case FlatClientProperties.STYLE:
case FlatClientProperties.STYLE_CLASS:
if( shared && FlatStylingSupport.hasStyleProperty( b ) ) {
// unshare component UI if necessary
// updateUI() invokes applyStyle() from installUI()
b.updateUI();
} else
installStyle( b );
b.revalidate();
b.repaint();
break;
}
}
/** @since 2 */
protected void installStyle( AbstractButton b ) {
try {
applyStyle( b, FlatStylingSupport.getResolvedStyle( b, getStyleType() ) );
} catch( RuntimeException ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex );
}
}
/** @since 2 */
String getStyleType() {
return "RadioButton";
}
/** @since 2 */
protected void applyStyle( AbstractButton b, Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style,
(key, value) -> applyStyleProperty( b, key, value ) );
}
/** @since 2 */
protected Object applyStyleProperty( AbstractButton b, String key, Object value ) {
// style icon
if( key.startsWith( "icon." ) ) {
if( !(icon instanceof FlatCheckBoxIcon) )
return new UnknownStyleException( key );
if( iconShared ) {
icon = FlatStylingSupport.cloneIcon( icon );
iconShared = false;
}
key = key.substring( "icon.".length() );
return ((FlatCheckBoxIcon)icon).applyStyleProperty( key, value );
}
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, b, key, value );
}
/** @since 2 */
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
Map<String, Class<?>> infos = FlatStylingSupport.getAnnotatedStyleableInfos( this );
if( icon instanceof FlatCheckBoxIcon ) {
for( Map.Entry<String, Class<?>> e : ((FlatCheckBoxIcon)icon).getStyleableInfos().entrySet() )
infos.put( "icon.".concat( e.getKey() ), e.getValue() );
}
return infos;
}
private static Insets tempInsets = new Insets( 0, 0, 0, 0 );
@Override
@@ -122,11 +225,11 @@ public class FlatRadioButtonUI
public void paint( Graphics g, JComponent c ) {
// fill background even if not opaque if
// - contentAreaFilled is true and
// - used as cell renderer (because of selection background)
// - or if background was explicitly set to a non-UIResource color
// - if background color is different to default background color
// (this paints selection if using the component as cell renderer)
if( !c.isOpaque() &&
((AbstractButton)c).isContentAreaFilled() &&
(c.getParent() instanceof CellRendererPane || !(c.getBackground() instanceof UIResource)))
!Objects.equals( c.getBackground(), getDefaultBackground( c ) ) )
{
g.setColor( c.getBackground() );
g.fillRect( 0, 0, c.getWidth(), c.getHeight() );
@@ -155,7 +258,7 @@ public class FlatRadioButtonUI
}
}
super.paint( g, c );
super.paint( FlatLabelUI.createGraphicsHTMLTextYCorrection( g, c ), c );
}
@Override
@@ -163,10 +266,46 @@ public class FlatRadioButtonUI
FlatButtonUI.paintText( g, b, textRect, text, b.isEnabled() ? b.getForeground() : disabledText );
}
/**
* Returns the default background color of the component.
* If the component is used as cell renderer (e.g. in JTable),
* then the background color of the renderer container is returned.
*/
private Color getDefaultBackground( JComponent c ) {
Container parent = c.getParent();
return (parent instanceof CellRendererPane && parent.getParent() != null)
? parent.getParent().getBackground()
: defaultBackground;
}
private int getIconFocusWidth( JComponent c ) {
AbstractButton b = (AbstractButton) c;
return (b.getIcon() == null && getDefaultIcon() instanceof FlatCheckBoxIcon)
? UIScale.scale( ((FlatCheckBoxIcon)getDefaultIcon()).focusWidth )
Icon icon = b.getIcon();
if( icon == null )
icon = getDefaultIcon();
return (icon instanceof FlatCheckBoxIcon)
? Math.round( UIScale.scale( ((FlatCheckBoxIcon)icon).getFocusWidth() ) )
: 0;
}
//---- class FlatRadioButtonListener --------------------------------------
/** @since 2 */
protected class FlatRadioButtonListener
extends BasicButtonListener
{
private final AbstractButton b;
protected FlatRadioButtonListener( AbstractButton b ) {
super( b );
this.b = b;
}
@Override
public void propertyChange( PropertyChangeEvent e ) {
super.propertyChange( e );
FlatRadioButtonUI.this.propertyChange( b, e );
}
}
}

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