Compare commits

...

111 Commits
1.1.1 ... 1.2

Author SHA1 Message Date
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
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
bffac60bf8 JIDE: JideTabbedPane:
- support selected tab background
- support tab separators
2021-03-25 18:49:16 +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
SchiopuMatei
ed91aa4648 Added option for downscaling 2021-03-15 20:41:40 +02:00
207 changed files with 7577 additions and 1451 deletions

View File

@@ -1,13 +1,116 @@
FlatLaf Change Log FlatLaf Change Log
================== ==================
## 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 ## 1.1.1
#### New features and improvements #### New features and improvements
- Native window decorations: Support disabling native window decorations per - Native window decorations: Support disabling native window decorations per
window. (set client property `JRootPane.useWindowDecorations` to `false` on window. (set client property `JRootPane.useWindowDecorations` on root pane to
root pane). `false`).
- Support running on WinPE. (issue #279) - Support running on WinPE. (issue #279)
#### Fixed bugs #### Fixed bugs
@@ -130,7 +233,7 @@ FlatLaf Change Log
- CheckBox and RadioButton: Fill component background as soon as background - CheckBox and RadioButton: Fill component background as soon as background
color is different to default background color, even if component is not color is different to default background color, even if component is not
opaque (which is the default). This paints selection if using the component as opaque (which is the default). This paints selection if using the component as
cell renderer a Table, Tree or List. cell renderer in Table, Tree or List.
- TextComponents: Border of focused non-editable text components had wrong - TextComponents: Border of focused non-editable text components had wrong
color. color.
- Custom window decorations: Fixed top window border in dark themes when running - Custom window decorations: Fixed top window border in dark themes when running

View File

@@ -104,6 +104,7 @@ Buzz
---- ----
- [What others say about FlatLaf on Twitter](https://twitter.com/search?f=live&q=flatlaf) - [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/) - [FlatLaf announcement on Reddit](https://www.reddit.com/r/java/comments/dl0hu3/flatlaf_flat_look_and_feel/)

View File

@@ -14,8 +14,8 @@
* limitations under the License. * limitations under the License.
*/ */
val releaseVersion = "1.1.1" val releaseVersion = "1.2"
val developmentVersion = "1.2-SNAPSHOT" val developmentVersion = "1.3-SNAPSHOT"
version = if( java.lang.Boolean.getBoolean( "release" ) ) releaseVersion else developmentVersion version = if( java.lang.Boolean.getBoolean( "release" ) ) releaseVersion else developmentVersion
@@ -47,19 +47,35 @@ allprojects {
targetCompatibility = "1.8" targetCompatibility = "1.8"
options.encoding = "ISO-8859-1" options.encoding = "ISO-8859-1"
options.isDeprecation = false
} }
withType<Jar>().configureEach { withType<Jar>().configureEach {
// manifest for all created JARs // manifest for all created JARs
manifest.attributes(mapOf( manifest.attributes(
"Implementation-Vendor" to "FormDev Software GmbH", "Implementation-Vendor" to "FormDev Software GmbH",
"Implementation-Copyright" to "Copyright (C) 2019-${java.time.LocalDate.now().year} FormDev Software GmbH. All rights reserved.", "Implementation-Copyright" to "Copyright (C) 2019-${java.time.LocalDate.now().year} FormDev Software GmbH. All rights reserved.",
"Implementation-Version" to project.version)) "Implementation-Version" to project.version
)
// add META-INF/LICENSE to all created JARs // add META-INF/LICENSE to all created JARs
from("${rootDir}/LICENSE") { from( "${rootDir}/LICENSE" ) {
into("META-INF") into( "META-INF" )
} }
} }
withType<Javadoc>().configureEach {
options {
this as StandardJavadocDocletOptions
title = "${project.name} $version"
header = title
isUse = true
tags = listOf( "uiDefault", "clientProperty" )
addStringOption( "Xdoclint:all,-missing", "-Xdoclint:all,-missing" )
links( "https://docs.oracle.com/en/java/javase/11/docs/api/" )
}
isFailOnError = false
}
} }
} }

View File

@@ -45,21 +45,11 @@ tasks {
} }
} }
javadoc { named<Jar>( "sourcesJar" ) {
options {
this as StandardJavadocDocletOptions
use( true )
tags = listOf( "uiDefault", "clientProperty" )
addStringOption( "Xdoclint:all,-missing", "-Xdoclint:all,-missing" )
}
isFailOnError = false
}
named<Jar>("sourcesJar" ) {
archiveBaseName.set( "flatlaf" ) archiveBaseName.set( "flatlaf" )
} }
named<Jar>("javadocJar" ) { named<Jar>( "javadocJar" ) {
archiveBaseName.set( "flatlaf" ) archiveBaseName.set( "flatlaf" )
} }
} }

View File

@@ -39,8 +39,9 @@ public interface FlatClientProperties
* {@link #BUTTON_TYPE_SQUARE}, * {@link #BUTTON_TYPE_SQUARE},
* {@link #BUTTON_TYPE_ROUND_RECT}, * {@link #BUTTON_TYPE_ROUND_RECT},
* {@link #BUTTON_TYPE_TAB}, * {@link #BUTTON_TYPE_TAB},
* {@link #BUTTON_TYPE_HELP} or * {@link #BUTTON_TYPE_HELP},
* {@link BUTTON_TYPE_TOOLBAR_BUTTON} * {@link #BUTTON_TYPE_TOOLBAR_BUTTON} or
* {@link #BUTTON_TYPE_BORDERLESS}
*/ */
String BUTTON_TYPE = "JButton.buttonType"; String BUTTON_TYPE = "JButton.buttonType";
@@ -89,6 +90,16 @@ public interface FlatClientProperties
*/ */
String BUTTON_TYPE_TOOLBAR_BUTTON = "toolBarButton"; String BUTTON_TYPE_TOOLBAR_BUTTON = "toolBarButton";
/**
* Paint the button without a border in the unfocused state.
* <p>
* <strong>Components</strong> {@link javax.swing.JButton} and {@link javax.swing.JToggleButton}
*
* @see #BUTTON_TYPE
* @since 1.2
*/
String BUTTON_TYPE_BORDERLESS = "borderless";
/** /**
* Specifies selected state of a checkbox. * Specifies selected state of a checkbox.
* <p> * <p>
@@ -233,10 +244,14 @@ public interface FlatClientProperties
/** /**
* Specifies whether FlatLaf native window decorations should be used * Specifies whether FlatLaf native window decorations should be used
* when creating {@code JFrame} or {@code JDialog}. * for {@code JFrame} or {@code JDialog}.
* <p> * <p>
* Setting this to {@code false} disables using FlatLaf native window decorations * Setting this enables/disables using FlatLaf native window decorations
* for the window that contains the root pane. Needs to be set before showing the window. * 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> * <p>
* (requires Window 10) * (requires Window 10)
* <p> * <p>
@@ -248,8 +263,15 @@ public interface FlatClientProperties
String USE_WINDOW_DECORATIONS = "JRootPane.useWindowDecorations"; String USE_WINDOW_DECORATIONS = "JRootPane.useWindowDecorations";
/** /**
* Specifies whether the menu bar is embedded into the title pane if custom * Specifies whether the menu bar is embedded into the window title pane
* window decorations are enabled. Default is {@code true}. * 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> * <p>
* (requires Window 10) * (requires Window 10)
* <p> * <p>
@@ -258,6 +280,30 @@ public interface FlatClientProperties
*/ */
String MENU_BAR_EMBEDDED = "JRootPane.menuBarEmbedded"; String MENU_BAR_EMBEDDED = "JRootPane.menuBarEmbedded";
/**
* 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 ------------------------------------------- //---- JScrollBar / JScrollPane -------------------------------------------
/** /**

View File

@@ -16,6 +16,8 @@
package com.formdev.flatlaf; package com.formdev.flatlaf;
import javax.swing.UIManager;
/** /**
* A Flat LaF that has a dark color scheme and looks like Darcula LaF. * A Flat LaF that has a dark color scheme and looks like Darcula LaF.
* <p> * <p>
@@ -29,10 +31,28 @@ public class FlatDarculaLaf
{ {
public static final String NAME = "FlatLaf Darcula"; public static final String NAME = "FlatLaf Darcula";
public static boolean install() { /**
return install( new FlatDarculaLaf() ); * Sets the application look and feel to this LaF
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
*/
public static boolean setup() {
return setup( new FlatDarculaLaf() );
} }
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
/**
* Adds this look and feel to the set of available look and feels.
* <p>
* Useful if your application uses {@link UIManager#getInstalledLookAndFeels()}
* to query available LaFs and display them to the user in a combobox.
*/
public static void installLafInfo() { public static void installLafInfo() {
installLafInfo( NAME, FlatDarculaLaf.class ); installLafInfo( NAME, FlatDarculaLaf.class );
} }

View File

@@ -34,8 +34,16 @@ public class FlatDarkLaf
* Sets the application look and feel to this LaF * Sets the application look and feel to this LaF
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}. * using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
*/ */
public static boolean setup() {
return setup( new FlatDarkLaf() );
}
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() { public static boolean install() {
return install( new FlatDarkLaf() ); return setup();
} }
/** /**

View File

@@ -16,6 +16,8 @@
package com.formdev.flatlaf; package com.formdev.flatlaf;
import javax.swing.UIManager;
/** /**
* A Flat LaF that has a light color scheme and looks like IntelliJ LaF. * A Flat LaF that has a light color scheme and looks like IntelliJ LaF.
* <p> * <p>
@@ -29,10 +31,28 @@ public class FlatIntelliJLaf
{ {
public static final String NAME = "FlatLaf IntelliJ"; public static final String NAME = "FlatLaf IntelliJ";
public static boolean install() { /**
return install( new FlatIntelliJLaf() ); * Sets the application look and feel to this LaF
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
*/
public static boolean setup() {
return setup( new FlatIntelliJLaf() );
} }
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
/**
* Adds this look and feel to the set of available look and feels.
* <p>
* Useful if your application uses {@link UIManager#getInstalledLookAndFeels()}
* to query available LaFs and display them to the user in a combobox.
*/
public static void installLafInfo() { public static void installLafInfo() {
installLafInfo( NAME, FlatIntelliJLaf.class ); installLafInfo( NAME, FlatIntelliJLaf.class );
} }

View File

@@ -32,6 +32,7 @@ import java.beans.PropertyChangeListener;
import java.io.File; import java.io.File;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
@@ -46,6 +47,7 @@ import javax.swing.JDialog;
import javax.swing.JFrame; import javax.swing.JFrame;
import javax.swing.LookAndFeel; import javax.swing.LookAndFeel;
import javax.swing.PopupFactory; import javax.swing.PopupFactory;
import javax.swing.RootPaneContainer;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import javax.swing.UIDefaults; import javax.swing.UIDefaults;
import javax.swing.UIDefaults.ActiveValue; import javax.swing.UIDefaults.ActiveValue;
@@ -53,12 +55,14 @@ import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException; import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.plaf.ColorUIResource; import javax.swing.plaf.ColorUIResource;
import javax.swing.plaf.FontUIResource; import javax.swing.plaf.FontUIResource;
import javax.swing.plaf.IconUIResource;
import javax.swing.plaf.UIResource; import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicLookAndFeel; import javax.swing.plaf.basic.BasicLookAndFeel;
import javax.swing.text.StyleContext; import javax.swing.text.StyleContext;
import javax.swing.text.html.HTMLEditorKit; import javax.swing.text.html.HTMLEditorKit;
import com.formdev.flatlaf.ui.FlatNativeWindowBorder; import com.formdev.flatlaf.ui.FlatNativeWindowBorder;
import com.formdev.flatlaf.ui.FlatPopupFactory; import com.formdev.flatlaf.ui.FlatPopupFactory;
import com.formdev.flatlaf.ui.FlatRootPaneUI;
import com.formdev.flatlaf.util.GrayFilter; import com.formdev.flatlaf.util.GrayFilter;
import com.formdev.flatlaf.util.LoggingFacade; import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.MultiResolutionImageSupport; import com.formdev.flatlaf.util.MultiResolutionImageSupport;
@@ -93,16 +97,24 @@ public abstract class FlatLaf
* Sets the application look and feel to the given LaF * Sets the application look and feel to the given LaF
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}. * using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
*/ */
public static boolean install( LookAndFeel newLookAndFeel ) { public static boolean setup( LookAndFeel newLookAndFeel ) {
try { try {
UIManager.setLookAndFeel( newLookAndFeel ); UIManager.setLookAndFeel( newLookAndFeel );
return true; return true;
} catch( Exception ex ) { } catch( Exception ex ) {
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to initialize look and feel '" + newLookAndFeel.getClass().getName() + "'.", ex ); LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to setup look and feel '" + newLookAndFeel.getClass().getName() + "'.", ex );
return false; return false;
} }
} }
/**
* @deprecated use {@link #setup(LookAndFeel)} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install( LookAndFeel newLookAndFeel ) {
return setup( newLookAndFeel );
}
/** /**
* Adds the given look and feel to the set of available look and feels. * Adds the given look and feel to the set of available look and feels.
* <p> * <p>
@@ -157,7 +169,7 @@ public abstract class FlatLaf
*/ */
@Override @Override
public boolean getSupportsWindowDecorations() { public boolean getSupportsWindowDecorations() {
if( SystemInfo.isProjector || SystemInfo.isWinPE ) if( SystemInfo.isProjector || SystemInfo.isWebswing || SystemInfo.isWinPE )
return false; return false;
if( SystemInfo.isWindows_10_orLater && if( SystemInfo.isWindows_10_orLater &&
@@ -179,8 +191,10 @@ public abstract class FlatLaf
@Override @Override
public Icon getDisabledIcon( JComponent component, Icon icon ) { public Icon getDisabledIcon( JComponent component, Icon icon ) {
if( icon instanceof DisabledIconProvider ) if( icon instanceof DisabledIconProvider ) {
return ((DisabledIconProvider)icon).getDisabledIcon(); Icon disabledIcon = ((DisabledIconProvider)icon).getDisabledIcon();
return !(disabledIcon instanceof UIResource) ? new IconUIResource( disabledIcon ) : disabledIcon;
}
if( icon instanceof ImageIcon ) { if( icon instanceof ImageIcon ) {
Object grayFilter = UIManager.get( "Component.grayFilter" ); Object grayFilter = UIManager.get( "Component.grayFilter" );
@@ -316,7 +330,7 @@ public abstract class FlatLaf
Method m = UIManager.class.getMethod( "createLookAndFeel", String.class ); Method m = UIManager.class.getMethod( "createLookAndFeel", String.class );
aquaLaf = (BasicLookAndFeel) m.invoke( null, "Mac OS X" ); aquaLaf = (BasicLookAndFeel) m.invoke( null, "Mac OS X" );
} else } else
aquaLaf = (BasicLookAndFeel) Class.forName( aquaLafClassName ).newInstance(); aquaLaf = (BasicLookAndFeel) Class.forName( aquaLafClassName ).getDeclaredConstructor().newInstance();
} catch( Exception ex ) { } catch( Exception ex ) {
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to initialize Aqua look and feel '" + aquaLafClassName + "'.", ex ); LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to initialize Aqua look and feel '" + aquaLafClassName + "'.", ex );
throw new IllegalStateException(); throw new IllegalStateException();
@@ -443,12 +457,17 @@ public abstract class FlatLaf
FontUIResource uiFont = null; FontUIResource uiFont = null;
if( SystemInfo.isWindows ) { if( SystemInfo.isWindows ) {
// on WinPE use "win.defaultGUI.font", which is usually Tahoma, Font winFont = (Font) Toolkit.getDefaultToolkit().getDesktopProperty( "win.messagebox.font" );
// because Segoe UI font is not available on WinPE if( winFont != null ) {
Font winFont = (Font) Toolkit.getDefaultToolkit().getDesktopProperty( if( SystemInfo.isWinPE ) {
SystemInfo.isWinPE ? "win.defaultGUI.font" : "win.messagebox.font" ); // on WinPE use "win.defaultGUI.font", which is usually Tahoma,
if( winFont != null ) // because Segoe UI font is not available on WinPE
uiFont = createCompositeFont( winFont.getFamily(), winFont.getStyle(), winFont.getSize() ); Font winPEFont = (Font) Toolkit.getDefaultToolkit().getDesktopProperty( "win.defaultGUI.font" );
if( winPEFont != null )
uiFont = createCompositeFont( winPEFont.getFamily(), winPEFont.getStyle(), winFont.getSize() );
} else
uiFont = createCompositeFont( winFont.getFamily(), winFont.getStyle(), winFont.getSize() );
}
} else if( SystemInfo.isMacOS ) { } else if( SystemInfo.isMacOS ) {
String fontName; String fontName;
@@ -546,6 +565,8 @@ public abstract class FlatLaf
defaults.put( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON ); defaults.put( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON );
} else if( SystemInfo.isJava_9_orLater ) { } else if( SystemInfo.isJava_9_orLater ) {
Object desktopHints = Toolkit.getDefaultToolkit().getDesktopProperty( DESKTOPFONTHINTS ); Object desktopHints = Toolkit.getDefaultToolkit().getDesktopProperty( DESKTOPFONTHINTS );
if( desktopHints == null )
desktopHints = fallbackAATextInfo();
if( desktopHints instanceof Map ) { if( desktopHints instanceof Map ) {
@SuppressWarnings( "unchecked" ) @SuppressWarnings( "unchecked" )
Map<Object, Object> hints = (Map<Object, Object>) desktopHints; Map<Object, Object> hints = (Map<Object, Object>) desktopHints;
@@ -568,6 +589,8 @@ public abstract class FlatLaf
Object value = Class.forName( "sun.swing.SwingUtilities2$AATextInfo" ) Object value = Class.forName( "sun.swing.SwingUtilities2$AATextInfo" )
.getMethod( "getAATextInfo", boolean.class ) .getMethod( "getAATextInfo", boolean.class )
.invoke( null, true ); .invoke( null, true );
if( value == null )
value = fallbackAATextInfo();
defaults.put( key, value ); defaults.put( key, value );
} catch( Exception ex ) { } catch( Exception ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex ); LoggingFacade.INSTANCE.logSevere( null, ex );
@@ -576,6 +599,47 @@ public abstract class FlatLaf
} }
} }
private Object fallbackAATextInfo() {
// do nothing if explicitly overridden
if( System.getProperty( "awt.useSystemAAFontSettings" ) != null )
return null;
Object aaHint = null;
Integer lcdContrastHint = null;
if( SystemInfo.isLinux ) {
// see sun.awt.UNIXToolkit.getDesktopAAHints()
Toolkit toolkit = Toolkit.getDefaultToolkit();
if( toolkit.getDesktopProperty( "gnome.Xft/Antialias" ) == null &&
toolkit.getDesktopProperty( "fontconfig/Antialias" ) == null )
{
// no Gnome or KDE Desktop properties available
// --> enable antialiasing
aaHint = RenderingHints.VALUE_TEXT_ANTIALIAS_ON;
}
}
if( aaHint == null )
return null;
if( SystemInfo.isJava_9_orLater ) {
Map<Object, Object> hints = new HashMap<>();
hints.put( RenderingHints.KEY_TEXT_ANTIALIASING, aaHint );
hints.put( RenderingHints.KEY_TEXT_LCD_CONTRAST, lcdContrastHint );
return hints;
} else {
// Java 8
try {
return Class.forName( "sun.swing.SwingUtilities2$AATextInfo" )
.getConstructor( Object.class, Integer.class )
.newInstance( aaHint, lcdContrastHint );
} catch( Exception ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex );
throw new RuntimeException( ex );
}
}
}
private void putDefaults( UIDefaults defaults, Object value, String... keys ) { private void putDefaults( UIDefaults defaults, Object value, String... keys ) {
for( String key : keys ) for( String key : keys )
defaults.put( key, value ); defaults.put( key, value );
@@ -710,6 +774,79 @@ public abstract class FlatLaf
} ); } );
} }
/**
* Returns whether native window decorations are supported on current platform.
* <p>
* This requires Windows 10, but may be disabled if running in special environments
* (JetBrains Projector, Webswing or WinPE) or if loading native library fails.
* If system property {@link FlatSystemProperties#USE_WINDOW_DECORATIONS} is set to
* {@code false}, then this method also returns {@code false}.
*
* @since 1.1.2
*/
public static boolean supportsNativeWindowDecorations() {
return SystemInfo.isWindows_10_orLater && FlatNativeWindowBorder.isSupported();
}
/**
* Returns whether native window decorations are enabled.
*
* @since 1.1.2
*/
public static boolean isUseNativeWindowDecorations() {
return UIManager.getBoolean( "TitlePane.useWindowDecorations" );
}
/**
* Sets whether native window decorations are enabled.
* <p>
* Existing frames and dialogs will be updated.
*
* @since 1.1.2
*/
public static void setUseNativeWindowDecorations( boolean enabled ) {
UIManager.put( "TitlePane.useWindowDecorations", enabled );
if( !(UIManager.getLookAndFeel() instanceof FlatLaf) )
return;
// update existing frames and dialogs
for( Window w : Window.getWindows() ) {
if( isDisplayableFrameOrDialog( w ) )
FlatRootPaneUI.updateNativeWindowBorder( ((RootPaneContainer)w).getRootPane() );
}
}
/**
* Revalidate and repaint all displayable frames and dialogs.
*
* @since 1.1.2
*/
public static void revalidateAndRepaintAllFramesAndDialogs() {
for( Window w : Window.getWindows() ) {
if( isDisplayableFrameOrDialog( w ) ) {
w.revalidate();
w.repaint();
}
}
}
/**
* Repaint all displayable frames and dialogs.
*
* @since 1.1.2
*/
public static void repaintAllFramesAndDialogs() {
for( Window w : Window.getWindows() ) {
if( isDisplayableFrameOrDialog( w ) )
w.repaint();
}
}
private static boolean isDisplayableFrameOrDialog( Window w ) {
return w.isDisplayable() && (w instanceof JFrame || w instanceof JDialog);
}
public static boolean isShowMnemonics() { public static boolean isShowMnemonics() {
return MnemonicHandler.isShowMnemonics(); return MnemonicHandler.isShowMnemonics();
} }
@@ -753,6 +890,10 @@ public abstract class FlatLaf
public Object createValue( UIDefaults table ) { public Object createValue( UIDefaults table ) {
Font defaultFont = UIManager.getFont( "defaultFont" ); Font defaultFont = UIManager.getFont( "defaultFont" );
// fallback (to avoid NPE in case that this is used in another Laf)
if( defaultFont == null )
defaultFont = UIManager.getFont( "Label.font" );
if( lastDefaultFont != defaultFont ) { if( lastDefaultFont != defaultFont ) {
lastDefaultFont = defaultFont; lastDefaultFont = defaultFont;

View File

@@ -34,8 +34,16 @@ public class FlatLightLaf
* Sets the application look and feel to this LaF * Sets the application look and feel to this LaF
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}. * using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
*/ */
public static boolean setup() {
return setup( new FlatLightLaf() );
}
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() { public static boolean install() {
return install( new FlatLightLaf() ); return setup();
} }
/** /**

View File

@@ -16,6 +16,8 @@
package com.formdev.flatlaf; package com.formdev.flatlaf;
import com.formdev.flatlaf.util.UIScale;
/** /**
* Defines/documents own system properties used in FlatLaf. * Defines/documents own system properties used in FlatLaf.
* *
@@ -32,6 +34,8 @@ public interface FlatSystemProperties
* To replace the Java 9+ system scale factor, use system property "sun.java2d.uiScale", * To replace the Java 9+ system scale factor, use system property "sun.java2d.uiScale",
* which has the same syntax as this one. * which has the same syntax as this one.
* <p> * <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> * <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"; String UI_SCALE = "flatlaf.uiScale";
@@ -44,6 +48,17 @@ public interface FlatSystemProperties
*/ */
String UI_SCALE_ENABLED = "flatlaf.uiScale.enabled"; 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. * Specifies whether Ubuntu font should be used on Ubuntu Linux.
* By default, if not running in a JetBrains Runtime, the Liberation Sans font * By default, if not running in a JetBrains Runtime, the Liberation Sans font
@@ -55,13 +70,16 @@ public interface FlatSystemProperties
String USE_UBUNTU_FONT = "flatlaf.useUbuntuFont"; String USE_UBUNTU_FONT = "flatlaf.useUbuntuFont";
/** /**
* Specifies whether FlatLaf native window decorations should be used * Specifies whether native window decorations should be used
* when creating {@code JFrame} or {@code JDialog}. * when creating {@code JFrame} or {@code JDialog}.
* <p> * <p>
* Setting this to {@code true} forces using FlatLaf native window decorations * Setting this to {@code true} forces using native window decorations
* even if they are not enabled by the application. * even if they are not enabled by the application.<br>
* Setting this to {@code false} disables using native window decorations.
* <p> * <p>
* Setting this to {@code false} disables using FlatLaf native window decorations. * This system property has higher priority than client property
* {@link FlatClientProperties#USE_WINDOW_DECORATIONS} and
* UI default {@code TitlePane.useWindowDecorations}.
* <p> * <p>
* (requires Window 10) * (requires Window 10)
* <p> * <p>
@@ -77,26 +95,32 @@ public interface FlatSystemProperties
* <a href="https://confluence.jetbrains.com/display/JBR/JetBrains+Runtime">JetBrains Runtime</a> * <a href="https://confluence.jetbrains.com/display/JBR/JetBrains+Runtime">JetBrains Runtime</a>
* (based on OpenJDK). * (based on OpenJDK).
* <p> * <p>
* Setting this to {@code true} forces using JetBrains Runtime custom window decorations
* even if they are not enabled by the application.
* <p>
* Setting this to {@code false} disables using JetBrains Runtime custom window decorations. * Setting this to {@code false} disables using JetBrains Runtime custom window decorations.
* <p> * Then FlatLaf native window decorations are used.
* (requires Window 10)
* <p>
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
* <strong>Default</strong> none
*/
String USE_JETBRAINS_CUSTOM_DECORATIONS = "flatlaf.useJetBrainsCustomDecorations";
/**
* Specifies whether menubar is embedded into custom window decorations.
* <p> * <p>
* (requires Window 10) * (requires Window 10)
* <p> * <p>
* <strong>Allowed Values</strong> {@code false} and {@code true}<br> * <strong>Allowed Values</strong> {@code false} and {@code true}<br>
* <strong>Default</strong> {@code true} * <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"; String MENUBAR_EMBEDDED = "flatlaf.menuBarEmbedded";
/** /**

View File

@@ -34,6 +34,7 @@ import javax.swing.UIDefaults;
import javax.swing.plaf.ColorUIResource; import javax.swing.plaf.ColorUIResource;
import com.formdev.flatlaf.json.Json; import com.formdev.flatlaf.json.Json;
import com.formdev.flatlaf.json.ParseException; import com.formdev.flatlaf.json.ParseException;
import com.formdev.flatlaf.util.ColorFunctions;
import com.formdev.flatlaf.util.LoggingFacade; import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.StringUtils; import com.formdev.flatlaf.util.StringUtils;
@@ -67,20 +68,28 @@ public class IntelliJTheme
/** /**
* Loads a IntelliJ .theme.json file from the given input stream, * Loads a IntelliJ .theme.json file from the given input stream,
* creates a Laf instance for it and installs it. * creates a Laf instance for it and sets it up.
* *
* The input stream is automatically closed. * The input stream is automatically closed.
* Using a buffered input stream is not necessary. * Using a buffered input stream is not necessary.
*/ */
public static boolean install( InputStream in ) { public static boolean setup( InputStream in ) {
try { try {
return FlatLaf.install( createLaf( in ) ); return FlatLaf.setup( createLaf( in ) );
} catch( Exception ex ) { } catch( Exception ex ) {
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to load IntelliJ theme", ex ); LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to load IntelliJ theme", ex );
return false; return false;
} }
} }
/**
* @deprecated use {@link #setup(InputStream)} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install( InputStream in ) {
return setup( in );
}
/** /**
* Loads a IntelliJ .theme.json file from the given input stream and * Loads a IntelliJ .theme.json file from the given input stream and
* creates a Laf instance for it. * creates a Laf instance for it.
@@ -215,6 +224,12 @@ public class IntelliJTheme
if( !uiKeys.contains( "ToggleButton.foreground" ) && uiKeys.contains( "Button.foreground" ) ) if( !uiKeys.contains( "ToggleButton.foreground" ) && uiKeys.contains( "Button.foreground" ) )
defaults.put( "ToggleButton.foreground", defaults.get( "Button.foreground" ) ); defaults.put( "ToggleButton.foreground", defaults.get( "Button.foreground" ) );
// fix DesktopPane background (use Panel.background and make it 5% darker/lighter)
Color desktopBackgroundBase = defaults.getColor( "Panel.background" );
Color desktopBackground = ColorFunctions.applyFunctions( desktopBackgroundBase,
new ColorFunctions.HSLIncreaseDecrease( 2, dark, 5, false, true ) );
defaults.put( "Desktop.background", new ColorUIResource( desktopBackground ) );
// fix List and Table background colors in Material UI Lite themes // fix List and Table background colors in Material UI Lite themes
if( isMaterialUILite ) { if( isMaterialUILite ) {
defaults.put( "List.background", defaults.get( "Tree.background" ) ); defaults.put( "List.background", defaults.get( "Tree.background" ) );
@@ -241,9 +256,10 @@ public class IntelliJTheme
// remove theme specific UI defaults and remember only those for current theme // remove theme specific UI defaults and remember only those for current theme
Map<Object, Object> themeSpecificDefaults = new HashMap<>(); Map<Object, Object> themeSpecificDefaults = new HashMap<>();
String currentThemePrefix = '[' + name.replace( ' ', '_' ) + ']'; String currentThemePrefix = '[' + name.replace( ' ', '_' ) + ']';
String currentThemeAndAuthorPrefix = '[' + name.replace( ' ', '_' ) + "---" + author.replace( ' ', '_' ) + ']';
String currentAuthorPrefix = "[author-" + author.replace( ' ', '_' ) + ']'; String currentAuthorPrefix = "[author-" + author.replace( ' ', '_' ) + ']';
String allThemesPrefix = "[*]"; String allThemesPrefix = "[*]";
String[] prefixes = { currentThemePrefix, currentAuthorPrefix, allThemesPrefix }; String[] prefixes = { currentThemePrefix, currentThemeAndAuthorPrefix, currentAuthorPrefix, allThemesPrefix };
for( String key : themeSpecificKeys ) { for( String key : themeSpecificKeys ) {
Object value = defaults.remove( key ); Object value = defaults.remove( key );
for( String prefix : prefixes ) { for( String prefix : prefixes ) {
@@ -344,6 +360,10 @@ public class IntelliJTheme
// replace all values in UI defaults that match the wildcard key // replace all values in UI defaults that match the wildcard key
for( Object k : defaultsKeysCache ) { for( Object k : defaultsKeysCache ) {
if( k.equals( "Desktop.background" ) ||
k.equals( "DesktopIcon.background" ) )
continue;
if( k instanceof String ) { if( k instanceof String ) {
// support replacing of mapped keys // support replacing of mapped keys
// (e.g. set ComboBox.buttonEditableBackground to *.background // (e.g. set ComboBox.buttonEditableBackground to *.background

View File

@@ -55,24 +55,38 @@ class LinuxFontPolicy
String family = ""; String family = "";
int style = Font.PLAIN; int style = Font.PLAIN;
int size = 10; double dsize = 10;
// parse pango font description
// see https://developer.gnome.org/pango/1.46/pango-Fonts.html#pango-font-description-from-string
StringTokenizer st = new StringTokenizer( (String) fontName ); StringTokenizer st = new StringTokenizer( (String) fontName );
while( st.hasMoreTokens() ) { while( st.hasMoreTokens() ) {
String word = st.nextToken(); String word = st.nextToken();
if( word.equalsIgnoreCase( "italic" ) ) // remove trailing ',' (e.g. in "Ubuntu Condensed, 11" or "Ubuntu Condensed, Bold 11")
if( word.endsWith( "," ) )
word = word.substring( 0, word.length() - 1 ).trim();
String lword = word.toLowerCase();
if( lword.equals( "italic" ) || lword.equals( "oblique" ) )
style |= Font.ITALIC; style |= Font.ITALIC;
else if( word.equalsIgnoreCase( "bold" ) ) else if( lword.equals( "bold" ) )
style |= Font.BOLD; style |= Font.BOLD;
else if( Character.isDigit( word.charAt( 0 ) ) ) { else if( Character.isDigit( word.charAt( 0 ) ) ) {
try { try {
size = Integer.parseInt( word ); dsize = Double.parseDouble( word );
} catch( NumberFormatException ex ) { } catch( NumberFormatException ex ) {
// ignore // ignore
} }
} else } else {
// remove '-' from "Semi-Bold", "Extra-Light", etc
if( lword.startsWith( "semi-" ) || lword.startsWith( "demi-" ) )
word = word.substring( 0, 4 ) + word.substring( 5 );
else if( lword.startsWith( "extra-" ) || lword.startsWith( "ultra-" ) )
word = word.substring( 0, 5 ) + word.substring( 6 );
family = family.isEmpty() ? word : (family + ' ' + word); family = family.isEmpty() ? word : (family + ' ' + word);
}
} }
// Ubuntu font is rendered poorly (except if running in JetBrains VM) // Ubuntu font is rendered poorly (except if running in JetBrains VM)
@@ -83,8 +97,8 @@ class LinuxFontPolicy
family = "Liberation Sans"; family = "Liberation Sans";
// scale font size // scale font size
double dsize = size * getGnomeFontScale(); dsize *= getGnomeFontScale();
size = (int) (dsize + 0.5); int size = (int) (dsize + 0.5);
if( size < 1 ) if( size < 1 )
size = 1; size = 1;
@@ -93,7 +107,37 @@ class LinuxFontPolicy
if( logicalFamily != null ) if( logicalFamily != null )
family = logicalFamily; family = logicalFamily;
return createFont( family, style, size, dsize ); return createFontEx( family, style, size, dsize );
}
/**
* Create a font for the given family, style and size.
* If the font family does not match any font on the system,
* then the last word (usually a font weight) from the family name is removed and tried again.
* E.g. family 'URW Bookman Light' is not found, but 'URW Bookman' is found.
* If still not found, then font of family 'Dialog' is returned.
*/
private static Font createFontEx( String family, int style, int size, double dsize ) {
for(;;) {
Font font = createFont( family, style, size, dsize );
// if the font family does not match any font on the system, "Dialog" family is returned
if( !"Dialog".equals( font.getFamily() ) || "Dialog".equals( family ) )
return font;
// find last word in family
int index = family.lastIndexOf( ' ' );
if( index < 0 )
return createFont( "Dialog", style, size, dsize );;
// check whether last work contains some font weight (e.g. Ultra-Bold or Heavy)
String lastWord = family.substring( index + 1 ).toLowerCase();
if( lastWord.contains( "bold" ) || lastWord.contains( "heavy" ) || lastWord.contains( "black" ) )
style |= Font.BOLD;
// remove last word from family and try again
family = family.substring( 0, index );
}
} }
private static Font createFont( String family, int style, int size, double dsize ) { private static Font createFont( String family, int style, int size, double dsize ) {

View File

@@ -442,8 +442,8 @@ class UIDefaultsLoader
private static Object parseInstance( String value, List<ClassLoader> addonClassLoaders ) { private static Object parseInstance( String value, List<ClassLoader> addonClassLoaders ) {
return (LazyValue) t -> { return (LazyValue) t -> {
try { try {
return findClass( value, addonClassLoaders ).newInstance(); return findClass( value, addonClassLoaders ).getDeclaredConstructor().newInstance();
} catch( InstantiationException | IllegalAccessException | ClassNotFoundException ex ) { } catch( Exception ex ) {
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to instantiate '" + value + "'.", ex ); LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to instantiate '" + value + "'.", ex );
return null; return null;
} }

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

@@ -141,6 +141,21 @@ public class FlatArrowButton
return FlatUIUtils.deriveColor( foreground, this.foreground ); return FlatUIUtils.deriveColor( foreground, this.foreground );
} }
/**
* Returns the color used to paint the arrow.
*
* @since 1.2
*/
protected Color getArrowColor() {
return isEnabled()
? (pressedForeground != null && isPressed()
? pressedForeground
: (hoverForeground != null && isHover()
? hoverForeground
: foreground))
: disabledForeground;
}
@Override @Override
public Dimension getPreferredSize() { public Dimension getPreferredSize() {
return scale( super.getPreferredSize() ); return scale( super.getPreferredSize() );
@@ -170,13 +185,7 @@ public class FlatArrowButton
} }
// paint arrow // paint arrow
g.setColor( deriveForeground( isEnabled() g.setColor( deriveForeground( getArrowColor() ) );
? (pressedForeground != null && isPressed()
? pressedForeground
: (hoverForeground != null && isHover()
? hoverForeground
: foreground))
: disabledForeground ) );
paintArrow( (Graphics2D) g ); paintArrow( (Graphics2D) g );
FlatUIUtils.resetRenderingHints( g, oldRenderingHints ); FlatUIUtils.resetRenderingHints( g, oldRenderingHints );

View File

@@ -75,6 +75,7 @@ public class FlatButtonBorder
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) { public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
if( FlatButtonUI.isContentAreaFilled( c ) && if( FlatButtonUI.isContentAreaFilled( c ) &&
!FlatButtonUI.isToolBarButton( c ) && !FlatButtonUI.isToolBarButton( c ) &&
(!FlatButtonUI.isBorderlessButton( c ) || FlatUIUtils.isPermanentFocusOwner( c )) &&
!FlatButtonUI.isHelpButton( c ) && !FlatButtonUI.isHelpButton( c ) &&
!FlatToggleButtonUI.isTabButton( c ) ) !FlatToggleButtonUI.isTabButton( c ) )
super.paintBorder( c, g, x, y, width, height ); super.paintBorder( c, g, x, y, width, height );

View File

@@ -285,6 +285,10 @@ public class FlatButtonUI
(c instanceof AbstractButton && clientPropertyEquals( (AbstractButton) c, BUTTON_TYPE, BUTTON_TYPE_TOOLBAR_BUTTON )); (c instanceof AbstractButton && clientPropertyEquals( (AbstractButton) c, BUTTON_TYPE, BUTTON_TYPE_TOOLBAR_BUTTON ));
} }
static boolean isBorderlessButton( Component c ) {
return c instanceof AbstractButton && clientPropertyEquals( (AbstractButton) c, BUTTON_TYPE, BUTTON_TYPE_BORDERLESS );
}
@Override @Override
public void update( Graphics g, JComponent c ) { public void update( Graphics g, JComponent c ) {
// fill background if opaque to avoid garbage if user sets opaque to true // fill background if opaque to avoid garbage if user sets opaque to true
@@ -332,8 +336,9 @@ public class FlatButtonUI
// paint shadow // paint shadow
Color shadowColor = def ? defaultShadowColor : this.shadowColor; Color shadowColor = def ? defaultShadowColor : this.shadowColor;
if( !isToolBarButton && shadowColor != null && shadowWidth > 0 && focusWidth > 0 && if( shadowColor != null && shadowWidth > 0 && focusWidth > 0 && c.isEnabled() &&
!(isFocusPainted( c ) && FlatUIUtils.isPermanentFocusOwner( c )) && c.isEnabled() ) !isToolBarButton && !isBorderlessButton( c ) &&
!(isFocusPainted( c ) && FlatUIUtils.isPermanentFocusOwner( c )) )
{ {
g2.setColor( shadowColor ); g2.setColor( shadowColor );
g2.fill( new RoundRectangle2D.Float( focusWidth, focusWidth + UIScale.scale( (float) shadowWidth ), g2.fill( new RoundRectangle2D.Float( focusWidth, focusWidth + UIScale.scale( (float) shadowWidth ),
@@ -388,41 +393,35 @@ public class FlatButtonUI
} }
protected Color getBackground( JComponent c ) { protected Color getBackground( JComponent c ) {
boolean toolBarButton = isToolBarButton( c ) || isBorderlessButton( c );
// selected state
if( ((AbstractButton)c).isSelected() ) { if( ((AbstractButton)c).isSelected() ) {
// in toolbar use same colors for disabled and enabled because // in toolbar use same background colors for disabled and enabled because
// we assume that toolbar icon is shown disabled // we assume that toolbar icon is shown disabled
boolean toolBarButton = isToolBarButton( c );
return buttonStateColor( c, return buttonStateColor( c,
toolBarButton ? toolbarSelectedBackground : selectedBackground, toolBarButton ? toolbarSelectedBackground : selectedBackground,
toolBarButton ? toolbarSelectedBackground : disabledSelectedBackground, toolBarButton ? toolbarSelectedBackground : disabledSelectedBackground,
null, null, null,
null,
toolBarButton ? toolbarPressedBackground : pressedBackground ); toolBarButton ? toolbarPressedBackground : pressedBackground );
} }
if( !c.isEnabled() )
return disabledBackground;
// toolbar button // toolbar button
if( isToolBarButton( c ) ) { if( toolBarButton ) {
ButtonModel model = ((AbstractButton)c).getModel();
if( model.isPressed() )
return toolbarPressedBackground;
if( model.isRollover() )
return toolbarHoverBackground;
// use component background if explicitly set
Color bg = c.getBackground(); Color bg = c.getBackground();
if( isCustomBackground( bg ) ) return buttonStateColor( c,
return bg; isCustomBackground( bg ) ? bg : null,
null,
// do not paint background null,
return null; toolbarHoverBackground,
toolbarPressedBackground );
} }
boolean def = isDefaultButton( c ); boolean def = isDefaultButton( c );
return buttonStateColor( c, return buttonStateColor( c,
getBackgroundBase( c, def ), getBackgroundBase( c, def ),
null, disabledBackground,
isCustomBackground( c.getBackground() ) ? null : (def ? defaultFocusedBackground : focusedBackground), isCustomBackground( c.getBackground() ) ? null : (def ? defaultFocusedBackground : focusedBackground),
def ? defaultHoverBackground : hoverBackground, def ? defaultHoverBackground : hoverBackground,
def ? defaultPressedBackground : pressedBackground ); def ? defaultPressedBackground : pressedBackground );
@@ -444,16 +443,18 @@ public class FlatButtonUI
public static Color buttonStateColor( Component c, Color enabledColor, Color disabledColor, public static Color buttonStateColor( Component c, Color enabledColor, Color disabledColor,
Color focusedColor, Color hoverColor, Color pressedColor ) Color focusedColor, Color hoverColor, Color pressedColor )
{ {
AbstractButton b = (c instanceof AbstractButton) ? (AbstractButton) c : null;
if( !c.isEnabled() ) if( !c.isEnabled() )
return disabledColor; return disabledColor;
if( pressedColor != null && b != null && b.getModel().isPressed() ) if( c instanceof AbstractButton ) {
return pressedColor; ButtonModel model = ((AbstractButton)c).getModel();
if( hoverColor != null && b != null && b.getModel().isRollover() ) if( pressedColor != null && model.isPressed() )
return hoverColor; return pressedColor;
if( hoverColor != null && model.isRollover() )
return hoverColor;
}
if( focusedColor != null && isFocusPainted( c ) && FlatUIUtils.isPermanentFocusOwner( c ) ) if( focusedColor != null && isFocusPainted( c ) && FlatUIUtils.isPermanentFocusOwner( c ) )
return focusedColor; return focusedColor;
@@ -465,7 +466,7 @@ public class FlatButtonUI
if( !c.isEnabled() ) if( !c.isEnabled() )
return disabledText; return disabledText;
if( ((AbstractButton)c).isSelected() && !isToolBarButton( c ) ) if( ((AbstractButton)c).isSelected() && !(isToolBarButton( c ) || isBorderlessButton( c )) )
return selectedForeground; return selectedForeground;
// use component foreground if explicitly set // use component foreground if explicitly set

View File

@@ -42,6 +42,7 @@ import java.beans.PropertyChangeListener;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import javax.swing.AbstractAction; import javax.swing.AbstractAction;
import javax.swing.BorderFactory; import javax.swing.BorderFactory;
import javax.swing.CellRendererPane;
import javax.swing.ComboBoxEditor; import javax.swing.ComboBoxEditor;
import javax.swing.DefaultListCellRenderer; import javax.swing.DefaultListCellRenderer;
import javax.swing.InputMap; import javax.swing.InputMap;
@@ -243,7 +244,24 @@ public class FlatComboBoxUI
public void layoutContainer( Container parent ) { public void layoutContainer( Container parent ) {
super.layoutContainer( parent ); super.layoutContainer( parent );
if ( editor != null && padding != null ) { if( arrowButton != null ) {
Insets insets = getInsets();
int buttonWidth = parent.getPreferredSize().height - insets.top - insets.bottom;
if( buttonWidth != arrowButton.getWidth() ) {
// set width of arrow button to preferred height of combobox
int xOffset = comboBox.getComponentOrientation().isLeftToRight()
? arrowButton.getWidth() - buttonWidth
: 0;
arrowButton.setBounds( arrowButton.getX() + xOffset, arrowButton.getY(),
buttonWidth, arrowButton.getHeight() );
// update editor bounds
if( editor != null )
editor.setBounds( rectangleForCurrentValue() );
}
}
if( editor != null && padding != null ) {
// fix editor bounds by subtracting padding // fix editor bounds by subtracting padding
editor.setBounds( FlatUIUtils.subtractInsets( editor.getBounds(), padding ) ); editor.setBounds( FlatUIUtils.subtractInsets( editor.getBounds(), padding ) );
} }
@@ -373,6 +391,15 @@ public class FlatComboBoxUI
public void update( Graphics g, JComponent c ) { public void update( Graphics g, JComponent c ) {
float focusWidth = FlatUIUtils.getBorderFocusWidth( c ); float focusWidth = FlatUIUtils.getBorderFocusWidth( c );
float arc = FlatUIUtils.getBorderArc( c ); float arc = FlatUIUtils.getBorderArc( c );
boolean paintBackground = true;
// check whether used as cell renderer
boolean isCellRenderer = c.getParent() instanceof CellRendererPane;
if( isCellRenderer ) {
focusWidth = 0;
arc = 0;
paintBackground = isCellRendererBackgroundChanged();
}
// fill background if opaque to avoid garbage if user sets opaque to true // fill background if opaque to avoid garbage if user sets opaque to true
if( c.isOpaque() && (focusWidth > 0 || arc > 0) ) if( c.isOpaque() && (focusWidth > 0 || arc > 0) )
@@ -390,27 +417,29 @@ public class FlatComboBoxUI
boolean isLeftToRight = comboBox.getComponentOrientation().isLeftToRight(); boolean isLeftToRight = comboBox.getComponentOrientation().isLeftToRight();
// paint background // paint background
g2.setColor( getBackground( enabled ) ); if( paintBackground || c.isOpaque() ) {
FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc ); g2.setColor( getBackground( enabled ) );
// paint arrow button background
if( enabled ) {
g2.setColor( paintButton ? buttonEditableBackground : buttonBackground );
Shape oldClip = g2.getClip();
if( isLeftToRight )
g2.clipRect( arrowX, 0, width - arrowX, height );
else
g2.clipRect( 0, 0, arrowX + arrowWidth, height );
FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc ); FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc );
g2.setClip( oldClip );
}
// paint vertical line between value and arrow button // paint arrow button background
if( paintButton ) { if( enabled && !isCellRenderer ) {
g2.setColor( enabled ? borderColor : disabledBorderColor ); g2.setColor( paintButton ? buttonEditableBackground : buttonBackground );
float lw = scale( 1f ); Shape oldClip = g2.getClip();
float lx = isLeftToRight ? arrowX : arrowX + arrowWidth - lw; if( isLeftToRight )
g2.fill( new Rectangle2D.Float( lx, focusWidth, lw, height - 1 - (focusWidth * 2)) ); g2.clipRect( arrowX, 0, width - arrowX, height );
else
g2.clipRect( 0, 0, arrowX + arrowWidth, height );
FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc );
g2.setClip( oldClip );
}
// paint vertical line between value and arrow button
if( paintButton ) {
g2.setColor( enabled ? borderColor : disabledBorderColor );
float lw = scale( 1f );
float lx = isLeftToRight ? arrowX : arrowX + arrowWidth - lw;
g2.fill( new Rectangle2D.Float( lx, focusWidth, lw, height - 1 - (focusWidth * 2)) );
}
} }
// avoid that the "current value" renderer is invoked with enabled antialiasing // avoid that the "current value" renderer is invoked with enabled antialiasing
@@ -537,6 +566,16 @@ public class FlatComboBoxUI
} }
} }
private boolean isCellRenderer() {
return comboBox.getParent() instanceof CellRendererPane;
}
private boolean isCellRendererBackgroundChanged() {
// parent is a CellRendererPane, parentParent is e.g. a JTable
Container parentParent = comboBox.getParent().getParent();
return parentParent != null && !comboBox.getBackground().equals( parentParent.getBackground() );
}
//---- class FlatComboBoxButton ------------------------------------------- //---- class FlatComboBoxButton -------------------------------------------
protected class FlatComboBoxButton protected class FlatComboBoxButton
@@ -563,6 +602,14 @@ public class FlatComboBoxUI
protected boolean isPressed() { protected boolean isPressed() {
return super.isPressed() || (!comboBox.isEditable() ? pressed : false); return super.isPressed() || (!comboBox.isEditable() ? pressed : false);
} }
@Override
protected Color getArrowColor() {
if( isCellRenderer() && isCellRendererBackgroundChanged() )
return comboBox.getForeground();
return super.getArrowColor();
}
} }
//---- class FlatComboPopup ----------------------------------------------- //---- class FlatComboPopup -----------------------------------------------

View File

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

View File

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

View File

@@ -16,6 +16,7 @@
package com.formdev.flatlaf.ui; package com.formdev.flatlaf.ui;
import java.awt.Color;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Window; import java.awt.Window;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
@@ -53,8 +54,6 @@ import com.formdev.flatlaf.util.SystemInfo;
public class FlatMenuBarUI public class FlatMenuBarUI
extends BasicMenuBarUI extends BasicMenuBarUI
{ {
protected boolean unifiedBackground;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatMenuBarUI(); return new FlatMenuBarUI();
} }
@@ -69,8 +68,6 @@ public class FlatMenuBarUI
super.installDefaults(); super.installDefaults();
LookAndFeel.installProperty( menuBar, "opaque", false ); LookAndFeel.installProperty( menuBar, "opaque", false );
unifiedBackground = UIManager.getBoolean( "TitlePane.unifiedBackground" );
} }
@Override @Override
@@ -88,34 +85,39 @@ public class FlatMenuBarUI
@Override @Override
public void update( Graphics g, JComponent c ) { public void update( Graphics g, JComponent c ) {
// paint background // paint background
if( isFillBackground( c ) ) { Color background = getBackground( c );
g.setColor( c.getBackground() ); if( background != null ) {
g.setColor( background );
g.fillRect( 0, 0, c.getWidth(), c.getHeight() ); g.fillRect( 0, 0, c.getWidth(), c.getHeight() );
} }
paint( g, c ); paint( g, c );
} }
protected boolean isFillBackground( JComponent c ) { protected Color getBackground( JComponent c ) {
Color background = c.getBackground();
// paint background if opaque or if having custom background color // paint background if opaque or if having custom background color
if( c.isOpaque() || !(c.getBackground() instanceof UIResource) ) if( c.isOpaque() || !(background instanceof UIResource) )
return true; return background;
// paint background if menu bar is not the "main" menu bar // paint background if menu bar is not the "main" menu bar
JRootPane rootPane = SwingUtilities.getRootPane( c ); JRootPane rootPane = SwingUtilities.getRootPane( c );
if( rootPane == null || !(rootPane.getParent() instanceof Window) || rootPane.getJMenuBar() != c ) if( rootPane == null || !(rootPane.getParent() instanceof Window) || rootPane.getJMenuBar() != c )
return true; return background;
// do not paint background for unified title pane // use parent background for unified title pane
if( unifiedBackground ) // (not storing value of "TitlePane.unifiedBackground" in class to allow changing at runtime)
return false; if( UIManager.getBoolean( "TitlePane.unifiedBackground" ) &&
FlatNativeWindowBorder.hasCustomDecoration( (Window) rootPane.getParent() ) )
background = FlatUIUtils.getParentBackground( c );
// paint background in full screen mode // paint background in full screen mode
if( FlatUIUtils.isFullScreen( rootPane ) ) if( FlatUIUtils.isFullScreen( rootPane ) )
return true; return background;
// do not paint background if menu bar is embedded into title pane // do not paint background if menu bar is embedded into title pane
return !FlatRootPaneUI.isMenuBarEmbedded( rootPane ); return FlatRootPaneUI.isMenuBarEmbedded( rootPane ) ? null : background;
} }
//---- class TakeFocus ---------------------------------------------------- //---- class TakeFocus ----------------------------------------------------

View File

@@ -41,9 +41,22 @@ import com.formdev.flatlaf.util.SystemInfo;
*/ */
public class FlatNativeWindowBorder 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 // check this field before using class JBRCustomDecorations to avoid unnecessary loading of that class
private static final boolean canUseJBRCustomDecorations private static final boolean canUseJBRCustomDecorations =
= SystemInfo.isJetBrainsJVM_11_orLater && SystemInfo.isWindows_10_orLater; canUseWindowDecorations &&
SystemInfo.isJetBrainsJVM_11_orLater &&
FlatSystemProperties.getBoolean( FlatSystemProperties.USE_JETBRAINS_CUSTOM_DECORATIONS, true );
private static Boolean supported; private static Boolean supported;
private static Provider nativeProvider; private static Provider nativeProvider;
@@ -72,7 +85,7 @@ public class FlatNativeWindowBorder
// It could be also be a window that is currently hidden, but may be shown later. // It could be also be a window that is currently hidden, but may be shown later.
Window window = SwingUtilities.windowForComponent( rootPane ); Window window = SwingUtilities.windowForComponent( rootPane );
if( window != null && window.isDisplayable() ) if( window != null && window.isDisplayable() )
install( window, FlatSystemProperties.USE_WINDOW_DECORATIONS ); install( window );
// Install FlatLaf native window border, which must be done late, // Install FlatLaf native window border, which must be done late,
// when the native window is already created, because it needs access to the window. // when the native window is already created, because it needs access to the window.
@@ -81,7 +94,7 @@ public class FlatNativeWindowBorder
PropertyChangeListener ancestorListener = e -> { PropertyChangeListener ancestorListener = e -> {
Object newValue = e.getNewValue(); Object newValue = e.getNewValue();
if( newValue instanceof Window ) if( newValue instanceof Window )
install( (Window) newValue, FlatSystemProperties.USE_WINDOW_DECORATIONS ); install( (Window) newValue );
else if( newValue == null && e.getOldValue() instanceof Window ) else if( newValue == null && e.getOldValue() instanceof Window )
uninstall( (Window) e.getOldValue() ); uninstall( (Window) e.getOldValue() );
}; };
@@ -89,7 +102,7 @@ public class FlatNativeWindowBorder
return ancestorListener; return ancestorListener;
} }
static void install( Window window, String systemPropertyKey ) { static void install( Window window ) {
if( hasCustomDecoration( window ) ) if( hasCustomDecoration( window ) )
return; return;
@@ -99,18 +112,12 @@ public class FlatNativeWindowBorder
if( window instanceof JFrame ) { if( window instanceof JFrame ) {
JFrame frame = (JFrame) window; JFrame frame = (JFrame) window;
JRootPane rootPane = frame.getRootPane();
// check whether disabled via client property // check whether disabled via system property, client property or UI default
if( !FlatClientProperties.clientPropertyBoolean( frame.getRootPane(), FlatClientProperties.USE_WINDOW_DECORATIONS, true ) ) if( !useWindowDecorations( rootPane ) )
return; return;
// do not enable native window border if JFrame should use system window decorations
// and if not forced to use FlatLaf/JBR native window decorations
if( !JFrame.isDefaultLookAndFeelDecorated() &&
!UIManager.getBoolean( "TitlePane.useWindowDecorations" ) &&
!FlatSystemProperties.getBoolean( systemPropertyKey, false ) )
return;
// do not enable native window border if frame is undecorated // do not enable native window border if frame is undecorated
if( frame.isUndecorated() ) if( frame.isUndecorated() )
return; return;
@@ -118,23 +125,21 @@ public class FlatNativeWindowBorder
// enable native window border for window // enable native window border for window
setHasCustomDecoration( frame, true ); setHasCustomDecoration( frame, true );
// avoid double window title bar if enabling native window border failed
if( !hasCustomDecoration( frame ) )
return;
// enable Swing window decoration // enable Swing window decoration
frame.getRootPane().setWindowDecorationStyle( JRootPane.FRAME ); rootPane.setWindowDecorationStyle( JRootPane.FRAME );
} else if( window instanceof JDialog ) { } else if( window instanceof JDialog ) {
JDialog dialog = (JDialog) window; JDialog dialog = (JDialog) window;
JRootPane rootPane = dialog.getRootPane();
// check whether disabled via client property // check whether disabled via system property, client property or UI default
if( !FlatClientProperties.clientPropertyBoolean( dialog.getRootPane(), FlatClientProperties.USE_WINDOW_DECORATIONS, true ) ) if( !useWindowDecorations( rootPane ) )
return; return;
// do not enable native window border if JDialog should use system window decorations
// and if not forced to use FlatLaf/JBR native window decorations
if( !JDialog.isDefaultLookAndFeelDecorated() &&
!UIManager.getBoolean( "TitlePane.useWindowDecorations" ) &&
!FlatSystemProperties.getBoolean( systemPropertyKey, false ) )
return;
// do not enable native window border if dialog is undecorated // do not enable native window border if dialog is undecorated
if( dialog.isUndecorated() ) if( dialog.isUndecorated() )
return; return;
@@ -142,8 +147,12 @@ public class FlatNativeWindowBorder
// enable native window border for window // enable native window border for window
setHasCustomDecoration( dialog, true ); setHasCustomDecoration( dialog, true );
// avoid double window title bar if enabling native window border failed
if( !hasCustomDecoration( dialog ) )
return;
// enable Swing window decoration // enable Swing window decoration
dialog.getRootPane().setWindowDecorationStyle( JRootPane.PLAIN_DIALOG ); rootPane.setWindowDecorationStyle( JRootPane.PLAIN_DIALOG );
} }
} }
@@ -153,12 +162,15 @@ public class FlatNativeWindowBorder
return; return;
} }
if( !isSupported() )
return;
// remove listener // remove listener
if( data instanceof PropertyChangeListener ) if( data instanceof PropertyChangeListener )
rootPane.removePropertyChangeListener( "ancestor", (PropertyChangeListener) data ); rootPane.removePropertyChangeListener( "ancestor", (PropertyChangeListener) data );
// do not uninstall when switching to another FlatLaf theme // do not uninstall when switching to another FlatLaf theme and if still enabled
if( UIManager.getLookAndFeel() instanceof FlatLaf ) if( UIManager.getLookAndFeel() instanceof FlatLaf && useWindowDecorations( rootPane ) )
return; return;
// uninstall native window border // uninstall native window border
@@ -188,6 +200,14 @@ public class FlatNativeWindowBorder
} }
} }
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 ) { public static boolean hasCustomDecoration( Window window ) {
if( canUseJBRCustomDecorations ) if( canUseJBRCustomDecorations )
return JBRCustomDecorations.hasCustomDecoration( window ); return JBRCustomDecorations.hasCustomDecoration( window );
@@ -238,16 +258,7 @@ public class FlatNativeWindowBorder
return; return;
supported = false; supported = false;
// requires Windows 10 if( !canUseWindowDecorations )
if( !SystemInfo.isWindows_10_orLater )
return;
// do not use when running in JetBrains Projector or WinPE
if( SystemInfo.isProjector || SystemInfo.isWinPE )
return;
// check whether disabled via system property
if( !FlatSystemProperties.getBoolean( FlatSystemProperties.USE_WINDOW_DECORATIONS, true ) )
return; return;
try { try {

View File

@@ -24,6 +24,7 @@ import java.awt.Insets;
import java.awt.MouseInfo; import java.awt.MouseInfo;
import java.awt.Panel; import java.awt.Panel;
import java.awt.Point; import java.awt.Point;
import java.awt.PointerInfo;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.awt.Window; import java.awt.Window;
import java.awt.event.ComponentEvent; import java.awt.event.ComponentEvent;
@@ -70,7 +71,7 @@ public class FlatPopupFactory
boolean forceHeavyWeight = isOptionEnabled( owner, contents, FlatClientProperties.POPUP_FORCE_HEAVY_WEIGHT, "Popup.forceHeavyWeight" ); 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 ) 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 ); return new NonFlashingPopup( getPopupForScreenOfOwner( owner, contents, x, y, forceHeavyWeight ), contents );
// macOS and Linux adds drop shadow to heavy weight popups // macOS and Linux adds drop shadow to heavy weight popups
@@ -216,7 +217,11 @@ public class FlatPopupFactory
if( !(contents instanceof JToolTip) || !wasInvokedFromToolTipManager() ) if( !(contents instanceof JToolTip) || !wasInvokedFromToolTipManager() )
return null; return null;
Point mouseLocation = MouseInfo.getPointerInfo().getLocation(); PointerInfo pointerInfo = MouseInfo.getPointerInfo();
if( pointerInfo == null )
return null;
Point mouseLocation = pointerInfo.getLocation();
Dimension tipSize = contents.getPreferredSize(); Dimension tipSize = contents.getPreferredSize();
// check whether mouse location is within tooltip bounds // check whether mouse location is within tooltip bounds

View File

@@ -18,11 +18,14 @@ package com.formdev.flatlaf.ui;
import static com.formdev.flatlaf.util.UIScale.scale; import static com.formdev.flatlaf.util.UIScale.scale;
import java.awt.Color; import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Insets; import java.awt.Insets;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.util.Objects;
import javax.swing.AbstractButton; import javax.swing.AbstractButton;
import javax.swing.CellRendererPane;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.LookAndFeel; import javax.swing.LookAndFeel;
import javax.swing.UIManager; import javax.swing.UIManager;
@@ -120,10 +123,11 @@ public class FlatRadioButtonUI
public void paint( Graphics g, JComponent c ) { public void paint( Graphics g, JComponent c ) {
// fill background even if not opaque if // fill background even if not opaque if
// - contentAreaFilled is true and // - contentAreaFilled is true and
// - if background was explicitly set to a non-UIResource color // - if background color is different to default background color
// (this paints selection if using the component as cell renderer)
if( !c.isOpaque() && if( !c.isOpaque() &&
((AbstractButton)c).isContentAreaFilled() && ((AbstractButton)c).isContentAreaFilled() &&
!defaultBackground.equals( c.getBackground() ) ) !Objects.equals( c.getBackground(), getDefaultBackground( c ) ) )
{ {
g.setColor( c.getBackground() ); g.setColor( c.getBackground() );
g.fillRect( 0, 0, c.getWidth(), c.getHeight() ); g.fillRect( 0, 0, c.getWidth(), c.getHeight() );
@@ -160,6 +164,18 @@ public class FlatRadioButtonUI
FlatButtonUI.paintText( g, b, textRect, text, b.isEnabled() ? b.getForeground() : disabledText ); FlatButtonUI.paintText( g, b, textRect, text, b.isEnabled() ? b.getForeground() : disabledText );
} }
/**
* Returns the default background color of the component.
* If the component is used as cell renderer (e.g. in JTable),
* then the background color of the renderer container is returned.
*/
private Color getDefaultBackground( JComponent c ) {
Container parent = c.getParent();
return (parent instanceof CellRendererPane && parent.getParent() != null)
? parent.getParent().getBackground()
: defaultBackground;
}
private int getIconFocusWidth( JComponent c ) { private int getIconFocusWidth( JComponent c ) {
AbstractButton b = (AbstractButton) c; AbstractButton b = (AbstractButton) c;
return (b.getIcon() == null && getDefaultIcon() instanceof FlatCheckBoxIcon) return (b.getIcon() == null && getDefaultIcon() instanceof FlatCheckBoxIcon)

View File

@@ -95,7 +95,7 @@ public class FlatRootPaneUI
else else
installBorder(); installBorder();
nativeWindowBorderData = FlatNativeWindowBorder.install( rootPane ); installNativeWindowBorder();
} }
protected void installBorder() { protected void installBorder() {
@@ -110,8 +110,7 @@ public class FlatRootPaneUI
public void uninstallUI( JComponent c ) { public void uninstallUI( JComponent c ) {
super.uninstallUI( c ); super.uninstallUI( c );
FlatNativeWindowBorder.uninstall( rootPane, nativeWindowBorderData ); uninstallNativeWindowBorder();
uninstallClientDecorations(); uninstallClientDecorations();
rootPane = null; rootPane = null;
} }
@@ -137,6 +136,34 @@ public class FlatRootPaneUI
c.putClientProperty( "jetbrains.awt.windowDarkAppearance", FlatLaf.isLafDark() ); c.putClientProperty( "jetbrains.awt.windowDarkAppearance", FlatLaf.isLafDark() );
} }
/**
* @since 1.1.2
*/
protected void installNativeWindowBorder() {
nativeWindowBorderData = FlatNativeWindowBorder.install( rootPane );
}
/**
* @since 1.1.2
*/
protected void uninstallNativeWindowBorder() {
FlatNativeWindowBorder.uninstall( rootPane, nativeWindowBorderData );
nativeWindowBorderData = null;
}
/**
* @since 1.1.2
*/
public static void updateNativeWindowBorder( JRootPane rootPane ) {
RootPaneUI rui = rootPane.getUI();
if( !(rui instanceof FlatRootPaneUI) )
return;
FlatRootPaneUI ui = (FlatRootPaneUI) rui;
ui.uninstallNativeWindowBorder();
ui.installNativeWindowBorder();
}
protected void installClientDecorations() { protected void installClientDecorations() {
boolean isNativeWindowBorderSupported = FlatNativeWindowBorder.isSupported(); boolean isNativeWindowBorderSupported = FlatNativeWindowBorder.isSupported();
@@ -218,6 +245,10 @@ public class FlatRootPaneUI
installBorder(); installBorder();
break; break;
case FlatClientProperties.USE_WINDOW_DECORATIONS:
updateNativeWindowBorder( rootPane );
break;
case FlatClientProperties.MENU_BAR_EMBEDDED: case FlatClientProperties.MENU_BAR_EMBEDDED:
if( titlePane != null ) { if( titlePane != null ) {
titlePane.menuBarChanged(); titlePane.menuBarChanged();
@@ -225,6 +256,12 @@ public class FlatRootPaneUI
rootPane.repaint(); rootPane.repaint();
} }
break; break;
case FlatClientProperties.TITLE_BAR_BACKGROUND:
case FlatClientProperties.TITLE_BAR_FOREGROUND:
if( titlePane != null )
titlePane.titleBarColorsChanged();
break;
} }
} }

View File

@@ -375,8 +375,8 @@ public class FlatSpinnerUI
Rectangle editorRect = new Rectangle( r ); Rectangle editorRect = new Rectangle( r );
Rectangle buttonsRect = new Rectangle( r ); Rectangle buttonsRect = new Rectangle( r );
// make button area square // make button area square (if spinner has preferred height)
int buttonsWidth = r.height; int buttonsWidth = parent.getPreferredSize().height - insets.top - insets.bottom;
buttonsRect.width = buttonsWidth; buttonsRect.width = buttonsWidth;
if( parent.getComponentOrientation().isLeftToRight() ) { if( parent.getComponentOrientation().isLeftToRight() ) {

View File

@@ -46,10 +46,13 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault SplitPaneDivider.border Border * @uiDefault SplitPaneDivider.border Border
* @uiDefault SplitPaneDivider.draggingColor Color only used if continuousLayout is false * @uiDefault SplitPaneDivider.draggingColor Color only used if continuousLayout is false
* *
* <!-- JSplitPane -->
*
* @uiDefault SplitPane.continuousLayout boolean
*
* <!-- FlatSplitPaneUI --> * <!-- FlatSplitPaneUI -->
* *
* @uiDefault Component.arrowType String chevron (default) or triangle * @uiDefault Component.arrowType String chevron (default) or triangle
* @uiDefault SplitPane.continuousLayout boolean
* @uiDefault SplitPaneDivider.oneTouchArrowColor Color * @uiDefault SplitPaneDivider.oneTouchArrowColor Color
* @uiDefault SplitPaneDivider.oneTouchHoverArrowColor Color * @uiDefault SplitPaneDivider.oneTouchHoverArrowColor Color
* @uiDefault SplitPaneDivider.oneTouchPressedArrowColor Color * @uiDefault SplitPaneDivider.oneTouchPressedArrowColor Color
@@ -65,7 +68,6 @@ public class FlatSplitPaneUI
extends BasicSplitPaneUI extends BasicSplitPaneUI
{ {
protected String arrowType; protected String arrowType;
private Boolean continuousLayout;
protected Color oneTouchArrowColor; protected Color oneTouchArrowColor;
protected Color oneTouchHoverArrowColor; protected Color oneTouchHoverArrowColor;
protected Color oneTouchPressedArrowColor; protected Color oneTouchPressedArrowColor;
@@ -85,8 +87,6 @@ public class FlatSplitPaneUI
oneTouchPressedArrowColor = UIManager.getColor( "SplitPaneDivider.oneTouchPressedArrowColor" ); oneTouchPressedArrowColor = UIManager.getColor( "SplitPaneDivider.oneTouchPressedArrowColor" );
super.installDefaults(); super.installDefaults();
continuousLayout = (Boolean) UIManager.get( "SplitPane.continuousLayout" );
} }
@Override @Override
@@ -98,11 +98,6 @@ public class FlatSplitPaneUI
oneTouchPressedArrowColor = null; oneTouchPressedArrowColor = null;
} }
@Override
public boolean isContinuousLayout() {
return super.isContinuousLayout() || (continuousLayout != null && Boolean.TRUE.equals( continuousLayout ));
}
@Override @Override
public BasicSplitPaneDivider createDefaultDivider() { public BasicSplitPaneDivider createDefaultDivider() {
return new FlatSplitPaneDivider( this ); return new FlatSplitPaneDivider( this );

View File

@@ -58,6 +58,8 @@ import java.util.function.BiConsumer;
import java.util.function.IntConsumer; import java.util.function.IntConsumer;
import javax.accessibility.Accessible; import javax.accessibility.Accessible;
import javax.accessibility.AccessibleContext; import javax.accessibility.AccessibleContext;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.ButtonModel; import javax.swing.ButtonModel;
import javax.swing.Icon; import javax.swing.Icon;
import javax.swing.JButton; import javax.swing.JButton;
@@ -325,7 +327,7 @@ public class FlatTabbedPaneUI
// the default also includes Ctrl+TAB/Ctrl+Shift+TAB, which we need to switch tabs // the default also includes Ctrl+TAB/Ctrl+Shift+TAB, which we need to switch tabs
if( focusForwardTraversalKeys == null ) { if( focusForwardTraversalKeys == null ) {
focusForwardTraversalKeys = Collections.singleton( KeyStroke.getKeyStroke( KeyEvent.VK_TAB, 0 ) ); focusForwardTraversalKeys = Collections.singleton( KeyStroke.getKeyStroke( KeyEvent.VK_TAB, 0 ) );
focusBackwardTraversalKeys = Collections.singleton( KeyStroke.getKeyStroke( KeyEvent.VK_TAB, InputEvent.SHIFT_MASK ) ); focusBackwardTraversalKeys = Collections.singleton( KeyStroke.getKeyStroke( KeyEvent.VK_TAB, InputEvent.SHIFT_DOWN_MASK ) );
} }
// Ideally we should use `LookAndFeel.installProperty( tabPane, "focusTraversalKeysForward", keys )` here // Ideally we should use `LookAndFeel.installProperty( tabPane, "focusTraversalKeysForward", keys )` here
// instead of `tabPane.setFocusTraversalKeys()`, but WindowsTabbedPaneUI also uses later method // instead of `tabPane.setFocusTraversalKeys()`, but WindowsTabbedPaneUI also uses later method
@@ -490,6 +492,20 @@ public class FlatTabbedPaneUI
} }
} }
@Override
protected void installKeyboardActions() {
super.installKeyboardActions();
// get shared action map, used for all tabbed panes
ActionMap map = SwingUtilities.getUIActionMap( tabPane );
if( map != null ) {
// this is required for the case that those actions are used from outside
// (e.g. wheel tab scroller in NetBeans)
RunWithOriginalLayoutManagerDelegateAction.install( map, "scrollTabsForwardAction" );
RunWithOriginalLayoutManagerDelegateAction.install( map, "scrollTabsBackwardAction" );
}
}
private Handler getHandler() { private Handler getHandler() {
if( handler == null ) if( handler == null )
handler = new Handler(); handler = new Handler();
@@ -722,6 +738,13 @@ public class FlatTabbedPaneUI
} }
protected Insets getRealTabAreaInsets( int tabPlacement ) { protected Insets getRealTabAreaInsets( int tabPlacement ) {
// this is to avoid potential NPE in ensureSelectedTabIsVisible()
// (see https://github.com/JFormDesigner/FlatLaf/issues/299)
// but now should actually never occur because added more checks to
// ensureSelectedTabIsVisibleLater() and ensureSelectedTabIsVisible()
if( tabAreaInsets == null )
tabAreaInsets = new Insets( 0, 0, 0, 0 );
Insets currentTabAreaInsets = super.getTabAreaInsets( tabPlacement ); Insets currentTabAreaInsets = super.getTabAreaInsets( tabPlacement );
Insets insets = (Insets) currentTabAreaInsets.clone(); Insets insets = (Insets) currentTabAreaInsets.clone();
@@ -1386,13 +1409,18 @@ public class FlatTabbedPaneUI
} }
protected void ensureSelectedTabIsVisibleLater() { protected void ensureSelectedTabIsVisibleLater() {
// do nothing if not yet displayable or if not invoked from dispatch thread,
// which may be the case when creating/modifying in another thread
if( !tabPane.isDisplayable() || !EventQueue.isDispatchThread() )
return;
EventQueue.invokeLater( () -> { EventQueue.invokeLater( () -> {
ensureSelectedTabIsVisible(); ensureSelectedTabIsVisible();
} ); } );
} }
protected void ensureSelectedTabIsVisible() { protected void ensureSelectedTabIsVisible() {
if( tabPane == null || tabViewport == null ) if( tabPane == null || tabViewport == null || !tabPane.isDisplayable() )
return; return;
ensureCurrentLayout(); ensureCurrentLayout();
@@ -2947,4 +2975,51 @@ public class FlatTabbedPaneUI
scrollBackwardButtonPrefSize = backwardButton.getPreferredSize(); scrollBackwardButtonPrefSize = backwardButton.getPreferredSize();
} }
} }
//---- class RunWithOriginalLayoutManagerDelegateAction -------------------
private static class RunWithOriginalLayoutManagerDelegateAction
implements Action
{
private final Action delegate;
static void install( ActionMap map, String key ) {
Action oldAction = map.get( key );
if( oldAction == null || oldAction instanceof RunWithOriginalLayoutManagerDelegateAction )
return; // not found or already installed
map.put( key, new RunWithOriginalLayoutManagerDelegateAction( oldAction ) );
}
private RunWithOriginalLayoutManagerDelegateAction( Action delegate ) {
this.delegate = delegate;
}
@Override
public Object getValue( String key ) {
return delegate.getValue( key );
}
@Override
public boolean isEnabled() {
return delegate.isEnabled();
}
@Override public void putValue( String key, Object value ) {}
@Override public void setEnabled( boolean b ) {}
@Override public void addPropertyChangeListener( PropertyChangeListener listener ) {}
@Override public void removePropertyChangeListener( PropertyChangeListener listener ) {}
@Override
public void actionPerformed( ActionEvent e ) {
JTabbedPane tabbedPane = (JTabbedPane) e.getSource();
ComponentUI ui = tabbedPane.getUI();
if( ui instanceof FlatTabbedPaneUI ) {
((FlatTabbedPaneUI)ui).runWithOriginalLayoutManager( () -> {
delegate.actionPerformed( e );
} );
} else
delegate.actionPerformed( e );
}
}
} }

View File

@@ -0,0 +1,124 @@
/*
* Copyright 2021 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.ui;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumn;
import com.formdev.flatlaf.util.UIScale;
/**
* Cell border for {@code sun.swing.table.DefaultTableCellHeaderRenderer}
* (used by {@link javax.swing.table.JTableHeader}).
* <p>
* Uses separate cell margins from UI defaults to allow easy customizing.
*
* @author Karl Tauber
* @since 1.2
*/
public class FlatTableHeaderBorder
extends FlatEmptyBorder
{
protected Color separatorColor = UIManager.getColor( "TableHeader.separatorColor" );
protected Color bottomSeparatorColor = UIManager.getColor( "TableHeader.bottomSeparatorColor" );
public FlatTableHeaderBorder() {
super( UIManager.getInsets( "TableHeader.cellMargins" ) );
}
@Override
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
JTableHeader header = (JTableHeader) SwingUtilities.getAncestorOfClass( JTableHeader.class, c );
boolean leftToRight = (header != null ? header : c).getComponentOrientation().isLeftToRight();
boolean paintLeft = !leftToRight;
boolean paintRight = leftToRight;
if( header != null ) {
int hx = SwingUtilities.convertPoint( c, x, y, header ).x;
if( isDraggedColumn( header, hx ) )
paintLeft = paintRight = true;
else {
if( hx <= 0 && !leftToRight && hideTrailingVerticalLine( header ) )
paintLeft = false;
if( hx + width >= header.getWidth() && leftToRight && hideTrailingVerticalLine( header ) )
paintRight = false;
}
}
float lineWidth = UIScale.scale( 1f );
Graphics2D g2 = (Graphics2D) g.create();
try {
FlatUIUtils.setRenderingHints( g2 );
// paint column separator lines
g2.setColor( separatorColor );
if( paintLeft )
g2.fill( new Rectangle2D.Float( x, y, lineWidth, height - lineWidth ) );
if( paintRight )
g2.fill( new Rectangle2D.Float( x + width - lineWidth, y, lineWidth, height - lineWidth ) );
// paint bottom line
g2.setColor( bottomSeparatorColor );
g2.fill( new Rectangle2D.Float( x, y + height - lineWidth, width, lineWidth ) );
} finally {
g2.dispose();
}
}
protected boolean isDraggedColumn( JTableHeader header, int x ) {
TableColumn draggedColumn = header.getDraggedColumn();
if( draggedColumn == null )
return false;
int draggedDistance = header.getDraggedDistance();
if( draggedDistance == 0 )
return false;
int columnCount = header.getColumnModel().getColumnCount();
for( int i = 0; i < columnCount; i++ ) {
if( header.getHeaderRect( i ).x + draggedDistance == x )
return true;
}
return false;
}
protected boolean hideTrailingVerticalLine( JTableHeader header ) {
Container viewport = header.getParent();
Container viewportParent = (viewport != null) ? viewport.getParent() : null;
if( !(viewportParent instanceof JScrollPane) )
return true;
JScrollBar vsb = ((JScrollPane)viewportParent).getVerticalScrollBar();
if( vsb == null || !vsb.isVisible() )
return true;
// if "ScrollPane.fillUpperCorner" is true, then javax.swing.ScrollPaneLayout
// extends the vertical scrollbar into the upper right/left corner
return vsb.getY() == viewport.getY();
}
}

View File

@@ -18,20 +18,16 @@ package com.formdev.flatlaf.ui;
import java.awt.Color; import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Insets; import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.util.Objects; import java.util.Objects;
import javax.swing.Icon; import javax.swing.Icon;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JLabel; import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable; import javax.swing.JTable;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingConstants; import javax.swing.SwingConstants;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.border.Border; import javax.swing.border.Border;
@@ -39,7 +35,6 @@ import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource; import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicTableHeaderUI; import javax.swing.plaf.basic.BasicTableHeaderUI;
import javax.swing.table.TableCellRenderer; import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel; import javax.swing.table.TableColumnModel;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
@@ -54,17 +49,21 @@ import com.formdev.flatlaf.util.UIScale;
* *
* <!-- FlatTableHeaderUI --> * <!-- FlatTableHeaderUI -->
* *
* @uiDefault TableHeader.separatorColor Color
* @uiDefault TableHeader.bottomSeparatorColor Color * @uiDefault TableHeader.bottomSeparatorColor Color
* @uiDefault TableHeader.height int * @uiDefault TableHeader.height int
* @uiDefault TableHeader.sortIconPosition String right (default), left, top or bottom * @uiDefault TableHeader.sortIconPosition String right (default), left, top or bottom
* *
* <!-- FlatTableHeaderBorder -->
*
* @uiDefault TableHeader.cellMargins Insets
* @uiDefault TableHeader.separatorColor Color
* @uiDefault TableHeader.bottomSeparatorColor Color
*
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatTableHeaderUI public class FlatTableHeaderUI
extends BasicTableHeaderUI extends BasicTableHeaderUI
{ {
protected Color separatorColor;
protected Color bottomSeparatorColor; protected Color bottomSeparatorColor;
protected int height; protected int height;
protected int sortIconPosition; protected int sortIconPosition;
@@ -77,7 +76,6 @@ public class FlatTableHeaderUI
protected void installDefaults() { protected void installDefaults() {
super.installDefaults(); super.installDefaults();
separatorColor = UIManager.getColor( "TableHeader.separatorColor" );
bottomSeparatorColor = UIManager.getColor( "TableHeader.bottomSeparatorColor" ); bottomSeparatorColor = UIManager.getColor( "TableHeader.bottomSeparatorColor" );
height = UIManager.getInt( "TableHeader.height" ); height = UIManager.getInt( "TableHeader.height" );
switch( Objects.toString( UIManager.getString( "TableHeader.sortIconPosition" ), "right" ) ) { switch( Objects.toString( UIManager.getString( "TableHeader.sortIconPosition" ), "right" ) ) {
@@ -93,27 +91,38 @@ public class FlatTableHeaderUI
protected void uninstallDefaults() { protected void uninstallDefaults() {
super.uninstallDefaults(); super.uninstallDefaults();
separatorColor = null;
bottomSeparatorColor = null; bottomSeparatorColor = null;
} }
@Override @Override
public void paint( Graphics g, JComponent c ) { public void paint( Graphics g, JComponent c ) {
if( header.getColumnModel().getColumnCount() <= 0 ) TableColumnModel columnModel = header.getColumnModel();
if( columnModel.getColumnCount() <= 0 )
return; return;
// do not paint borders if JTableHeader.setDefaultRenderer() was used // compute total width of all columns
TableCellRenderer defaultRenderer = header.getDefaultRenderer(); int columnCount = columnModel.getColumnCount();
boolean paintBorders = isSystemDefaultRenderer( defaultRenderer ); int totalWidth = 0;
if( !paintBorders ) { for( int i = 0; i < columnCount; i++ )
// check whether the renderer delegates to the system default renderer totalWidth += columnModel.getColumn( i ).getWidth();
Component rendererComponent = defaultRenderer.getTableCellRendererComponent(
header.getTable(), "", false, false, -1, 0 );
paintBorders = isSystemDefaultRenderer( rendererComponent );
}
if( paintBorders ) if( totalWidth < header.getWidth() ) {
paintColumnBorders( g, c ); // do not paint bottom separator if JTableHeader.setDefaultRenderer() was used
TableCellRenderer defaultRenderer = header.getDefaultRenderer();
boolean paintBottomSeparator = isSystemDefaultRenderer( defaultRenderer );
if( !paintBottomSeparator && header.getTable() != null ) {
// check whether the renderer delegates to the system default renderer
Component rendererComponent = defaultRenderer.getTableCellRendererComponent(
header.getTable(), "", false, false, -1, 0 );
paintBottomSeparator = isSystemDefaultRenderer( rendererComponent );
}
if( paintBottomSeparator ) {
int w = c.getWidth() - totalWidth;
int x = header.getComponentOrientation().isLeftToRight() ? c.getWidth() - w : 0;
paintBottomSeparator( g, c, x, w );
}
}
// temporary use own default renderer if necessary // temporary use own default renderer if necessary
FlatTableCellHeaderRenderer sortIconRenderer = null; FlatTableCellHeaderRenderer sortIconRenderer = null;
@@ -130,9 +139,6 @@ public class FlatTableHeaderUI
sortIconRenderer.reset(); sortIconRenderer.reset();
header.setDefaultRenderer( sortIconRenderer.delegate ); header.setDefaultRenderer( sortIconRenderer.delegate );
} }
if( paintBorders )
paintDraggedColumnBorders( g, c );
} }
private boolean isSystemDefaultRenderer( Object headerRenderer ) { private boolean isSystemDefaultRenderer( Object headerRenderer ) {
@@ -141,17 +147,8 @@ public class FlatTableHeaderUI
rendererClassName.equals( "sun.swing.FilePane$AlignableTableHeaderRenderer" ); rendererClassName.equals( "sun.swing.FilePane$AlignableTableHeaderRenderer" );
} }
protected void paintColumnBorders( Graphics g, JComponent c ) { protected void paintBottomSeparator( Graphics g, JComponent c, int x, int w ) {
int width = c.getWidth();
int height = c.getHeight();
float lineWidth = UIScale.scale( 1f ); float lineWidth = UIScale.scale( 1f );
float topLineIndent = lineWidth;
float bottomLineIndent = lineWidth * 3;
TableColumnModel columnModel = header.getColumnModel();
int columnCount = columnModel.getColumnCount();
int sepCount = columnCount;
if( hideLastVerticalLine() )
sepCount--;
Graphics2D g2 = (Graphics2D) g.create(); Graphics2D g2 = (Graphics2D) g.create();
try { try {
@@ -159,78 +156,7 @@ public class FlatTableHeaderUI
// paint bottom line // paint bottom line
g2.setColor( bottomSeparatorColor ); g2.setColor( bottomSeparatorColor );
g2.fill( new Rectangle2D.Float( 0, height - lineWidth, width, lineWidth ) ); g2.fill( new Rectangle2D.Float( x, c.getHeight() - lineWidth, w, lineWidth ) );
// paint column separator lines
g2.setColor( separatorColor );
float y = topLineIndent;
float h = height - bottomLineIndent;
if( header.getComponentOrientation().isLeftToRight() ) {
int x = 0;
for( int i = 0; i < sepCount; i++ ) {
x += columnModel.getColumn( i ).getWidth();
g2.fill( new Rectangle2D.Float( x - lineWidth, y, lineWidth, h ) );
}
// paint trailing separator (on right side)
if( !hideTrailingVerticalLine() )
g2.fill( new Rectangle2D.Float( header.getWidth() - lineWidth, y, lineWidth, h ) );
} else {
Rectangle cellRect = header.getHeaderRect( 0 );
int x = cellRect.x + cellRect.width;
for( int i = 0; i < sepCount; i++ ) {
x -= columnModel.getColumn( i ).getWidth();
g2.fill( new Rectangle2D.Float( x - (i < sepCount - 1 ? lineWidth : 0), y, lineWidth, h ) );
}
// paint trailing separator (on left side)
if( !hideTrailingVerticalLine() )
g2.fill( new Rectangle2D.Float( 0, y, lineWidth, h ) );
}
} finally {
g2.dispose();
}
}
private void paintDraggedColumnBorders( Graphics g, JComponent c ) {
TableColumn draggedColumn = header.getDraggedColumn();
if( draggedColumn == null )
return;
// find index of dragged column
TableColumnModel columnModel = header.getColumnModel();
int columnCount = columnModel.getColumnCount();
int draggedColumnIndex = -1;
for( int i = 0; i < columnCount; i++ ) {
if( columnModel.getColumn( i ) == draggedColumn ) {
draggedColumnIndex = i;
break;
}
}
if( draggedColumnIndex < 0 )
return;
float lineWidth = UIScale.scale( 1f );
float topLineIndent = lineWidth;
float bottomLineIndent = lineWidth * 3;
Rectangle r = header.getHeaderRect( draggedColumnIndex );
r.x += header.getDraggedDistance();
Graphics2D g2 = (Graphics2D) g.create();
try {
FlatUIUtils.setRenderingHints( g2 );
// paint dragged bottom line
g2.setColor( bottomSeparatorColor );
g2.fill( new Rectangle2D.Float( r.x, r.y + r.height - lineWidth, r.width, lineWidth ) );
// paint dragged column separator lines
g2.setColor( separatorColor );
g2.fill( new Rectangle2D.Float( r.x, topLineIndent, lineWidth, r.height - bottomLineIndent ) );
g2.fill( new Rectangle2D.Float( r.x + r.width - lineWidth, r.y + topLineIndent, lineWidth, r.height - bottomLineIndent ) );
} finally { } finally {
g2.dispose(); g2.dispose();
} }
@@ -244,32 +170,6 @@ public class FlatTableHeaderUI
return size; return size;
} }
protected boolean hideLastVerticalLine() {
Container viewport = header.getParent();
Container viewportParent = (viewport != null) ? viewport.getParent() : null;
if( !(viewportParent instanceof JScrollPane) )
return false;
Rectangle cellRect = header.getHeaderRect( header.getColumnModel().getColumnCount() - 1 );
// using component orientation of scroll pane here because it is also used in FlatTableUI
JScrollPane scrollPane = (JScrollPane) viewportParent;
return scrollPane.getComponentOrientation().isLeftToRight()
? cellRect.x + cellRect.width >= viewport.getWidth()
: cellRect.x <= 0;
}
protected boolean hideTrailingVerticalLine() {
Container viewport = header.getParent();
Container viewportParent = (viewport != null) ? viewport.getParent() : null;
if( !(viewportParent instanceof JScrollPane) )
return false;
JScrollPane scrollPane = (JScrollPane) viewportParent;
return viewport == scrollPane.getColumnHeader() &&
scrollPane.getCorner( ScrollPaneConstants.UPPER_TRAILING_CORNER ) == null;
}
//---- class FlatTableCellHeaderRenderer ---------------------------------- //---- class FlatTableCellHeaderRenderer ----------------------------------
/** /**

View File

@@ -16,6 +16,7 @@
package com.formdev.flatlaf.ui; package com.formdev.flatlaf.ui;
import static com.formdev.flatlaf.FlatClientProperties.*;
import java.awt.BorderLayout; import java.awt.BorderLayout;
import java.awt.Color; import java.awt.Color;
import java.awt.Component; import java.awt.Component;
@@ -105,7 +106,6 @@ public class FlatTitlePane
protected final Color embeddedForeground = UIManager.getColor( "TitlePane.embeddedForeground" ); protected final Color embeddedForeground = UIManager.getColor( "TitlePane.embeddedForeground" );
protected final Color borderColor = UIManager.getColor( "TitlePane.borderColor" ); protected final Color borderColor = UIManager.getColor( "TitlePane.borderColor" );
protected final boolean unifiedBackground = UIManager.getBoolean( "TitlePane.unifiedBackground" );
protected final Dimension iconSize = UIManager.getDimension( "TitlePane.iconSize" ); protected final Dimension iconSize = UIManager.getDimension( "TitlePane.iconSize" );
protected final int buttonMaximizedHeight = UIManager.getInt( "TitlePane.buttonMaximizedHeight" ); protected final int buttonMaximizedHeight = UIManager.getInt( "TitlePane.buttonMaximizedHeight" );
protected final boolean centerTitle = UIManager.getBoolean( "TitlePane.centerTitle" ); protected final boolean centerTitle = UIManager.getBoolean( "TitlePane.centerTitle" );
@@ -266,10 +266,17 @@ public class FlatTitlePane
} }
protected void activeChanged( boolean active ) { protected void activeChanged( boolean active ) {
boolean hasEmbeddedMenuBar = hasVisibleEmbeddedMenuBar( rootPane.getJMenuBar() ); Color background = clientPropertyColor( rootPane, TITLE_BAR_BACKGROUND, null );
Color background = FlatUIUtils.nonUIResource( active ? activeBackground : inactiveBackground ); Color foreground = clientPropertyColor( rootPane, TITLE_BAR_FOREGROUND, null );
Color foreground = FlatUIUtils.nonUIResource( active ? activeForeground : inactiveForeground ); Color titleForeground = foreground;
Color titleForeground = (hasEmbeddedMenuBar && active) ? FlatUIUtils.nonUIResource( embeddedForeground ) : foreground; if( background == null )
background = FlatUIUtils.nonUIResource( active ? activeBackground : inactiveBackground );
if( foreground == null ) {
foreground = FlatUIUtils.nonUIResource( active ? activeForeground : inactiveForeground );
titleForeground = (active && hasVisibleEmbeddedMenuBar( rootPane.getJMenuBar() ))
? FlatUIUtils.nonUIResource( embeddedForeground )
: foreground;
}
setBackground( background ); setBackground( background );
titleLabel.setForeground( titleForeground ); titleLabel.setForeground( titleForeground );
@@ -344,7 +351,7 @@ public class FlatTitlePane
// set icon // set icon
if( !images.isEmpty() ) if( !images.isEmpty() )
iconLabel.setIcon( FlatTitlePaneIcon.create( images, iconSize ) ); iconLabel.setIcon( new FlatTitlePaneIcon( images, iconSize ) );
else { else {
// no icon set on window --> use default icon // no icon set on window --> use default icon
Icon defaultIcon = UIManager.getIcon( "TitlePane.icon" ); Icon defaultIcon = UIManager.getIcon( "TitlePane.icon" );
@@ -430,9 +437,11 @@ public class FlatTitlePane
*/ */
protected boolean isMenuBarEmbedded() { protected boolean isMenuBarEmbedded() {
// not storing value of "TitlePane.menuBarEmbedded" in class to allow changing at runtime // not storing value of "TitlePane.menuBarEmbedded" in class to allow changing at runtime
return UIManager.getBoolean( "TitlePane.menuBarEmbedded" ) && return FlatUIUtils.getBoolean( rootPane,
FlatClientProperties.clientPropertyBoolean( rootPane, FlatClientProperties.MENU_BAR_EMBEDDED, true ) && FlatSystemProperties.MENUBAR_EMBEDDED,
FlatSystemProperties.getBoolean( FlatSystemProperties.MENUBAR_EMBEDDED, true ); FlatClientProperties.MENU_BAR_EMBEDDED,
"TitlePane.menuBarEmbedded",
false );
} }
protected Rectangle getMenuBarBounds() { protected Rectangle getMenuBarBounds() {
@@ -479,6 +488,11 @@ public class FlatTitlePane
return null; return null;
} }
protected void titleBarColorsChanged() {
activeChanged( window == null || window.isActive() );
repaint();
}
protected void menuBarChanged() { protected void menuBarChanged() {
menuBarPlaceholder.invalidate(); menuBarPlaceholder.invalidate();
@@ -507,13 +521,13 @@ public class FlatTitlePane
g.drawLine( 0, debugTitleBarHeight, getWidth(), debugTitleBarHeight ); g.drawLine( 0, debugTitleBarHeight, getWidth(), debugTitleBarHeight );
} }
if( debugHitTestSpots != null ) { if( debugHitTestSpots != null ) {
g.setColor( Color.blue ); g.setColor( Color.red );
Point offset = SwingUtilities.convertPoint( this, 0, 0, window ); Point offset = SwingUtilities.convertPoint( this, 0, 0, window );
for( Rectangle r : debugHitTestSpots ) for( Rectangle r : debugHitTestSpots )
g.drawRect( r.x - offset.x, r.y - offset.y, r.width - 1, r.height - 1 ); g.drawRect( r.x - offset.x, r.y - offset.y, r.width - 1, r.height - 1 );
} }
if( debugAppIconBounds != null ) { if( debugAppIconBounds != null ) {
g.setColor( Color.red ); g.setColor( Color.blue);
Point offset = SwingUtilities.convertPoint( this, 0, 0, window ); Point offset = SwingUtilities.convertPoint( this, 0, 0, window );
Rectangle r = debugAppIconBounds; Rectangle r = debugAppIconBounds;
g.drawRect( r.x - offset.x, r.y - offset.y, r.width - 1, r.height - 1 ); g.drawRect( r.x - offset.x, r.y - offset.y, r.width - 1, r.height - 1 );
@@ -523,10 +537,12 @@ debug*/
@Override @Override
protected void paintComponent( Graphics g ) { protected void paintComponent( Graphics g ) {
if( !unifiedBackground ) { // not storing value of "TitlePane.unifiedBackground" in class to allow changing at runtime
g.setColor( getBackground() ); g.setColor( (UIManager.getBoolean( "TitlePane.unifiedBackground" ) &&
g.fillRect( 0, 0, getWidth(), getHeight() ); clientPropertyColor( rootPane, TITLE_BAR_BACKGROUND, null ) == null)
} ? FlatUIUtils.getParentBackground( this )
: getBackground() );
g.fillRect( 0, 0, getWidth(), getHeight() );
} }
protected void repaintWindowBorder() { protected void repaintWindowBorder() {
@@ -707,14 +723,29 @@ debug*/
List<Rectangle> hitTestSpots = new ArrayList<>(); List<Rectangle> hitTestSpots = new ArrayList<>();
Rectangle appIconBounds = null; Rectangle appIconBounds = null;
if( iconLabel.isVisible() ) { if( iconLabel.isVisible() ) {
// compute real icon size (without insets) // compute real icon size (without insets; 1px wider for easier hitting)
Point location = SwingUtilities.convertPoint( iconLabel, 0, 0, window ); Point location = SwingUtilities.convertPoint( iconLabel, 0, 0, window );
Insets iconInsets = iconLabel.getInsets(); Insets iconInsets = iconLabel.getInsets();
Rectangle iconBounds = new Rectangle( Rectangle iconBounds = new Rectangle(
location.x + iconInsets.left, location.x + iconInsets.left - 1,
location.y + iconInsets.top, location.y + iconInsets.top - 1,
iconLabel.getWidth() - iconInsets.left - iconInsets.right, iconLabel.getWidth() - iconInsets.left - iconInsets.right + 2,
iconLabel.getHeight() - iconInsets.top - iconInsets.bottom ); iconLabel.getHeight() - iconInsets.top - iconInsets.bottom + 2 );
// if frame is maximized, increase icon bounds to upper-left corner
// of window to allow closing window via double-click in upper-left corner
if( window instanceof Frame &&
(((Frame)window).getExtendedState() & Frame.MAXIMIZED_BOTH) != 0 )
{
iconBounds.height += iconBounds.y;
iconBounds.y = 0;
if( window.getComponentOrientation().isLeftToRight() ) {
iconBounds.width += iconBounds.x;
iconBounds.x = 0;
} else
iconBounds.width += iconInsets.right;
}
if( hasJBRCustomDecoration() ) if( hasJBRCustomDecoration() )
hitTestSpots.add( iconBounds ); hitTestSpots.add( iconBounds );
@@ -803,7 +834,7 @@ debug*/
} else if( borderColor != null && (rootPane.getJMenuBar() == null || !rootPane.getJMenuBar().isVisible()) ) } else if( borderColor != null && (rootPane.getJMenuBar() == null || !rootPane.getJMenuBar().isVisible()) )
insets.bottom += UIScale.scale( 1 ); insets.bottom += UIScale.scale( 1 );
if( hasNativeCustomDecoration() ) if( hasNativeCustomDecoration() && !isWindowMaximized( c ) )
insets = FlatUIUtils.addInsets( insets, WindowTopBorder.getInstance().getBorderInsets() ); insets = FlatUIUtils.addInsets( insets, WindowTopBorder.getInstance().getBorderInsets() );
return insets; return insets;
@@ -822,7 +853,7 @@ debug*/
FlatUIUtils.paintFilledRectangle( g, borderColor, x, y + height - lineHeight, width, lineHeight ); FlatUIUtils.paintFilledRectangle( g, borderColor, x, y + height - lineHeight, width, lineHeight );
} }
if( hasNativeCustomDecoration() ) if( hasNativeCustomDecoration() && !isWindowMaximized( c ) )
WindowTopBorder.getInstance().paintBorder( c, g, x, y, width, height ); WindowTopBorder.getInstance().paintBorder( c, g, x, y, width, height );
} }
@@ -830,6 +861,12 @@ debug*/
JMenuBar menuBar = rootPane.getJMenuBar(); JMenuBar menuBar = rootPane.getJMenuBar();
return hasVisibleEmbeddedMenuBar( menuBar ) ? menuBar.getBorder() : null; return hasVisibleEmbeddedMenuBar( menuBar ) ? menuBar.getBorder() : null;
} }
protected boolean isWindowMaximized( Component c ) {
return window instanceof Frame
? (((Frame)window).getExtendedState() & Frame.MAXIMIZED_BOTH) != 0
: false;
}
} }
//---- class FlatTitleLabelUI --------------------------------------------- //---- class FlatTitleLabelUI ---------------------------------------------

View File

@@ -20,8 +20,6 @@ import java.awt.Dimension;
import java.awt.Image; import java.awt.Image;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import com.formdev.flatlaf.util.MultiResolutionImageSupport; import com.formdev.flatlaf.util.MultiResolutionImageSupport;
import com.formdev.flatlaf.util.ScaledImageIcon; import com.formdev.flatlaf.util.ScaledImageIcon;
@@ -31,40 +29,43 @@ import com.formdev.flatlaf.util.ScaledImageIcon;
public class FlatTitlePaneIcon public class FlatTitlePaneIcon
extends ScaledImageIcon extends ScaledImageIcon
{ {
public static Icon create( List<Image> images, Dimension size ) { private final List<Image> images;
// collect all images including multi-resolution variants
/**
* @since 1.2
*/
public FlatTitlePaneIcon( List<Image> images, Dimension size ) {
super( null, size.width, size.height );
this.images = images;
}
@Override
protected Image getResolutionVariant( int destImageWidth, int destImageHeight ) {
// collect all images including multi-resolution variants for requested size
List<Image> allImages = new ArrayList<>(); List<Image> allImages = new ArrayList<>();
for( Image image : images ) { for( Image image : images ) {
if( MultiResolutionImageSupport.isMultiResolutionImage( image ) ) if( MultiResolutionImageSupport.isMultiResolutionImage( image ) )
allImages.addAll( MultiResolutionImageSupport.getResolutionVariants( image ) ); allImages.add( MultiResolutionImageSupport.getResolutionVariant( image, destImageWidth, destImageHeight ) );
else else
allImages.add( image ); allImages.add( image );
} }
if( allImages.size() == 1 )
return allImages.get( 0 );
// sort images by size // sort images by size
allImages.sort( (image1, image2) -> { allImages.sort( (image1, image2) -> {
return image1.getWidth( null ) - image2.getWidth( null ); return image1.getWidth( null ) - image2.getWidth( null );
} ); } );
// create icon // search for optimal image size
return new FlatTitlePaneIcon( allImages, size ); for( Image image : allImages ) {
}
private final List<Image> images;
private FlatTitlePaneIcon( List<Image> images, Dimension size ) {
super( new ImageIcon( images.get( 0 ) ), size.width, size.height );
this.images = images;
}
@Override
protected Image getResolutionVariant( int destImageWidth, int destImageHeight ) {
for( Image image : images ) {
if( destImageWidth <= image.getWidth( null ) && if( destImageWidth <= image.getWidth( null ) &&
destImageHeight <= image.getHeight( null ) ) destImageHeight <= image.getHeight( null ) )
return image; return image;
} }
return images.get( images.size() - 1 ); // use largest image
return allImages.get( allImages.size() - 1 );
} }
} }

View File

@@ -107,6 +107,8 @@ public class FlatTreeUI
protected boolean wideSelection; protected boolean wideSelection;
protected boolean showCellFocusIndicator; protected boolean showCellFocusIndicator;
private Color defaultCellNonSelectionBackground;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatTreeUI(); return new FlatTreeUI();
} }
@@ -125,6 +127,8 @@ public class FlatTreeUI
wideSelection = UIManager.getBoolean( "Tree.wideSelection" ); wideSelection = UIManager.getBoolean( "Tree.wideSelection" );
showCellFocusIndicator = UIManager.getBoolean( "Tree.showCellFocusIndicator" ); showCellFocusIndicator = UIManager.getBoolean( "Tree.showCellFocusIndicator" );
defaultCellNonSelectionBackground = UIManager.getColor( "Tree.textBackground" );
// scale // scale
int rowHeight = FlatUIUtils.getUIInt( "Tree.rowHeight", 16 ); int rowHeight = FlatUIUtils.getUIInt( "Tree.rowHeight", 16 );
if( rowHeight > 0 ) if( rowHeight > 0 )
@@ -144,6 +148,8 @@ public class FlatTreeUI
selectionInactiveBackground = null; selectionInactiveBackground = null;
selectionInactiveForeground = null; selectionInactiveForeground = null;
selectionBorderColor = null; selectionBorderColor = null;
defaultCellNonSelectionBackground = null;
} }
@Override @Override
@@ -306,24 +312,24 @@ public class FlatTreeUI
} }
} else { } else {
// non-wide selection // non-wide selection
int xOffset = 0; paintCellBackground( g, rendererComponent, bounds );
int imageOffset = 0;
if( rendererComponent instanceof JLabel ) {
JLabel label = (JLabel) rendererComponent;
Icon icon = label.getIcon();
imageOffset = (icon != null && label.getText() != null)
? icon.getIconWidth() + Math.max( label.getIconTextGap() - 1, 0 )
: 0;
xOffset = label.getComponentOrientation().isLeftToRight() ? imageOffset : 0;
}
g.fillRect( bounds.x + xOffset, bounds.y, bounds.width - imageOffset, bounds.height );
} }
// this is actually not necessary because renderer should always set color // this is actually not necessary because renderer should always set color
// before painting, but doing anyway to avoid any side effect (in bad renderers) // before painting, but doing anyway to avoid any side effect (in bad renderers)
g.setColor( oldColor ); g.setColor( oldColor );
} else {
// paint cell background if DefaultTreeCellRenderer.getBackgroundNonSelectionColor() is set
if( rendererComponent instanceof DefaultTreeCellRenderer ) {
DefaultTreeCellRenderer renderer = (DefaultTreeCellRenderer) rendererComponent;
Color bg = renderer.getBackgroundNonSelectionColor();
if( bg != null && !bg.equals( defaultCellNonSelectionBackground ) ) {
Color oldColor = g.getColor();
g.setColor( bg );
paintCellBackground( g, rendererComponent, bounds );
g.setColor( oldColor );
}
}
} }
// paint renderer // paint renderer
@@ -337,6 +343,22 @@ public class FlatTreeUI
((DefaultTreeCellRenderer)rendererComponent).setBorderSelectionColor( oldBorderSelectionColor ); ((DefaultTreeCellRenderer)rendererComponent).setBorderSelectionColor( oldBorderSelectionColor );
} }
private void paintCellBackground( Graphics g, Component rendererComponent, Rectangle bounds ) {
int xOffset = 0;
int imageOffset = 0;
if( rendererComponent instanceof JLabel ) {
JLabel label = (JLabel) rendererComponent;
Icon icon = label.getIcon();
imageOffset = (icon != null && label.getText() != null)
? icon.getIconWidth() + Math.max( label.getIconTextGap() - 1, 0 )
: 0;
xOffset = label.getComponentOrientation().isLeftToRight() ? imageOffset : 0;
}
g.fillRect( bounds.x + xOffset, bounds.y, bounds.width - imageOffset, bounds.height );
}
/** /**
* Checks whether dropping on a row. * Checks whether dropping on a row.
* See DefaultTreeCellRenderer.getTreeCellRendererComponent(). * See DefaultTreeCellRenderer.getTreeCellRendererComponent().

View File

@@ -54,6 +54,7 @@ import javax.swing.border.CompoundBorder;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource; import javax.swing.plaf.UIResource;
import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatSystemProperties;
import com.formdev.flatlaf.util.DerivedColor; import com.formdev.flatlaf.util.DerivedColor;
import com.formdev.flatlaf.util.Graphics2DProxy; import com.formdev.flatlaf.util.Graphics2DProxy;
import com.formdev.flatlaf.util.HiDPIUtils; import com.formdev.flatlaf.util.HiDPIUtils;
@@ -140,6 +141,25 @@ public class FlatUIUtils
return (value instanceof Number) ? ((Number)value).floatValue() : defaultValue; return (value instanceof Number) ? ((Number)value).floatValue() : defaultValue;
} }
/**
* @since 1.1.2
*/
public static boolean getBoolean( JComponent c, String systemPropertyKey,
String clientPropertyKey, String uiKey, boolean defaultValue )
{
// check whether forced to true/false via system property
Boolean value = FlatSystemProperties.getBooleanStrict( systemPropertyKey, null );
if( value != null )
return value;
// check whether forced to true/false via client property
value = FlatClientProperties.clientPropertyBooleanStrict( c, clientPropertyKey, null );
if( value != null )
return value;
return getUIBoolean( uiKey, defaultValue );
}
public static boolean isChevron( String arrowType ) { public static boolean isChevron( String arrowType ) {
return !"triangle".equals( arrowType ); return !"triangle".equals( arrowType );
} }

View File

@@ -103,8 +103,7 @@ class FlatWindowsNativeWindowBorder
if( SystemInfo.isX86_64 ) if( SystemInfo.isX86_64 )
libraryName += "_64"; libraryName += "_64";
nativeLibrary = new NativeLibrary( libraryName, nativeLibrary = new NativeLibrary( libraryName, null, true );
FlatWindowsNativeWindowBorder.class.getClassLoader(), true );
} }
// check whether native library was successfully loaded // check whether native library was successfully loaded
@@ -309,18 +308,11 @@ class FlatWindowsNativeWindowBorder
this.window = window; this.window = window;
hwnd = installImpl( window ); hwnd = installImpl( window );
if( hwnd == 0 )
return;
// remove the OS window title bar // remove the OS window title bar
if( window instanceof JFrame && ((JFrame)window).getExtendedState() != 0 ) { updateFrame( hwnd, (window instanceof JFrame) ? ((JFrame)window).getExtendedState() : 0 );
// In case that the frame should be maximized or minimized immediately
// when showing, then it is necessary to defer ::SetWindowPos() invocation.
// Otherwise the frame will not be maximized or minimized.
// This occurs only if frame.pack() was no invoked.
EventQueue.invokeLater( () -> {
updateFrame( hwnd );
});
} else
updateFrame( hwnd );
} }
void uninstall() { void uninstall() {
@@ -332,7 +324,7 @@ class FlatWindowsNativeWindowBorder
private native long installImpl( Window window ); private native long installImpl( Window window );
private native void uninstallImpl( long hwnd ); private native void uninstallImpl( long hwnd );
private native void updateFrame( long hwnd ); private native void updateFrame( long hwnd, int state );
private native void showWindow( long hwnd, int cmd ); private native void showWindow( long hwnd, int cmd );
// invoked from native code // invoked from native code

View File

@@ -36,7 +36,6 @@ import javax.swing.SwingUtilities;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.BorderUIResource; import javax.swing.plaf.BorderUIResource;
import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.FlatSystemProperties;
import com.formdev.flatlaf.util.LoggingFacade; import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.HiDPIUtils; import com.formdev.flatlaf.util.HiDPIUtils;
import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.SystemInfo;
@@ -73,7 +72,7 @@ public class JBRCustomDecorations
// check whether root pane already has a parent, which is the case when switching LaF // check whether root pane already has a parent, which is the case when switching LaF
Window window = SwingUtilities.windowForComponent( rootPane ); Window window = SwingUtilities.windowForComponent( rootPane );
if( window != null ) { if( window != null ) {
FlatNativeWindowBorder.install( window, FlatSystemProperties.USE_JETBRAINS_CUSTOM_DECORATIONS ); FlatNativeWindowBorder.install( window );
return null; return null;
} }
@@ -89,7 +88,7 @@ public class JBRCustomDecorations
Container parent = e.getChangedParent(); Container parent = e.getChangedParent();
if( parent instanceof Window ) if( parent instanceof Window )
FlatNativeWindowBorder.install( (Window) parent, FlatSystemProperties.USE_JETBRAINS_CUSTOM_DECORATIONS ); FlatNativeWindowBorder.install( (Window) parent );
// remove listener since it is actually not possible to uninstall JBR decorations // remove listener since it is actually not possible to uninstall JBR decorations
// use invokeLater to remove listener to avoid that listener // use invokeLater to remove listener to avoid that listener
@@ -165,10 +164,6 @@ public class JBRCustomDecorations
if( !SystemInfo.isJetBrainsJVM_11_orLater || !SystemInfo.isWindows_10_orLater ) if( !SystemInfo.isJetBrainsJVM_11_orLater || !SystemInfo.isWindows_10_orLater )
return; return;
// check whether disabled via system property
if( !FlatSystemProperties.getBoolean( FlatSystemProperties.USE_JETBRAINS_CUSTOM_DECORATIONS, true ) )
return;
try { try {
Class<?> awtAcessorClass = Class.forName( "sun.awt.AWTAccessor" ); Class<?> awtAcessorClass = Class.forName( "sun.awt.AWTAccessor" );
Class<?> compAccessorClass = Class.forName( "sun.awt.AWTAccessor$ComponentAccessor" ); Class<?> compAccessorClass = Class.forName( "sun.awt.AWTAccessor$ComponentAccessor" );

View File

@@ -256,11 +256,6 @@ public class Graphics2DProxy
delegate.dispose(); delegate.dispose();
} }
@Override
public void finalize() {
delegate.finalize();
}
@Override @Override
public String toString() { public String toString() {
return delegate.toString(); return delegate.toString();

View File

@@ -20,6 +20,7 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.URL; import java.net.URL;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
@@ -42,9 +43,15 @@ public class NativeLibrary
/** /**
* Load native library from given classloader. * Load native library from given classloader.
* <p>
* Note regarding Java Platform Module System (JPMS):
* If classloader is {@code null}, the library can be only loaded from the module
* that contains this class.
* If classloader is not {@code null}, then the package that contains the library
* must be specified as "open" in module-info.java of the module that contains the library.
* *
* @param libraryName resource name of the native library (without "lib" prefix and without extension) * @param libraryName resource name of the native library (without "lib" prefix and without extension)
* @param classLoader the classloader used to locate the library * @param classLoader the classloader used to locate the library, or {@code null}
* @param supported whether the native library is supported on the current platform * @param supported whether the native library is supported on the current platform
*/ */
public NativeLibrary( String libraryName, ClassLoader classLoader, boolean supported ) { public NativeLibrary( String libraryName, ClassLoader classLoader, boolean supported ) {
@@ -68,7 +75,9 @@ public class NativeLibrary
libraryName = decorateLibraryName( libraryName ); libraryName = decorateLibraryName( libraryName );
// find library // find library
URL libraryUrl = classLoader.getResource( libraryName ); URL libraryUrl = (classLoader != null)
? classLoader.getResource( libraryName )
: NativeLibrary.class.getResource( "/" + libraryName );
if( libraryUrl == null ) { if( libraryUrl == null ) {
log( "Library '" + libraryName + "' not found", null ); log( "Library '" + libraryName + "' not found", null );
return false; return false;
@@ -136,26 +145,46 @@ public class NativeLibrary
String suffix = (dot >= 0) ? name.substring( dot ) : ""; String suffix = (dot >= 0) ? name.substring( dot ) : "";
Path tempDir = getTempDir(); Path tempDir = getTempDir();
if( tempDir != null ) {
deleteTemporaryFiles( tempDir );
return Files.createTempFile( tempDir, prefix, suffix ); // Note:
} else // Not using Files.createTempFile() here because it uses random number generator SecureRandom,
return Files.createTempFile( prefix, suffix ); // which may take 5-10 seconds to initialize under particular conditions.
// Use current time in nanoseconds instead of a random number.
// To avoid (theoretical) collisions, append a counter.
long nanoTime = System.nanoTime();
for( int i = 0;; i++ ) {
String s = prefix + Long.toUnsignedString( nanoTime ) + i + suffix;
try {
return Files.createFile( tempDir.resolve( s ) );
} catch( FileAlreadyExistsException ex ) {
// ignore --> increment counter and try again
}
}
} }
private static Path getTempDir() throws IOException { private static Path getTempDir() throws IOException {
// get standard temporary directory
String tmpdir = System.getProperty( "java.io.tmpdir" );
if( SystemInfo.isWindows ) { if( SystemInfo.isWindows ) {
// On Windows, where File.delete() and File.deleteOnExit() does not work // On Windows, where File.delete() and File.deleteOnExit() does not work
// for loaded native libraries, they will be deleted on next application startup. // for loaded native libraries, they will be deleted on next application startup.
// The default temporary directory may contain hundreds or thousands of files. // The default temporary directory may contain hundreds or thousands of files.
// To make searching for "marked for deletion" files as fast as possible, // To make searching for "marked for deletion" files as fast as possible,
// use a sub directory that contains only our temporary native libraries. // use a sub directory that contains only our temporary native libraries.
Path tempDir = Paths.get( System.getProperty( "java.io.tmpdir" ) + "/flatlaf.temp" ); tmpdir += "\\flatlaf.temp";
Files.createDirectories( tempDir ); }
return tempDir;
} else // create temporary directory
return null; // use standard temporary directory Path tempDir = Paths.get( tmpdir );
Files.createDirectories( tempDir );
// delete no longer needed temporary files (from already exited applications)
if( SystemInfo.isWindows )
deleteTemporaryFiles( tempDir );
return tempDir;
} }
private static void deleteTemporaryFiles( Path tempDir ) { private static void deleteTemporaryFiles( Path tempDir ) {

View File

@@ -77,7 +77,7 @@ debug*/
double scaleFactor = systemScaleFactor * userScaleFactor; double scaleFactor = systemScaleFactor * userScaleFactor;
// paint input image icon if not necessary to scale // paint input image icon if not necessary to scale
if( scaleFactor == 1 && iconWidth == imageIcon.getIconWidth() && iconHeight == imageIcon.getIconHeight() ) { if( scaleFactor == 1 && imageIcon != null && iconWidth == imageIcon.getIconWidth() && iconHeight == imageIcon.getIconHeight() ) {
imageIcon.paintIcon( c, g, x, y ); imageIcon.paintIcon( c, g, x, y );
return; return;
} }

View File

@@ -56,6 +56,7 @@ public class SystemInfo
// other // other
/** @since 1.1 */ public static final boolean isProjector; /** @since 1.1 */ public static final boolean isProjector;
/** @since 1.1.2 */ public static final boolean isWebswing;
/** @since 1.1.1 */ public static final boolean isWinPE; /** @since 1.1.1 */ public static final boolean isWinPE;
static { static {
@@ -92,6 +93,7 @@ public class SystemInfo
// other // other
isProjector = Boolean.getBoolean( "org.jetbrains.projector.server.enable" ); isProjector = Boolean.getBoolean( "org.jetbrains.projector.server.enable" );
isWebswing = (System.getProperty( "webswing.rootDir" ) != null);
isWinPE = isWindows && "X:\\Windows\\System32".equalsIgnoreCase( System.getProperty( "user.dir" ) ); isWinPE = isWindows && "X:\\Windows\\System32".equalsIgnoreCase( System.getProperty( "user.dir" ) );
} }

View File

@@ -43,7 +43,7 @@ import com.formdev.flatlaf.FlatSystemProperties;
* <p> * <p>
* Two scaling modes are supported by FlatLaf for HiDPI displays: * Two scaling modes are supported by FlatLaf for HiDPI displays:
* *
* <h3>1) system scaling mode</h3> * <h2>1) system scaling mode</h2>
* *
* This mode is supported since Java 9 on all platforms and in some Java 8 VMs * This mode is supported since Java 9 on all platforms and in some Java 8 VMs
* (e.g. Apple and JetBrains). The JRE determines the scale factor per-display and * (e.g. Apple and JetBrains). The JRE determines the scale factor per-display and
@@ -54,7 +54,7 @@ import com.formdev.flatlaf.FlatSystemProperties;
* The scale factor may be different for each connected display. * The scale factor may be different for each connected display.
* The scale factor may change for a window when moving the window from one display to another one. * The scale factor may change for a window when moving the window from one display to another one.
* *
* <h3>2) user scaling mode</h3> * <h2>2) user scaling mode</h2>
* *
* This mode is mainly for Java 8 compatibility, but is also used on Linux * This mode is mainly for Java 8 compatibility, but is also used on Linux
* or if the default font is changed. * or if the default font is changed.
@@ -180,7 +180,7 @@ public class UIScale
// apply custom scale factor specified in system property "flatlaf.uiScale" // apply custom scale factor specified in system property "flatlaf.uiScale"
float customScaleFactor = getCustomScaleFactor(); float customScaleFactor = getCustomScaleFactor();
if( customScaleFactor > 0 ) { if( customScaleFactor > 0 ) {
setUserScaleFactor( customScaleFactor ); setUserScaleFactor( customScaleFactor, false );
return; return;
} }
@@ -230,7 +230,7 @@ public class UIScale
} else } else
newScaleFactor = computeScaleFactor( font ); newScaleFactor = computeScaleFactor( font );
setUserScaleFactor( newScaleFactor ); setUserScaleFactor( newScaleFactor, true );
} }
private static float computeScaleFactor( Font font ) { private static float computeScaleFactor( Font font ) {
@@ -274,7 +274,7 @@ public class UIScale
if( scaleFactor == fontScaleFactor ) if( scaleFactor == fontScaleFactor )
return font; return font;
int newFontSize = Math.round( (font.getSize() / fontScaleFactor) * scaleFactor ); int newFontSize = Math.max( Math.round( (font.getSize() / fontScaleFactor) * scaleFactor ), 1 );
return new FontUIResource( font.deriveFont( (float) newFontSize ) ); return new FontUIResource( font.deriveFont( (float) newFontSize ) );
} }
@@ -322,11 +322,18 @@ public class UIScale
/** /**
* Sets the user scale factor. * Sets the user scale factor.
*/ */
private static void setUserScaleFactor( float scaleFactor ) { private static void setUserScaleFactor( float scaleFactor, boolean normalize ) {
if( scaleFactor <= 1f ) if( normalize ) {
scaleFactor = 1f; if( scaleFactor < 1f ) {
else // round scale factor to 1/4 scaleFactor = FlatSystemProperties.getBoolean( FlatSystemProperties.UI_SCALE_ALLOW_SCALE_DOWN, false )
scaleFactor = Math.round( scaleFactor * 4f ) / 4f; ? Math.round( scaleFactor * 10f ) / 10f // round small scale factor to 1/10
: 1f;
} else if( scaleFactor > 1f ) // round scale factor to 1/4
scaleFactor = Math.round( scaleFactor * 4f ) / 4f;
}
// minimum scale factor
scaleFactor = Math.max( scaleFactor, 0.1f );
float oldScaleFactor = UIScale.scaleFactor; float oldScaleFactor = UIScale.scaleFactor;
UIScale.scaleFactor = scaleFactor; UIScale.scaleFactor = scaleFactor;

View File

@@ -166,7 +166,7 @@ Desktop.background = #3E434C
#---- DesktopIcon ---- #---- DesktopIcon ----
DesktopIcon.background = lighten($Desktop.background,10%) DesktopIcon.background = lighten($Desktop.background,10%,derived)
#---- InternalFrame ---- #---- InternalFrame ----

View File

@@ -642,7 +642,8 @@ Table.dropLineShortColor = @dropLineShortColor
#---- TableHeader ---- #---- TableHeader ----
TableHeader.height = 25 TableHeader.height = 25
TableHeader.cellBorder = 2,3,2,3 TableHeader.cellBorder = com.formdev.flatlaf.ui.FlatTableHeaderBorder
TableHeader.cellMargins = 2,3,2,3
TableHeader.focusCellBackground = $TableHeader.background TableHeader.focusCellBackground = $TableHeader.background
TableHeader.background = @textComponentBackground TableHeader.background = @textComponentBackground

View File

@@ -172,7 +172,7 @@ Desktop.background = #E6EBF0
#---- DesktopIcon ---- #---- DesktopIcon ----
DesktopIcon.background = darken($Desktop.background,10%) DesktopIcon.background = darken($Desktop.background,10%,derived)
#---- HelpButton ---- #---- HelpButton ----

View File

@@ -22,6 +22,28 @@
# - https://www.formdev.com/flatlaf/how-to-customize/ # - https://www.formdev.com/flatlaf/how-to-customize/
# #
#---- system colors ----
# fix (most) system colors because they are usually not set in .json files
desktop = lazy(TextField.background)
activeCaptionText = lazy(TextField.foreground)
inactiveCaptionText = lazy(TextField.foreground)
window = lazy(Panel.background)
windowBorder = lazy(TextField.foreground)
windowText = lazy(TextField.foreground)
menu = lazy(Menu.background)
menuText = lazy(Menu.foreground)
text = lazy(TextField.background)
textText = lazy(TextField.foreground)
textHighlight = lazy(TextField.selectionBackground)
textHighlightText = lazy(TextField.selectionForeground)
textInactiveText = lazy(TextField.inactiveForeground)
control = lazy(Panel.background)
controlText = lazy(TextField.foreground)
info = lazy(ToolTip.background)
infoText = lazy(ToolTip.foreground)
#---- Button ---- #---- Button ----
Button.startBackground = $Button.background Button.startBackground = $Button.background
@@ -111,8 +133,8 @@ ToggleButton.endBackground = $ToggleButton.background
[Dark_purple]Slider.focusedColor = fade($Component.focusColor,70%,derived) [Dark_purple]Slider.focusedColor = fade($Component.focusColor,70%,derived)
[Dracula]ProgressBar.selectionBackground = #fff [Dracula---Zihan_Ma]ProgressBar.selectionBackground = #fff
[Dracula]ProgressBar.selectionForeground = #fff [Dracula---Zihan_Ma]ProgressBar.selectionForeground = #fff
[Gradianto_Dark_Fuchsia]MenuItem.checkBackground = @ijMenuCheckBackgroundL10 [Gradianto_Dark_Fuchsia]MenuItem.checkBackground = @ijMenuCheckBackgroundL10
[Gradianto_Dark_Fuchsia]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10 [Gradianto_Dark_Fuchsia]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
@@ -159,7 +181,7 @@ ToggleButton.endBackground = $ToggleButton.background
[One_Dark]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10 [One_Dark]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
[One_Dark]Slider.focusedColor = fade(#568af2,40%) [One_Dark]Slider.focusedColor = fade(#568af2,40%)
[Solarized_Dark]Slider.focusedColor = fade($Component.focusColor,80%,derived) [Solarized_Dark---4lex4]Slider.focusedColor = fade($Component.focusColor,80%,derived)
[vuesion-theme]MenuItem.checkBackground = @ijMenuCheckBackgroundL10 [vuesion-theme]MenuItem.checkBackground = @ijMenuCheckBackgroundL10
[vuesion-theme]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10 [vuesion-theme]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
@@ -176,6 +198,9 @@ ToggleButton.endBackground = $ToggleButton.background
[dark][author-Mallowigi]MenuItem.checkBackground = @ijMenuCheckBackgroundL20 [dark][author-Mallowigi]MenuItem.checkBackground = @ijMenuCheckBackgroundL20
[dark][author-Mallowigi]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL20 [dark][author-Mallowigi]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL20
[Dracula---Mallowigi]ProgressBar.selectionBackground = #fff
[Dracula---Mallowigi]ProgressBar.selectionForeground = #fff
[Dracula_Contrast]ProgressBar.selectionBackground = #fff [Dracula_Contrast]ProgressBar.selectionBackground = #fff
[Dracula_Contrast]ProgressBar.selectionForeground = #fff [Dracula_Contrast]ProgressBar.selectionForeground = #fff
@@ -215,14 +240,14 @@ ToggleButton.endBackground = $ToggleButton.background
[Night_Owl_Contrast]ProgressBar.selectionBackground = #ddd [Night_Owl_Contrast]ProgressBar.selectionBackground = #ddd
[Night_Owl_Contrast]ProgressBar.selectionForeground = #ddd [Night_Owl_Contrast]ProgressBar.selectionForeground = #ddd
[Solarized_Dark]ProgressBar.selectionBackground = #ccc [Solarized_Dark---Mallowigi]ProgressBar.selectionBackground = #ccc
[Solarized_Dark]ProgressBar.selectionForeground = #ccc [Solarized_Dark---Mallowigi]ProgressBar.selectionForeground = #ccc
[Material_Solarized_Dark_Contrast]ProgressBar.selectionBackground = #ccc [Solarized_Dark_Contrast]ProgressBar.selectionBackground = #ccc
[Material_Solarized_Dark_Contrast]ProgressBar.selectionForeground = #ccc [Solarized_Dark_Contrast]ProgressBar.selectionForeground = #ccc
[Solarized_Light]ProgressBar.selectionBackground = #222 [Solarized_Light---Mallowigi]ProgressBar.selectionBackground = #222
[Solarized_Light]ProgressBar.selectionForeground = #fff [Solarized_Light---Mallowigi]ProgressBar.selectionForeground = #fff
[Material_Solarized_Light_Contrast]ProgressBar.selectionBackground = #222 [Solarized_Light_Contrast]ProgressBar.selectionBackground = #222
[Material_Solarized_Light_Contrast]ProgressBar.selectionForeground = #fff [Solarized_Light_Contrast]ProgressBar.selectionForeground = #fff

View File

@@ -18,18 +18,11 @@ plugins {
`java-library` `java-library`
} }
repositories {
maven {
// for using MigLayout snapshot
url = uri( "https://oss.sonatype.org/content/repositories/snapshots/" )
}
}
dependencies { dependencies {
implementation( project( ":flatlaf-core" ) ) implementation( project( ":flatlaf-core" ) )
implementation( project( ":flatlaf-extras" ) ) implementation( project( ":flatlaf-extras" ) )
implementation( project( ":flatlaf-intellij-themes" ) ) implementation( project( ":flatlaf-intellij-themes" ) )
implementation( "com.miglayout:miglayout-swing:5.3-SNAPSHOT" ) implementation( "com.miglayout:miglayout-swing:5.3" )
implementation( "com.jgoodies:jgoodies-forms:1.9.0" ) implementation( "com.jgoodies:jgoodies-forms:1.9.0" )
// implementation( project( ":flatlaf-natives-jna" ) ) // implementation( project( ":flatlaf-natives-jna" ) )
} }

View File

@@ -24,7 +24,6 @@ import java.util.prefs.Preferences;
import javax.swing.*; import javax.swing.*;
import javax.swing.text.DefaultEditorKit; import javax.swing.text.DefaultEditorKit;
import javax.swing.text.StyleContext; import javax.swing.text.StyleContext;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.demo.HintManager.Hint; import com.formdev.flatlaf.demo.HintManager.Hint;
import com.formdev.flatlaf.demo.extras.*; import com.formdev.flatlaf.demo.extras.*;
@@ -35,8 +34,8 @@ import com.formdev.flatlaf.extras.FlatUIDefaultsInspector;
import com.formdev.flatlaf.extras.components.FlatButton; import com.formdev.flatlaf.extras.components.FlatButton;
import com.formdev.flatlaf.extras.components.FlatButton.ButtonType; import com.formdev.flatlaf.extras.components.FlatButton.ButtonType;
import com.formdev.flatlaf.extras.FlatSVGUtils; import com.formdev.flatlaf.extras.FlatSVGUtils;
import com.formdev.flatlaf.ui.FlatNativeWindowBorder;
import com.formdev.flatlaf.ui.JBRCustomDecorations; import com.formdev.flatlaf.ui.JBRCustomDecorations;
import com.formdev.flatlaf.util.SystemInfo;
import net.miginfocom.layout.ConstraintParser; import net.miginfocom.layout.ConstraintParser;
import net.miginfocom.layout.LC; import net.miginfocom.layout.LC;
import net.miginfocom.layout.UnitValue; import net.miginfocom.layout.UnitValue;
@@ -144,35 +143,21 @@ class DemoFrame
private void windowDecorationsChanged() { private void windowDecorationsChanged() {
boolean windowDecorations = windowDecorationsCheckBoxMenuItem.isSelected(); boolean windowDecorations = windowDecorationsCheckBoxMenuItem.isSelected();
// change window decoration of demo main frame // change window decoration of all frames and dialogs
if( FlatNativeWindowBorder.isSupported() ) { FlatLaf.setUseNativeWindowDecorations( windowDecorations );
FlatNativeWindowBorder.setHasCustomDecoration( this, windowDecorations );
getRootPane().setWindowDecorationStyle( windowDecorations ? JRootPane.FRAME : JRootPane.NONE );
} else {
dispose();
setUndecorated( windowDecorations );
getRootPane().setWindowDecorationStyle( windowDecorations ? JRootPane.FRAME : JRootPane.NONE );
setVisible( true );
}
menuBarEmbeddedCheckBoxMenuItem.setEnabled( windowDecorations );
// enable/disable window decoration for later created frames/dialogs menuBarEmbeddedCheckBoxMenuItem.setEnabled( windowDecorations );
UIManager.put( "TitlePane.useWindowDecorations", windowDecorations ); unifiedTitleBarMenuItem.setEnabled( windowDecorations );
} }
private void menuBarEmbeddedChanged() { private void menuBarEmbeddedChanged() {
getRootPane().putClientProperty( FlatClientProperties.MENU_BAR_EMBEDDED, UIManager.put( "TitlePane.menuBarEmbedded", menuBarEmbeddedCheckBoxMenuItem.isSelected() );
menuBarEmbeddedCheckBoxMenuItem.isSelected() ? null : false ); FlatLaf.revalidateAndRepaintAllFramesAndDialogs();
// alternative method for all frames and menu bars in an application
// UIManager.put( "TitlePane.menuBarEmbedded", menuBarEmbeddedCheckBoxMenuItem.isSelected() );
// revalidate();
// repaint();
} }
private void unifiedTitleBar() { private void unifiedTitleBar() {
UIManager.put( "TitlePane.unifiedBackground", unifiedTitleBarMenuItem.isSelected() ); UIManager.put( "TitlePane.unifiedBackground", unifiedTitleBarMenuItem.isSelected() );
FlatLaf.updateUI(); FlatLaf.repaintAllFramesAndDialogs();
} }
private void underlineMenuSelection() { private void underlineMenuSelection() {
@@ -280,7 +265,7 @@ class DemoFrame
// add font sizes // add font sizes
fontMenu.addSeparator(); fontMenu.addSeparator();
ArrayList<String> sizes = new ArrayList<>( Arrays.asList( ArrayList<String> sizes = new ArrayList<>( Arrays.asList(
"10", "12", "14", "16", "18", "20", "24", "28" ) ); "10", "11", "12", "14", "16", "18", "20", "24", "28" ) );
if( !sizes.contains( currentSize ) ) if( !sizes.contains( currentSize ) )
sizes.add( currentSize ); sizes.add( currentSize );
sizes.sort( String.CASE_INSENSITIVE_ORDER ); sizes.sort( String.CASE_INSENSITIVE_ORDER );
@@ -602,7 +587,7 @@ class DemoFrame
optionsMenu.add(menuBarEmbeddedCheckBoxMenuItem); optionsMenu.add(menuBarEmbeddedCheckBoxMenuItem);
//---- unifiedTitleBarMenuItem ---- //---- unifiedTitleBarMenuItem ----
unifiedTitleBarMenuItem.setText("Unified Title Bar"); unifiedTitleBarMenuItem.setText("Unified window title bar");
unifiedTitleBarMenuItem.addActionListener(e -> unifiedTitleBar()); unifiedTitleBarMenuItem.addActionListener(e -> unifiedTitleBar());
optionsMenu.add(unifiedTitleBarMenuItem); optionsMenu.add(unifiedTitleBarMenuItem);
@@ -748,10 +733,20 @@ class DemoFrame
copyMenuItem.addActionListener( new DefaultEditorKit.CopyAction() ); copyMenuItem.addActionListener( new DefaultEditorKit.CopyAction() );
pasteMenuItem.addActionListener( new DefaultEditorKit.PasteAction() ); pasteMenuItem.addActionListener( new DefaultEditorKit.PasteAction() );
boolean supportsWindowDecorations = UIManager.getLookAndFeel() if( FlatLaf.supportsNativeWindowDecorations() ) {
.getSupportsWindowDecorations() || FlatNativeWindowBorder.isSupported(); if( JBRCustomDecorations.isSupported() ) {
windowDecorationsCheckBoxMenuItem.setEnabled( supportsWindowDecorations && !JBRCustomDecorations.isSupported() ); // If the JetBrains Runtime is used, it forces the use of it's own custom
menuBarEmbeddedCheckBoxMenuItem.setEnabled( supportsWindowDecorations ); // window decoration, which can not disabled.
windowDecorationsCheckBoxMenuItem.setEnabled( false );
}
} else {
unsupported( windowDecorationsCheckBoxMenuItem );
unsupported( menuBarEmbeddedCheckBoxMenuItem );
unsupported( unifiedTitleBarMenuItem );
}
if( SystemInfo.isMacOS )
unsupported( underlineMenuSelectionMenuItem );
// remove contentPanel bottom insets // remove contentPanel bottom insets
MigLayout layout = (MigLayout) contentPanel.getLayout(); MigLayout layout = (MigLayout) contentPanel.getLayout();
@@ -766,6 +761,12 @@ class DemoFrame
layout.setLayoutConstraints( lc ); layout.setLayoutConstraints( lc );
} }
private void unsupported( JCheckBoxMenuItem menuItem ) {
menuItem.setEnabled( false );
menuItem.setSelected( false );
menuItem.setToolTipText( "Not supported on your system." );
}
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables // JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
private JMenu fontMenu; private JMenu fontMenu;
private JMenu optionsMenu; private JMenu optionsMenu;

View File

@@ -1,4 +1,4 @@
JFDML JFormDesigner: "7.0.3.1.342" Java: "15" encoding: "UTF-8" JFDML JFormDesigner: "7.0.3.1.342" Java: "16" encoding: "UTF-8"
new FormModel { new FormModel {
contentType: "form/swing" contentType: "form/swing"
@@ -362,7 +362,7 @@ new FormModel {
} ) } )
add( new FormComponent( "javax.swing.JCheckBoxMenuItem" ) { add( new FormComponent( "javax.swing.JCheckBoxMenuItem" ) {
name: "unifiedTitleBarMenuItem" name: "unifiedTitleBarMenuItem"
"text": "Unified Title Bar" "text": "Unified window title bar"
auxiliary() { auxiliary() {
"JavaCodeGenerator.variableLocal": false "JavaCodeGenerator.variableLocal": false
} }

View File

@@ -50,7 +50,7 @@ public class DemoPrefs
state = Preferences.userRoot().node( rootPath ); state = Preferences.userRoot().node( rootPath );
} }
public static void initLaf( String[] args ) { public static void setupLaf( String[] args ) {
// set look and feel // set look and feel
try { try {
if( args.length > 0 ) if( args.length > 0 )
@@ -60,11 +60,11 @@ public class DemoPrefs
if( IntelliJTheme.ThemeLaf.class.getName().equals( lafClassName ) ) { if( IntelliJTheme.ThemeLaf.class.getName().equals( lafClassName ) ) {
String theme = state.get( KEY_LAF_THEME, "" ); String theme = state.get( KEY_LAF_THEME, "" );
if( theme.startsWith( RESOURCE_PREFIX ) ) if( theme.startsWith( RESOURCE_PREFIX ) )
IntelliJTheme.install( IJThemesPanel.class.getResourceAsStream( IJThemesPanel.THEMES_PACKAGE + theme.substring( RESOURCE_PREFIX.length() ) ) ); IntelliJTheme.setup( IJThemesPanel.class.getResourceAsStream( IJThemesPanel.THEMES_PACKAGE + theme.substring( RESOURCE_PREFIX.length() ) ) );
else if( theme.startsWith( FILE_PREFIX ) ) else if( theme.startsWith( FILE_PREFIX ) )
FlatLaf.install( IntelliJTheme.createLaf( new FileInputStream( theme.substring( FILE_PREFIX.length() ) ) ) ); FlatLaf.setup( IntelliJTheme.createLaf( new FileInputStream( theme.substring( FILE_PREFIX.length() ) ) ) );
else else
FlatLightLaf.install(); FlatLightLaf.setup();
if( !theme.isEmpty() ) if( !theme.isEmpty() )
UIManager.getLookAndFeelDefaults().put( THEME_UI_KEY, theme ); UIManager.getLookAndFeelDefaults().put( THEME_UI_KEY, theme );
@@ -73,9 +73,9 @@ public class DemoPrefs
if( theme.startsWith( FILE_PREFIX ) ) { if( theme.startsWith( FILE_PREFIX ) ) {
File themeFile = new File( theme.substring( FILE_PREFIX.length() ) ); File themeFile = new File( theme.substring( FILE_PREFIX.length() ) );
String themeName = StringUtils.removeTrailing( themeFile.getName(), ".properties" ); String themeName = StringUtils.removeTrailing( themeFile.getName(), ".properties" );
FlatLaf.install( new FlatPropertiesLaf( themeName, themeFile ) ); FlatLaf.setup( new FlatPropertiesLaf( themeName, themeFile ) );
} else } else
FlatLightLaf.install(); FlatLightLaf.setup();
if( !theme.isEmpty() ) if( !theme.isEmpty() )
UIManager.getLookAndFeelDefaults().put( THEME_UI_KEY, theme ); UIManager.getLookAndFeelDefaults().put( THEME_UI_KEY, theme );
@@ -86,7 +86,7 @@ public class DemoPrefs
ex.printStackTrace(); ex.printStackTrace();
// fallback // fallback
FlatLightLaf.install(); FlatLightLaf.setup();
} }
// remember active look and feel // remember active look and feel

View File

@@ -48,7 +48,7 @@ public class FlatLafDemo
FlatLaf.registerCustomDefaultsSource( "com.formdev.flatlaf.demo" ); FlatLaf.registerCustomDefaultsSource( "com.formdev.flatlaf.demo" );
// set look and feel // set look and feel
DemoPrefs.initLaf( args ); DemoPrefs.setupLaf( args );
// install inspectors // install inspectors
FlatInspector.install( "ctrl shift alt X" ); FlatInspector.install( "ctrl shift alt X" );

View File

@@ -18,8 +18,13 @@ package com.formdev.flatlaf.demo.extras;
import javax.swing.*; import javax.swing.*;
import com.formdev.flatlaf.extras.*; import com.formdev.flatlaf.extras.*;
import com.formdev.flatlaf.extras.FlatSVGIcon.ColorFilter;
import com.formdev.flatlaf.extras.components.FlatTriStateCheckBox; import com.formdev.flatlaf.extras.components.FlatTriStateCheckBox;
import com.formdev.flatlaf.util.HSLColor;
import net.miginfocom.swing.*; import net.miginfocom.swing.*;
import java.awt.*;
import java.awt.event.HierarchyEvent;
import java.util.function.Function;
/** /**
* @author Karl Tauber * @author Karl Tauber
@@ -27,6 +32,9 @@ import net.miginfocom.swing.*;
public class ExtrasPanel public class ExtrasPanel
extends JPanel extends JPanel
{ {
private Timer rainbowIconTimer;
private int rainbowCounter = 0;
public ExtrasPanel() { public ExtrasPanel() {
initComponents(); initComponents();
@@ -50,6 +58,34 @@ public class ExtrasPanel
addSVGIcon( "errorDialog.svg" ); addSVGIcon( "errorDialog.svg" );
addSVGIcon( "informationDialog.svg" ); addSVGIcon( "informationDialog.svg" );
addSVGIcon( "warningDialog.svg" ); addSVGIcon( "warningDialog.svg" );
initRainbowIcon();
}
private void initRainbowIcon() {
FlatSVGIcon icon = new FlatSVGIcon( "com/formdev/flatlaf/demo/extras/svg/informationDialog.svg" );
icon.setColorFilter( new ColorFilter( color -> {
rainbowCounter += 1;
rainbowCounter %= 255;
return Color.getHSBColor( rainbowCounter / 255f, 1, 1 );
} ) );
rainbowIcon.setIcon( icon );
rainbowIconTimer = new Timer( 30, e -> {
rainbowIcon.repaint();
} );
// start rainbow timer only if panel is shown ("Extras" tab is active)
addHierarchyListener( e -> {
if( e.getID() == HierarchyEvent.HIERARCHY_CHANGED &&
(e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0 )
{
if( isShowing() )
rainbowIconTimer.start();
else
rainbowIconTimer.stop();
}
} );
} }
private void addSVGIcon( String name ) { private void addSVGIcon( String name ) {
@@ -60,6 +96,36 @@ public class ExtrasPanel
triStateLabel1.setText( triStateCheckBox1.getState().toString() ); triStateLabel1.setText( triStateCheckBox1.getState().toString() );
} }
private void redChanged() {
brighterToggleButton.setSelected( false );
Function<Color, Color> mapper = null;
if( redToggleButton.isSelected() ) {
float[] redHSL = HSLColor.fromRGB( Color.red );
mapper = color -> {
float[] hsl = HSLColor.fromRGB( color );
return HSLColor.toRGB( redHSL[0], 70, hsl[2] );
};
}
FlatSVGIcon.ColorFilter.getInstance().setMapper( mapper );
// repaint whole application window because global color filter also affects
// icons in menubar, toolbar, etc.
SwingUtilities.windowForComponent( this ).repaint();
}
private void brighterChanged() {
redToggleButton.setSelected( false );
FlatSVGIcon.ColorFilter.getInstance().setMapper( brighterToggleButton.isSelected()
? color -> color.brighter().brighter()
: null );
// repaint whole application window because global color filter also affects
// icons in menubar, toolbar, etc.
SwingUtilities.windowForComponent( this ).repaint();
}
private void initComponents() { private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents // JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
label4 = new JLabel(); label4 = new JLabel();
@@ -69,6 +135,13 @@ public class ExtrasPanel
label2 = new JLabel(); label2 = new JLabel();
svgIconsPanel = new JPanel(); svgIconsPanel = new JPanel();
label3 = new JLabel(); label3 = new JLabel();
separator1 = new JSeparator();
label5 = new JLabel();
label6 = new JLabel();
rainbowIcon = new JLabel();
label7 = new JLabel();
redToggleButton = new JToggleButton();
brighterToggleButton = new JToggleButton();
//======== this ======== //======== this ========
setLayout(new MigLayout( setLayout(new MigLayout(
@@ -81,6 +154,10 @@ public class ExtrasPanel
"[]para" + "[]para" +
"[]" + "[]" +
"[]" + "[]" +
"[]" +
"[]" +
"[]" +
"[]" +
"[]")); "[]"));
//---- label4 ---- //---- label4 ----
@@ -119,6 +196,30 @@ public class ExtrasPanel
//---- label3 ---- //---- label3 ----
label3.setText("The icons may change colors when switching to another theme."); label3.setText("The icons may change colors when switching to another theme.");
add(label3, "cell 1 3 2 1"); add(label3, "cell 1 3 2 1");
add(separator1, "cell 1 4 2 1,growx");
//---- label5 ----
label5.setText("Color filters can be also applied to icons. Globally or for each instance.");
add(label5, "cell 1 5 2 1");
//---- label6 ----
label6.setText("Rainbow color filter");
add(label6, "cell 1 6 2 1");
add(rainbowIcon, "cell 1 6 2 1");
//---- label7 ----
label7.setText("Global icon color filter");
add(label7, "cell 1 7 2 1");
//---- redToggleButton ----
redToggleButton.setText("Toggle RED");
redToggleButton.addActionListener(e -> redChanged());
add(redToggleButton, "cell 1 7 2 1");
//---- brighterToggleButton ----
brighterToggleButton.setText("Toggle brighter");
brighterToggleButton.addActionListener(e -> brighterChanged());
add(brighterToggleButton, "cell 1 7 2 1");
// JFormDesigner - End of component initialization //GEN-END:initComponents // JFormDesigner - End of component initialization //GEN-END:initComponents
} }
@@ -130,5 +231,12 @@ public class ExtrasPanel
private JLabel label2; private JLabel label2;
private JPanel svgIconsPanel; private JPanel svgIconsPanel;
private JLabel label3; private JLabel label3;
private JSeparator separator1;
private JLabel label5;
private JLabel label6;
private JLabel rainbowIcon;
private JLabel label7;
private JToggleButton redToggleButton;
private JToggleButton brighterToggleButton;
// JFormDesigner - End of variables declaration //GEN-END:variables // JFormDesigner - End of variables declaration //GEN-END:variables
} }

View File

@@ -1,4 +1,4 @@
JFDML JFormDesigner: "7.0.2.0.298" Java: "14" encoding: "UTF-8" JFDML JFormDesigner: "7.0.3.1.342" Java: "16" encoding: "UTF-8"
new FormModel { new FormModel {
contentType: "form/swing" contentType: "form/swing"
@@ -6,7 +6,7 @@ new FormModel {
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "insets dialog,hidemode 3" "$layoutConstraints": "insets dialog,hidemode 3"
"$columnConstraints": "[][][left]" "$columnConstraints": "[][][left]"
"$rowConstraints": "[]para[][][]" "$rowConstraints": "[]para[][][][][][][]"
} ) { } ) {
name: "this" name: "this"
add( new FormComponent( "javax.swing.JLabel" ) { add( new FormComponent( "javax.swing.JLabel" ) {
@@ -56,6 +56,48 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 3 2 1" "value": "cell 1 3 2 1"
} ) } )
add( new FormComponent( "javax.swing.JSeparator" ) {
name: "separator1"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 4 2 1,growx"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "label5"
"text": "Color filters can be also applied to icons. Globally or for each instance."
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 5 2 1"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "label6"
"text": "Rainbow color filter"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 6 2 1"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "rainbowIcon"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 6 2 1"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "label7"
"text": "Global icon color filter"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 7 2 1"
} )
add( new FormComponent( "javax.swing.JToggleButton" ) {
name: "redToggleButton"
"text": "Toggle RED"
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "redChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 7 2 1"
} )
add( new FormComponent( "javax.swing.JToggleButton" ) {
name: "brighterToggleButton"
"text": "Toggle brighter"
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "brighterChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 7 2 1"
} )
}, new FormLayoutConstraints( null ) { }, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 0, 0 ) "location": new java.awt.Point( 0, 0 )
"size": new java.awt.Dimension( 500, 300 ) "size": new java.awt.Dimension( 500, 300 )

View File

@@ -160,14 +160,22 @@ public class IJThemesClassGenerator
"{\n" + "{\n" +
" public static final String NAME = \"${themeName}\";\n" + " public static final String NAME = \"${themeName}\";\n" +
"\n" + "\n" +
" public static boolean install() {\n" + " public static boolean setup() {\n" +
" try {\n" + " try {\n" +
" return install( new ${themeClass}() );\n" + " return setup( new ${themeClass}() );\n" +
" } catch( RuntimeException ex ) {\n" + " } catch( RuntimeException ex ) {\n" +
" return false;\n" + " return false;\n" +
" }\n" + " }\n" +
" }\n" + " }\n" +
"\n" + "\n" +
" /**\n" +
" * @deprecated use {@link #setup()} instead; this method will be removed in a future version\n" +
" */\n" +
" @Deprecated\n" +
" public static boolean install() {\n" +
" return setup();\n" +
" }\n" +
"\n" +
" public static void installLafInfo() {\n" + " public static void installLafInfo() {\n" +
" installLafInfo( NAME, ${themeClass}.class );\n" + " installLafInfo( NAME, ${themeClass}.class );\n" +
" }\n" + " }\n" +

View File

@@ -0,0 +1,72 @@
/*
* Copyright 2021 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.demo.intellijthemes;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.Map;
import com.formdev.flatlaf.json.Json;
import com.formdev.flatlaf.json.ParseException;
/**
* This tool checks whether there are duplicate name fields in all theme .json files.
*
* This is important for following file, where the name is used for theme specific UI defaults:
* flatlaf-core/src/main/resources/com/formdev/flatlaf/IntelliJTheme$ThemeLaf.properties
*
* @author Karl Tauber
*/
public class IJThemesDuplicateNameChecker
{
public static void main( String[] args ) {
IJThemesManager themesManager = new IJThemesManager();
themesManager.loadBundledThemes();
HashSet<String> names = new HashSet<>();
for( IJThemeInfo ti : themesManager.bundledThemes ) {
if( ti.sourceCodeUrl == null || ti.sourceCodePath == null )
continue;
String jsonPath = "../flatlaf-intellij-themes/src/main/resources" + IJThemesPanel.THEMES_PACKAGE + ti.resourceName;
String name;
try {
name = readNameFromJson( jsonPath );
} catch( IOException ex ) {
System.err.println( "Failed to read '" + jsonPath + "'" );
continue;
}
if( names.contains( name ) )
System.out.println( "Duplicate name '" + name + "'" );
names.add( name );
}
}
private static String readNameFromJson( String jsonPath ) throws IOException {
try( Reader reader = new InputStreamReader( new FileInputStream( jsonPath ), StandardCharsets.UTF_8 ) ) {
@SuppressWarnings( "unchecked" )
Map<String, Object> json = (Map<String, Object>) Json.parse( reader );
return (String) json.get( "name" );
} catch( ParseException ex ) {
throw new IOException( ex.getMessage(), ex );
}
}
}

View File

@@ -267,9 +267,9 @@ public class IJThemesPanel
try { try {
if( themeInfo.themeFile.getName().endsWith( ".properties" ) ) { if( themeInfo.themeFile.getName().endsWith( ".properties" ) ) {
FlatLaf.install( new FlatPropertiesLaf( themeInfo.name, themeInfo.themeFile ) ); FlatLaf.setup( new FlatPropertiesLaf( themeInfo.name, themeInfo.themeFile ) );
} else } else
FlatLaf.install( IntelliJTheme.createLaf( new FileInputStream( themeInfo.themeFile ) ) ); FlatLaf.setup( IntelliJTheme.createLaf( new FileInputStream( themeInfo.themeFile ) ) );
DemoPrefs.getState().put( DemoPrefs.KEY_LAF_THEME, DemoPrefs.FILE_PREFIX + themeInfo.themeFile ); DemoPrefs.getState().put( DemoPrefs.KEY_LAF_THEME, DemoPrefs.FILE_PREFIX + themeInfo.themeFile );
} catch( Exception ex ) { } catch( Exception ex ) {
@@ -279,7 +279,7 @@ public class IJThemesPanel
} else { } else {
FlatAnimatedLafChange.showSnapshot(); FlatAnimatedLafChange.showSnapshot();
IntelliJTheme.install( getClass().getResourceAsStream( THEMES_PACKAGE + themeInfo.resourceName ) ); IntelliJTheme.setup( getClass().getResourceAsStream( THEMES_PACKAGE + themeInfo.resourceName ) );
DemoPrefs.getState().put( DemoPrefs.KEY_LAF_THEME, DemoPrefs.RESOURCE_PREFIX + themeInfo.resourceName ); DemoPrefs.getState().put( DemoPrefs.KEY_LAF_THEME, DemoPrefs.RESOURCE_PREFIX + themeInfo.resourceName );
} }

View File

@@ -302,6 +302,22 @@
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite", "sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/GitHub Contrast.theme.json" "sourceCodePath": "blob/master/src/main/resources/themes/GitHub Contrast.theme.json"
}, },
"material-theme-ui-lite/GitHub Dark.theme.json": {
"name": "Material Theme UI Lite / GitHub Dark",
"dark": true,
"license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/GitHub Dark.theme.json"
},
"material-theme-ui-lite/GitHub Dark Contrast.theme.json": {
"name": "Material Theme UI Lite / GitHub Dark Contrast",
"dark": true,
"license": "MIT",
"licenseFile": "material-theme-ui-lite/Material Theme UI Lite.LICENSE.txt",
"sourceCodeUrl": "https://github.com/mallowigi/material-theme-ui-lite",
"sourceCodePath": "blob/master/src/main/resources/themes/GitHub Dark Contrast.theme.json"
},
"material-theme-ui-lite/Light Owl.theme.json": { "material-theme-ui-lite/Light Owl.theme.json": {
"name": "Material Theme UI Lite / Light Owl", "name": "Material Theme UI Lite / Light Owl",
"license": "MIT", "license": "MIT",

View File

@@ -34,18 +34,6 @@ java {
withJavadocJar() withJavadocJar()
} }
tasks {
javadoc {
options {
this as StandardJavadocDocletOptions
use( true )
tags = listOf( "uiDefault", "clientProperty" )
addStringOption( "Xdoclint:all,-missing", "-Xdoclint:all,-missing" )
}
isFailOnError = false
}
}
flatlafPublish { flatlafPublish {
artifactId = "flatlaf-extras" artifactId = "flatlaf-extras"
name = "FlatLaf Extras" name = "FlatLaf Extras"

View File

@@ -46,6 +46,7 @@ import java.beans.PropertyChangeSupport;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import javax.swing.AbstractButton; import javax.swing.AbstractButton;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JLayeredPane;
import javax.swing.JMenuBar; import javax.swing.JMenuBar;
import javax.swing.JRootPane; import javax.swing.JRootPane;
import javax.swing.JToolBar; import javax.swing.JToolBar;
@@ -55,6 +56,7 @@ import javax.swing.Popup;
import javax.swing.PopupFactory; import javax.swing.PopupFactory;
import javax.swing.RootPaneContainer; import javax.swing.RootPaneContainer;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.Border; import javax.swing.border.Border;
import javax.swing.border.EmptyBorder; import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder; import javax.swing.border.LineBorder;
@@ -87,9 +89,13 @@ import com.formdev.flatlaf.util.UIScale;
*/ */
public class FlatInspector public class FlatInspector
{ {
private static final Integer HIGHLIGHT_LAYER = 401; private static final Integer HIGHLIGHT_LAYER = JLayeredPane.POPUP_LAYER - 1;
private static final int KEY_MODIFIERS_MASK = InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK | InputEvent.ALT_DOWN_MASK | InputEvent.META_DOWN_MASK; private static final int KEY_MODIFIERS_MASK =
InputEvent.CTRL_DOWN_MASK |
InputEvent.SHIFT_DOWN_MASK |
InputEvent.ALT_DOWN_MASK |
InputEvent.META_DOWN_MASK;
private final JRootPane rootPane; private final JRootPane rootPane;
private final MouseMotionListener mouseMotionListener; private final MouseMotionListener mouseMotionListener;
@@ -103,7 +109,8 @@ public class FlatInspector
private int lastX; private int lastX;
private int lastY; private int lastY;
private int inspectParentLevel; private int inspectParentLevel;
private boolean wasCtrlOrShiftKeyPressed; private boolean wasModifierKeyPressed;
private boolean showClassHierarchy;
private JComponent highlightFigure; private JComponent highlightFigure;
private Popup popup; private Popup popup;
@@ -160,9 +167,9 @@ public class FlatInspector
if( id == KeyEvent.KEY_PRESSED ) { if( id == KeyEvent.KEY_PRESSED ) {
// this avoids that the inspection level is changed when UI inspector // this avoids that the inspection level is changed when UI inspector
// is enabled with keyboard shortcut (e.g. Ctrl+Shift+Alt+X) // is enabled with keyboard shortcut (e.g. Ctrl+Shift+Alt+X)
if( keyCode == KeyEvent.VK_CONTROL || keyCode == KeyEvent.VK_SHIFT ) if( keyCode == KeyEvent.VK_CONTROL || keyCode == KeyEvent.VK_SHIFT || keyCode == KeyEvent.VK_ALT )
wasCtrlOrShiftKeyPressed = true; wasModifierKeyPressed = true;
} else if( id == KeyEvent.KEY_RELEASED && wasCtrlOrShiftKeyPressed ) { } else if( id == KeyEvent.KEY_RELEASED && wasModifierKeyPressed ) {
if( keyCode == KeyEvent.VK_CONTROL ) { if( keyCode == KeyEvent.VK_CONTROL ) {
inspectParentLevel++; inspectParentLevel++;
int parentLevel = inspect( lastX, lastY ); int parentLevel = inspect( lastX, lastY );
@@ -179,6 +186,9 @@ public class FlatInspector
inspectParentLevel = Math.max( parentLevel - 1, 0 ); inspectParentLevel = Math.max( parentLevel - 1, 0 );
inspect( lastX, lastY ); inspect( lastX, lastY );
} }
} else if( keyCode == KeyEvent.VK_ALT && lastComponent != null) {
showClassHierarchy = !showClassHierarchy;
showToolTip( lastComponent, lastX, lastY, inspectParentLevel );
} }
} }
@@ -401,7 +411,7 @@ public class FlatInspector
return; return;
JToolTip tip = new JToolTip(); JToolTip tip = new JToolTip();
tip.setTipText( buildToolTipText( c, parentLevel ) ); tip.setTipText( buildToolTipText( c, parentLevel, showClassHierarchy ) );
tip.putClientProperty( FlatClientProperties.POPUP_FORCE_HEAVY_WEIGHT, true ); tip.putClientProperty( FlatClientProperties.POPUP_FORCE_HEAVY_WEIGHT, true );
Point pt = new Point( x, y ); Point pt = new Point( x, y );
@@ -427,16 +437,13 @@ public class FlatInspector
popup.show(); popup.show();
} }
private static String buildToolTipText( Component c, int parentLevel ) { private static String buildToolTipText( Component c, int parentLevel, boolean classHierarchy ) {
StringBuilder buf = new StringBuilder( 1500 ); StringBuilder buf = new StringBuilder( 1500 );
buf.append( "<html><style>" ); buf.append( "<html><style>" );
buf.append( "td { padding: 0 10 0 0; }" ); buf.append( "td { padding: 0 10 0 0; }" );
buf.append( "</style><table>" ); buf.append( "</style><table>" );
String name = c.getClass().getName(); appendRow( buf, "Class", toString( c.getClass(), classHierarchy ) );
name = name.substring( name.lastIndexOf( '.' ) + 1 );
Package pkg = c.getClass().getPackage();
appendRow( buf, "Class", name + " (" + (pkg != null ? pkg.getName() : "-") + ")" );
appendRow( buf, "Size", c.getWidth() + ", " + c.getHeight() + "&nbsp;&nbsp; @ " + c.getX() + ", " + c.getY() ); appendRow( buf, "Size", c.getWidth() + ", " + c.getHeight() + "&nbsp;&nbsp; @ " + c.getX() + ", " + c.getY() );
if( c instanceof Container ) if( c instanceof Container )
@@ -463,7 +470,7 @@ public class FlatInspector
appendRow( buf, "Max size", maxSize.width + ", " + maxSize.height ); appendRow( buf, "Max size", maxSize.width + ", " + maxSize.height );
if( c instanceof JComponent ) if( c instanceof JComponent )
appendRow( buf, "Border", toString( ((JComponent)c).getBorder() ) ); appendRow( buf, "Border", toString( ((JComponent)c).getBorder(), classHierarchy ) );
appendRow( buf, "Background", toString( c.getBackground() ) ); appendRow( buf, "Background", toString( c.getBackground() ) );
appendRow( buf, "Foreground", toString( c.getForeground() ) ); appendRow( buf, "Foreground", toString( c.getForeground() ) );
@@ -474,7 +481,7 @@ public class FlatInspector
Field f = JComponent.class.getDeclaredField( "ui" ); Field f = JComponent.class.getDeclaredField( "ui" );
f.setAccessible( true ); f.setAccessible( true );
Object ui = f.get( c ); Object ui = f.get( c );
appendRow( buf, "UI", (ui != null ? ui.getClass().getName() : "null") ); appendRow( buf, "UI", (ui != null ? toString( ui.getClass(), classHierarchy ) : "null") );
} catch( Exception ex ) { } catch( Exception ex ) {
// ignore // ignore
} }
@@ -483,7 +490,7 @@ public class FlatInspector
if( c instanceof Container ) { if( c instanceof Container ) {
LayoutManager layout = ((Container)c).getLayout(); LayoutManager layout = ((Container)c).getLayout();
if( layout != null ) if( layout != null )
appendRow( buf, "Layout", layout.getClass().getName() ); appendRow( buf, "Layout", toString( layout.getClass(), classHierarchy ) );
} }
appendRow( buf, "Enabled", String.valueOf( c.isEnabled() ) ); appendRow( buf, "Enabled", String.valueOf( c.isEnabled() ) );
@@ -493,16 +500,23 @@ public class FlatInspector
appendRow( buf, "ContentAreaFilled", String.valueOf( ((AbstractButton)c).isContentAreaFilled() ) ); appendRow( buf, "ContentAreaFilled", String.valueOf( ((AbstractButton)c).isContentAreaFilled() ) );
appendRow( buf, "Focusable", String.valueOf( c.isFocusable() ) ); appendRow( buf, "Focusable", String.valueOf( c.isFocusable() ) );
appendRow( buf, "Left-to-right", String.valueOf( c.getComponentOrientation().isLeftToRight() ) ); appendRow( buf, "Left-to-right", String.valueOf( c.getComponentOrientation().isLeftToRight() ) );
appendRow( buf, "Parent", (c.getParent() != null ? c.getParent().getClass().getName() : "null") ); appendRow( buf, "Parent", (c.getParent() != null ? toString( c.getParent().getClass(), classHierarchy ) : "null") );
// append parent level
buf.append( "<tr><td colspan=\"2\">" ); buf.append( "<tr><td colspan=\"2\">" );
if( parentLevel > 0 ) if( parentLevel > 0 )
buf.append( "<br>Parent level: " + parentLevel ); buf.append( "<br>Parent level: " + parentLevel );
if( parentLevel > 0 ) // append modifier keys hint
buf.append( "<br>(press Ctrl/Shift to increase/decrease level)" ); buf.append( "<br>(" )
else .append( (parentLevel > 0)
buf.append( "<br>(press Ctrl key to inspect parent)" ); ? "press <b>Ctrl/Shift</b> to increase/decrease level"
: "press <b>Ctrl</b> key to inspect parent" )
.append( "; &nbsp;" )
.append( classHierarchy
? "press <b>Alt</b> key to hide class hierarchy"
: "press <b>Alt</b> key to show class hierarchy" )
.append( ')' );
buf.append( "</td></tr>" ); buf.append( "</td></tr>" );
buf.append( "</table></html>" ); buf.append( "</table></html>" );
@@ -511,13 +525,43 @@ public class FlatInspector
} }
private static void appendRow( StringBuilder buf, String key, String value ) { private static void appendRow( StringBuilder buf, String key, String value ) {
buf.append( "<tr><td>" ) buf.append( "<tr><td valign=\"top\">" )
.append( key ) .append( key )
.append( ":</td><td>" ) .append( ":</td><td>" )
.append( value ) .append( value )
.append( "</td></tr>" ); .append( "</td></tr>" );
} }
private static String toString( Class<?> cls, boolean classHierarchy ) {
StringBuilder buf = new StringBuilder( 100 );
int level = 0;
while( cls != null ) {
if( level > 0 ) {
if( cls == Object.class )
break;
buf.append( "<br>&nbsp;" );
for( int i = 1; i < level; i++ )
buf.append( "&nbsp;&nbsp;&nbsp;&nbsp;" );
buf.append( "\u2570 " );
}
level++;
String name = cls.getName();
int dot = name.lastIndexOf( '.' );
String pkg = (dot >= 0) ? name.substring( 0, dot ) : "-";
String simpleName = (dot >= 0) ? name.substring( dot + 1 ) : name;
buf.append( simpleName ).append( ' ' ).append( toDimmedText( "(" + pkg + ")" ) );
if( !classHierarchy )
break;
cls = cls.getSuperclass();
}
return buf.toString();
}
private static String toString( Insets insets ) { private static String toString( Insets insets ) {
if( insets == null ) if( insets == null )
return "null"; return "null";
@@ -563,11 +607,11 @@ public class FlatInspector
+ (f instanceof UIResource ? " UI" : ""); + (f instanceof UIResource ? " UI" : "");
} }
private static String toString( Border b ) { private static String toString( Border b, boolean classHierarchy ) {
if( b == null ) if( b == null )
return "null"; return "null";
String s = b.getClass().getName(); String s = toString( b.getClass(), classHierarchy );
if( b instanceof EmptyBorder ) if( b instanceof EmptyBorder )
s += '(' + toString( ((EmptyBorder)b).getBorderInsets() ) + ')'; s += '(' + toString( ((EmptyBorder)b).getBorderInsets() ) + ')';
@@ -577,4 +621,14 @@ public class FlatInspector
return s; return s;
} }
private static String toDimmedText( String text ) {
Color color = UIManager.getColor( "Label.disabledForeground" );
if( color == null )
color = UIManager.getColor( "Label.disabledText" );
if( color == null )
color = Color.GRAY;
return String.format( "<span color=\"#%06x\">%s</span>",
color.getRGB() & 0xffffff, text );
}
} }

View File

@@ -29,6 +29,7 @@ import java.awt.image.BufferedImage;
import java.awt.image.RGBImageFilter; import java.awt.image.RGBImageFilter;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.function.Function; import java.util.function.Function;
@@ -66,6 +67,8 @@ public class FlatSVGIcon
private final boolean disabled; private final boolean disabled;
private final ClassLoader classLoader; private final ClassLoader classLoader;
private ColorFilter colorFilter;
private SVGDiagram diagram; private SVGDiagram diagram;
private boolean dark; private boolean dark;
@@ -159,17 +162,82 @@ public class FlatSVGIcon
this( name, -1, -1, scale, false, classLoader ); this( name, -1, -1, scale, false, classLoader );
} }
private FlatSVGIcon( String name, int width, int height, float scale, boolean disabled, ClassLoader classLoader ) { protected FlatSVGIcon( String name, int width, int height, float scale, boolean disabled, ClassLoader classLoader ) {
this.name = name; this.name = name;
this.classLoader = classLoader;
this.width = width; this.width = width;
this.height = height; this.height = height;
this.scale = scale; this.scale = scale;
this.disabled = disabled; this.disabled = disabled;
this.classLoader = classLoader;
}
/**
* Returns the name of the SVG resource (a '/'-separated path).
*
* @since 1.2
*/
public String getName() {
return name;
}
/**
* Returns the custom icon width specified in {@link #FlatSVGIcon(String, int, int)},
* {@link #FlatSVGIcon(String, int, int, ClassLoader)} or {@link #derive(int, int)}.
* Otherwise {@code -1} is returned.
* <p>
* To get the painted icon width, use {@link #getIconWidth()}.
*
* @since 1.2
*/
public int getWidth() {
return width;
}
/**
* Returns the custom icon height specified in {@link #FlatSVGIcon(String, int, int)},
* {@link #FlatSVGIcon(String, int, int, ClassLoader)} or {@link #derive(int, int)}.
* Otherwise {@code -1} is returned.
* <p>
* To get the painted icon height, use {@link #getIconHeight()}.
*
* @since 1.2
*/
public int getHeight() {
return height;
}
/**
* Returns the amount by which the icon size is scaled. Usually {@code 1}.
*
* @since 1.2
*/
public float getScale() {
return scale;
}
/**
* Returns whether the icon is pained in "disabled" state.
*
* @see #getDisabledIcon()
* @since 1.2
*/
public boolean isDisabled() {
return disabled;
}
/**
* Returns the class loader used to load the SVG resource.
*
* @since 1.2
*/
public ClassLoader getClassLoader() {
return classLoader;
} }
/** /**
* Creates a new icon with given width and height, which is derived from this icon. * Creates a new icon with given width and height, which is derived from this icon.
* <p>
* If the icon has a color filter, then it is shared with the new icon.
* *
* @param width the width of the new icon * @param width the width of the new icon
* @param height the height of the new icon * @param height the height of the new icon
@@ -179,7 +247,8 @@ public class FlatSVGIcon
if( width == this.width && height == this.height ) if( width == this.width && height == this.height )
return this; return this;
FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, false, classLoader ); FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, disabled, classLoader );
icon.colorFilter = colorFilter;
icon.diagram = diagram; icon.diagram = diagram;
icon.dark = dark; icon.dark = dark;
return icon; return icon;
@@ -187,6 +256,8 @@ public class FlatSVGIcon
/** /**
* Creates a new icon with given scaling, which is derived from this icon. * Creates a new icon with given scaling, which is derived from this icon.
* <p>
* If the icon has a color filter, then it is shared with the new icon.
* *
* @param scale the amount by which the icon size is scaled * @param scale the amount by which the icon size is scaled
* @return a new icon * @return a new icon
@@ -195,7 +266,8 @@ public class FlatSVGIcon
if( scale == this.scale ) if( scale == this.scale )
return this; return this;
FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, false, classLoader ); FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, disabled, classLoader );
icon.colorFilter = colorFilter;
icon.diagram = diagram; icon.diagram = diagram;
icon.dark = dark; icon.dark = dark;
return icon; return icon;
@@ -203,6 +275,8 @@ public class FlatSVGIcon
/** /**
* Creates a new icon with disabled appearance, which is derived from this icon. * Creates a new icon with disabled appearance, which is derived from this icon.
* <p>
* If the icon has a color filter, then it is shared with the new icon.
* *
* @return a new icon * @return a new icon
*/ */
@@ -212,11 +286,42 @@ public class FlatSVGIcon
return this; return this;
FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, true, classLoader ); FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, true, classLoader );
icon.colorFilter = colorFilter;
icon.diagram = diagram; icon.diagram = diagram;
icon.dark = dark; icon.dark = dark;
return icon; return icon;
} }
/**
* Returns the currently active color filter or {@code null}.
*
* @since 1.2
*/
public ColorFilter getColorFilter() {
return colorFilter;
}
/**
* Sets a color filter that can freely modify colors of this icon during painting.
* <p>
* This method accepts a {@link ColorFilter}. Usually you would want to use a ColorFilter created using the
* {@link ColorFilter#ColorFilter(Function)} constructor.
* <p>
* This can be used to brighten colors of the icon:
* <pre>icon.setColorFilter( new FlatSVGIcon.ColorFilter( color -&gt; color.brighter() ) );</pre>
* <p>
* Using a filter, icons can also be turned monochrome (painted with a single color):
* <pre>icon.setColorFilter( new FlatSVGIcon.ColorFilter( color -&gt; Color.RED ) );</pre>
* <p>
* Note: If a filter is already set, it will be replaced.
*
* @param colorFilter The color filter
* @since 1.2
*/
public void setColorFilter( ColorFilter colorFilter ) {
this.colorFilter = colorFilter;
}
private void update() { private void update() {
if( dark == isDarkLaf() && diagram != null ) if( dark == isDarkLaf() && diagram != null )
return; return;
@@ -303,7 +408,7 @@ public class FlatSVGIcon
: GrayFilter.createDisabledIconFilter( dark ); : GrayFilter.createDisabledIconFilter( dark );
} }
Graphics2D g2 = new GraphicsFilter( (Graphics2D) g.create(), ColorFilter.getInstance(), grayFilter ); Graphics2D g2 = new GraphicsFilter( (Graphics2D) g.create(), colorFilter, ColorFilter.getInstance(), grayFilter );
try { try {
FlatUIUtils.setRenderingHints( g2 ); FlatUIUtils.setRenderingHints( g2 );
@@ -383,7 +488,14 @@ public class FlatSVGIcon
private static Boolean darkLaf; private static Boolean darkLaf;
private static boolean isDarkLaf() { /**
* Checks whether the current look and feel is dark.
* <p>
* Uses {@link FlatLaf#isLafDark()} and caches the result.
*
* @since 1.2
*/
public static boolean isDarkLaf() {
if( darkLaf == null ) { if( darkLaf == null ) {
lafChanged(); lafChanged();
@@ -401,53 +513,253 @@ public class FlatSVGIcon
//---- class ColorFilter -------------------------------------------------- //---- class ColorFilter --------------------------------------------------
/**
* A color filter that can modify colors of a painted {@link FlatSVGIcon}.
* <p>
* The ColorFilter modifies color in two ways.
* Either using a color map, where specific colors are mapped to different ones.
* And/or by modifying the colors in a mapper function.
* <p>
* When filtering a color, mappings are applied first, then the mapper function is applied.
* <p>
* Global {@link FlatSVGIcon} ColorFilter can be retrieved using the {@link ColorFilter#getInstance()} method.
*/
public static class ColorFilter public static class ColorFilter
{ {
private static ColorFilter instance; private static ColorFilter instance;
private final Map<Integer, String> rgb2keyMap = new HashMap<>(); private Map<Integer, String> rgb2keyMap;
private final Map<Color, Color> color2colorMap = new HashMap<>(); private Map<Color, Color> colorMap;
private Map<Color, Color> darkColorMap;
private Function<Color, Color> mapper;
/**
* Returns the global ColorFilter that is applied to all icons.
*/
public static ColorFilter getInstance() { public static ColorFilter getInstance() {
if( instance == null ) if( instance == null ) {
instance = new ColorFilter(); instance = new ColorFilter();
// add default color palette
instance.rgb2keyMap = new HashMap<>();
for( FlatIconColors c : FlatIconColors.values() )
instance.rgb2keyMap.put( c.rgb, c.key );
}
return instance; return instance;
} }
/**
* Creates an empty color filter.
*/
public ColorFilter() { public ColorFilter() {
for( FlatIconColors c : FlatIconColors.values() )
rgb2keyMap.put( c.rgb, c.key );
} }
public void addAll( Map<Color, Color> from2toMap ) { /**
color2colorMap.putAll( from2toMap ); * Creates a color filter with a color modifying function that changes painted colors.
* The {@link Function} gets passed the original color and returns a modified one.
* <p>
* Examples:
* A ColorFilter can be used to brighten colors of the icon:
* <pre>new ColorFilter( color -&gt; color.brighter() );</pre>
* <p>
* Using a ColorFilter, icons can also be turned monochrome (painted with a single color):
* <pre>new ColorFilter( color -&gt; Color.RED );</pre>
*
* @param mapper The color mapper function
* @since 1.2
*/
public ColorFilter( Function<Color, Color> mapper ) {
setMapper( mapper );
} }
public void add( Color from, Color to ) { /**
color2colorMap.put( from, to ); * Returns a color modifying function or {@code null}
*
* @since 1.2
*/
public Function<Color, Color> getMapper() {
return mapper;
} }
public void remove( Color from ) { /**
color2colorMap.remove( from ); * Sets a color modifying function that changes painted colors.
* The {@link Function} gets passed the original color and returns a modified one.
* <p>
* Examples:
* A ColorFilter can be used to brighten colors of the icon:
* <pre>filter.setMapper( color -&gt; color.brighter() );</pre>
* <p>
* Using a ColorFilter, icons can also be turned monochrome (painted with a single color):
* <pre>filter.setMapper( color -&gt; Color.RED );</pre>
*
* @param mapper The color mapper function
* @since 1.2
*/
public void setMapper( Function<Color, Color> mapper ) {
this.mapper = mapper;
}
/**
* Returns the color mappings used for light themes.
*
* @since 1.2
*/
public Map<Color, Color> getLightColorMap() {
return (colorMap != null)
? Collections.unmodifiableMap( colorMap )
: Collections.emptyMap();
}
/**
* Returns the color mappings used for dark themes.
*
* @since 1.2
*/
public Map<Color, Color> getDarkColorMap() {
return (darkColorMap != null)
? Collections.unmodifiableMap( darkColorMap )
: getLightColorMap();
}
/**
* Adds color mappings. Used for light and dark themes.
*/
public ColorFilter addAll( Map<Color, Color> from2toMap ) {
ensureColorMap();
colorMap.putAll( from2toMap );
if( darkColorMap != null )
darkColorMap.putAll( from2toMap );
return this;
}
/**
* Adds a color mappings, which has different colors for light and dark themes.
*
* @since 1.2
*/
public ColorFilter addAll( Map<Color, Color> from2toLightMap, Map<Color, Color> from2toDarkMap ) {
ensureColorMap();
ensureDarkColorMap();
colorMap.putAll( from2toLightMap );
darkColorMap.putAll( from2toDarkMap );
return this;
}
/**
* Adds a color mapping. Used for light and dark themes.
*/
public ColorFilter add( Color from, Color to ) {
ensureColorMap();
colorMap.put( from, to );
if( darkColorMap != null )
darkColorMap.put( from, to );
return this;
}
/**
* Adds a color mapping, which has different colors for light and dark themes.
*
* @since 1.2
*/
public ColorFilter add( Color from, Color toLight, Color toDark ) {
ensureColorMap();
ensureDarkColorMap();
if( toLight != null )
colorMap.put( from, toLight );
if( toDark != null )
darkColorMap.put( from, toDark );
return this;
}
/**
* Removes a specific color mapping.
*/
public ColorFilter remove( Color from ) {
if( colorMap != null )
colorMap.remove( from );
if( darkColorMap != null )
darkColorMap.remove( from );
return this;
}
/**
* Removes all color mappings.
*
* @since 1.2
*/
public ColorFilter removeAll() {
colorMap = null;
darkColorMap = null;
return this;
}
private void ensureColorMap() {
if( colorMap == null )
colorMap = new HashMap<>();
}
private void ensureDarkColorMap() {
if( darkColorMap == null )
darkColorMap = new HashMap<>( colorMap );
} }
public Color filter( Color color ) { public Color filter( Color color ) {
Color newColor = color2colorMap.get( color ); // apply mappings
if( newColor != null ) color = applyMappings( color );
return newColor;
String colorKey = rgb2keyMap.get( color.getRGB() & 0xffffff ); // apply mapper function
if( colorKey == null ) if( mapper != null )
return color; color = mapper.apply( color );
newColor = UIManager.getColor( colorKey ); return color;
if( newColor == null )
return color;
return (newColor.getAlpha() != color.getAlpha())
? new Color( (newColor.getRGB() & 0x00ffffff) | (color.getRGB() & 0xff000000) )
: newColor;
}; };
private Color applyMappings( Color color ) {
if( colorMap != null ) {
Map<Color, Color> map = (darkColorMap != null && isDarkLaf()) ? darkColorMap : colorMap;
Color newColor = map.get( color );
if( newColor != null )
return newColor;
}
if( rgb2keyMap != null ) {
// RGB is mapped to a key in UI defaults, which contains the real color.
// IntelliJ themes define such theme specific icon colors in .theme.json files.
String colorKey = rgb2keyMap.get( color.getRGB() & 0xffffff );
if( colorKey == null )
return color;
Color newColor = UIManager.getColor( colorKey );
if( newColor == null )
return color;
// preserve alpha of original color
return (newColor.getAlpha() != color.getAlpha())
? new Color( (newColor.getRGB() & 0x00ffffff) | (color.getRGB() & 0xff000000) )
: newColor;
}
return color;
}
/**
* Creates a color modifying function that uses {@link RGBImageFilter#filterRGB(int, int, int)}.
* Can be set to a {@link ColorFilter} using {@link ColorFilter#setMapper(Function)}.
*
* @see GrayFilter
* @since 1.2
*/
public static Function<Color, Color> createRGBImageFilterFunction( RGBImageFilter rgbImageFilter ) {
return color -> {
int oldRGB = color.getRGB();
int newRGB = rgbImageFilter.filterRGB( 0, 0, oldRGB );
return (newRGB != oldRGB) ? new Color( newRGB, true ) : color;
};
}
} }
//---- class GraphicsFilter ----------------------------------------------- //---- class GraphicsFilter -----------------------------------------------
@@ -456,11 +768,15 @@ public class FlatSVGIcon
extends Graphics2DProxy extends Graphics2DProxy
{ {
private final ColorFilter colorFilter; private final ColorFilter colorFilter;
private final ColorFilter globalColorFilter;
private final RGBImageFilter grayFilter; private final RGBImageFilter grayFilter;
public GraphicsFilter( Graphics2D delegate, ColorFilter colorFilter, RGBImageFilter grayFilter ) { GraphicsFilter( Graphics2D delegate, ColorFilter colorFilter,
ColorFilter globalColorFilter, RGBImageFilter grayFilter )
{
super( delegate ); super( delegate );
this.colorFilter = colorFilter; this.colorFilter = colorFilter;
this.globalColorFilter = globalColorFilter;
this.grayFilter = grayFilter; this.grayFilter = grayFilter;
} }
@@ -477,8 +793,14 @@ public class FlatSVGIcon
} }
private Color filterColor( Color color ) { private Color filterColor( Color color ) {
if( colorFilter != null ) if( colorFilter != null ) {
color = colorFilter.filter( color ); Color newColor = colorFilter.filter( color );
color = (newColor != color)
? newColor
: globalColorFilter.filter( color );
} else
color = globalColorFilter.filter( color );
if( grayFilter != null ) { if( grayFilter != null ) {
int oldRGB = color.getRGB(); int oldRGB = color.getRGB();
int newRGB = grayFilter.filterRGB( 0, 0, oldRGB ); int newRGB = grayFilter.filterRGB( 0, 0, oldRGB );

View File

@@ -16,6 +16,7 @@
package com.formdev.flatlaf.extras; package com.formdev.flatlaf.extras;
import java.awt.Dimension;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Image; import java.awt.Image;
import java.awt.RenderingHints; import java.awt.RenderingHints;
@@ -23,8 +24,11 @@ import java.awt.image.BufferedImage;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.List; import java.util.List;
import javax.swing.JWindow; import javax.swing.JWindow;
import com.formdev.flatlaf.util.MultiResolutionImageSupport;
import com.formdev.flatlaf.util.SystemInfo;
import com.kitfox.svg.SVGCache; import com.kitfox.svg.SVGCache;
import com.kitfox.svg.SVGDiagram; import com.kitfox.svg.SVGDiagram;
import com.kitfox.svg.SVGException; import com.kitfox.svg.SVGException;
@@ -40,22 +44,51 @@ public class FlatSVGUtils
* Creates from the given SVG a list of icon images with different sizes that * Creates from the given SVG a list of icon images with different sizes that
* can be used for windows headers. The SVG should have a size of 16x16, * can be used for windows headers. The SVG should have a size of 16x16,
* otherwise it is scaled. * otherwise it is scaled.
* <p>
* If running on Windows in Java 9 or later and multi-resolution image support is available,
* then a single multi-resolution image is returned that creates images on demand
* for requested sizes from SVG.
* This has the advantage that only images for used sizes are created.
* Also if unusual sizes are requested (e.g. 18x18), then they are created from SVG.
* *
* @param svgName the name of the SVG resource (a '/'-separated path) * @param svgName the name of the SVG resource (a '/'-separated path)
* @return list of icon images with different sizes (16x16, 24x24, 32x32, 48x48 and 64x64) * @return list of icon images with different sizes (16x16, 20x20, 24x24, 28x28, 32x32, 48x48 and 64x64)
* @throws RuntimeException if failed to load or render SVG file * @throws RuntimeException if failed to load or render SVG file
* @see JWindow#setIconImages(List) * @see JWindow#setIconImages(List)
*/ */
public static List<Image> createWindowIconImages( String svgName ) { public static List<Image> createWindowIconImages( String svgName ) {
SVGDiagram diagram = loadSVG( svgName ); SVGDiagram diagram = loadSVG( svgName );
return Arrays.asList( if( SystemInfo.isWindows && MultiResolutionImageSupport.isAvailable() ) {
svg2image( diagram, 16, 16 ), // use a multi-resolution image that creates images on demand for requested sizes
svg2image( diagram, 24, 24 ), return Collections.singletonList( MultiResolutionImageSupport.create( 0,
svg2image( diagram, 32, 32 ), new Dimension[] {
svg2image( diagram, 48, 48 ), // Listing all these sizes here is actually not necessary because
svg2image( diagram, 64, 64 ) // any size is created on demand when
); // MultiResolutionImage.getResolutionVariant(double destImageWidth, double destImageHeight)
// is invoked.
// This sizes are only used by MultiResolutionImage.getResolutionVariants().
new Dimension( 16, 16 ), // 100%
new Dimension( 20, 20 ), // 125%
new Dimension( 24, 24 ), // 150%
new Dimension( 28, 28 ), // 175%
new Dimension( 32, 32 ), // 200%
new Dimension( 48, 48 ), // 300%
new Dimension( 64, 64 ), // 400%
}, dim -> {
return svg2image( diagram, dim.width, dim.height );
} ) );
} else {
return Arrays.asList(
svg2image( diagram, 16, 16 ), // 100%
svg2image( diagram, 20, 20 ), // 125%
svg2image( diagram, 24, 24 ), // 150%
svg2image( diagram, 28, 28 ), // 175%
svg2image( diagram, 32, 32 ), // 200%
svg2image( diagram, 48, 48 ), // 300%
svg2image( diagram, 64, 64 ) // 400%
);
}
} }
/** /**

View File

@@ -30,7 +30,7 @@ public class FlatButton
implements FlatComponentExtension implements FlatComponentExtension
{ {
// NOTE: enum names must be equal to allowed strings // NOTE: enum names must be equal to allowed strings
public enum ButtonType { none, square, roundRect, tab, help, toolBarButton }; public enum ButtonType { none, square, roundRect, tab, help, toolBarButton, borderless }
/** /**
* Returns type of a button. * Returns type of a button.

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.extras.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

@@ -88,6 +88,11 @@ ComboBox.buttonPressedArrowColor = ComboBox.buttonArrowColor
Component.custom.borderColor = null Component.custom.borderColor = null
#---- HelpButton ----
DesktopIcon.background = Desktop.background
#---- HelpButton ---- #---- HelpButton ----
HelpButton.disabledBackground = HelpButton.background HelpButton.disabledBackground = HelpButton.background

View File

@@ -86,6 +86,8 @@ Name | Class
[Dracula Contrast (Material)](https://github.com/mallowigi/material-theme-ui-lite) | `com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatDraculaContrastIJTheme` [Dracula Contrast (Material)](https://github.com/mallowigi/material-theme-ui-lite) | `com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatDraculaContrastIJTheme`
[GitHub (Material)](https://github.com/mallowigi/material-theme-ui-lite) | `com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatGitHubIJTheme` [GitHub (Material)](https://github.com/mallowigi/material-theme-ui-lite) | `com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatGitHubIJTheme`
[GitHub Contrast (Material)](https://github.com/mallowigi/material-theme-ui-lite) | `com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatGitHubContrastIJTheme` [GitHub Contrast (Material)](https://github.com/mallowigi/material-theme-ui-lite) | `com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatGitHubContrastIJTheme`
[GitHub Dark (Material)](https://github.com/mallowigi/material-theme-ui-lite) | `com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatGitHubDarkIJTheme`
[GitHub Dark Contrast (Material)](https://github.com/mallowigi/material-theme-ui-lite) | `com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatGitHubDarkContrastIJTheme`
[Light Owl (Material)](https://github.com/mallowigi/material-theme-ui-lite) | `com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatLightOwlIJTheme` [Light Owl (Material)](https://github.com/mallowigi/material-theme-ui-lite) | `com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatLightOwlIJTheme`
[Light Owl Contrast (Material)](https://github.com/mallowigi/material-theme-ui-lite) | `com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatLightOwlContrastIJTheme` [Light Owl Contrast (Material)](https://github.com/mallowigi/material-theme-ui-lite) | `com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatLightOwlContrastIJTheme`
[Material Darker (Material)](https://github.com/mallowigi/material-theme-ui-lite) | `com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatMaterialDarkerIJTheme` [Material Darker (Material)](https://github.com/mallowigi/material-theme-ui-lite) | `com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatMaterialDarkerIJTheme`

View File

@@ -33,17 +33,6 @@ java {
withJavadocJar() withJavadocJar()
} }
tasks {
javadoc {
options {
this as StandardJavadocDocletOptions
use( true )
tags = listOf( "uiDefault", "clientProperty" )
}
isFailOnError = false
}
}
flatlafPublish { flatlafPublish {
artifactId = "flatlaf-intellij-themes" artifactId = "flatlaf-intellij-themes"
name = "FlatLaf IntelliJ Themes Pack" name = "FlatLaf IntelliJ Themes Pack"

View File

@@ -68,6 +68,8 @@ public class FlatAllIJThemes
new FlatIJLookAndFeelInfo( "Dracula Contrast (Material)", "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatDraculaContrastIJTheme", true ), new FlatIJLookAndFeelInfo( "Dracula Contrast (Material)", "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatDraculaContrastIJTheme", true ),
new FlatIJLookAndFeelInfo( "GitHub (Material)", "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatGitHubIJTheme", false ), new FlatIJLookAndFeelInfo( "GitHub (Material)", "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatGitHubIJTheme", false ),
new FlatIJLookAndFeelInfo( "GitHub Contrast (Material)", "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatGitHubContrastIJTheme", false ), new FlatIJLookAndFeelInfo( "GitHub Contrast (Material)", "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatGitHubContrastIJTheme", false ),
new FlatIJLookAndFeelInfo( "GitHub Dark (Material)", "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatGitHubDarkIJTheme", true ),
new FlatIJLookAndFeelInfo( "GitHub Dark Contrast (Material)", "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatGitHubDarkContrastIJTheme", true ),
new FlatIJLookAndFeelInfo( "Light Owl (Material)", "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatLightOwlIJTheme", false ), new FlatIJLookAndFeelInfo( "Light Owl (Material)", "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatLightOwlIJTheme", false ),
new FlatIJLookAndFeelInfo( "Light Owl Contrast (Material)", "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatLightOwlContrastIJTheme", false ), new FlatIJLookAndFeelInfo( "Light Owl Contrast (Material)", "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatLightOwlContrastIJTheme", false ),
new FlatIJLookAndFeelInfo( "Material Darker (Material)", "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatMaterialDarkerIJTheme", true ), new FlatIJLookAndFeelInfo( "Material Darker (Material)", "com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatMaterialDarkerIJTheme", true ),

View File

@@ -31,14 +31,22 @@ public class FlatArcDarkIJTheme
{ {
public static final String NAME = "Arc Dark"; public static final String NAME = "Arc Dark";
public static boolean install() { public static boolean setup() {
try { try {
return install( new FlatArcDarkIJTheme() ); return setup( new FlatArcDarkIJTheme() );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
return false; return false;
} }
} }
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
public static void installLafInfo() { public static void installLafInfo() {
installLafInfo( NAME, FlatArcDarkIJTheme.class ); installLafInfo( NAME, FlatArcDarkIJTheme.class );
} }

View File

@@ -31,14 +31,22 @@ public class FlatArcDarkOrangeIJTheme
{ {
public static final String NAME = "Arc Dark - Orange"; public static final String NAME = "Arc Dark - Orange";
public static boolean install() { public static boolean setup() {
try { try {
return install( new FlatArcDarkOrangeIJTheme() ); return setup( new FlatArcDarkOrangeIJTheme() );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
return false; return false;
} }
} }
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
public static void installLafInfo() { public static void installLafInfo() {
installLafInfo( NAME, FlatArcDarkOrangeIJTheme.class ); installLafInfo( NAME, FlatArcDarkOrangeIJTheme.class );
} }

View File

@@ -31,14 +31,22 @@ public class FlatArcIJTheme
{ {
public static final String NAME = "Arc"; public static final String NAME = "Arc";
public static boolean install() { public static boolean setup() {
try { try {
return install( new FlatArcIJTheme() ); return setup( new FlatArcIJTheme() );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
return false; return false;
} }
} }
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
public static void installLafInfo() { public static void installLafInfo() {
installLafInfo( NAME, FlatArcIJTheme.class ); installLafInfo( NAME, FlatArcIJTheme.class );
} }

View File

@@ -31,14 +31,22 @@ public class FlatArcOrangeIJTheme
{ {
public static final String NAME = "Arc - Orange"; public static final String NAME = "Arc - Orange";
public static boolean install() { public static boolean setup() {
try { try {
return install( new FlatArcOrangeIJTheme() ); return setup( new FlatArcOrangeIJTheme() );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
return false; return false;
} }
} }
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
public static void installLafInfo() { public static void installLafInfo() {
installLafInfo( NAME, FlatArcOrangeIJTheme.class ); installLafInfo( NAME, FlatArcOrangeIJTheme.class );
} }

View File

@@ -31,14 +31,22 @@ public class FlatCarbonIJTheme
{ {
public static final String NAME = "Carbon"; public static final String NAME = "Carbon";
public static boolean install() { public static boolean setup() {
try { try {
return install( new FlatCarbonIJTheme() ); return setup( new FlatCarbonIJTheme() );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
return false; return false;
} }
} }
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
public static void installLafInfo() { public static void installLafInfo() {
installLafInfo( NAME, FlatCarbonIJTheme.class ); installLafInfo( NAME, FlatCarbonIJTheme.class );
} }

View File

@@ -31,14 +31,22 @@ public class FlatCobalt2IJTheme
{ {
public static final String NAME = "Cobalt 2"; public static final String NAME = "Cobalt 2";
public static boolean install() { public static boolean setup() {
try { try {
return install( new FlatCobalt2IJTheme() ); return setup( new FlatCobalt2IJTheme() );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
return false; return false;
} }
} }
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
public static void installLafInfo() { public static void installLafInfo() {
installLafInfo( NAME, FlatCobalt2IJTheme.class ); installLafInfo( NAME, FlatCobalt2IJTheme.class );
} }

View File

@@ -31,14 +31,22 @@ public class FlatCyanLightIJTheme
{ {
public static final String NAME = "Cyan light"; public static final String NAME = "Cyan light";
public static boolean install() { public static boolean setup() {
try { try {
return install( new FlatCyanLightIJTheme() ); return setup( new FlatCyanLightIJTheme() );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
return false; return false;
} }
} }
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
public static void installLafInfo() { public static void installLafInfo() {
installLafInfo( NAME, FlatCyanLightIJTheme.class ); installLafInfo( NAME, FlatCyanLightIJTheme.class );
} }

View File

@@ -31,14 +31,22 @@ public class FlatDarkFlatIJTheme
{ {
public static final String NAME = "Dark Flat"; public static final String NAME = "Dark Flat";
public static boolean install() { public static boolean setup() {
try { try {
return install( new FlatDarkFlatIJTheme() ); return setup( new FlatDarkFlatIJTheme() );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
return false; return false;
} }
} }
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
public static void installLafInfo() { public static void installLafInfo() {
installLafInfo( NAME, FlatDarkFlatIJTheme.class ); installLafInfo( NAME, FlatDarkFlatIJTheme.class );
} }

View File

@@ -31,14 +31,22 @@ public class FlatDarkPurpleIJTheme
{ {
public static final String NAME = "Dark purple"; public static final String NAME = "Dark purple";
public static boolean install() { public static boolean setup() {
try { try {
return install( new FlatDarkPurpleIJTheme() ); return setup( new FlatDarkPurpleIJTheme() );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
return false; return false;
} }
} }
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
public static void installLafInfo() { public static void installLafInfo() {
installLafInfo( NAME, FlatDarkPurpleIJTheme.class ); installLafInfo( NAME, FlatDarkPurpleIJTheme.class );
} }

View File

@@ -31,14 +31,22 @@ public class FlatDraculaIJTheme
{ {
public static final String NAME = "Dracula"; public static final String NAME = "Dracula";
public static boolean install() { public static boolean setup() {
try { try {
return install( new FlatDraculaIJTheme() ); return setup( new FlatDraculaIJTheme() );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
return false; return false;
} }
} }
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
public static void installLafInfo() { public static void installLafInfo() {
installLafInfo( NAME, FlatDraculaIJTheme.class ); installLafInfo( NAME, FlatDraculaIJTheme.class );
} }

View File

@@ -31,14 +31,22 @@ public class FlatGradiantoDarkFuchsiaIJTheme
{ {
public static final String NAME = "Gradianto Dark Fuchsia"; public static final String NAME = "Gradianto Dark Fuchsia";
public static boolean install() { public static boolean setup() {
try { try {
return install( new FlatGradiantoDarkFuchsiaIJTheme() ); return setup( new FlatGradiantoDarkFuchsiaIJTheme() );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
return false; return false;
} }
} }
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
public static void installLafInfo() { public static void installLafInfo() {
installLafInfo( NAME, FlatGradiantoDarkFuchsiaIJTheme.class ); installLafInfo( NAME, FlatGradiantoDarkFuchsiaIJTheme.class );
} }

View File

@@ -31,14 +31,22 @@ public class FlatGradiantoDeepOceanIJTheme
{ {
public static final String NAME = "Gradianto Deep Ocean"; public static final String NAME = "Gradianto Deep Ocean";
public static boolean install() { public static boolean setup() {
try { try {
return install( new FlatGradiantoDeepOceanIJTheme() ); return setup( new FlatGradiantoDeepOceanIJTheme() );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
return false; return false;
} }
} }
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
public static void installLafInfo() { public static void installLafInfo() {
installLafInfo( NAME, FlatGradiantoDeepOceanIJTheme.class ); installLafInfo( NAME, FlatGradiantoDeepOceanIJTheme.class );
} }

View File

@@ -31,14 +31,22 @@ public class FlatGradiantoMidnightBlueIJTheme
{ {
public static final String NAME = "Gradianto Midnight Blue"; public static final String NAME = "Gradianto Midnight Blue";
public static boolean install() { public static boolean setup() {
try { try {
return install( new FlatGradiantoMidnightBlueIJTheme() ); return setup( new FlatGradiantoMidnightBlueIJTheme() );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
return false; return false;
} }
} }
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
public static void installLafInfo() { public static void installLafInfo() {
installLafInfo( NAME, FlatGradiantoMidnightBlueIJTheme.class ); installLafInfo( NAME, FlatGradiantoMidnightBlueIJTheme.class );
} }

View File

@@ -31,14 +31,22 @@ public class FlatGradiantoNatureGreenIJTheme
{ {
public static final String NAME = "Gradianto Nature Green"; public static final String NAME = "Gradianto Nature Green";
public static boolean install() { public static boolean setup() {
try { try {
return install( new FlatGradiantoNatureGreenIJTheme() ); return setup( new FlatGradiantoNatureGreenIJTheme() );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
return false; return false;
} }
} }
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
public static void installLafInfo() { public static void installLafInfo() {
installLafInfo( NAME, FlatGradiantoNatureGreenIJTheme.class ); installLafInfo( NAME, FlatGradiantoNatureGreenIJTheme.class );
} }

View File

@@ -31,14 +31,22 @@ public class FlatGrayIJTheme
{ {
public static final String NAME = "Gray"; public static final String NAME = "Gray";
public static boolean install() { public static boolean setup() {
try { try {
return install( new FlatGrayIJTheme() ); return setup( new FlatGrayIJTheme() );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
return false; return false;
} }
} }
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
public static void installLafInfo() { public static void installLafInfo() {
installLafInfo( NAME, FlatGrayIJTheme.class ); installLafInfo( NAME, FlatGrayIJTheme.class );
} }

View File

@@ -31,14 +31,22 @@ public class FlatGruvboxDarkHardIJTheme
{ {
public static final String NAME = "Gruvbox Dark Hard"; public static final String NAME = "Gruvbox Dark Hard";
public static boolean install() { public static boolean setup() {
try { try {
return install( new FlatGruvboxDarkHardIJTheme() ); return setup( new FlatGruvboxDarkHardIJTheme() );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
return false; return false;
} }
} }
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
public static void installLafInfo() { public static void installLafInfo() {
installLafInfo( NAME, FlatGruvboxDarkHardIJTheme.class ); installLafInfo( NAME, FlatGruvboxDarkHardIJTheme.class );
} }

View File

@@ -31,14 +31,22 @@ public class FlatGruvboxDarkMediumIJTheme
{ {
public static final String NAME = "Gruvbox Dark Medium"; public static final String NAME = "Gruvbox Dark Medium";
public static boolean install() { public static boolean setup() {
try { try {
return install( new FlatGruvboxDarkMediumIJTheme() ); return setup( new FlatGruvboxDarkMediumIJTheme() );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
return false; return false;
} }
} }
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
public static void installLafInfo() { public static void installLafInfo() {
installLafInfo( NAME, FlatGruvboxDarkMediumIJTheme.class ); installLafInfo( NAME, FlatGruvboxDarkMediumIJTheme.class );
} }

View File

@@ -31,14 +31,22 @@ public class FlatGruvboxDarkSoftIJTheme
{ {
public static final String NAME = "Gruvbox Dark Soft"; public static final String NAME = "Gruvbox Dark Soft";
public static boolean install() { public static boolean setup() {
try { try {
return install( new FlatGruvboxDarkSoftIJTheme() ); return setup( new FlatGruvboxDarkSoftIJTheme() );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
return false; return false;
} }
} }
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
public static void installLafInfo() { public static void installLafInfo() {
installLafInfo( NAME, FlatGruvboxDarkSoftIJTheme.class ); installLafInfo( NAME, FlatGruvboxDarkSoftIJTheme.class );
} }

View File

@@ -31,14 +31,22 @@ public class FlatHiberbeeDarkIJTheme
{ {
public static final String NAME = "Hiberbee Dark"; public static final String NAME = "Hiberbee Dark";
public static boolean install() { public static boolean setup() {
try { try {
return install( new FlatHiberbeeDarkIJTheme() ); return setup( new FlatHiberbeeDarkIJTheme() );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
return false; return false;
} }
} }
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
public static void installLafInfo() { public static void installLafInfo() {
installLafInfo( NAME, FlatHiberbeeDarkIJTheme.class ); installLafInfo( NAME, FlatHiberbeeDarkIJTheme.class );
} }

View File

@@ -31,14 +31,22 @@ public class FlatHighContrastIJTheme
{ {
public static final String NAME = "High contrast"; public static final String NAME = "High contrast";
public static boolean install() { public static boolean setup() {
try { try {
return install( new FlatHighContrastIJTheme() ); return setup( new FlatHighContrastIJTheme() );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
return false; return false;
} }
} }
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
public static void installLafInfo() { public static void installLafInfo() {
installLafInfo( NAME, FlatHighContrastIJTheme.class ); installLafInfo( NAME, FlatHighContrastIJTheme.class );
} }

View File

@@ -31,14 +31,22 @@ public class FlatLightFlatIJTheme
{ {
public static final String NAME = "Light Flat"; public static final String NAME = "Light Flat";
public static boolean install() { public static boolean setup() {
try { try {
return install( new FlatLightFlatIJTheme() ); return setup( new FlatLightFlatIJTheme() );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
return false; return false;
} }
} }
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
public static void installLafInfo() { public static void installLafInfo() {
installLafInfo( NAME, FlatLightFlatIJTheme.class ); installLafInfo( NAME, FlatLightFlatIJTheme.class );
} }

View File

@@ -31,14 +31,22 @@ public class FlatMaterialDesignDarkIJTheme
{ {
public static final String NAME = "Material Design Dark"; public static final String NAME = "Material Design Dark";
public static boolean install() { public static boolean setup() {
try { try {
return install( new FlatMaterialDesignDarkIJTheme() ); return setup( new FlatMaterialDesignDarkIJTheme() );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
return false; return false;
} }
} }
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
public static void installLafInfo() { public static void installLafInfo() {
installLafInfo( NAME, FlatMaterialDesignDarkIJTheme.class ); installLafInfo( NAME, FlatMaterialDesignDarkIJTheme.class );
} }

View File

@@ -31,14 +31,22 @@ public class FlatMonocaiIJTheme
{ {
public static final String NAME = "Monocai"; public static final String NAME = "Monocai";
public static boolean install() { public static boolean setup() {
try { try {
return install( new FlatMonocaiIJTheme() ); return setup( new FlatMonocaiIJTheme() );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
return false; return false;
} }
} }
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
public static void installLafInfo() { public static void installLafInfo() {
installLafInfo( NAME, FlatMonocaiIJTheme.class ); installLafInfo( NAME, FlatMonocaiIJTheme.class );
} }

View File

@@ -31,14 +31,22 @@ public class FlatNordIJTheme
{ {
public static final String NAME = "Nord"; public static final String NAME = "Nord";
public static boolean install() { public static boolean setup() {
try { try {
return install( new FlatNordIJTheme() ); return setup( new FlatNordIJTheme() );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
return false; return false;
} }
} }
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
public static void installLafInfo() { public static void installLafInfo() {
installLafInfo( NAME, FlatNordIJTheme.class ); installLafInfo( NAME, FlatNordIJTheme.class );
} }

View File

@@ -31,14 +31,22 @@ public class FlatOneDarkIJTheme
{ {
public static final String NAME = "One Dark"; public static final String NAME = "One Dark";
public static boolean install() { public static boolean setup() {
try { try {
return install( new FlatOneDarkIJTheme() ); return setup( new FlatOneDarkIJTheme() );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
return false; return false;
} }
} }
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
public static void installLafInfo() { public static void installLafInfo() {
installLafInfo( NAME, FlatOneDarkIJTheme.class ); installLafInfo( NAME, FlatOneDarkIJTheme.class );
} }

View File

@@ -31,14 +31,22 @@ public class FlatSolarizedDarkIJTheme
{ {
public static final String NAME = "Solarized Dark"; public static final String NAME = "Solarized Dark";
public static boolean install() { public static boolean setup() {
try { try {
return install( new FlatSolarizedDarkIJTheme() ); return setup( new FlatSolarizedDarkIJTheme() );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
return false; return false;
} }
} }
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
public static void installLafInfo() { public static void installLafInfo() {
installLafInfo( NAME, FlatSolarizedDarkIJTheme.class ); installLafInfo( NAME, FlatSolarizedDarkIJTheme.class );
} }

View File

@@ -31,14 +31,22 @@ public class FlatSolarizedLightIJTheme
{ {
public static final String NAME = "Solarized Light"; public static final String NAME = "Solarized Light";
public static boolean install() { public static boolean setup() {
try { try {
return install( new FlatSolarizedLightIJTheme() ); return setup( new FlatSolarizedLightIJTheme() );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
return false; return false;
} }
} }
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
public static void installLafInfo() { public static void installLafInfo() {
installLafInfo( NAME, FlatSolarizedLightIJTheme.class ); installLafInfo( NAME, FlatSolarizedLightIJTheme.class );
} }

View File

@@ -31,14 +31,22 @@ public class FlatSpacegrayIJTheme
{ {
public static final String NAME = "Spacegray"; public static final String NAME = "Spacegray";
public static boolean install() { public static boolean setup() {
try { try {
return install( new FlatSpacegrayIJTheme() ); return setup( new FlatSpacegrayIJTheme() );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
return false; return false;
} }
} }
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
public static void installLafInfo() { public static void installLafInfo() {
installLafInfo( NAME, FlatSpacegrayIJTheme.class ); installLafInfo( NAME, FlatSpacegrayIJTheme.class );
} }

View File

@@ -31,14 +31,22 @@ public class FlatVuesionIJTheme
{ {
public static final String NAME = "Vuesion"; public static final String NAME = "Vuesion";
public static boolean install() { public static boolean setup() {
try { try {
return install( new FlatVuesionIJTheme() ); return setup( new FlatVuesionIJTheme() );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
return false; return false;
} }
} }
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
public static void installLafInfo() { public static void installLafInfo() {
installLafInfo( NAME, FlatVuesionIJTheme.class ); installLafInfo( NAME, FlatVuesionIJTheme.class );
} }

View File

@@ -31,14 +31,22 @@ public class FlatArcDarkContrastIJTheme
{ {
public static final String NAME = "Arc Dark Contrast (Material)"; public static final String NAME = "Arc Dark Contrast (Material)";
public static boolean install() { public static boolean setup() {
try { try {
return install( new FlatArcDarkContrastIJTheme() ); return setup( new FlatArcDarkContrastIJTheme() );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
return false; return false;
} }
} }
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
public static void installLafInfo() { public static void installLafInfo() {
installLafInfo( NAME, FlatArcDarkContrastIJTheme.class ); installLafInfo( NAME, FlatArcDarkContrastIJTheme.class );
} }

View File

@@ -31,14 +31,22 @@ public class FlatArcDarkIJTheme
{ {
public static final String NAME = "Arc Dark (Material)"; public static final String NAME = "Arc Dark (Material)";
public static boolean install() { public static boolean setup() {
try { try {
return install( new FlatArcDarkIJTheme() ); return setup( new FlatArcDarkIJTheme() );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
return false; return false;
} }
} }
/**
* @deprecated use {@link #setup()} instead; this method will be removed in a future version
*/
@Deprecated
public static boolean install() {
return setup();
}
public static void installLafInfo() { public static void installLafInfo() {
installLafInfo( NAME, FlatArcDarkIJTheme.class ); installLafInfo( NAME, FlatArcDarkIJTheme.class );
} }

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